genoutput.c revision 90075
118334Speter/* Generate code from to output assembler insns as recognized from rtl. 290075Sobrien Copyright (C) 1987, 1988, 1992, 1994, 1995, 1997, 1998, 1999, 2000 390075Sobrien Free Software Foundation, Inc. 418334Speter 590075SobrienThis file is part of GCC. 618334Speter 790075SobrienGCC is free software; you can redistribute it and/or modify it under 890075Sobrienthe terms of the GNU General Public License as published by the Free 990075SobrienSoftware Foundation; either version 2, or (at your option) any later 1090075Sobrienversion. 1118334Speter 1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1490075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1590075Sobrienfor more details. 1618334Speter 1718334SpeterYou should have received a copy of the GNU General Public License 1890075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2090075Sobrien02111-1307, USA. */ 2118334Speter 2218334Speter 2318334Speter/* This program reads the machine description for the compiler target machine 2418334Speter and produces a file containing these things: 2518334Speter 2690075Sobrien 1. An array of `struct insn_data', which is indexed by insn code number, 2790075Sobrien which contains: 2818334Speter 2990075Sobrien a. `name' is the name for that pattern. Nameless patterns are 3090075Sobrien given a name. 3118334Speter 3290075Sobrien b. `output' hold either the output template, an array of output 3390075Sobrien templates, or an output function. 3418334Speter 3590075Sobrien c. `genfun' is the function to generate a body for that pattern, 3690075Sobrien given operands as arguments. 3718334Speter 3890075Sobrien d. `n_operands' is the number of distinct operands in the pattern 3990075Sobrien for that insn, 4018334Speter 4190075Sobrien e. `n_dups' is the number of match_dup's that appear in the insn's 4290075Sobrien pattern. This says how many elements of `recog_data.dup_loc' are 4390075Sobrien significant after an insn has been recognized. 4418334Speter 4590075Sobrien f. `n_alternatives' is the number of alternatives in the constraints 4690075Sobrien of each pattern. 4718334Speter 4890075Sobrien g. `output_format' tells what type of thing `output' is. 4918334Speter 5090075Sobrien h. `operand' is the base of an array of operand data for the insn. 5118334Speter 5290075Sobrien 2. An array of `struct insn_operand data', used by `operand' above. 5318334Speter 5490075Sobrien a. `predicate', an int-valued function, is the match_operand predicate 5590075Sobrien for this operand. 5618334Speter 5790075Sobrien b. `constraint' is the constraint for this operand. This exists 5890075Sobrien only if register constraints appear in match_operand rtx's. 5918334Speter 6090075Sobrien c. `address_p' indicates that the operand appears within ADDRESS 6190075Sobrien rtx's. This exists only if there are *no* register constraints 6290075Sobrien in the match_operand rtx's. 6318334Speter 6490075Sobrien d. `mode' is the machine mode that that operand is supposed to have. 6590075Sobrien 6690075Sobrien e. `strict_low', is nonzero for operands contained in a STRICT_LOW_PART. 6790075Sobrien 6890075Sobrien f. `eliminable', is nonzero for operands that are matched normally by 6990075Sobrien MATCH_OPERAND; it is zero for operands that should not be changed during 7090075Sobrien register elimination such as MATCH_OPERATORs. 7190075Sobrien 7290075Sobrien The code number of an insn is simply its position in the machine 7390075Sobrien description; code numbers are assigned sequentially to entries in 7490075Sobrien the description, starting with code number 0. 7590075Sobrien 7690075Sobrien Thus, the following entry in the machine description 7790075Sobrien 7818334Speter (define_insn "clrdf" 7918334Speter [(set (match_operand:DF 0 "general_operand" "") 8018334Speter (const_int 0))] 8118334Speter "" 8218334Speter "clrd %0") 8318334Speter 8490075Sobrien assuming it is the 25th entry present, would cause 8590075Sobrien insn_data[24].template to be "clrd %0", and 8690075Sobrien insn_data[24].n_operands to be 1. */ 8718334Speter 8818334Speter#include "hconfig.h" 8950397Sobrien#include "system.h" 9018334Speter#include "rtl.h" 9190075Sobrien#include "errors.h" 9290075Sobrien#include "gensupport.h" 9318334Speter 9490075Sobrien/* No instruction can have more operands than this. Sorry for this 9590075Sobrien arbitrary limit, but what machine will have an instruction with 9690075Sobrien this many operands? */ 9718334Speter 9818334Speter#define MAX_MAX_OPERANDS 40 9918334Speter 10090075Sobrienstatic int n_occurrences PARAMS ((int, const char *)); 10190075Sobrienstatic const char *strip_whitespace PARAMS ((const char *)); 10218334Speter 10318334Speter/* insns in the machine description are assigned sequential code numbers 10418334Speter that are used by insn-recog.c (produced by genrecog) to communicate 10518334Speter to insn-output.c (produced by this program). */ 10618334Speter 10718334Speterstatic int next_code_number; 10818334Speter 10918334Speter/* This counts all definitions in the md file, 11018334Speter for the sake of error messages. */ 11118334Speter 11218334Speterstatic int next_index_number; 11318334Speter 11490075Sobrien/* This counts all operands used in the md file. The first is null. */ 11590075Sobrien 11690075Sobrienstatic int next_operand_number = 1; 11790075Sobrien 11890075Sobrien/* Record in this chain all information about the operands we will output. */ 11990075Sobrien 12090075Sobrienstruct operand_data 12190075Sobrien{ 12290075Sobrien struct operand_data *next; 12390075Sobrien int index; 12490075Sobrien const char *predicate; 12590075Sobrien const char *constraint; 12690075Sobrien enum machine_mode mode; 12790075Sobrien unsigned char n_alternatives; 12890075Sobrien char address_p; 12990075Sobrien char strict_low; 13090075Sobrien char eliminable; 13190075Sobrien char seen; 13290075Sobrien}; 13390075Sobrien 13490075Sobrien/* Begin with a null operand at index 0. */ 13590075Sobrien 13690075Sobrienstatic struct operand_data null_operand = 13790075Sobrien{ 13890075Sobrien 0, 0, "", "", VOIDmode, 0, 0, 0, 0, 0 13990075Sobrien}; 14090075Sobrien 14190075Sobrienstatic struct operand_data *odata = &null_operand; 14290075Sobrienstatic struct operand_data **odata_end = &null_operand.next; 14390075Sobrien 14490075Sobrien/* Must match the constants in recog.h. */ 14590075Sobrien 14690075Sobrien#define INSN_OUTPUT_FORMAT_NONE 0 /* abort */ 14790075Sobrien#define INSN_OUTPUT_FORMAT_SINGLE 1 /* const char * */ 14890075Sobrien#define INSN_OUTPUT_FORMAT_MULTI 2 /* const char * const * */ 14990075Sobrien#define INSN_OUTPUT_FORMAT_FUNCTION 3 /* const char * (*)(...) */ 15090075Sobrien 15118334Speter/* Record in this chain all information that we will output, 15218334Speter associated with the code number of the insn. */ 15318334Speter 15418334Speterstruct data 15518334Speter{ 15690075Sobrien struct data *next; 15790075Sobrien const char *name; 15890075Sobrien const char *template; 15918334Speter int code_number; 16018334Speter int index_number; 16190075Sobrien int lineno; 16218334Speter int n_operands; /* Number of operands this insn recognizes */ 16318334Speter int n_dups; /* Number times match_dup appears in pattern */ 16418334Speter int n_alternatives; /* Number of alternatives in each constraint */ 16590075Sobrien int operand_number; /* Operand index in the big array. */ 16690075Sobrien int output_format; /* INSN_OUTPUT_FORMAT_*. */ 16790075Sobrien struct operand_data operand[MAX_MAX_OPERANDS]; 16818334Speter}; 16918334Speter 17090075Sobrien/* This variable points to the first link in the insn chain. */ 17118334Speter 17290075Sobrienstatic struct data *idata, **idata_end = &idata; 17318334Speter 17490075Sobrienstatic void output_prologue PARAMS ((void)); 17590075Sobrienstatic void output_predicate_decls PARAMS ((void)); 17690075Sobrienstatic void output_operand_data PARAMS ((void)); 17790075Sobrienstatic void output_insn_data PARAMS ((void)); 17890075Sobrienstatic void output_get_insn_name PARAMS ((void)); 17990075Sobrienstatic void scan_operands PARAMS ((struct data *, rtx, int, int)); 18090075Sobrienstatic int compare_operands PARAMS ((struct operand_data *, 18190075Sobrien struct operand_data *)); 18290075Sobrienstatic void place_operands PARAMS ((struct data *)); 18390075Sobrienstatic void process_template PARAMS ((struct data *, const char *)); 18490075Sobrienstatic void validate_insn_alternatives PARAMS ((struct data *)); 18590075Sobrienstatic void validate_insn_operands PARAMS ((struct data *)); 18690075Sobrienstatic void gen_insn PARAMS ((rtx, int)); 18790075Sobrienstatic void gen_peephole PARAMS ((rtx, int)); 18890075Sobrienstatic void gen_expand PARAMS ((rtx, int)); 18990075Sobrienstatic void gen_split PARAMS ((rtx, int)); 19050397Sobrien 19190075Sobrienconst char * 19290075Sobrienget_insn_name (index) 19352284Sobrien int index; 19452284Sobrien{ 19552284Sobrien static char buf[100]; 19652284Sobrien 19752284Sobrien struct data *i, *last_named = NULL; 19890075Sobrien for (i = idata; i ; i = i->next) 19952284Sobrien { 20052284Sobrien if (i->index_number == index) 20152284Sobrien return i->name; 20252284Sobrien if (i->name) 20352284Sobrien last_named = i; 20452284Sobrien } 20552284Sobrien 20652284Sobrien if (last_named) 20752284Sobrien sprintf(buf, "%s+%d", last_named->name, index - last_named->index_number); 20852284Sobrien else 20952284Sobrien sprintf(buf, "insn %d", index); 21052284Sobrien 21152284Sobrien return buf; 21252284Sobrien} 21352284Sobrien 21418334Speterstatic void 21518334Speteroutput_prologue () 21618334Speter{ 21718334Speter printf ("/* Generated automatically by the program `genoutput'\n\ 21890075Sobrien from the machine description file `md'. */\n\n"); 21918334Speter 22018334Speter printf ("#include \"config.h\"\n"); 22150397Sobrien printf ("#include \"system.h\"\n"); 22250397Sobrien printf ("#include \"flags.h\"\n"); 22390075Sobrien printf ("#include \"ggc.h\"\n"); 22418334Speter printf ("#include \"rtl.h\"\n"); 22590075Sobrien printf ("#include \"expr.h\"\n"); 22690075Sobrien printf ("#include \"insn-codes.h\"\n"); 22790075Sobrien printf ("#include \"tm_p.h\"\n"); 22890075Sobrien printf ("#include \"function.h\"\n"); 22918334Speter printf ("#include \"regs.h\"\n"); 23018334Speter printf ("#include \"hard-reg-set.h\"\n"); 23118334Speter printf ("#include \"real.h\"\n"); 23218334Speter printf ("#include \"insn-config.h\"\n\n"); 23318334Speter printf ("#include \"conditions.h\"\n"); 23418334Speter printf ("#include \"insn-attr.h\"\n\n"); 23518334Speter printf ("#include \"recog.h\"\n\n"); 23690075Sobrien printf ("#include \"toplev.h\"\n"); 23718334Speter printf ("#include \"output.h\"\n"); 23818334Speter} 23918334Speter 24090075Sobrien 24190075Sobrien/* We need to define all predicates used. Keep a list of those we 24290075Sobrien have defined so far. There normally aren't very many predicates 24390075Sobrien used, so a linked list should be fast enough. */ 24490075Sobrienstruct predicate { const char *name; struct predicate *next; }; 24590075Sobrien 24618334Speterstatic void 24790075Sobrienoutput_predicate_decls () 24818334Speter{ 24990075Sobrien struct predicate *predicates = 0; 25090075Sobrien struct operand_data *d; 25190075Sobrien struct predicate *p, *next; 25218334Speter 25390075Sobrien for (d = odata; d; d = d->next) 25490075Sobrien if (d->predicate && d->predicate[0]) 25590075Sobrien { 25690075Sobrien for (p = predicates; p; p = p->next) 25790075Sobrien if (strcmp (p->name, d->predicate) == 0) 25890075Sobrien break; 25990075Sobrien 26090075Sobrien if (p == 0) 26190075Sobrien { 26290075Sobrien printf ("extern int %s PARAMS ((rtx, enum machine_mode));\n", 26390075Sobrien d->predicate); 26490075Sobrien p = (struct predicate *) xmalloc (sizeof (struct predicate)); 26590075Sobrien p->name = d->predicate; 26690075Sobrien p->next = predicates; 26790075Sobrien predicates = p; 26890075Sobrien } 26990075Sobrien } 27090075Sobrien 27190075Sobrien printf ("\n\n"); 27290075Sobrien for (p = predicates; p; p = next) 27318334Speter { 27490075Sobrien next = p->next; 27590075Sobrien free (p); 27618334Speter } 27790075Sobrien} 27818334Speter 27990075Sobrienstatic void 28090075Sobrienoutput_operand_data () 28190075Sobrien{ 28290075Sobrien struct operand_data *d; 28390075Sobrien 28490075Sobrien printf ("\nstatic const struct insn_operand_data operand_data[] = \n{\n"); 28590075Sobrien 28690075Sobrien for (d = odata; d; d = d->next) 28718334Speter { 28890075Sobrien printf (" {\n"); 28918334Speter 29090075Sobrien printf (" %s,\n", 29190075Sobrien d->predicate && d->predicate[0] ? d->predicate : "0"); 29290075Sobrien 29390075Sobrien printf (" \"%s\",\n", d->constraint ? d->constraint : ""); 29490075Sobrien 29590075Sobrien printf (" %smode,\n", GET_MODE_NAME (d->mode)); 29690075Sobrien 29790075Sobrien printf (" %d,\n", d->strict_low); 29890075Sobrien 29990075Sobrien printf (" %d\n", d->eliminable); 30090075Sobrien 30190075Sobrien printf(" },\n"); 30218334Speter } 30390075Sobrien printf("};\n\n\n"); 30490075Sobrien} 30518334Speter 30690075Sobrienstatic void 30790075Sobrienoutput_insn_data () 30890075Sobrien{ 30990075Sobrien struct data *d; 31090075Sobrien int name_offset = 0; 31190075Sobrien int next_name_offset; 31290075Sobrien const char * last_name = 0; 31390075Sobrien const char * next_name = 0; 31490075Sobrien struct data *n; 31518334Speter 31690075Sobrien for (n = idata, next_name_offset = 1; n; n = n->next, next_name_offset++) 31790075Sobrien if (n->name) 31818334Speter { 31990075Sobrien next_name = n->name; 32090075Sobrien break; 32118334Speter } 32218334Speter 32390075Sobrien printf ("\nconst struct insn_data insn_data[] = \n{\n"); 32418334Speter 32590075Sobrien for (d = idata; d; d = d->next) 32690075Sobrien { 32790075Sobrien printf (" {\n"); 32818334Speter 32990075Sobrien if (d->name) 33018334Speter { 33190075Sobrien printf (" \"%s\",\n", d->name); 33290075Sobrien name_offset = 0; 33390075Sobrien last_name = d->name; 33490075Sobrien next_name = 0; 33590075Sobrien for (n = d->next, next_name_offset = 1; n; 33690075Sobrien n = n->next, next_name_offset++) 33718334Speter { 33890075Sobrien if (n->name) 33990075Sobrien { 34090075Sobrien next_name = n->name; 34190075Sobrien break; 34290075Sobrien } 34318334Speter } 34418334Speter } 34590075Sobrien else 34618334Speter { 34790075Sobrien name_offset++; 34890075Sobrien if (next_name && (last_name == 0 34990075Sobrien || name_offset > next_name_offset / 2)) 35090075Sobrien printf (" \"%s-%d\",\n", next_name, 35190075Sobrien next_name_offset - name_offset); 35290075Sobrien else 35390075Sobrien printf (" \"%s+%d\",\n", last_name, name_offset); 35418334Speter } 35518334Speter 35690075Sobrien switch (d->output_format) 35790075Sobrien { 35890075Sobrien case INSN_OUTPUT_FORMAT_NONE: 35990075Sobrien printf (" 0,\n"); 36090075Sobrien break; 36190075Sobrien case INSN_OUTPUT_FORMAT_SINGLE: 36218334Speter { 36390075Sobrien const char *p = d->template; 36490075Sobrien char prev = 0; 36590075Sobrien 36690075Sobrien printf (" \""); 36790075Sobrien while (*p) 36818334Speter { 36990075Sobrien if (*p == '\n' && prev != '\\') 37090075Sobrien printf ("\\n\\\n"); 37190075Sobrien else 37290075Sobrien putchar (*p); 37390075Sobrien prev = *p; 37490075Sobrien ++p; 37518334Speter } 37690075Sobrien printf ("\",\n"); 37718334Speter } 37890075Sobrien break; 37990075Sobrien case INSN_OUTPUT_FORMAT_MULTI: 38090075Sobrien case INSN_OUTPUT_FORMAT_FUNCTION: 38190075Sobrien printf (" (const PTR) output_%d,\n", d->code_number); 38290075Sobrien break; 38390075Sobrien default: 38490075Sobrien abort (); 38590075Sobrien } 38618334Speter 38790075Sobrien if (d->name && d->name[0] != '*') 38890075Sobrien printf (" (insn_gen_fn) gen_%s,\n", d->name); 38990075Sobrien else 39090075Sobrien printf (" 0,\n"); 39190075Sobrien 39290075Sobrien printf (" &operand_data[%d],\n", d->operand_number); 39390075Sobrien printf (" %d,\n", d->n_operands); 39490075Sobrien printf (" %d,\n", d->n_dups); 39590075Sobrien printf (" %d,\n", d->n_alternatives); 39690075Sobrien printf (" %d\n", d->output_format); 39790075Sobrien 39890075Sobrien printf(" },\n"); 39990075Sobrien } 40090075Sobrien printf ("};\n\n\n"); 40118334Speter} 40290075Sobrien 40390075Sobrienstatic void 40490075Sobrienoutput_get_insn_name () 40590075Sobrien{ 40690075Sobrien printf ("const char *\n"); 40790075Sobrien printf ("get_insn_name (code)\n"); 40890075Sobrien printf (" int code;\n"); 40990075Sobrien printf ("{\n"); 41090075Sobrien printf (" return insn_data[code].name;\n"); 41190075Sobrien printf ("}\n"); 41290075Sobrien} 41390075Sobrien 41418334Speter 41590075Sobrien/* Stores in max_opno the largest operand number present in `part', if 41690075Sobrien that is larger than the previous value of max_opno, and the rest of 41790075Sobrien the operand data into `d->operand[i]'. 41818334Speter 41918334Speter THIS_ADDRESS_P is nonzero if the containing rtx was an ADDRESS. 42018334Speter THIS_STRICT_LOW is nonzero if the containing rtx was a STRICT_LOW_PART. */ 42118334Speter 42218334Speterstatic int max_opno; 42318334Speterstatic int num_dups; 42418334Speter 42518334Speterstatic void 42690075Sobrienscan_operands (d, part, this_address_p, this_strict_low) 42790075Sobrien struct data *d; 42818334Speter rtx part; 42918334Speter int this_address_p; 43018334Speter int this_strict_low; 43118334Speter{ 43290075Sobrien int i, j; 43390075Sobrien const char *format_ptr; 43418334Speter int opno; 43518334Speter 43618334Speter if (part == 0) 43718334Speter return; 43818334Speter 43918334Speter switch (GET_CODE (part)) 44018334Speter { 44118334Speter case MATCH_OPERAND: 44218334Speter opno = XINT (part, 0); 44318334Speter if (opno > max_opno) 44418334Speter max_opno = opno; 44518334Speter if (max_opno >= MAX_MAX_OPERANDS) 44618334Speter { 44790075Sobrien message_with_line (d->lineno, 44890075Sobrien "maximum number of operands exceeded"); 44990075Sobrien have_error = 1; 45018334Speter return; 45118334Speter } 45290075Sobrien if (d->operand[opno].seen) 45318334Speter { 45490075Sobrien message_with_line (d->lineno, 45590075Sobrien "repeated operand number %d\n", opno); 45690075Sobrien have_error = 1; 45718334Speter } 45890075Sobrien 45990075Sobrien d->operand[opno].seen = 1; 46090075Sobrien d->operand[opno].mode = GET_MODE (part); 46190075Sobrien d->operand[opno].strict_low = this_strict_low; 46290075Sobrien d->operand[opno].predicate = XSTR (part, 1); 46390075Sobrien d->operand[opno].constraint = strip_whitespace (XSTR (part, 2)); 46490075Sobrien d->operand[opno].n_alternatives 46590075Sobrien = n_occurrences (',', d->operand[opno].constraint) + 1; 46690075Sobrien d->operand[opno].address_p = this_address_p; 46790075Sobrien d->operand[opno].eliminable = 1; 46818334Speter return; 46918334Speter 47018334Speter case MATCH_SCRATCH: 47118334Speter opno = XINT (part, 0); 47218334Speter if (opno > max_opno) 47318334Speter max_opno = opno; 47418334Speter if (max_opno >= MAX_MAX_OPERANDS) 47518334Speter { 47690075Sobrien message_with_line (d->lineno, 47790075Sobrien "maximum number of operands exceeded"); 47890075Sobrien have_error = 1; 47918334Speter return; 48018334Speter } 48190075Sobrien if (d->operand[opno].seen) 48218334Speter { 48390075Sobrien message_with_line (d->lineno, 48490075Sobrien "repeated operand number %d\n", opno); 48590075Sobrien have_error = 1; 48618334Speter } 48790075Sobrien 48890075Sobrien d->operand[opno].seen = 1; 48990075Sobrien d->operand[opno].mode = GET_MODE (part); 49090075Sobrien d->operand[opno].strict_low = 0; 49190075Sobrien d->operand[opno].predicate = "scratch_operand"; 49290075Sobrien d->operand[opno].constraint = strip_whitespace (XSTR (part, 1)); 49390075Sobrien d->operand[opno].n_alternatives 49490075Sobrien = n_occurrences (',', d->operand[opno].constraint) + 1; 49590075Sobrien d->operand[opno].address_p = 0; 49690075Sobrien d->operand[opno].eliminable = 0; 49718334Speter return; 49818334Speter 49918334Speter case MATCH_OPERATOR: 50018334Speter case MATCH_PARALLEL: 50118334Speter opno = XINT (part, 0); 50218334Speter if (opno > max_opno) 50318334Speter max_opno = opno; 50418334Speter if (max_opno >= MAX_MAX_OPERANDS) 50518334Speter { 50690075Sobrien message_with_line (d->lineno, 50790075Sobrien "maximum number of operands exceeded"); 50890075Sobrien have_error = 1; 50918334Speter return; 51018334Speter } 51190075Sobrien if (d->operand[opno].seen) 51290075Sobrien { 51390075Sobrien message_with_line (d->lineno, 51490075Sobrien "repeated operand number %d\n", opno); 51590075Sobrien have_error = 1; 51690075Sobrien } 51790075Sobrien 51890075Sobrien d->operand[opno].seen = 1; 51990075Sobrien d->operand[opno].mode = GET_MODE (part); 52090075Sobrien d->operand[opno].strict_low = 0; 52190075Sobrien d->operand[opno].predicate = XSTR (part, 1); 52290075Sobrien d->operand[opno].constraint = 0; 52390075Sobrien d->operand[opno].address_p = 0; 52490075Sobrien d->operand[opno].eliminable = 0; 52518334Speter for (i = 0; i < XVECLEN (part, 2); i++) 52690075Sobrien scan_operands (d, XVECEXP (part, 2, i), 0, 0); 52718334Speter return; 52818334Speter 52918334Speter case MATCH_DUP: 53018334Speter case MATCH_OP_DUP: 53118334Speter case MATCH_PAR_DUP: 53218334Speter ++num_dups; 53318334Speter return; 53418334Speter 53518334Speter case ADDRESS: 53690075Sobrien scan_operands (d, XEXP (part, 0), 1, 0); 53718334Speter return; 53818334Speter 53918334Speter case STRICT_LOW_PART: 54090075Sobrien scan_operands (d, XEXP (part, 0), 0, 1); 54118334Speter return; 54250397Sobrien 54350397Sobrien default: 54450397Sobrien break; 54518334Speter } 54618334Speter 54718334Speter format_ptr = GET_RTX_FORMAT (GET_CODE (part)); 54818334Speter 54918334Speter for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) 55018334Speter switch (*format_ptr++) 55118334Speter { 55218334Speter case 'e': 55350397Sobrien case 'u': 55490075Sobrien scan_operands (d, XEXP (part, i), 0, 0); 55518334Speter break; 55618334Speter case 'E': 55718334Speter if (XVEC (part, i) != NULL) 55818334Speter for (j = 0; j < XVECLEN (part, i); j++) 55990075Sobrien scan_operands (d, XVECEXP (part, i, j), 0, 0); 56018334Speter break; 56118334Speter } 56218334Speter} 56390075Sobrien 56490075Sobrien/* Compare two operands for content equality. */ 56590075Sobrien 56690075Sobrienstatic int 56790075Sobriencompare_operands (d0, d1) 56890075Sobrien struct operand_data *d0, *d1; 56990075Sobrien{ 57090075Sobrien const char *p0, *p1; 57190075Sobrien 57290075Sobrien p0 = d0->predicate; 57390075Sobrien if (!p0) 57490075Sobrien p0 = ""; 57590075Sobrien p1 = d1->predicate; 57690075Sobrien if (!p1) 57790075Sobrien p1 = ""; 57890075Sobrien if (strcmp (p0, p1) != 0) 57990075Sobrien return 0; 58090075Sobrien 58190075Sobrien p0 = d0->constraint; 58290075Sobrien if (!p0) 58390075Sobrien p0 = ""; 58490075Sobrien p1 = d1->constraint; 58590075Sobrien if (!p1) 58690075Sobrien p1 = ""; 58790075Sobrien if (strcmp (p0, p1) != 0) 58890075Sobrien return 0; 58990075Sobrien 59090075Sobrien if (d0->mode != d1->mode) 59190075Sobrien return 0; 59290075Sobrien 59390075Sobrien if (d0->strict_low != d1->strict_low) 59490075Sobrien return 0; 59590075Sobrien 59690075Sobrien if (d0->eliminable != d1->eliminable) 59790075Sobrien return 0; 59890075Sobrien 59990075Sobrien return 1; 60090075Sobrien} 60190075Sobrien 60290075Sobrien/* Scan the list of operands we've already committed to output and either 60390075Sobrien find a subsequence that is the same, or allocate a new one at the end. */ 60490075Sobrien 60590075Sobrienstatic void 60690075Sobrienplace_operands (d) 60790075Sobrien struct data *d; 60890075Sobrien{ 60990075Sobrien struct operand_data *od, *od2; 61090075Sobrien int i; 61190075Sobrien 61290075Sobrien if (d->n_operands == 0) 61390075Sobrien { 61490075Sobrien d->operand_number = 0; 61590075Sobrien return; 61690075Sobrien } 61790075Sobrien 61890075Sobrien /* Brute force substring search. */ 61990075Sobrien for (od = odata, i = 0; od; od = od->next, i = 0) 62090075Sobrien if (compare_operands (od, &d->operand[0])) 62190075Sobrien { 62290075Sobrien od2 = od->next; 62390075Sobrien i = 1; 62490075Sobrien while (1) 62590075Sobrien { 62690075Sobrien if (i == d->n_operands) 62790075Sobrien goto full_match; 62890075Sobrien if (od2 == NULL) 62990075Sobrien goto partial_match; 63090075Sobrien if (! compare_operands (od2, &d->operand[i])) 63190075Sobrien break; 63290075Sobrien ++i, od2 = od2->next; 63390075Sobrien } 63490075Sobrien } 63590075Sobrien 63690075Sobrien /* Either partial match at the end of the list, or no match. In either 63790075Sobrien case, we tack on what operands are remaining to the end of the list. */ 63890075Sobrien partial_match: 63990075Sobrien d->operand_number = next_operand_number - i; 64090075Sobrien for (; i < d->n_operands; ++i) 64190075Sobrien { 64290075Sobrien od2 = &d->operand[i]; 64390075Sobrien *odata_end = od2; 64490075Sobrien odata_end = &od2->next; 64590075Sobrien od2->index = next_operand_number++; 64690075Sobrien } 64790075Sobrien *odata_end = NULL; 64890075Sobrien return; 64990075Sobrien 65090075Sobrien full_match: 65190075Sobrien d->operand_number = od->index; 65290075Sobrien return; 65390075Sobrien} 65490075Sobrien 65518334Speter 65618334Speter/* Process an assembler template from a define_insn or a define_peephole. 65718334Speter It is either the assembler code template, a list of assembler code 65818334Speter templates, or C code to generate the assembler code template. */ 65918334Speter 66018334Speterstatic void 66118334Speterprocess_template (d, template) 66218334Speter struct data *d; 66390075Sobrien const char *template; 66418334Speter{ 66590075Sobrien const char *cp; 66690075Sobrien int i; 66718334Speter 66890075Sobrien /* Templates starting with * contain straight code to be run. */ 66990075Sobrien if (template[0] == '*') 67018334Speter { 67190075Sobrien d->template = 0; 67290075Sobrien d->output_format = INSN_OUTPUT_FORMAT_FUNCTION; 67318334Speter 67490075Sobrien printf ("\nstatic const char *output_%d PARAMS ((rtx *, rtx));\n", 67590075Sobrien d->code_number); 67690075Sobrien puts ("\nstatic const char *"); 67790075Sobrien printf ("output_%d (operands, insn)\n", d->code_number); 67890075Sobrien puts (" rtx *operands ATTRIBUTE_UNUSED;"); 67990075Sobrien puts (" rtx insn ATTRIBUTE_UNUSED;"); 68090075Sobrien puts ("{"); 68118334Speter 68290075Sobrien puts (template + 1); 68390075Sobrien puts ("}"); 68490075Sobrien } 68518334Speter 68618334Speter /* If the assembler code template starts with a @ it is a newline-separated 68790075Sobrien list of assembler code templates, one for each alternative. */ 68890075Sobrien else if (template[0] == '@') 68918334Speter { 69090075Sobrien d->template = 0; 69190075Sobrien d->output_format = INSN_OUTPUT_FORMAT_MULTI; 69218334Speter 69390075Sobrien printf ("\nstatic const char * const output_%d[] = {\n", d->code_number); 69418334Speter 69518334Speter for (i = 0, cp = &template[1]; *cp; ) 69618334Speter { 69718334Speter while (*cp == '\n' || *cp == ' ' || *cp== '\t') 69818334Speter cp++; 69918334Speter 70090075Sobrien printf (" \""); 70118334Speter while (*cp != '\n' && *cp != '\0') 70250397Sobrien { 70350397Sobrien putchar (*cp); 70450397Sobrien cp++; 70550397Sobrien } 70618334Speter 70718334Speter printf ("\",\n"); 70818334Speter i++; 70918334Speter } 71090075Sobrien if (i == 1) 71190075Sobrien message_with_line (d->lineno, 71290075Sobrien "'@' is redundant for output template with single alternative"); 71318334Speter if (i != d->n_alternatives) 71490075Sobrien { 71590075Sobrien message_with_line (d->lineno, 71690075Sobrien "wrong number of alternatives in the output template"); 71790075Sobrien have_error = 1; 71890075Sobrien } 71918334Speter 72090075Sobrien printf ("};\n"); 72118334Speter } 72218334Speter else 72318334Speter { 72490075Sobrien d->template = template; 72590075Sobrien d->output_format = INSN_OUTPUT_FORMAT_SINGLE; 72618334Speter } 72718334Speter} 72818334Speter 72918334Speter/* Check insn D for consistency in number of constraint alternatives. */ 73018334Speter 73118334Speterstatic void 73218334Spetervalidate_insn_alternatives (d) 73318334Speter struct data *d; 73418334Speter{ 73590075Sobrien int n = 0, start; 73690075Sobrien 73790075Sobrien /* Make sure all the operands have the same number of alternatives 73890075Sobrien in their constraints. Let N be that number. */ 73918334Speter for (start = 0; start < d->n_operands; start++) 74090075Sobrien if (d->operand[start].n_alternatives > 0) 74118334Speter { 74218334Speter if (n == 0) 74390075Sobrien n = d->operand[start].n_alternatives; 74490075Sobrien else if (n != d->operand[start].n_alternatives) 74590075Sobrien { 74690075Sobrien message_with_line (d->lineno, 74790075Sobrien "wrong number of alternatives in operand %d", 74890075Sobrien start); 74990075Sobrien have_error = 1; 75090075Sobrien } 75118334Speter } 75290075Sobrien 75318334Speter /* Record the insn's overall number of alternatives. */ 75418334Speter d->n_alternatives = n; 75518334Speter} 75690075Sobrien 75790075Sobrien/* Verify that there are no gaps in operand numbers for INSNs. */ 75890075Sobrien 75990075Sobrienstatic void 76090075Sobrienvalidate_insn_operands (d) 76190075Sobrien struct data *d; 76290075Sobrien{ 76390075Sobrien int i; 76490075Sobrien 76590075Sobrien for (i = 0; i < d->n_operands; ++i) 76690075Sobrien if (d->operand[i].seen == 0) 76790075Sobrien { 76890075Sobrien message_with_line (d->lineno, "missing operand %d", i); 76990075Sobrien have_error = 1; 77090075Sobrien } 77190075Sobrien} 77218334Speter 77390075Sobrien/* Look at a define_insn just read. Assign its code number. Record 77490075Sobrien on idata the template and the number of arguments. If the insn has 77590075Sobrien a hairy output action, output a function for now. */ 77618334Speter 77718334Speterstatic void 77890075Sobriengen_insn (insn, lineno) 77918334Speter rtx insn; 78090075Sobrien int lineno; 78118334Speter{ 78290075Sobrien struct data *d = (struct data *) xmalloc (sizeof (struct data)); 78390075Sobrien int i; 78418334Speter 78590075Sobrien d->code_number = next_code_number; 78618334Speter d->index_number = next_index_number; 78790075Sobrien d->lineno = lineno; 78818334Speter if (XSTR (insn, 0)[0]) 78918334Speter d->name = XSTR (insn, 0); 79018334Speter else 79118334Speter d->name = 0; 79218334Speter 79318334Speter /* Build up the list in the same order as the insns are seen 79418334Speter in the machine description. */ 79518334Speter d->next = 0; 79690075Sobrien *idata_end = d; 79790075Sobrien idata_end = &d->next; 79818334Speter 79918334Speter max_opno = -1; 80018334Speter num_dups = 0; 80190075Sobrien memset (d->operand, 0, sizeof (d->operand)); 80218334Speter 80318334Speter for (i = 0; i < XVECLEN (insn, 1); i++) 80490075Sobrien scan_operands (d, XVECEXP (insn, 1, i), 0, 0); 80518334Speter 80618334Speter d->n_operands = max_opno + 1; 80718334Speter d->n_dups = num_dups; 80818334Speter 80990075Sobrien validate_insn_operands (d); 81018334Speter validate_insn_alternatives (d); 81190075Sobrien place_operands (d); 81290075Sobrien process_template (d, XTMPL (insn, 3)); 81318334Speter} 81418334Speter 81518334Speter/* Look at a define_peephole just read. Assign its code number. 81690075Sobrien Record on idata the template and the number of arguments. 81718334Speter If the insn has a hairy output action, output it now. */ 81818334Speter 81918334Speterstatic void 82090075Sobriengen_peephole (peep, lineno) 82118334Speter rtx peep; 82290075Sobrien int lineno; 82318334Speter{ 82490075Sobrien struct data *d = (struct data *) xmalloc (sizeof (struct data)); 82590075Sobrien int i; 82618334Speter 82790075Sobrien d->code_number = next_code_number; 82818334Speter d->index_number = next_index_number; 82990075Sobrien d->lineno = lineno; 83018334Speter d->name = 0; 83118334Speter 83218334Speter /* Build up the list in the same order as the insns are seen 83318334Speter in the machine description. */ 83418334Speter d->next = 0; 83590075Sobrien *idata_end = d; 83690075Sobrien idata_end = &d->next; 83718334Speter 83818334Speter max_opno = -1; 83990075Sobrien num_dups = 0; 84090075Sobrien memset (d->operand, 0, sizeof (d->operand)); 84118334Speter 84290075Sobrien /* Get the number of operands by scanning all the patterns of the 84390075Sobrien peephole optimizer. But ignore all the rest of the information 84490075Sobrien thus obtained. */ 84518334Speter for (i = 0; i < XVECLEN (peep, 0); i++) 84690075Sobrien scan_operands (d, XVECEXP (peep, 0, i), 0, 0); 84718334Speter 84818334Speter d->n_operands = max_opno + 1; 84918334Speter d->n_dups = 0; 85018334Speter 85118334Speter validate_insn_alternatives (d); 85290075Sobrien place_operands (d); 85390075Sobrien process_template (d, XTMPL (peep, 2)); 85418334Speter} 85518334Speter 85618334Speter/* Process a define_expand just read. Assign its code number, 85718334Speter only for the purposes of `insn_gen_function'. */ 85818334Speter 85918334Speterstatic void 86090075Sobriengen_expand (insn, lineno) 86118334Speter rtx insn; 86290075Sobrien int lineno; 86318334Speter{ 86490075Sobrien struct data *d = (struct data *) xmalloc (sizeof (struct data)); 86590075Sobrien int i; 86618334Speter 86790075Sobrien d->code_number = next_code_number; 86818334Speter d->index_number = next_index_number; 86990075Sobrien d->lineno = lineno; 87018334Speter if (XSTR (insn, 0)[0]) 87118334Speter d->name = XSTR (insn, 0); 87218334Speter else 87318334Speter d->name = 0; 87418334Speter 87518334Speter /* Build up the list in the same order as the insns are seen 87618334Speter in the machine description. */ 87718334Speter d->next = 0; 87890075Sobrien *idata_end = d; 87990075Sobrien idata_end = &d->next; 88018334Speter 88118334Speter max_opno = -1; 88218334Speter num_dups = 0; 88390075Sobrien memset (d->operand, 0, sizeof (d->operand)); 88418334Speter 88518334Speter /* Scan the operands to get the specified predicates and modes, 88618334Speter since expand_binop needs to know them. */ 88718334Speter 88818334Speter if (XVEC (insn, 1)) 88918334Speter for (i = 0; i < XVECLEN (insn, 1); i++) 89090075Sobrien scan_operands (d, XVECEXP (insn, 1, i), 0, 0); 89118334Speter 89218334Speter d->n_operands = max_opno + 1; 89318334Speter d->n_dups = num_dups; 89490075Sobrien d->template = 0; 89590075Sobrien d->output_format = INSN_OUTPUT_FORMAT_NONE; 89618334Speter 89718334Speter validate_insn_alternatives (d); 89890075Sobrien place_operands (d); 89918334Speter} 90018334Speter 90118334Speter/* Process a define_split just read. Assign its code number, 90218334Speter only for reasons of consistency and to simplify genrecog. */ 90318334Speter 90418334Speterstatic void 90590075Sobriengen_split (split, lineno) 90618334Speter rtx split; 90790075Sobrien int lineno; 90818334Speter{ 90990075Sobrien struct data *d = (struct data *) xmalloc (sizeof (struct data)); 91090075Sobrien int i; 91118334Speter 91290075Sobrien d->code_number = next_code_number; 91318334Speter d->index_number = next_index_number; 91490075Sobrien d->lineno = lineno; 91518334Speter d->name = 0; 91618334Speter 91718334Speter /* Build up the list in the same order as the insns are seen 91818334Speter in the machine description. */ 91918334Speter d->next = 0; 92090075Sobrien *idata_end = d; 92190075Sobrien idata_end = &d->next; 92218334Speter 92318334Speter max_opno = -1; 92418334Speter num_dups = 0; 92590075Sobrien memset (d->operand, 0, sizeof (d->operand)); 92618334Speter 92790075Sobrien /* Get the number of operands by scanning all the patterns of the 92890075Sobrien split patterns. But ignore all the rest of the information thus 92990075Sobrien obtained. */ 93018334Speter for (i = 0; i < XVECLEN (split, 0); i++) 93190075Sobrien scan_operands (d, XVECEXP (split, 0, i), 0, 0); 93218334Speter 93318334Speter d->n_operands = max_opno + 1; 93418334Speter d->n_dups = 0; 93518334Speter d->n_alternatives = 0; 93618334Speter d->template = 0; 93790075Sobrien d->output_format = INSN_OUTPUT_FORMAT_NONE; 93818334Speter 93990075Sobrien place_operands (d); 94018334Speter} 94118334Speter 94290075Sobrienextern int main PARAMS ((int, char **)); 94318334Speter 94418334Speterint 94518334Spetermain (argc, argv) 94618334Speter int argc; 94718334Speter char **argv; 94818334Speter{ 94918334Speter rtx desc; 95018334Speter 95190075Sobrien progname = "genoutput"; 95218334Speter 95318334Speter if (argc <= 1) 95490075Sobrien fatal ("no input file name"); 95518334Speter 95690075Sobrien if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE) 95790075Sobrien return (FATAL_EXIT_CODE); 95818334Speter 95918334Speter output_prologue (); 96018334Speter next_code_number = 0; 96118334Speter next_index_number = 0; 96218334Speter 96318334Speter /* Read the machine description. */ 96418334Speter 96518334Speter while (1) 96618334Speter { 96790075Sobrien int line_no; 96890075Sobrien 96990075Sobrien desc = read_md_rtx (&line_no, &next_code_number); 97090075Sobrien if (desc == NULL) 97118334Speter break; 97218334Speter 97318334Speter if (GET_CODE (desc) == DEFINE_INSN) 97490075Sobrien gen_insn (desc, line_no); 97518334Speter if (GET_CODE (desc) == DEFINE_PEEPHOLE) 97690075Sobrien gen_peephole (desc, line_no); 97718334Speter if (GET_CODE (desc) == DEFINE_EXPAND) 97890075Sobrien gen_expand (desc, line_no); 97990075Sobrien if (GET_CODE (desc) == DEFINE_SPLIT 98090075Sobrien || GET_CODE (desc) == DEFINE_PEEPHOLE2) 98190075Sobrien gen_split (desc, line_no); 98218334Speter next_index_number++; 98318334Speter } 98418334Speter 98590075Sobrien printf("\n\n"); 98690075Sobrien output_predicate_decls (); 98790075Sobrien output_operand_data (); 98890075Sobrien output_insn_data (); 98990075Sobrien output_get_insn_name (); 99018334Speter 99118334Speter fflush (stdout); 99290075Sobrien return (ferror (stdout) != 0 || have_error 99318334Speter ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); 99418334Speter} 99518334Speter 99690075Sobrien/* Return the number of occurrences of character C in string S or 99790075Sobrien -1 if S is the null string. */ 99890075Sobrien 99918334Speterstatic int 100018334Spetern_occurrences (c, s) 100118334Speter int c; 100290075Sobrien const char *s; 100318334Speter{ 100418334Speter int n = 0; 100590075Sobrien 100690075Sobrien if (s == 0 || *s == '\0') 100790075Sobrien return -1; 100890075Sobrien 100918334Speter while (*s) 101018334Speter n += (*s++ == c); 101190075Sobrien 101218334Speter return n; 101318334Speter} 101490075Sobrien 101590075Sobrien/* Remove whitespace in `s' by moving up characters until the end. 101690075Sobrien Return a new string. */ 101790075Sobrien 101890075Sobrienstatic const char * 101990075Sobrienstrip_whitespace (s) 102090075Sobrien const char *s; 102190075Sobrien{ 102290075Sobrien char *p, *q; 102390075Sobrien char ch; 102490075Sobrien 102590075Sobrien if (s == 0) 102690075Sobrien return 0; 102790075Sobrien 102890075Sobrien p = q = xmalloc (strlen (s) + 1); 102990075Sobrien while ((ch = *s++) != '\0') 103090075Sobrien if (! ISSPACE (ch)) 103190075Sobrien *p++ = ch; 103290075Sobrien 103390075Sobrien *p = '\0'; 103490075Sobrien return q; 103590075Sobrien} 1036