118334Speter/* Generate code from machine description to emit insns as rtl. 2132718Skan Copyright (C) 1987, 1988, 1991, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 3169689Skan 2003, 2004, 2005 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 19169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 20169689Skan02110-1301, USA. */ 2118334Speter 2218334Speter 23132718Skan#include "bconfig.h" 2450397Sobrien#include "system.h" 25132718Skan#include "coretypes.h" 26132718Skan#include "tm.h" 2718334Speter#include "rtl.h" 2890075Sobrien#include "errors.h" 2990075Sobrien#include "gensupport.h" 3018334Speter 3118334Speter 3218334Speterstatic int max_opno; 3318334Speterstatic int max_dup_opno; 3490075Sobrienstatic int max_scratch_opno; 3518334Speterstatic int insn_code_number; 3618334Speterstatic int insn_index_number; 3718334Speter 3818334Speter/* Data structure for recording the patterns of insns that have CLOBBERs. 39132718Skan We use this to output a function that adds these CLOBBERs to a 4018334Speter previously-allocated PARALLEL expression. */ 4118334Speter 4218334Speterstruct clobber_pat 4318334Speter{ 4418334Speter struct clobber_ent *insns; 4518334Speter rtx pattern; 4618334Speter int first_clobber; 4718334Speter struct clobber_pat *next; 4890075Sobrien int has_hard_reg; 4918334Speter} *clobber_list; 5018334Speter 5118334Speter/* Records one insn that uses the clobber list. */ 5218334Speter 5318334Speterstruct clobber_ent 5418334Speter{ 5518334Speter int code_number; /* Counts only insns. */ 5618334Speter struct clobber_ent *next; 5718334Speter}; 5818334Speter 59132718Skanstatic void max_operand_1 (rtx); 60132718Skanstatic int max_operand_vec (rtx, int); 61132718Skanstatic void print_code (RTX_CODE); 62132718Skanstatic void gen_exp (rtx, enum rtx_code, char *); 63132718Skanstatic void gen_insn (rtx, int); 64132718Skanstatic void gen_expand (rtx); 65132718Skanstatic void gen_split (rtx); 66132718Skanstatic void output_add_clobbers (void); 67132718Skanstatic void output_added_clobbers_hard_reg_p (void); 68132718Skanstatic void gen_rtx_scratch (rtx, enum rtx_code); 69132718Skanstatic void output_peephole2_scratches (rtx); 7050397Sobrien 7150397Sobrien 7218334Speterstatic void 73132718Skanmax_operand_1 (rtx x) 7418334Speter{ 7590075Sobrien RTX_CODE code; 7690075Sobrien int i; 7790075Sobrien int len; 7890075Sobrien const char *fmt; 7918334Speter 8018334Speter if (x == 0) 8118334Speter return; 8218334Speter 8318334Speter code = GET_CODE (x); 8418334Speter 8518334Speter if (code == MATCH_OPERAND || code == MATCH_OPERATOR 8618334Speter || code == MATCH_PARALLEL) 8718334Speter max_opno = MAX (max_opno, XINT (x, 0)); 8818334Speter if (code == MATCH_DUP || code == MATCH_OP_DUP || code == MATCH_PAR_DUP) 8918334Speter max_dup_opno = MAX (max_dup_opno, XINT (x, 0)); 9090075Sobrien if (code == MATCH_SCRATCH) 9190075Sobrien max_scratch_opno = MAX (max_scratch_opno, XINT (x, 0)); 9218334Speter 9318334Speter fmt = GET_RTX_FORMAT (code); 9418334Speter len = GET_RTX_LENGTH (code); 9518334Speter for (i = 0; i < len; i++) 9618334Speter { 9718334Speter if (fmt[i] == 'e' || fmt[i] == 'u') 9818334Speter max_operand_1 (XEXP (x, i)); 9918334Speter else if (fmt[i] == 'E') 10018334Speter { 10118334Speter int j; 10218334Speter for (j = 0; j < XVECLEN (x, i); j++) 10318334Speter max_operand_1 (XVECEXP (x, i, j)); 10418334Speter } 10518334Speter } 10618334Speter} 10718334Speter 10818334Speterstatic int 109132718Skanmax_operand_vec (rtx insn, int arg) 11018334Speter{ 11190075Sobrien int len = XVECLEN (insn, arg); 11290075Sobrien int i; 11318334Speter 11418334Speter max_opno = -1; 11518334Speter max_dup_opno = -1; 11690075Sobrien max_scratch_opno = -1; 11718334Speter 11818334Speter for (i = 0; i < len; i++) 11918334Speter max_operand_1 (XVECEXP (insn, arg, i)); 12018334Speter 12118334Speter return max_opno + 1; 12218334Speter} 12318334Speter 12418334Speterstatic void 125132718Skanprint_code (RTX_CODE code) 12618334Speter{ 12790075Sobrien const char *p1; 12818334Speter for (p1 = GET_RTX_NAME (code); *p1; p1++) 12990075Sobrien putchar (TOUPPER(*p1)); 13090075Sobrien} 13190075Sobrien 13290075Sobrienstatic void 133132718Skangen_rtx_scratch (rtx x, enum rtx_code subroutine_type) 13490075Sobrien{ 13590075Sobrien if (subroutine_type == DEFINE_PEEPHOLE2) 13618334Speter { 13790075Sobrien printf ("operand%d", XINT (x, 0)); 13818334Speter } 13990075Sobrien else 14090075Sobrien { 14190075Sobrien printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x))); 14290075Sobrien } 14318334Speter} 14418334Speter 14518334Speter/* Print a C expression to construct an RTX just like X, 14618334Speter substituting any operand references appearing within. */ 14718334Speter 14818334Speterstatic void 149132718Skangen_exp (rtx x, enum rtx_code subroutine_type, char *used) 15018334Speter{ 15190075Sobrien RTX_CODE code; 15290075Sobrien int i; 15390075Sobrien int len; 15490075Sobrien const char *fmt; 15518334Speter 15618334Speter if (x == 0) 15718334Speter { 15818334Speter printf ("NULL_RTX"); 15918334Speter return; 16018334Speter } 16118334Speter 16218334Speter code = GET_CODE (x); 16318334Speter 16418334Speter switch (code) 16518334Speter { 16618334Speter case MATCH_OPERAND: 16718334Speter case MATCH_DUP: 16896263Sobrien if (used) 16996263Sobrien { 17096263Sobrien if (used[XINT (x, 0)]) 17196263Sobrien { 17296263Sobrien printf ("copy_rtx (operand%d)", XINT (x, 0)); 17396263Sobrien return; 17496263Sobrien } 17596263Sobrien used[XINT (x, 0)] = 1; 17696263Sobrien } 17718334Speter printf ("operand%d", XINT (x, 0)); 17818334Speter return; 17918334Speter 18018334Speter case MATCH_OP_DUP: 181169689Skan printf ("gen_rtx_fmt_"); 182169689Skan for (i = 0; i < XVECLEN (x, 1); i++) 183169689Skan printf ("e"); 184169689Skan printf (" (GET_CODE (operand%d), ", XINT (x, 0)); 18550397Sobrien if (GET_MODE (x) == VOIDmode) 18650397Sobrien printf ("GET_MODE (operand%d)", XINT (x, 0)); 18750397Sobrien else 18850397Sobrien printf ("%smode", GET_MODE_NAME (GET_MODE (x))); 18918334Speter for (i = 0; i < XVECLEN (x, 1); i++) 19018334Speter { 19118334Speter printf (",\n\t\t"); 19296263Sobrien gen_exp (XVECEXP (x, 1, i), subroutine_type, used); 19318334Speter } 19418334Speter printf (")"); 19518334Speter return; 19618334Speter 19718334Speter case MATCH_OPERATOR: 198169689Skan printf ("gen_rtx_fmt_"); 199169689Skan for (i = 0; i < XVECLEN (x, 2); i++) 200169689Skan printf ("e"); 201169689Skan printf (" (GET_CODE (operand%d)", XINT (x, 0)); 20218334Speter printf (", %smode", GET_MODE_NAME (GET_MODE (x))); 20318334Speter for (i = 0; i < XVECLEN (x, 2); i++) 20418334Speter { 20518334Speter printf (",\n\t\t"); 20696263Sobrien gen_exp (XVECEXP (x, 2, i), subroutine_type, used); 20718334Speter } 20818334Speter printf (")"); 20918334Speter return; 21018334Speter 21118334Speter case MATCH_PARALLEL: 21218334Speter case MATCH_PAR_DUP: 21318334Speter printf ("operand%d", XINT (x, 0)); 21418334Speter return; 21518334Speter 21618334Speter case MATCH_SCRATCH: 21790075Sobrien gen_rtx_scratch (x, subroutine_type); 21818334Speter return; 21918334Speter 22018334Speter case ADDRESS: 22118334Speter fatal ("ADDRESS expression code used in named instruction pattern"); 22218334Speter 22318334Speter case PC: 22418334Speter printf ("pc_rtx"); 22518334Speter return; 226169689Skan case CLOBBER: 227169689Skan if (REG_P (XEXP (x, 0))) 228169689Skan { 229169689Skan printf ("gen_hard_reg_clobber (%smode, %i)", GET_MODE_NAME (GET_MODE (XEXP (x, 0))), 230169689Skan REGNO (XEXP (x, 0))); 231169689Skan return; 232169689Skan } 233169689Skan break; 23418334Speter 23518334Speter case CC0: 23618334Speter printf ("cc0_rtx"); 23718334Speter return; 23818334Speter 23918334Speter case CONST_INT: 24018334Speter if (INTVAL (x) == 0) 24118334Speter printf ("const0_rtx"); 24218334Speter else if (INTVAL (x) == 1) 24318334Speter printf ("const1_rtx"); 24418334Speter else if (INTVAL (x) == -1) 24518334Speter printf ("constm1_rtx"); 246169689Skan else if (-MAX_SAVED_CONST_INT <= INTVAL (x) 247169689Skan && INTVAL (x) <= MAX_SAVED_CONST_INT) 248169689Skan printf ("const_int_rtx[MAX_SAVED_CONST_INT + (%d)]", 249169689Skan (int) INTVAL (x)); 25018334Speter else if (INTVAL (x) == STORE_FLAG_VALUE) 25118334Speter printf ("const_true_rtx"); 25218334Speter else 25350397Sobrien { 25450397Sobrien printf ("GEN_INT ("); 255117395Skan printf (HOST_WIDE_INT_PRINT_DEC_C, INTVAL (x)); 25650397Sobrien printf (")"); 25750397Sobrien } 25818334Speter return; 25918334Speter 26018334Speter case CONST_DOUBLE: 26118334Speter /* These shouldn't be written in MD files. Instead, the appropriate 26218334Speter routines in varasm.c should be called. */ 263169689Skan gcc_unreachable (); 26450397Sobrien 26550397Sobrien default: 26650397Sobrien break; 26718334Speter } 26818334Speter 26950397Sobrien printf ("gen_rtx_"); 27018334Speter print_code (code); 27150397Sobrien printf (" (%smode", GET_MODE_NAME (GET_MODE (x))); 27218334Speter 27318334Speter fmt = GET_RTX_FORMAT (code); 27418334Speter len = GET_RTX_LENGTH (code); 27518334Speter for (i = 0; i < len; i++) 27618334Speter { 27718334Speter if (fmt[i] == '0') 27818334Speter break; 27918334Speter printf (",\n\t"); 280169689Skan switch (fmt[i]) 28118334Speter { 282169689Skan case 'e': case 'u': 283169689Skan gen_exp (XEXP (x, i), subroutine_type, used); 284169689Skan break; 285169689Skan 286169689Skan case 'i': 287169689Skan printf ("%u", XINT (x, i)); 288169689Skan break; 289169689Skan 290169689Skan case 's': 291169689Skan printf ("\"%s\"", XSTR (x, i)); 292169689Skan break; 293169689Skan 294169689Skan case 'E': 295169689Skan { 296169689Skan int j; 297169689Skan printf ("gen_rtvec (%d", XVECLEN (x, i)); 298169689Skan for (j = 0; j < XVECLEN (x, i); j++) 299169689Skan { 300169689Skan printf (",\n\t\t"); 301169689Skan gen_exp (XVECEXP (x, i, j), subroutine_type, used); 302169689Skan } 303169689Skan printf (")"); 304169689Skan break; 305169689Skan } 306169689Skan 307169689Skan default: 308169689Skan gcc_unreachable (); 30918334Speter } 31018334Speter } 31118334Speter printf (")"); 312132718Skan} 31318334Speter 31418334Speter/* Generate the `gen_...' function for a DEFINE_INSN. */ 31518334Speter 31618334Speterstatic void 317132718Skangen_insn (rtx insn, int lineno) 31818334Speter{ 31918334Speter int operands; 32090075Sobrien int i; 32118334Speter 32218334Speter /* See if the pattern for this insn ends with a group of CLOBBERs of (hard) 32318334Speter registers or MATCH_SCRATCHes. If so, store away the information for 32450397Sobrien later. */ 32518334Speter 32618334Speter if (XVEC (insn, 1)) 32718334Speter { 32890075Sobrien int has_hard_reg = 0; 32990075Sobrien 33018334Speter for (i = XVECLEN (insn, 1) - 1; i > 0; i--) 33190075Sobrien { 33290075Sobrien if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER) 33390075Sobrien break; 33418334Speter 335169689Skan if (REG_P (XEXP (XVECEXP (insn, 1, i), 0))) 33690075Sobrien has_hard_reg = 1; 33790075Sobrien else if (GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != MATCH_SCRATCH) 33890075Sobrien break; 33990075Sobrien } 34090075Sobrien 34118334Speter if (i != XVECLEN (insn, 1) - 1) 34218334Speter { 34390075Sobrien struct clobber_pat *p; 344169689Skan struct clobber_ent *link = XNEW (struct clobber_ent); 34590075Sobrien int j; 34618334Speter 34718334Speter link->code_number = insn_code_number; 34818334Speter 34918334Speter /* See if any previous CLOBBER_LIST entry is the same as this 35018334Speter one. */ 35118334Speter 35218334Speter for (p = clobber_list; p; p = p->next) 35318334Speter { 35418334Speter if (p->first_clobber != i + 1 35518334Speter || XVECLEN (p->pattern, 1) != XVECLEN (insn, 1)) 35618334Speter continue; 35718334Speter 35818334Speter for (j = i + 1; j < XVECLEN (insn, 1); j++) 35918334Speter { 36018334Speter rtx old = XEXP (XVECEXP (p->pattern, 1, j), 0); 36118334Speter rtx new = XEXP (XVECEXP (insn, 1, j), 0); 36218334Speter 36318334Speter /* OLD and NEW are the same if both are to be a SCRATCH 364132718Skan of the same mode, 36518334Speter or if both are registers of the same mode and number. */ 36618334Speter if (! (GET_MODE (old) == GET_MODE (new) 36718334Speter && ((GET_CODE (old) == MATCH_SCRATCH 36818334Speter && GET_CODE (new) == MATCH_SCRATCH) 369169689Skan || (REG_P (old) && REG_P (new) 37018334Speter && REGNO (old) == REGNO (new))))) 37118334Speter break; 37218334Speter } 373132718Skan 37418334Speter if (j == XVECLEN (insn, 1)) 37518334Speter break; 37618334Speter } 37718334Speter 37818334Speter if (p == 0) 37918334Speter { 380169689Skan p = XNEW (struct clobber_pat); 381132718Skan 38218334Speter p->insns = 0; 38318334Speter p->pattern = insn; 38418334Speter p->first_clobber = i + 1; 38518334Speter p->next = clobber_list; 38690075Sobrien p->has_hard_reg = has_hard_reg; 38718334Speter clobber_list = p; 38818334Speter } 38918334Speter 39018334Speter link->next = p->insns; 39118334Speter p->insns = link; 39218334Speter } 39318334Speter } 39418334Speter 39518334Speter /* Don't mention instructions whose names are the null string 39618334Speter or begin with '*'. They are in the machine description just 39718334Speter to be recognized. */ 39818334Speter if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*') 39918334Speter return; 40018334Speter 401117395Skan printf ("/* %s:%d */\n", read_rtx_filename, lineno); 402117395Skan 403132718Skan /* Find out how many operands this function has. */ 40418334Speter operands = max_operand_vec (insn, 1); 40518334Speter if (max_dup_opno >= operands) 40618334Speter fatal ("match_dup operand number has no match_operand"); 40718334Speter 40818334Speter /* Output the function name and argument declarations. */ 40918334Speter printf ("rtx\ngen_%s (", XSTR (insn, 0)); 410132718Skan if (operands) 411132718Skan for (i = 0; i < operands; i++) 412132718Skan if (i) 413132718Skan printf (",\n\trtx operand%d ATTRIBUTE_UNUSED", i); 414132718Skan else 415132718Skan printf ("rtx operand%d ATTRIBUTE_UNUSED", i); 416132718Skan else 417132718Skan printf ("void"); 41818334Speter printf (")\n"); 41918334Speter printf ("{\n"); 42018334Speter 421132718Skan /* Output code to construct and return the rtl for the instruction body. */ 42218334Speter 42318334Speter if (XVECLEN (insn, 1) == 1) 42418334Speter { 42518334Speter printf (" return "); 42696263Sobrien gen_exp (XVECEXP (insn, 1, 0), DEFINE_INSN, NULL); 42718334Speter printf (";\n}\n\n"); 42818334Speter } 42918334Speter else 43018334Speter { 43190075Sobrien printf (" return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (%d", 43290075Sobrien XVECLEN (insn, 1)); 43390075Sobrien 43418334Speter for (i = 0; i < XVECLEN (insn, 1); i++) 43518334Speter { 43618334Speter printf (",\n\t\t"); 43796263Sobrien gen_exp (XVECEXP (insn, 1, i), DEFINE_INSN, NULL); 43818334Speter } 43918334Speter printf ("));\n}\n\n"); 44018334Speter } 44118334Speter} 44218334Speter 44318334Speter/* Generate the `gen_...' function for a DEFINE_EXPAND. */ 44418334Speter 44518334Speterstatic void 446132718Skangen_expand (rtx expand) 44718334Speter{ 44818334Speter int operands; 44990075Sobrien int i; 45018334Speter 45118334Speter if (strlen (XSTR (expand, 0)) == 0) 45218334Speter fatal ("define_expand lacks a name"); 45318334Speter if (XVEC (expand, 1) == 0) 45418334Speter fatal ("define_expand for %s lacks a pattern", XSTR (expand, 0)); 45518334Speter 456132718Skan /* Find out how many operands this function has. */ 45718334Speter operands = max_operand_vec (expand, 1); 45818334Speter 45918334Speter /* Output the function name and argument declarations. */ 46018334Speter printf ("rtx\ngen_%s (", XSTR (expand, 0)); 461132718Skan if (operands) 462132718Skan for (i = 0; i < operands; i++) 463132718Skan if (i) 464132718Skan printf (",\n\trtx operand%d", i); 465132718Skan else 466132718Skan printf ("rtx operand%d", i); 467132718Skan else 468132718Skan printf ("void"); 46918334Speter printf (")\n"); 47018334Speter printf ("{\n"); 47118334Speter 47218334Speter /* If we don't have any C code to write, only one insn is being written, 47318334Speter and no MATCH_DUPs are present, we can just return the desired insn 47418334Speter like we do for a DEFINE_INSN. This saves memory. */ 47518334Speter if ((XSTR (expand, 3) == 0 || *XSTR (expand, 3) == '\0') 47618334Speter && operands > max_dup_opno 47718334Speter && XVECLEN (expand, 1) == 1) 47818334Speter { 47918334Speter printf (" return "); 48096263Sobrien gen_exp (XVECEXP (expand, 1, 0), DEFINE_EXPAND, NULL); 48118334Speter printf (";\n}\n\n"); 48218334Speter return; 48318334Speter } 48418334Speter 48518334Speter /* For each operand referred to only with MATCH_DUPs, 48618334Speter make a local variable. */ 48718334Speter for (i = operands; i <= max_dup_opno; i++) 48818334Speter printf (" rtx operand%d;\n", i); 48990075Sobrien for (; i <= max_scratch_opno; i++) 49090075Sobrien printf (" rtx operand%d ATTRIBUTE_UNUSED;\n", i); 49118334Speter printf (" rtx _val = 0;\n"); 49218334Speter printf (" start_sequence ();\n"); 49318334Speter 49418334Speter /* The fourth operand of DEFINE_EXPAND is some code to be executed 49518334Speter before the actual construction. 49618334Speter This code expects to refer to `operands' 49718334Speter just as the output-code in a DEFINE_INSN does, 49818334Speter but here `operands' is an automatic array. 49918334Speter So copy the operand values there before executing it. */ 50018334Speter if (XSTR (expand, 3) && *XSTR (expand, 3)) 50118334Speter { 50290075Sobrien printf (" {\n"); 50390075Sobrien if (operands > 0 || max_dup_opno >= 0 || max_scratch_opno >= 0) 50490075Sobrien printf (" rtx operands[%d];\n", 50590075Sobrien MAX (operands, MAX (max_scratch_opno, max_dup_opno) + 1)); 50618334Speter /* Output code to copy the arguments into `operands'. */ 50718334Speter for (i = 0; i < operands; i++) 50890075Sobrien printf (" operands[%d] = operand%d;\n", i, i); 50918334Speter 51018334Speter /* Output the special code to be executed before the sequence 51118334Speter is generated. */ 512169689Skan print_rtx_ptr_loc (XSTR (expand, 3)); 51318334Speter printf ("%s\n", XSTR (expand, 3)); 51418334Speter 51518334Speter /* Output code to copy the arguments back out of `operands' 51618334Speter (unless we aren't going to use them at all). */ 51718334Speter if (XVEC (expand, 1) != 0) 51818334Speter { 51918334Speter for (i = 0; i < operands; i++) 52090075Sobrien printf (" operand%d = operands[%d];\n", i, i); 52118334Speter for (; i <= max_dup_opno; i++) 52290075Sobrien printf (" operand%d = operands[%d];\n", i, i); 52390075Sobrien for (; i <= max_scratch_opno; i++) 52490075Sobrien printf (" operand%d = operands[%d];\n", i, i); 52518334Speter } 52690075Sobrien printf (" }\n"); 52718334Speter } 52818334Speter 52918334Speter /* Output code to construct the rtl for the instruction bodies. 53018334Speter Use emit_insn to add them to the sequence being accumulated. 53118334Speter But don't do this if the user's code has set `no_more' nonzero. */ 53218334Speter 53318334Speter for (i = 0; i < XVECLEN (expand, 1); i++) 53418334Speter { 53518334Speter rtx next = XVECEXP (expand, 1, i); 53618334Speter if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC) 53718334Speter || (GET_CODE (next) == PARALLEL 538117395Skan && ((GET_CODE (XVECEXP (next, 0, 0)) == SET 539117395Skan && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC) 540117395Skan || GET_CODE (XVECEXP (next, 0, 0)) == RETURN)) 54118334Speter || GET_CODE (next) == RETURN) 54218334Speter printf (" emit_jump_insn ("); 54318334Speter else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL) 54418334Speter || GET_CODE (next) == CALL 54518334Speter || (GET_CODE (next) == PARALLEL 54618334Speter && GET_CODE (XVECEXP (next, 0, 0)) == SET 54718334Speter && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL) 54818334Speter || (GET_CODE (next) == PARALLEL 54918334Speter && GET_CODE (XVECEXP (next, 0, 0)) == CALL)) 55018334Speter printf (" emit_call_insn ("); 551169689Skan else if (LABEL_P (next)) 55218334Speter printf (" emit_label ("); 55318334Speter else if (GET_CODE (next) == MATCH_OPERAND 55490075Sobrien || GET_CODE (next) == MATCH_DUP 55518334Speter || GET_CODE (next) == MATCH_OPERATOR 55690075Sobrien || GET_CODE (next) == MATCH_OP_DUP 55718334Speter || GET_CODE (next) == MATCH_PARALLEL 55890075Sobrien || GET_CODE (next) == MATCH_PAR_DUP 55918334Speter || GET_CODE (next) == PARALLEL) 56018334Speter printf (" emit ("); 56118334Speter else 56218334Speter printf (" emit_insn ("); 56396263Sobrien gen_exp (next, DEFINE_EXPAND, NULL); 56418334Speter printf (");\n"); 56518334Speter if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC 56618334Speter && GET_CODE (SET_SRC (next)) == LABEL_REF) 56718334Speter printf (" emit_barrier ();"); 56818334Speter } 56918334Speter 570117395Skan /* Call `get_insns' to extract the list of all the 57118334Speter insns emitted within this gen_... function. */ 57218334Speter 573117395Skan printf (" _val = get_insns ();\n"); 57418334Speter printf (" end_sequence ();\n"); 57518334Speter printf (" return _val;\n}\n\n"); 57618334Speter} 57718334Speter 578117395Skan/* Like gen_expand, but generates insns resulting from splitting SPLIT. */ 57950397Sobrien 58018334Speterstatic void 581132718Skangen_split (rtx split) 58218334Speter{ 58390075Sobrien int i; 58418334Speter int operands; 58590075Sobrien const char *const name = 58690075Sobrien ((GET_CODE (split) == DEFINE_PEEPHOLE2) ? "peephole2" : "split"); 58790075Sobrien const char *unused; 58896263Sobrien char *used; 58918334Speter 59018334Speter if (XVEC (split, 0) == 0) 59190075Sobrien fatal ("define_%s (definition %d) lacks a pattern", name, 59290075Sobrien insn_index_number); 59318334Speter else if (XVEC (split, 2) == 0) 59490075Sobrien fatal ("define_%s (definition %d) lacks a replacement pattern", name, 59518334Speter insn_index_number); 59618334Speter 59718334Speter /* Find out how many operands this function has. */ 59818334Speter 59918334Speter max_operand_vec (split, 2); 60090075Sobrien operands = MAX (max_opno, MAX (max_dup_opno, max_scratch_opno)) + 1; 60190075Sobrien unused = (operands == 0 ? " ATTRIBUTE_UNUSED" : ""); 602169689Skan used = XCNEWVEC (char, operands); 60318334Speter 60490075Sobrien /* Output the prototype, function name and argument declarations. */ 60590075Sobrien if (GET_CODE (split) == DEFINE_PEEPHOLE2) 60690075Sobrien { 607132718Skan printf ("extern rtx gen_%s_%d (rtx, rtx *);\n", 60890075Sobrien name, insn_code_number); 609132718Skan printf ("rtx\ngen_%s_%d (rtx curr_insn ATTRIBUTE_UNUSED, rtx *operands%s)\n", 610132718Skan name, insn_code_number, unused); 61190075Sobrien } 61290075Sobrien else 61390075Sobrien { 614169689Skan printf ("extern rtx gen_split_%d (rtx, rtx *);\n", insn_code_number); 615169689Skan printf ("rtx\ngen_split_%d (rtx curr_insn ATTRIBUTE_UNUSED, rtx *operands%s)\n", 616169689Skan insn_code_number, unused); 61790075Sobrien } 61818334Speter printf ("{\n"); 61918334Speter 62018334Speter /* Declare all local variables. */ 62118334Speter for (i = 0; i < operands; i++) 62218334Speter printf (" rtx operand%d;\n", i); 62318334Speter printf (" rtx _val = 0;\n"); 62490075Sobrien 62590075Sobrien if (GET_CODE (split) == DEFINE_PEEPHOLE2) 62690075Sobrien output_peephole2_scratches (split); 62790075Sobrien 62818334Speter printf (" start_sequence ();\n"); 62918334Speter 63018334Speter /* The fourth operand of DEFINE_SPLIT is some code to be executed 63118334Speter before the actual construction. */ 63218334Speter 63318334Speter if (XSTR (split, 3)) 634169689Skan { 635169689Skan print_rtx_ptr_loc (XSTR (split, 3)); 636169689Skan printf ("%s\n", XSTR (split, 3)); 637169689Skan } 63818334Speter 63918334Speter /* Output code to copy the arguments back out of `operands' */ 64018334Speter for (i = 0; i < operands; i++) 64118334Speter printf (" operand%d = operands[%d];\n", i, i); 64218334Speter 64318334Speter /* Output code to construct the rtl for the instruction bodies. 64418334Speter Use emit_insn to add them to the sequence being accumulated. 64518334Speter But don't do this if the user's code has set `no_more' nonzero. */ 64618334Speter 64718334Speter for (i = 0; i < XVECLEN (split, 2); i++) 64818334Speter { 64918334Speter rtx next = XVECEXP (split, 2, i); 65018334Speter if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC) 65118334Speter || (GET_CODE (next) == PARALLEL 65218334Speter && GET_CODE (XVECEXP (next, 0, 0)) == SET 65318334Speter && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC) 65418334Speter || GET_CODE (next) == RETURN) 65518334Speter printf (" emit_jump_insn ("); 65618334Speter else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL) 65718334Speter || GET_CODE (next) == CALL 65818334Speter || (GET_CODE (next) == PARALLEL 65918334Speter && GET_CODE (XVECEXP (next, 0, 0)) == SET 66018334Speter && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL) 66118334Speter || (GET_CODE (next) == PARALLEL 66218334Speter && GET_CODE (XVECEXP (next, 0, 0)) == CALL)) 66318334Speter printf (" emit_call_insn ("); 664169689Skan else if (LABEL_P (next)) 66518334Speter printf (" emit_label ("); 66618334Speter else if (GET_CODE (next) == MATCH_OPERAND 66718334Speter || GET_CODE (next) == MATCH_OPERATOR 66818334Speter || GET_CODE (next) == MATCH_PARALLEL 66918334Speter || GET_CODE (next) == MATCH_OP_DUP 67018334Speter || GET_CODE (next) == MATCH_DUP 67118334Speter || GET_CODE (next) == PARALLEL) 67218334Speter printf (" emit ("); 67318334Speter else 67418334Speter printf (" emit_insn ("); 67596263Sobrien gen_exp (next, GET_CODE (split), used); 67618334Speter printf (");\n"); 67718334Speter if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC 67818334Speter && GET_CODE (SET_SRC (next)) == LABEL_REF) 67918334Speter printf (" emit_barrier ();"); 68018334Speter } 68118334Speter 682117395Skan /* Call `get_insns' to make a list of all the 68318334Speter insns emitted within this gen_... function. */ 68418334Speter 685117395Skan printf (" _val = get_insns ();\n"); 68618334Speter printf (" end_sequence ();\n"); 68718334Speter printf (" return _val;\n}\n\n"); 68896263Sobrien 68996263Sobrien free (used); 69018334Speter} 69118334Speter 69218334Speter/* Write a function, `add_clobbers', that is given a PARALLEL of sufficient 69318334Speter size for the insn and an INSN_CODE, and inserts the required CLOBBERs at 69418334Speter the end of the vector. */ 69518334Speter 69618334Speterstatic void 697132718Skanoutput_add_clobbers (void) 69818334Speter{ 69918334Speter struct clobber_pat *clobber; 70018334Speter struct clobber_ent *ent; 70118334Speter int i; 70218334Speter 703132718Skan printf ("\n\nvoid\nadd_clobbers (rtx pattern ATTRIBUTE_UNUSED, int insn_code_number)\n"); 70418334Speter printf ("{\n"); 70518334Speter printf (" switch (insn_code_number)\n"); 70618334Speter printf (" {\n"); 70718334Speter 70818334Speter for (clobber = clobber_list; clobber; clobber = clobber->next) 70918334Speter { 71018334Speter for (ent = clobber->insns; ent; ent = ent->next) 71118334Speter printf (" case %d:\n", ent->code_number); 71218334Speter 71318334Speter for (i = clobber->first_clobber; i < XVECLEN (clobber->pattern, 1); i++) 71418334Speter { 71518334Speter printf (" XVECEXP (pattern, 0, %d) = ", i); 71690075Sobrien gen_exp (XVECEXP (clobber->pattern, 1, i), 71796263Sobrien GET_CODE (clobber->pattern), NULL); 71818334Speter printf (";\n"); 71918334Speter } 72018334Speter 72118334Speter printf (" break;\n\n"); 72218334Speter } 72318334Speter 72418334Speter printf (" default:\n"); 725169689Skan printf (" gcc_unreachable ();\n"); 72618334Speter printf (" }\n"); 72718334Speter printf ("}\n"); 72818334Speter} 72918334Speter 730169689Skan/* Write a function, `added_clobbers_hard_reg_p' that is given an insn_code 731169689Skan number that will have clobbers added (as indicated by `recog') and returns 732169689Skan 1 if those include a clobber of a hard reg or 0 if all of them just clobber 733169689Skan SCRATCH. */ 73418334Speter 73518334Speterstatic void 736132718Skanoutput_added_clobbers_hard_reg_p (void) 73718334Speter{ 73890075Sobrien struct clobber_pat *clobber; 73990075Sobrien struct clobber_ent *ent; 74096263Sobrien int clobber_p, used; 74118334Speter 742132718Skan printf ("\n\nint\nadded_clobbers_hard_reg_p (int insn_code_number)\n"); 74390075Sobrien printf ("{\n"); 74490075Sobrien printf (" switch (insn_code_number)\n"); 74590075Sobrien printf (" {\n"); 74618334Speter 74790075Sobrien for (clobber_p = 0; clobber_p <= 1; clobber_p++) 74818334Speter { 74996263Sobrien used = 0; 75090075Sobrien for (clobber = clobber_list; clobber; clobber = clobber->next) 75190075Sobrien if (clobber->has_hard_reg == clobber_p) 75290075Sobrien for (ent = clobber->insns; ent; ent = ent->next) 75396263Sobrien { 75496263Sobrien printf (" case %d:\n", ent->code_number); 75596263Sobrien used++; 75696263Sobrien } 75790075Sobrien 75896263Sobrien if (used) 75996263Sobrien printf (" return %d;\n\n", clobber_p); 76018334Speter } 76118334Speter 76290075Sobrien printf (" default:\n"); 763169689Skan printf (" gcc_unreachable ();\n"); 76490075Sobrien printf (" }\n"); 76518334Speter printf ("}\n"); 76618334Speter} 76718334Speter 76890075Sobrien/* Generate code to invoke find_free_register () as needed for the 76990075Sobrien scratch registers used by the peephole2 pattern in SPLIT. */ 77018334Speter 77190075Sobrienstatic void 772132718Skanoutput_peephole2_scratches (rtx split) 77318334Speter{ 77490075Sobrien int i; 77590075Sobrien int insn_nr = 0; 77618334Speter 77790075Sobrien printf (" HARD_REG_SET _regs_allocated;\n"); 77890075Sobrien printf (" CLEAR_HARD_REG_SET (_regs_allocated);\n"); 77950397Sobrien 78090075Sobrien for (i = 0; i < XVECLEN (split, 0); i++) 78190075Sobrien { 78290075Sobrien rtx elt = XVECEXP (split, 0, i); 78390075Sobrien if (GET_CODE (elt) == MATCH_SCRATCH) 78490075Sobrien { 78590075Sobrien int last_insn_nr = insn_nr; 78690075Sobrien int cur_insn_nr = insn_nr; 78790075Sobrien int j; 78890075Sobrien for (j = i + 1; j < XVECLEN (split, 0); j++) 78990075Sobrien if (GET_CODE (XVECEXP (split, 0, j)) == MATCH_DUP) 79090075Sobrien { 79190075Sobrien if (XINT (XVECEXP (split, 0, j), 0) == XINT (elt, 0)) 79290075Sobrien last_insn_nr = cur_insn_nr; 79390075Sobrien } 79490075Sobrien else if (GET_CODE (XVECEXP (split, 0, j)) != MATCH_SCRATCH) 79590075Sobrien cur_insn_nr++; 79650397Sobrien 79790075Sobrien printf (" if ((operands[%d] = peep2_find_free_register (%d, %d, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\ 798132718Skan return NULL;\n", 79990075Sobrien XINT (elt, 0), 80090075Sobrien insn_nr, last_insn_nr, 80190075Sobrien XSTR (elt, 1), 80290075Sobrien GET_MODE_NAME (GET_MODE (elt))); 80350397Sobrien 80490075Sobrien } 80590075Sobrien else if (GET_CODE (elt) != MATCH_DUP) 80690075Sobrien insn_nr++; 80790075Sobrien } 80818334Speter} 80918334Speter 81018334Speterint 811132718Skanmain (int argc, char **argv) 81218334Speter{ 81318334Speter rtx desc; 81418334Speter 81590075Sobrien progname = "genemit"; 81618334Speter 81790075Sobrien if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE) 81890075Sobrien return (FATAL_EXIT_CODE); 81918334Speter 82018334Speter /* Assign sequential codes to all entries in the machine description 82118334Speter in parallel with the tables in insn-output.c. */ 82218334Speter 82318334Speter insn_code_number = 0; 82418334Speter insn_index_number = 0; 82518334Speter 82618334Speter printf ("/* Generated automatically by the program `genemit'\n\ 82718334Speterfrom the machine description file `md'. */\n\n"); 82818334Speter 82918334Speter printf ("#include \"config.h\"\n"); 83050397Sobrien printf ("#include \"system.h\"\n"); 831132718Skan printf ("#include \"coretypes.h\"\n"); 832132718Skan printf ("#include \"tm.h\"\n"); 83318334Speter printf ("#include \"rtl.h\"\n"); 83490075Sobrien printf ("#include \"tm_p.h\"\n"); 83590075Sobrien printf ("#include \"function.h\"\n"); 83618334Speter printf ("#include \"expr.h\"\n"); 83790075Sobrien printf ("#include \"optabs.h\"\n"); 83818334Speter printf ("#include \"real.h\"\n"); 83950397Sobrien printf ("#include \"flags.h\"\n"); 84018334Speter printf ("#include \"output.h\"\n"); 84152284Sobrien printf ("#include \"insn-config.h\"\n"); 84290075Sobrien printf ("#include \"hard-reg-set.h\"\n"); 84352284Sobrien printf ("#include \"recog.h\"\n"); 84490075Sobrien printf ("#include \"resource.h\"\n"); 84590075Sobrien printf ("#include \"reload.h\"\n"); 84690075Sobrien printf ("#include \"toplev.h\"\n"); 847169689Skan printf ("#include \"tm-constrs.h\"\n"); 84890075Sobrien printf ("#include \"ggc.h\"\n\n"); 849169689Skan printf ("#include \"basic-block.h\"\n\n"); 85052284Sobrien printf ("#define FAIL return (end_sequence (), _val)\n"); 851117395Skan printf ("#define DONE return (_val = get_insns (), end_sequence (), _val)\n\n"); 85218334Speter 85318334Speter /* Read the machine description. */ 85418334Speter 85518334Speter while (1) 85618334Speter { 85790075Sobrien int line_no; 85890075Sobrien 85990075Sobrien desc = read_md_rtx (&line_no, &insn_code_number); 86090075Sobrien if (desc == NULL) 86118334Speter break; 86218334Speter 86390075Sobrien switch (GET_CODE (desc)) 86418334Speter { 865117395Skan case DEFINE_INSN: 866117395Skan gen_insn (desc, line_no); 867117395Skan break; 86890075Sobrien 869117395Skan case DEFINE_EXPAND: 870117395Skan printf ("/* %s:%d */\n", read_rtx_filename, line_no); 871117395Skan gen_expand (desc); 872117395Skan break; 87390075Sobrien 874117395Skan case DEFINE_SPLIT: 875117395Skan printf ("/* %s:%d */\n", read_rtx_filename, line_no); 876117395Skan gen_split (desc); 877117395Skan break; 87890075Sobrien 879117395Skan case DEFINE_PEEPHOLE2: 880117395Skan printf ("/* %s:%d */\n", read_rtx_filename, line_no); 881117395Skan gen_split (desc); 882117395Skan break; 88390075Sobrien 884117395Skan default: 885117395Skan break; 886117395Skan } 88718334Speter ++insn_index_number; 88818334Speter } 88918334Speter 89090075Sobrien /* Write out the routines to add CLOBBERs to a pattern and say whether they 89190075Sobrien clobber a hard reg. */ 89218334Speter output_add_clobbers (); 89390075Sobrien output_added_clobbers_hard_reg_p (); 89418334Speter 89518334Speter fflush (stdout); 89690075Sobrien return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); 89718334Speter} 898