genrecog.c revision 169690
1189251Ssam/* Generate code from machine description to recognize rtl as insns. 2189251Ssam Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1997, 1998, 3281806Srpaulo 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 4189251Ssam 5252726Srpaulo This file is part of GCC. 6252726Srpaulo 7189251Ssam GCC is free software; you can redistribute it and/or modify it 8189251Ssam under the terms of the GNU General Public License as published by 9189251Ssam the Free Software Foundation; either version 2, or (at your option) 10189251Ssam any later version. 11189251Ssam 12189251Ssam GCC is distributed in the hope that it will be useful, but WITHOUT 13189251Ssam ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14189251Ssam or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15189251Ssam License for more details. 16189251Ssam 17189251Ssam You should have received a copy of the GNU General Public License 18189251Ssam along with GCC; see the file COPYING. If not, write to the Free 19189251Ssam Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 20189251Ssam 02110-1301, USA. */ 21189251Ssam 22189251Ssam 23252726Srpaulo/* This program is used to produce insn-recog.c, which contains a 24214734Srpaulo function called `recog' plus its subroutines. These functions 25214734Srpaulo contain a decision tree that recognizes whether an rtx, the 26281806Srpaulo argument given to recog, is a valid instruction. 27214734Srpaulo 28189251Ssam recog returns -1 if the rtx is not valid. If the rtx is valid, 29214734Srpaulo recog returns a nonnegative number which is the insn code number 30214734Srpaulo for the pattern that matched. This is the same as the order in the 31189251Ssam machine description of the entry that matched. This number can be 32189251Ssam used as an index into various insn_* tables, such as insn_template, 33189251Ssam insn_outfun, and insn_n_operands (found in insn-output.c). 34189251Ssam 35189251Ssam The third argument to recog is an optional pointer to an int. If 36252726Srpaulo present, recog will accept a pattern if it matches except for 37189251Ssam missing CLOBBER expressions at the end. In that case, the value 38189251Ssam pointed to by the optional pointer will be set to the number of 39189251Ssam CLOBBERs that need to be added (it should be initialized to zero by 40189251Ssam the caller). If it is set nonzero, the caller should allocate a 41189251Ssam PARALLEL of the appropriate size, copy the initial entries, and 42189251Ssam call add_clobbers (found in insn-emit.c) to fill in the CLOBBERs. 43189251Ssam 44189251Ssam This program also generates the function `split_insns', which 45189251Ssam returns 0 if the rtl could not be split, or it returns the split 46189251Ssam rtl as an INSN list. 47189251Ssam 48189251Ssam This program also generates the function `peephole2_insns', which 49189251Ssam returns 0 if the rtl could not be matched. If there was a match, 50189251Ssam the new rtl is returned in an INSN list, and LAST_INSN will point 51337817Scy to the last recognized insn in the old sequence. */ 52337817Scy 53189251Ssam#include "bconfig.h" 54189251Ssam#include "system.h" 55189251Ssam#include "coretypes.h" 56189251Ssam#include "tm.h" 57189251Ssam#include "rtl.h" 58189251Ssam#include "errors.h" 59189251Ssam#include "gensupport.h" 60189251Ssam 61189251Ssam#define OUTPUT_LABEL(INDENT_STRING, LABEL_NUMBER) \ 62189251Ssam printf("%sL%d: ATTRIBUTE_UNUSED_LABEL\n", (INDENT_STRING), (LABEL_NUMBER)) 63189251Ssam 64189251Ssam/* A listhead of decision trees. The alternatives to a node are kept 65189251Ssam in a doubly-linked list so we can easily add nodes to the proper 66189251Ssam place when merging. */ 67189251Ssam 68189251Ssamstruct decision_head 69189251Ssam{ 70189251Ssam struct decision *first; 71189251Ssam struct decision *last; 72189251Ssam}; 73189251Ssam 74189251Ssam/* A single test. The two accept types aren't tests per-se, but 75189251Ssam their equality (or lack thereof) does affect tree merging so 76189251Ssam it is convenient to keep them here. */ 77189251Ssam 78189251Ssamstruct decision_test 79189251Ssam{ 80189251Ssam /* A linked list through the tests attached to a node. */ 81189251Ssam struct decision_test *next; 82189251Ssam 83189251Ssam /* These types are roughly in the order in which we'd like to test them. */ 84189251Ssam enum decision_type 85189251Ssam { 86189251Ssam DT_num_insns, 87189251Ssam DT_mode, DT_code, DT_veclen, 88252726Srpaulo DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide, DT_elt_zero_wide_safe, 89252726Srpaulo DT_const_int, 90252726Srpaulo DT_veclen_ge, DT_dup, DT_pred, DT_c_test, 91252726Srpaulo DT_accept_op, DT_accept_insn 92252726Srpaulo } type; 93252726Srpaulo 94252726Srpaulo union 95252726Srpaulo { 96252726Srpaulo int num_insns; /* Number if insn in a define_peephole2. */ 97252726Srpaulo enum machine_mode mode; /* Machine mode of node. */ 98346981Scy RTX_CODE code; /* Code to test. */ 99346981Scy 100346981Scy struct 101346981Scy { 102346981Scy const char *name; /* Predicate to call. */ 103346981Scy const struct pred_data *data; 104346981Scy /* Optimization hints for this predicate. */ 105346981Scy enum machine_mode mode; /* Machine mode for node. */ 106281806Srpaulo } pred; 107281806Srpaulo 108281806Srpaulo const char *c_test; /* Additional test to perform. */ 109281806Srpaulo int veclen; /* Length of vector. */ 110281806Srpaulo int dup; /* Number of operand to compare against. */ 111281806Srpaulo HOST_WIDE_INT intval; /* Value for XINT for XWINT. */ 112281806Srpaulo int opno; /* Operand number matched. */ 113281806Srpaulo 114281806Srpaulo struct { 115189251Ssam int code_number; /* Insn number matched. */ 116189251Ssam int lineno; /* Line number of the insn. */ 117252726Srpaulo int num_clobbers_to_add; /* Number of CLOBBERs to be added. */ 118252726Srpaulo } insn; 119252726Srpaulo } u; 120189251Ssam}; 121189251Ssam 122189251Ssam/* Data structure for decision tree for recognizing legitimate insns. */ 123189251Ssam 124189251Ssamstruct decision 125189251Ssam{ 126189251Ssam struct decision_head success; /* Nodes to test on success. */ 127189251Ssam struct decision *next; /* Node to test on failure. */ 128189251Ssam struct decision *prev; /* Node whose failure tests us. */ 129189251Ssam struct decision *afterward; /* Node to test on success, 130189251Ssam but failure of successor nodes. */ 131189251Ssam 132346981Scy const char *position; /* String denoting position in pattern. */ 133189251Ssam 134346981Scy struct decision_test *tests; /* The tests for this node. */ 135189251Ssam 136189251Ssam int number; /* Node number, used for labels */ 137189251Ssam int subroutine_number; /* Number of subroutine this node starts */ 138189251Ssam int need_label; /* Label needs to be output. */ 139346981Scy}; 140346981Scy 141346981Scy#define SUBROUTINE_THRESHOLD 100 142189251Ssam 143189251Ssamstatic int next_subroutine_number; 144189251Ssam 145189251Ssam/* We can write three types of subroutines: One for insn recognition, 146189251Ssam one to split insns, and one for peephole-type optimizations. This 147189251Ssam defines which type is being written. */ 148189251Ssam 149189251Ssamenum routine_type { 150189251Ssam RECOG, SPLIT, PEEPHOLE2 151189251Ssam}; 152189251Ssam 153189251Ssam#define IS_SPLIT(X) ((X) != RECOG) 154189251Ssam 155189251Ssam/* Next available node number for tree nodes. */ 156189251Ssam 157189251Ssamstatic int next_number; 158189251Ssam 159346981Scy/* Next number to use as an insn_code. */ 160346981Scy 161346981Scystatic int next_insn_code; 162346981Scy 163346981Scy/* Record the highest depth we ever have so we know how many variables to 164346981Scy allocate in each subroutine we make. */ 165346981Scy 166346981Scystatic int max_depth; 167346981Scy 168346981Scy/* The line number of the start of the pattern currently being processed. */ 169346981Scystatic int pattern_lineno; 170346981Scy 171346981Scy/* Count of errors. */ 172346981Scystatic int error_count; 173346981Scy 174346981Scy/* Predicate handling. 175346981Scy 176346981Scy We construct from the machine description a table mapping each 177346981Scy predicate to a list of the rtl codes it can possibly match. The 178346981Scy function 'maybe_both_true' uses it to deduce that there are no 179346981Scy expressions that can be matches by certain pairs of tree nodes. 180346981Scy Also, if a predicate can match only one code, we can hardwire that 181346981Scy code into the node testing the predicate. 182346981Scy 183346981Scy Some predicates are flagged as special. validate_pattern will not 184346981Scy warn about modeless match_operand expressions if they have a 185346981Scy special predicate. Predicates that allow only constants are also 186346981Scy treated as special, for this purpose. 187346981Scy 188346981Scy validate_pattern will warn about predicates that allow non-lvalues 189346981Scy when they appear in destination operands. 190346981Scy 191346981Scy Calculating the set of rtx codes that can possibly be accepted by a 192346981Scy predicate expression EXP requires a three-state logic: any given 193346981Scy subexpression may definitively accept a code C (Y), definitively 194346981Scy reject a code C (N), or may have an indeterminate effect (I). N 195346981Scy and I is N; Y or I is Y; Y and I, N or I are both I. Here are full 196346981Scy truth tables. 197346981Scy 198346981Scy a b a&b a|b 199346981Scy Y Y Y Y 200346981Scy N Y N Y 201346981Scy N N N N 202346981Scy I Y I Y 203346981Scy I N N I 204346981Scy I I I I 205346981Scy 206346981Scy We represent Y with 1, N with 0, I with 2. If any code is left in 207346981Scy an I state by the complete expression, we must assume that that 208346981Scy code can be accepted. */ 209346981Scy 210189251Ssam#define N 0 211189251Ssam#define Y 1 212189251Ssam#define I 2 213189251Ssam 214189251Ssam#define TRISTATE_AND(a,b) \ 215189251Ssam ((a) == I ? ((b) == N ? N : I) : \ 216189251Ssam (b) == I ? ((a) == N ? N : I) : \ 217189251Ssam (a) && (b)) 218189251Ssam 219189251Ssam#define TRISTATE_OR(a,b) \ 220281806Srpaulo ((a) == I ? ((b) == Y ? Y : I) : \ 221281806Srpaulo (b) == I ? ((a) == Y ? Y : I) : \ 222189251Ssam (a) || (b)) 223189251Ssam 224189251Ssam#define TRISTATE_NOT(a) \ 225189251Ssam ((a) == I ? I : !(a)) 226281806Srpaulo 227189251Ssam/* 0 means no warning about that code yet, 1 means warned. */ 228189251Ssamstatic char did_you_mean_codes[NUM_RTX_CODE]; 229189251Ssam 230189251Ssam/* Recursively calculate the set of rtx codes accepted by the 231189251Ssam predicate expression EXP, writing the result to CODES. */ 232189251Ssamstatic void 233252726Srpaulocompute_predicate_codes (rtx exp, char codes[NUM_RTX_CODE]) 234189251Ssam{ 235189251Ssam char op0_codes[NUM_RTX_CODE]; 236189251Ssam char op1_codes[NUM_RTX_CODE]; 237281806Srpaulo char op2_codes[NUM_RTX_CODE]; 238281806Srpaulo int i; 239281806Srpaulo 240189251Ssam switch (GET_CODE (exp)) 241189251Ssam { 242189251Ssam case AND: 243189251Ssam compute_predicate_codes (XEXP (exp, 0), op0_codes); 244189251Ssam compute_predicate_codes (XEXP (exp, 1), op1_codes); 245189251Ssam for (i = 0; i < NUM_RTX_CODE; i++) 246189251Ssam codes[i] = TRISTATE_AND (op0_codes[i], op1_codes[i]); 247189251Ssam break; 248189251Ssam 249189251Ssam case IOR: 250189251Ssam compute_predicate_codes (XEXP (exp, 0), op0_codes); 251189251Ssam compute_predicate_codes (XEXP (exp, 1), op1_codes); 252189251Ssam for (i = 0; i < NUM_RTX_CODE; i++) 253189251Ssam codes[i] = TRISTATE_OR (op0_codes[i], op1_codes[i]); 254337817Scy break; 255337817Scy case NOT: 256337817Scy compute_predicate_codes (XEXP (exp, 0), op0_codes); 257337817Scy for (i = 0; i < NUM_RTX_CODE; i++) 258337817Scy codes[i] = TRISTATE_NOT (op0_codes[i]); 259337817Scy break; 260337817Scy 261337817Scy case IF_THEN_ELSE: 262189251Ssam /* a ? b : c accepts the same codes as (a & b) | (!a & c). */ 263189251Ssam compute_predicate_codes (XEXP (exp, 0), op0_codes); 264281806Srpaulo compute_predicate_codes (XEXP (exp, 1), op1_codes); 265281806Srpaulo compute_predicate_codes (XEXP (exp, 2), op2_codes); 266281806Srpaulo for (i = 0; i < NUM_RTX_CODE; i++) 267189251Ssam codes[i] = TRISTATE_OR (TRISTATE_AND (op0_codes[i], op1_codes[i]), 268189251Ssam TRISTATE_AND (TRISTATE_NOT (op0_codes[i]), 269189251Ssam op2_codes[i])); 270189251Ssam break; 271189251Ssam 272189251Ssam case MATCH_CODE: 273189251Ssam /* MATCH_CODE allows a specified list of codes. However, if it 274189251Ssam does not apply to the top level of the expression, it does not 275189251Ssam constrain the set of codes for the top level. */ 276189251Ssam if (XSTR (exp, 1)[0] != '\0') 277189251Ssam { 278189251Ssam memset (codes, Y, NUM_RTX_CODE); 279252726Srpaulo break; 280252726Srpaulo } 281252726Srpaulo 282252726Srpaulo memset (codes, N, NUM_RTX_CODE); 283252726Srpaulo { 284252726Srpaulo const char *next_code = XSTR (exp, 0); 285189251Ssam const char *code; 286189251Ssam 287189251Ssam if (*next_code == '\0') 288189251Ssam { 289189251Ssam message_with_line (pattern_lineno, "empty match_code expression"); 290189251Ssam error_count++; 291189251Ssam break; 292189251Ssam } 293189251Ssam 294189251Ssam while ((code = scan_comma_elt (&next_code)) != 0) 295189251Ssam { 296189251Ssam size_t n = next_code - code; 297189251Ssam int found_it = 0; 298189251Ssam 299189251Ssam for (i = 0; i < NUM_RTX_CODE; i++) 300189251Ssam if (!strncmp (code, GET_RTX_NAME (i), n) 301189251Ssam && GET_RTX_NAME (i)[n] == '\0') 302189251Ssam { 303189251Ssam codes[i] = Y; 304189251Ssam found_it = 1; 305189251Ssam break; 306189251Ssam } 307189251Ssam if (!found_it) 308189251Ssam { 309189251Ssam message_with_line (pattern_lineno, "match_code \"%.*s\" matches nothing", 310189251Ssam (int) n, code); 311189251Ssam error_count ++; 312189251Ssam for (i = 0; i < NUM_RTX_CODE; i++) 313189251Ssam if (!strncasecmp (code, GET_RTX_NAME (i), n) 314189251Ssam && GET_RTX_NAME (i)[n] == '\0' 315189251Ssam && !did_you_mean_codes[i]) 316189251Ssam { 317189251Ssam did_you_mean_codes[i] = 1; 318189251Ssam message_with_line (pattern_lineno, "(did you mean \"%s\"?)", GET_RTX_NAME (i)); 319189251Ssam } 320189251Ssam } 321189251Ssam 322189251Ssam } 323252726Srpaulo } 324189251Ssam break; 325189251Ssam 326189251Ssam case MATCH_OPERAND: 327189251Ssam /* MATCH_OPERAND disallows the set of codes that the named predicate 328189251Ssam disallows, and is indeterminate for the codes that it does allow. */ 329189251Ssam { 330189251Ssam struct pred_data *p = lookup_predicate (XSTR (exp, 1)); 331189251Ssam if (!p) 332252726Srpaulo { 333252726Srpaulo message_with_line (pattern_lineno, 334189251Ssam "reference to unknown predicate '%s'", 335189251Ssam XSTR (exp, 1)); 336189251Ssam error_count++; 337214734Srpaulo break; 338214734Srpaulo } 339214734Srpaulo for (i = 0; i < NUM_RTX_CODE; i++) 340252726Srpaulo codes[i] = p->codes[i] ? I : N; 341252726Srpaulo } 342189251Ssam break; 343189251Ssam 344189251Ssam 345214734Srpaulo case MATCH_TEST: 346214734Srpaulo /* (match_test WHATEVER) is completely indeterminate. */ 347214734Srpaulo memset (codes, I, NUM_RTX_CODE); 348252726Srpaulo break; 349252726Srpaulo 350189251Ssam default: 351189251Ssam message_with_line (pattern_lineno, 352189251Ssam "'%s' cannot be used in a define_predicate expression", 353189251Ssam GET_RTX_NAME (GET_CODE (exp))); 354189251Ssam error_count++; 355189251Ssam memset (codes, I, NUM_RTX_CODE); 356189251Ssam break; 357189251Ssam } 358189251Ssam} 359189251Ssam 360189251Ssam#undef TRISTATE_OR 361189251Ssam#undef TRISTATE_AND 362189251Ssam#undef TRISTATE_NOT 363189251Ssam 364189251Ssam/* Process a define_predicate expression: compute the set of predicates 365189251Ssam that can be matched, and record this as a known predicate. */ 366189251Ssamstatic void 367189251Ssamprocess_define_predicate (rtx desc) 368189251Ssam{ 369189251Ssam struct pred_data *pred = xcalloc (sizeof (struct pred_data), 1); 370189251Ssam char codes[NUM_RTX_CODE]; 371189251Ssam bool seen_one = false; 372189251Ssam int i; 373252726Srpaulo 374189251Ssam pred->name = XSTR (desc, 0); 375189251Ssam if (GET_CODE (desc) == DEFINE_SPECIAL_PREDICATE) 376189251Ssam pred->special = 1; 377189251Ssam 378189251Ssam compute_predicate_codes (XEXP (desc, 1), codes); 379189251Ssam 380189251Ssam for (i = 0; i < NUM_RTX_CODE; i++) 381252726Srpaulo if (codes[i] != N) 382252726Srpaulo { 383189251Ssam pred->codes[i] = true; 384189251Ssam if (GET_RTX_CLASS (i) != RTX_CONST_OBJ) 385189251Ssam pred->allows_non_const = true; 386337817Scy if (i != REG 387189251Ssam && i != SUBREG 388189251Ssam && i != MEM 389337817Scy && i != CONCAT 390337817Scy && i != PARALLEL 391337817Scy && i != STRICT_LOW_PART) 392189251Ssam pred->allows_non_lvalue = true; 393337817Scy 394189251Ssam if (seen_one) 395189251Ssam pred->singleton = UNKNOWN; 396189251Ssam else 397189251Ssam { 398189251Ssam pred->singleton = i; 399189251Ssam seen_one = true; 400189251Ssam } 401189251Ssam } 402189251Ssam add_predicate (pred); 403189251Ssam} 404189251Ssam#undef I 405189251Ssam#undef N 406189251Ssam#undef Y 407189251Ssam 408189251Ssam 409189251Ssamstatic struct decision *new_decision 410189251Ssam (const char *, struct decision_head *); 411189251Ssamstatic struct decision_test *new_decision_test 412189251Ssam (enum decision_type, struct decision_test ***); 413189251Ssamstatic rtx find_operand 414189251Ssam (rtx, int, rtx); 415189251Ssamstatic rtx find_matching_operand 416189251Ssam (rtx, int); 417189251Ssamstatic void validate_pattern 418189251Ssam (rtx, rtx, rtx, int); 419189251Ssamstatic struct decision *add_to_sequence 420189251Ssam (rtx, struct decision_head *, const char *, enum routine_type, int); 421189251Ssam 422189251Ssamstatic int maybe_both_true_2 423189251Ssam (struct decision_test *, struct decision_test *); 424189251Ssamstatic int maybe_both_true_1 425189251Ssam (struct decision_test *, struct decision_test *); 426189251Ssamstatic int maybe_both_true 427189251Ssam (struct decision *, struct decision *, int); 428189251Ssam 429189251Ssamstatic int nodes_identical_1 430189251Ssam (struct decision_test *, struct decision_test *); 431189251Ssamstatic int nodes_identical 432189251Ssam (struct decision *, struct decision *); 433281806Srpaulostatic void merge_accept_insn 434281806Srpaulo (struct decision *, struct decision *); 435346981Scystatic void merge_trees 436281806Srpaulo (struct decision_head *, struct decision_head *); 437281806Srpaulo 438281806Srpaulostatic void factor_tests 439281806Srpaulo (struct decision_head *); 440281806Srpaulostatic void simplify_tests 441281806Srpaulo (struct decision_head *); 442281806Srpaulostatic int break_out_subroutines 443281806Srpaulo (struct decision_head *, int); 444281806Srpaulostatic void find_afterward 445281806Srpaulo (struct decision_head *, struct decision *); 446281806Srpaulo 447281806Srpaulostatic void change_state 448281806Srpaulo (const char *, const char *, const char *); 449281806Srpaulostatic void print_code 450281806Srpaulo (enum rtx_code); 451281806Srpaulostatic void write_afterward 452281806Srpaulo (struct decision *, struct decision *, const char *); 453281806Srpaulostatic struct decision *write_switch 454281806Srpaulo (struct decision *, int); 455281806Srpaulostatic void write_cond 456281806Srpaulo (struct decision_test *, int, enum routine_type); 457281806Srpaulostatic void write_action 458281806Srpaulo (struct decision *, struct decision_test *, int, int, 459281806Srpaulo struct decision *, enum routine_type); 460281806Srpaulostatic int is_unconditional 461281806Srpaulo (struct decision_test *, enum routine_type); 462281806Srpaulostatic int write_node 463281806Srpaulo (struct decision *, int, enum routine_type); 464281806Srpaulostatic void write_tree_1 465281806Srpaulo (struct decision_head *, int, enum routine_type); 466281806Srpaulostatic void write_tree 467281806Srpaulo (struct decision_head *, const char *, enum routine_type, int); 468281806Srpaulostatic void write_subroutine 469281806Srpaulo (struct decision_head *, enum routine_type); 470281806Srpaulostatic void write_subroutines 471281806Srpaulo (struct decision_head *, enum routine_type); 472281806Srpaulostatic void write_header 473281806Srpaulo (void); 474281806Srpaulo 475281806Srpaulostatic struct decision_head make_insn_sequence 476346981Scy (rtx, enum routine_type); 477346981Scystatic void process_tree 478346981Scy (struct decision_head *, enum routine_type); 479346981Scy 480346981Scystatic void debug_decision_0 481346981Scy (struct decision *, int, int); 482346981Scystatic void debug_decision_1 483346981Scy (struct decision *, int); 484346981Scystatic void debug_decision_2 485346981Scy (struct decision_test *); 486346981Scyextern void debug_decision 487346981Scy (struct decision *); 488346981Scyextern void debug_decision_list 489346981Scy (struct decision *); 490346981Scy 491346981Scy/* Create a new node in sequence after LAST. */ 492346981Scy 493346981Scystatic struct decision * 494346981Scynew_decision (const char *position, struct decision_head *last) 495346981Scy{ 496346981Scy struct decision *new = xcalloc (1, sizeof (struct decision)); 497346981Scy 498346981Scy new->success = *last; 499346981Scy new->position = xstrdup (position); 500346981Scy new->number = next_number++; 501346981Scy 502346981Scy last->first = last->last = new; 503346981Scy return new; 504346981Scy} 505346981Scy 506346981Scy/* Create a new test and link it in at PLACE. */ 507346981Scy 508346981Scystatic struct decision_test * 509346981Scynew_decision_test (enum decision_type type, struct decision_test ***pplace) 510346981Scy{ 511346981Scy struct decision_test **place = *pplace; 512346981Scy struct decision_test *test; 513346981Scy 514346981Scy test = XNEW (struct decision_test); 515281806Srpaulo test->next = *place; 516281806Srpaulo test->type = type; 517281806Srpaulo *place = test; 518346981Scy 519346981Scy place = &test->next; 520346981Scy *pplace = place; 521346981Scy 522346981Scy return test; 523346981Scy} 524281806Srpaulo 525281806Srpaulo/* Search for and return operand N, stop when reaching node STOP. */ 526281806Srpaulo 527281806Srpaulostatic rtx 528281806Srpaulofind_operand (rtx pattern, int n, rtx stop) 529281806Srpaulo{ 530281806Srpaulo const char *fmt; 531281806Srpaulo RTX_CODE code; 532281806Srpaulo int i, j, len; 533281806Srpaulo rtx r; 534281806Srpaulo 535281806Srpaulo if (pattern == stop) 536281806Srpaulo return stop; 537281806Srpaulo 538281806Srpaulo code = GET_CODE (pattern); 539281806Srpaulo if ((code == MATCH_SCRATCH 540281806Srpaulo || code == MATCH_OPERAND 541281806Srpaulo || code == MATCH_OPERATOR 542281806Srpaulo || code == MATCH_PARALLEL) 543281806Srpaulo && XINT (pattern, 0) == n) 544281806Srpaulo return pattern; 545281806Srpaulo 546281806Srpaulo fmt = GET_RTX_FORMAT (code); 547281806Srpaulo len = GET_RTX_LENGTH (code); 548281806Srpaulo for (i = 0; i < len; i++) 549281806Srpaulo { 550281806Srpaulo switch (fmt[i]) 551281806Srpaulo { 552281806Srpaulo case 'e': case 'u': 553281806Srpaulo if ((r = find_operand (XEXP (pattern, i), n, stop)) != NULL_RTX) 554281806Srpaulo return r; 555281806Srpaulo break; 556281806Srpaulo 557281806Srpaulo case 'V': 558281806Srpaulo if (! XVEC (pattern, i)) 559281806Srpaulo break; 560281806Srpaulo /* Fall through. */ 561281806Srpaulo 562281806Srpaulo case 'E': 563281806Srpaulo for (j = 0; j < XVECLEN (pattern, i); j++) 564281806Srpaulo if ((r = find_operand (XVECEXP (pattern, i, j), n, stop)) 565281806Srpaulo != NULL_RTX) 566281806Srpaulo return r; 567281806Srpaulo break; 568281806Srpaulo 569281806Srpaulo case 'i': case 'w': case '0': case 's': 570281806Srpaulo break; 571281806Srpaulo 572281806Srpaulo default: 573281806Srpaulo gcc_unreachable (); 574281806Srpaulo } 575281806Srpaulo } 576346981Scy 577346981Scy return NULL; 578346981Scy} 579346981Scy 580346981Scy/* Search for and return operand M, such that it has a matching 581346981Scy constraint for operand N. */ 582346981Scy 583346981Scystatic rtx 584346981Scyfind_matching_operand (rtx pattern, int n) 585346981Scy{ 586346981Scy const char *fmt; 587346981Scy RTX_CODE code; 588346981Scy int i, j, len; 589346981Scy rtx r; 590346981Scy 591346981Scy code = GET_CODE (pattern); 592346981Scy if (code == MATCH_OPERAND 593346981Scy && (XSTR (pattern, 2)[0] == '0' + n 594346981Scy || (XSTR (pattern, 2)[0] == '%' 595346981Scy && XSTR (pattern, 2)[1] == '0' + n))) 596346981Scy return pattern; 597346981Scy 598346981Scy fmt = GET_RTX_FORMAT (code); 599346981Scy len = GET_RTX_LENGTH (code); 600346981Scy for (i = 0; i < len; i++) 601346981Scy { 602346981Scy switch (fmt[i]) 603346981Scy { 604346981Scy case 'e': case 'u': 605346981Scy if ((r = find_matching_operand (XEXP (pattern, i), n))) 606346981Scy return r; 607346981Scy break; 608346981Scy 609346981Scy case 'V': 610346981Scy if (! XVEC (pattern, i)) 611346981Scy break; 612346981Scy /* Fall through. */ 613346981Scy 614346981Scy case 'E': 615346981Scy for (j = 0; j < XVECLEN (pattern, i); j++) 616346981Scy if ((r = find_matching_operand (XVECEXP (pattern, i, j), n))) 617346981Scy return r; 618346981Scy break; 619346981Scy 620346981Scy case 'i': case 'w': case '0': case 's': 621346981Scy break; 622346981Scy 623346981Scy default: 624346981Scy gcc_unreachable (); 625346981Scy } 626346981Scy } 627346981Scy 628346981Scy return NULL; 629346981Scy} 630346981Scy 631346981Scy 632346981Scy/* Check for various errors in patterns. SET is nonnull for a destination, 633346981Scy and is the complete set pattern. SET_CODE is '=' for normal sets, and 634346981Scy '+' within a context that requires in-out constraints. */ 635346981Scy 636346981Scystatic void 637346981Scyvalidate_pattern (rtx pattern, rtx insn, rtx set, int set_code) 638346981Scy{ 639346981Scy const char *fmt; 640346981Scy RTX_CODE code; 641346981Scy size_t i, len; 642346981Scy int j; 643346981Scy 644346981Scy code = GET_CODE (pattern); 645346981Scy switch (code) 646346981Scy { 647346981Scy case MATCH_SCRATCH: 648346981Scy return; 649346981Scy case MATCH_DUP: 650346981Scy case MATCH_OP_DUP: 651346981Scy case MATCH_PAR_DUP: 652346981Scy if (find_operand (insn, XINT (pattern, 0), pattern) == pattern) 653346981Scy { 654346981Scy message_with_line (pattern_lineno, 655346981Scy "operand %i duplicated before defined", 656346981Scy XINT (pattern, 0)); 657346981Scy error_count++; 658346981Scy } 659281806Srpaulo break; 660281806Srpaulo case MATCH_OPERAND: 661281806Srpaulo case MATCH_OPERATOR: 662281806Srpaulo { 663281806Srpaulo const char *pred_name = XSTR (pattern, 1); 664281806Srpaulo const struct pred_data *pred; 665281806Srpaulo const char *c_test; 666281806Srpaulo 667281806Srpaulo if (GET_CODE (insn) == DEFINE_INSN) 668281806Srpaulo c_test = XSTR (insn, 2); 669281806Srpaulo else 670281806Srpaulo c_test = XSTR (insn, 1); 671281806Srpaulo 672281806Srpaulo if (pred_name[0] != 0) 673346981Scy { 674346981Scy pred = lookup_predicate (pred_name); 675346981Scy if (!pred) 676346981Scy message_with_line (pattern_lineno, 677346981Scy "warning: unknown predicate '%s'", 678346981Scy pred_name); 679281806Srpaulo } 680281806Srpaulo else 681281806Srpaulo pred = 0; 682281806Srpaulo 683346981Scy if (code == MATCH_OPERAND) 684346981Scy { 685281806Srpaulo const char constraints0 = XSTR (pattern, 2)[0]; 686346981Scy 687281806Srpaulo /* In DEFINE_EXPAND, DEFINE_SPLIT, and DEFINE_PEEPHOLE2, we 688281806Srpaulo don't use the MATCH_OPERAND constraint, only the predicate. 689281806Srpaulo This is confusing to folks doing new ports, so help them 690281806Srpaulo not make the mistake. */ 691281806Srpaulo if (GET_CODE (insn) == DEFINE_EXPAND 692281806Srpaulo || GET_CODE (insn) == DEFINE_SPLIT 693281806Srpaulo || GET_CODE (insn) == DEFINE_PEEPHOLE2) 694346981Scy { 695281806Srpaulo if (constraints0) 696281806Srpaulo message_with_line (pattern_lineno, 697281806Srpaulo "warning: constraints not supported in %s", 698281806Srpaulo rtx_name[GET_CODE (insn)]); 699281806Srpaulo } 700281806Srpaulo 701281806Srpaulo /* A MATCH_OPERAND that is a SET should have an output reload. */ 702281806Srpaulo else if (set && constraints0) 703281806Srpaulo { 704281806Srpaulo if (set_code == '+') 705281806Srpaulo { 706281806Srpaulo if (constraints0 == '+') 707281806Srpaulo ; 708281806Srpaulo /* If we've only got an output reload for this operand, 709281806Srpaulo we'd better have a matching input operand. */ 710281806Srpaulo else if (constraints0 == '=' 711281806Srpaulo && find_matching_operand (insn, XINT (pattern, 0))) 712281806Srpaulo ; 713281806Srpaulo else 714346981Scy { 715346981Scy message_with_line (pattern_lineno, 716346981Scy "operand %d missing in-out reload", 717346981Scy XINT (pattern, 0)); 718346981Scy error_count++; 719346981Scy } 720346981Scy } 721281806Srpaulo else if (constraints0 != '=' && constraints0 != '+') 722281806Srpaulo { 723281806Srpaulo message_with_line (pattern_lineno, 724281806Srpaulo "operand %d missing output reload", 725281806Srpaulo XINT (pattern, 0)); 726281806Srpaulo error_count++; 727281806Srpaulo } 728281806Srpaulo } 729346981Scy } 730346981Scy 731346981Scy /* Allowing non-lvalues in destinations -- particularly CONST_INT -- 732346981Scy while not likely to occur at runtime, results in less efficient 733346981Scy code from insn-recog.c. */ 734346981Scy if (set && pred && pred->allows_non_lvalue) 735346981Scy message_with_line (pattern_lineno, 736346981Scy "warning: destination operand %d " 737346981Scy "allows non-lvalue", 738346981Scy XINT (pattern, 0)); 739346981Scy 740346981Scy /* A modeless MATCH_OPERAND can be handy when we can check for 741346981Scy multiple modes in the c_test. In most other cases, it is a 742346981Scy mistake. Only DEFINE_INSN is eligible, since SPLIT and 743346981Scy PEEP2 can FAIL within the output pattern. Exclude special 744346981Scy predicates, which check the mode themselves. Also exclude 745346981Scy predicates that allow only constants. Exclude the SET_DEST 746281806Srpaulo of a call instruction, as that is a common idiom. */ 747281806Srpaulo 748281806Srpaulo if (GET_MODE (pattern) == VOIDmode 749281806Srpaulo && code == MATCH_OPERAND 750281806Srpaulo && GET_CODE (insn) == DEFINE_INSN 751281806Srpaulo && pred 752281806Srpaulo && !pred->special 753281806Srpaulo && pred->allows_non_const 754281806Srpaulo && strstr (c_test, "operands") == NULL 755281806Srpaulo && ! (set 756281806Srpaulo && GET_CODE (set) == SET 757281806Srpaulo && GET_CODE (SET_SRC (set)) == CALL)) 758281806Srpaulo message_with_line (pattern_lineno, 759281806Srpaulo "warning: operand %d missing mode?", 760281806Srpaulo XINT (pattern, 0)); 761281806Srpaulo return; 762281806Srpaulo } 763281806Srpaulo 764281806Srpaulo case SET: 765281806Srpaulo { 766346981Scy enum machine_mode dmode, smode; 767346981Scy rtx dest, src; 768281806Srpaulo 769346981Scy dest = SET_DEST (pattern); 770346981Scy src = SET_SRC (pattern); 771281806Srpaulo 772281806Srpaulo /* STRICT_LOW_PART is a wrapper. Its argument is the real 773281806Srpaulo destination, and it's mode should match the source. */ 774281806Srpaulo if (GET_CODE (dest) == STRICT_LOW_PART) 775281806Srpaulo dest = XEXP (dest, 0); 776281806Srpaulo 777281806Srpaulo /* Find the referent for a DUP. */ 778281806Srpaulo 779281806Srpaulo if (GET_CODE (dest) == MATCH_DUP 780281806Srpaulo || GET_CODE (dest) == MATCH_OP_DUP 781346981Scy || GET_CODE (dest) == MATCH_PAR_DUP) 782346981Scy dest = find_operand (insn, XINT (dest, 0), NULL); 783346981Scy 784346981Scy if (GET_CODE (src) == MATCH_DUP 785346981Scy || GET_CODE (src) == MATCH_OP_DUP 786281806Srpaulo || GET_CODE (src) == MATCH_PAR_DUP) 787281806Srpaulo src = find_operand (insn, XINT (src, 0), NULL); 788281806Srpaulo 789281806Srpaulo dmode = GET_MODE (dest); 790281806Srpaulo smode = GET_MODE (src); 791281806Srpaulo 792281806Srpaulo /* The mode of an ADDRESS_OPERAND is the mode of the memory 793346981Scy reference, not the mode of the address. */ 794281806Srpaulo if (GET_CODE (src) == MATCH_OPERAND 795281806Srpaulo && ! strcmp (XSTR (src, 1), "address_operand")) 796281806Srpaulo ; 797281806Srpaulo 798281806Srpaulo /* The operands of a SET must have the same mode unless one 799281806Srpaulo is VOIDmode. */ 800281806Srpaulo else if (dmode != VOIDmode && smode != VOIDmode && dmode != smode) 801281806Srpaulo { 802346981Scy message_with_line (pattern_lineno, 803281806Srpaulo "mode mismatch in set: %smode vs %smode", 804281806Srpaulo GET_MODE_NAME (dmode), GET_MODE_NAME (smode)); 805281806Srpaulo error_count++; 806281806Srpaulo } 807281806Srpaulo 808346981Scy /* If only one of the operands is VOIDmode, and PC or CC0 is 809281806Srpaulo not involved, it's probably a mistake. */ 810281806Srpaulo else if (dmode != smode 811346981Scy && GET_CODE (dest) != PC 812281806Srpaulo && GET_CODE (dest) != CC0 813281806Srpaulo && GET_CODE (src) != PC 814281806Srpaulo && GET_CODE (src) != CC0 815281806Srpaulo && GET_CODE (src) != CONST_INT) 816281806Srpaulo { 817281806Srpaulo const char *which; 818289549Srpaulo which = (dmode == VOIDmode ? "destination" : "source"); 819281806Srpaulo message_with_line (pattern_lineno, 820346981Scy "warning: %s missing a mode?", which); 821281806Srpaulo } 822346981Scy 823281806Srpaulo if (dest != SET_DEST (pattern)) 824281806Srpaulo validate_pattern (dest, insn, pattern, '='); 825281806Srpaulo validate_pattern (SET_DEST (pattern), insn, pattern, '='); 826281806Srpaulo validate_pattern (SET_SRC (pattern), insn, NULL_RTX, 0); 827281806Srpaulo return; 828281806Srpaulo } 829281806Srpaulo 830281806Srpaulo case CLOBBER: 831281806Srpaulo validate_pattern (SET_DEST (pattern), insn, pattern, '='); 832281806Srpaulo return; 833281806Srpaulo 834281806Srpaulo case ZERO_EXTRACT: 835281806Srpaulo validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0); 836346981Scy validate_pattern (XEXP (pattern, 1), insn, NULL_RTX, 0); 837281806Srpaulo validate_pattern (XEXP (pattern, 2), insn, NULL_RTX, 0); 838281806Srpaulo return; 839281806Srpaulo 840281806Srpaulo case STRICT_LOW_PART: 841281806Srpaulo validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0); 842346981Scy return; 843346981Scy 844346981Scy case LABEL_REF: 845346981Scy if (GET_MODE (XEXP (pattern, 0)) != VOIDmode) 846346981Scy { 847346981Scy message_with_line (pattern_lineno, 848346981Scy "operand to label_ref %smode not VOIDmode", 849346981Scy GET_MODE_NAME (GET_MODE (XEXP (pattern, 0)))); 850346981Scy error_count++; 851346981Scy } 852346981Scy break; 853346981Scy 854346981Scy default: 855346981Scy break; 856346981Scy } 857346981Scy 858281806Srpaulo fmt = GET_RTX_FORMAT (code); 859281806Srpaulo len = GET_RTX_LENGTH (code); 860281806Srpaulo for (i = 0; i < len; i++) 861281806Srpaulo { 862281806Srpaulo switch (fmt[i]) 863281806Srpaulo { 864281806Srpaulo case 'e': case 'u': 865281806Srpaulo validate_pattern (XEXP (pattern, i), insn, NULL_RTX, 0); 866189251Ssam break; 867189251Ssam 868189251Ssam case 'E': 869189251Ssam for (j = 0; j < XVECLEN (pattern, i); j++) 870189251Ssam validate_pattern (XVECEXP (pattern, i, j), insn, NULL_RTX, 0); 871189251Ssam break; 872189251Ssam 873189251Ssam case 'i': case 'w': case '0': case 's': 874252726Srpaulo break; 875189251Ssam 876189251Ssam default: 877189251Ssam gcc_unreachable (); 878189251Ssam } 879189251Ssam } 880189251Ssam} 881189251Ssam 882189251Ssam/* Create a chain of nodes to verify that an rtl expression matches 883252726Srpaulo PATTERN. 884252726Srpaulo 885252726Srpaulo LAST is a pointer to the listhead in the previous node in the chain (or 886252726Srpaulo in the calling function, for the first node). 887189251Ssam 888189251Ssam POSITION is the string representing the current position in the insn. 889189251Ssam 890189251Ssam INSN_TYPE is the type of insn for which we are emitting code. 891189251Ssam 892189251Ssam A pointer to the final node in the chain is returned. */ 893189251Ssam 894189251Ssamstatic struct decision * 895189251Ssamadd_to_sequence (rtx pattern, struct decision_head *last, const char *position, 896189251Ssam enum routine_type insn_type, int top) 897189251Ssam{ 898189251Ssam RTX_CODE code; 899189251Ssam struct decision *this, *sub; 900189251Ssam struct decision_test *test; 901189251Ssam struct decision_test **place; 902189251Ssam char *subpos; 903189251Ssam size_t i; 904189251Ssam const char *fmt; 905189251Ssam int depth = strlen (position); 906189251Ssam int len; 907189251Ssam enum machine_mode mode; 908189251Ssam 909189251Ssam if (depth > max_depth) 910189251Ssam max_depth = depth; 911189251Ssam 912281806Srpaulo subpos = xmalloc (depth + 2); 913189251Ssam strcpy (subpos, position); 914189251Ssam subpos[depth + 1] = 0; 915281806Srpaulo 916281806Srpaulo sub = this = new_decision (position, last); 917189251Ssam place = &this->tests; 918189251Ssam 919189251Ssam restart: 920189251Ssam mode = GET_MODE (pattern); 921189251Ssam code = GET_CODE (pattern); 922189251Ssam 923189251Ssam switch (code) 924189251Ssam { 925189251Ssam case PARALLEL: 926189251Ssam /* Toplevel peephole pattern. */ 927281806Srpaulo if (insn_type == PEEPHOLE2 && top) 928189251Ssam { 929189251Ssam int num_insns; 930281806Srpaulo 931281806Srpaulo /* Check we have sufficient insns. This avoids complications 932281806Srpaulo because we then know peep2_next_insn never fails. */ 933281806Srpaulo num_insns = XVECLEN (pattern, 0); 934281806Srpaulo if (num_insns > 1) 935281806Srpaulo { 936281806Srpaulo test = new_decision_test (DT_num_insns, &place); 937281806Srpaulo test->u.num_insns = num_insns; 938281806Srpaulo last = &sub->success; 939189251Ssam } 940189251Ssam else 941189251Ssam { 942189251Ssam /* We don't need the node we just created -- unlink it. */ 943189251Ssam last->first = last->last = NULL; 944189251Ssam } 945189251Ssam 946189251Ssam for (i = 0; i < (size_t) XVECLEN (pattern, 0); i++) 947189251Ssam { 948189251Ssam /* Which insn we're looking at is represented by A-Z. We don't 949189251Ssam ever use 'A', however; it is always implied. */ 950189251Ssam 951189251Ssam subpos[depth] = (i > 0 ? 'A' + i : 0); 952189251Ssam sub = add_to_sequence (XVECEXP (pattern, 0, i), 953289549Srpaulo last, subpos, insn_type, 0); 954189251Ssam last = &sub->success; 955189251Ssam } 956189251Ssam goto ret; 957281806Srpaulo } 958281806Srpaulo 959189251Ssam /* Else nothing special. */ 960281806Srpaulo break; 961189251Ssam 962189251Ssam case MATCH_PARALLEL: 963281806Srpaulo /* The explicit patterns within a match_parallel enforce a minimum 964189251Ssam length on the vector. The match_parallel predicate may allow 965189251Ssam for more elements. We do need to check for this minimum here 966189251Ssam or the code generated to match the internals may reference data 967189251Ssam beyond the end of the vector. */ 968189251Ssam test = new_decision_test (DT_veclen_ge, &place); 969189251Ssam test->u.veclen = XVECLEN (pattern, 2); 970189251Ssam /* Fall through. */ 971189251Ssam 972189251Ssam case MATCH_OPERAND: 973189251Ssam case MATCH_SCRATCH: 974189251Ssam case MATCH_OPERATOR: 975189251Ssam { 976189251Ssam RTX_CODE was_code = code; 977189251Ssam const char *pred_name; 978189251Ssam bool allows_const_int = true; 979189251Ssam 980189251Ssam if (code == MATCH_SCRATCH) 981189251Ssam { 982189251Ssam pred_name = "scratch_operand"; 983189251Ssam code = UNKNOWN; 984189251Ssam } 985189251Ssam else 986189251Ssam { 987189251Ssam pred_name = XSTR (pattern, 1); 988252726Srpaulo if (code == MATCH_PARALLEL) 989252726Srpaulo code = PARALLEL; 990189251Ssam else 991189251Ssam code = UNKNOWN; 992189251Ssam } 993189251Ssam 994189251Ssam if (pred_name[0] != 0) 995189251Ssam { 996189251Ssam const struct pred_data *pred; 997189251Ssam 998189251Ssam test = new_decision_test (DT_pred, &place); 999189251Ssam test->u.pred.name = pred_name; 1000189251Ssam test->u.pred.mode = mode; 1001189251Ssam 1002189251Ssam /* See if we know about this predicate. 1003189251Ssam If we do, remember it for use below. 1004189251Ssam 1005189251Ssam We can optimize the generated code a little if either 1006252726Srpaulo (a) the predicate only accepts one code, or (b) the 1007252726Srpaulo predicate does not allow CONST_INT, in which case it 1008189251Ssam can match only if the modes match. */ 1009189251Ssam pred = lookup_predicate (pred_name); 1010189251Ssam if (pred) 1011189251Ssam { 1012189251Ssam test->u.pred.data = pred; 1013189251Ssam allows_const_int = pred->codes[CONST_INT]; 1014189251Ssam if (was_code == MATCH_PARALLEL 1015189251Ssam && pred->singleton != PARALLEL) 1016189251Ssam message_with_line (pattern_lineno, 1017189251Ssam "predicate '%s' used in match_parallel " 1018189251Ssam "does not allow only PARALLEL", pred->name); 1019189251Ssam else 1020189251Ssam code = pred->singleton; 1021189251Ssam } 1022189251Ssam else 1023189251Ssam message_with_line (pattern_lineno, 1024189251Ssam "warning: unknown predicate '%s' in '%s' expression", 1025189251Ssam pred_name, GET_RTX_NAME (was_code)); 1026189251Ssam } 1027189251Ssam 1028189251Ssam /* Can't enforce a mode if we allow const_int. */ 1029189251Ssam if (allows_const_int) 1030189251Ssam mode = VOIDmode; 1031189251Ssam 1032189251Ssam /* Accept the operand, i.e. record it in `operands'. */ 1033189251Ssam test = new_decision_test (DT_accept_op, &place); 1034189251Ssam test->u.opno = XINT (pattern, 0); 1035189251Ssam 1036346981Scy if (was_code == MATCH_OPERATOR || was_code == MATCH_PARALLEL) 1037346981Scy { 1038189251Ssam char base = (was_code == MATCH_OPERATOR ? '0' : 'a'); 1039189251Ssam for (i = 0; i < (size_t) XVECLEN (pattern, 2); i++) 1040189251Ssam { 1041189251Ssam subpos[depth] = i + base; 1042189251Ssam sub = add_to_sequence (XVECEXP (pattern, 2, i), 1043189251Ssam &sub->success, subpos, insn_type, 0); 1044189251Ssam } 1045189251Ssam } 1046189251Ssam goto fini; 1047189251Ssam } 1048189251Ssam 1049189251Ssam case MATCH_OP_DUP: 1050189251Ssam code = UNKNOWN; 1051189251Ssam 1052189251Ssam test = new_decision_test (DT_dup, &place); 1053189251Ssam test->u.dup = XINT (pattern, 0); 1054189251Ssam 1055189251Ssam test = new_decision_test (DT_accept_op, &place); 1056189251Ssam test->u.opno = XINT (pattern, 0); 1057189251Ssam 1058189251Ssam for (i = 0; i < (size_t) XVECLEN (pattern, 1); i++) 1059189251Ssam { 1060346981Scy subpos[depth] = i + '0'; 1061346981Scy sub = add_to_sequence (XVECEXP (pattern, 1, i), 1062346981Scy &sub->success, subpos, insn_type, 0); 1063346981Scy } 1064346981Scy goto fini; 1065189251Ssam 1066189251Ssam case MATCH_DUP: 1067189251Ssam case MATCH_PAR_DUP: 1068189251Ssam code = UNKNOWN; 1069189251Ssam 1070189251Ssam test = new_decision_test (DT_dup, &place); 1071189251Ssam test->u.dup = XINT (pattern, 0); 1072189251Ssam goto fini; 1073189251Ssam 1074189251Ssam case ADDRESS: 1075189251Ssam pattern = XEXP (pattern, 0); 1076189251Ssam goto restart; 1077189251Ssam 1078189251Ssam default: 1079189251Ssam break; 1080189251Ssam } 1081189251Ssam 1082189251Ssam fmt = GET_RTX_FORMAT (code); 1083189251Ssam len = GET_RTX_LENGTH (code); 1084189251Ssam 1085189251Ssam /* Do tests against the current node first. */ 1086189251Ssam for (i = 0; i < (size_t) len; i++) 1087189251Ssam { 1088189251Ssam if (fmt[i] == 'i') 1089189251Ssam { 1090189251Ssam gcc_assert (i < 2); 1091189251Ssam 1092189251Ssam if (!i) 1093189251Ssam { 1094189251Ssam test = new_decision_test (DT_elt_zero_int, &place); 1095189251Ssam test->u.intval = XINT (pattern, i); 1096189251Ssam } 1097189251Ssam else 1098189251Ssam { 1099189251Ssam test = new_decision_test (DT_elt_one_int, &place); 1100189251Ssam test->u.intval = XINT (pattern, i); 1101189251Ssam } 1102189251Ssam } 1103189251Ssam else if (fmt[i] == 'w') 1104189251Ssam { 1105189251Ssam /* If this value actually fits in an int, we can use a switch 1106189251Ssam statement here, so indicate that. */ 1107189251Ssam enum decision_type type 1108189251Ssam = ((int) XWINT (pattern, i) == XWINT (pattern, i)) 1109189251Ssam ? DT_elt_zero_wide_safe : DT_elt_zero_wide; 1110189251Ssam 1111189251Ssam gcc_assert (!i); 1112189251Ssam 1113189251Ssam test = new_decision_test (type, &place); 1114189251Ssam test->u.intval = XWINT (pattern, i); 1115189251Ssam } 1116189251Ssam else if (fmt[i] == 'E') 1117189251Ssam { 1118189251Ssam gcc_assert (!i); 1119189251Ssam 1120189251Ssam test = new_decision_test (DT_veclen, &place); 1121189251Ssam test->u.veclen = XVECLEN (pattern, i); 1122189251Ssam } 1123189251Ssam } 1124189251Ssam 1125189251Ssam /* Now test our sub-patterns. */ 1126189251Ssam for (i = 0; i < (size_t) len; i++) 1127189251Ssam { 1128189251Ssam switch (fmt[i]) 1129189251Ssam { 1130189251Ssam case 'e': case 'u': 1131189251Ssam subpos[depth] = '0' + i; 1132189251Ssam sub = add_to_sequence (XEXP (pattern, i), &sub->success, 1133189251Ssam subpos, insn_type, 0); 1134189251Ssam break; 1135189251Ssam 1136189251Ssam case 'E': 1137189251Ssam { 1138189251Ssam int j; 1139189251Ssam for (j = 0; j < XVECLEN (pattern, i); j++) 1140189251Ssam { 1141189251Ssam subpos[depth] = 'a' + j; 1142189251Ssam sub = add_to_sequence (XVECEXP (pattern, i, j), 1143189251Ssam &sub->success, subpos, insn_type, 0); 1144189251Ssam } 1145189251Ssam break; 1146189251Ssam } 1147189251Ssam 1148189251Ssam case 'i': case 'w': 1149189251Ssam /* Handled above. */ 1150189251Ssam break; 1151189251Ssam case '0': 1152189251Ssam break; 1153189251Ssam 1154189251Ssam default: 1155189251Ssam gcc_unreachable (); 1156189251Ssam } 1157189251Ssam } 1158189251Ssam 1159189251Ssam fini: 1160189251Ssam /* Insert nodes testing mode and code, if they're still relevant, 1161189251Ssam before any of the nodes we may have added above. */ 1162189251Ssam if (code != UNKNOWN) 1163189251Ssam { 1164189251Ssam place = &this->tests; 1165189251Ssam test = new_decision_test (DT_code, &place); 1166289549Srpaulo test->u.code = code; 1167189251Ssam } 1168189251Ssam 1169189251Ssam if (mode != VOIDmode) 1170189251Ssam { 1171289549Srpaulo place = &this->tests; 1172189251Ssam test = new_decision_test (DT_mode, &place); 1173189251Ssam test->u.mode = mode; 1174189251Ssam } 1175189251Ssam 1176189251Ssam /* If we didn't insert any tests or accept nodes, hork. */ 1177189251Ssam gcc_assert (this->tests); 1178189251Ssam 1179189251Ssam ret: 1180189251Ssam free (subpos); 1181189251Ssam return sub; 1182189251Ssam} 1183189251Ssam 1184189251Ssam/* A subroutine of maybe_both_true; examines only one test. 1185189251Ssam Returns > 0 for "definitely both true" and < 0 for "maybe both true". */ 1186281806Srpaulo 1187281806Srpaulostatic int 1188281806Srpaulomaybe_both_true_2 (struct decision_test *d1, struct decision_test *d2) 1189281806Srpaulo{ 1190281806Srpaulo if (d1->type == d2->type) 1191281806Srpaulo { 1192281806Srpaulo switch (d1->type) 1193281806Srpaulo { 1194281806Srpaulo case DT_num_insns: 1195189251Ssam if (d1->u.num_insns == d2->u.num_insns) 1196189251Ssam return 1; 1197189251Ssam else 1198189251Ssam return -1; 1199189251Ssam 1200189251Ssam case DT_mode: 1201189251Ssam return d1->u.mode == d2->u.mode; 1202189251Ssam 1203189251Ssam case DT_code: 1204189251Ssam return d1->u.code == d2->u.code; 1205189251Ssam 1206189251Ssam case DT_veclen: 1207189251Ssam return d1->u.veclen == d2->u.veclen; 1208281806Srpaulo 1209281806Srpaulo case DT_elt_zero_int: 1210281806Srpaulo case DT_elt_one_int: 1211281806Srpaulo case DT_elt_zero_wide: 1212281806Srpaulo case DT_elt_zero_wide_safe: 1213281806Srpaulo return d1->u.intval == d2->u.intval; 1214281806Srpaulo 1215281806Srpaulo default: 1216281806Srpaulo break; 1217281806Srpaulo } 1218281806Srpaulo } 1219189251Ssam 1220189251Ssam /* If either has a predicate that we know something about, set 1221189251Ssam things up so that D1 is the one that always has a known 1222189251Ssam predicate. Then see if they have any codes in common. */ 1223189251Ssam 1224189251Ssam if (d1->type == DT_pred || d2->type == DT_pred) 1225189251Ssam { 1226189251Ssam if (d2->type == DT_pred) 1227189251Ssam { 1228189251Ssam struct decision_test *tmp; 1229189251Ssam tmp = d1, d1 = d2, d2 = tmp; 1230189251Ssam } 1231189251Ssam 1232189251Ssam /* If D2 tests a mode, see if it matches D1. */ 1233189251Ssam if (d1->u.pred.mode != VOIDmode) 1234189251Ssam { 1235189251Ssam if (d2->type == DT_mode) 1236189251Ssam { 1237189251Ssam if (d1->u.pred.mode != d2->u.mode 1238189251Ssam /* The mode of an address_operand predicate is the 1239189251Ssam mode of the memory, not the operand. It can only 1240189251Ssam be used for testing the predicate, so we must 1241189251Ssam ignore it here. */ 1242189251Ssam && strcmp (d1->u.pred.name, "address_operand") != 0) 1243189251Ssam return 0; 1244189251Ssam } 1245189251Ssam /* Don't check two predicate modes here, because if both predicates 1246189251Ssam accept CONST_INT, then both can still be true even if the modes 1247189251Ssam are different. If they don't accept CONST_INT, there will be a 1248189251Ssam separate DT_mode that will make maybe_both_true_1 return 0. */ 1249189251Ssam } 1250281806Srpaulo 1251281806Srpaulo if (d1->u.pred.data) 1252189251Ssam { 1253189251Ssam /* If D2 tests a code, see if it is in the list of valid 1254189251Ssam codes for D1's predicate. */ 1255189251Ssam if (d2->type == DT_code) 1256189251Ssam { 1257189251Ssam if (!d1->u.pred.data->codes[d2->u.code]) 1258189251Ssam return 0; 1259189251Ssam } 1260189251Ssam 1261189251Ssam /* Otherwise see if the predicates have any codes in common. */ 1262189251Ssam else if (d2->type == DT_pred && d2->u.pred.data) 1263189251Ssam { 1264189251Ssam bool common = false; 1265189251Ssam enum rtx_code c; 1266189251Ssam 1267189251Ssam for (c = 0; c < NUM_RTX_CODE; c++) 1268189251Ssam if (d1->u.pred.data->codes[c] && d2->u.pred.data->codes[c]) 1269189251Ssam { 1270189251Ssam common = true; 1271189251Ssam break; 1272189251Ssam } 1273189251Ssam 1274189251Ssam if (!common) 1275189251Ssam return 0; 1276189251Ssam } 1277189251Ssam } 1278189251Ssam } 1279189251Ssam 1280189251Ssam /* Tests vs veclen may be known when strict equality is involved. */ 1281281806Srpaulo if (d1->type == DT_veclen && d2->type == DT_veclen_ge) 1282281806Srpaulo return d1->u.veclen >= d2->u.veclen; 1283281806Srpaulo if (d1->type == DT_veclen_ge && d2->type == DT_veclen) 1284281806Srpaulo return d2->u.veclen >= d1->u.veclen; 1285281806Srpaulo 1286281806Srpaulo return -1; 1287281806Srpaulo} 1288281806Srpaulo 1289189251Ssam/* A subroutine of maybe_both_true; examines all the tests for a given node. 1290189251Ssam Returns > 0 for "definitely both true" and < 0 for "maybe both true". */ 1291281806Srpaulo 1292281806Srpaulostatic int 1293281806Srpaulomaybe_both_true_1 (struct decision_test *d1, struct decision_test *d2) 1294189251Ssam{ 1295189251Ssam struct decision_test *t1, *t2; 1296189251Ssam 1297189251Ssam /* A match_operand with no predicate can match anything. Recognize 1298189251Ssam this by the existence of a lone DT_accept_op test. */ 1299189251Ssam if (d1->type == DT_accept_op || d2->type == DT_accept_op) 1300189251Ssam return 1; 1301189251Ssam 1302189251Ssam /* Eliminate pairs of tests while they can exactly match. */ 1303189251Ssam while (d1 && d2 && d1->type == d2->type) 1304189251Ssam { 1305189251Ssam if (maybe_both_true_2 (d1, d2) == 0) 1306189251Ssam return 0; 1307189251Ssam d1 = d1->next, d2 = d2->next; 1308189251Ssam } 1309189251Ssam 1310189251Ssam /* After that, consider all pairs. */ 1311189251Ssam for (t1 = d1; t1 ; t1 = t1->next) 1312189251Ssam for (t2 = d2; t2 ; t2 = t2->next) 1313189251Ssam if (maybe_both_true_2 (t1, t2) == 0) 1314189251Ssam return 0; 1315189251Ssam 1316189251Ssam return -1; 1317189251Ssam} 1318189251Ssam 1319189251Ssam/* Return 0 if we can prove that there is no RTL that can match both 1320189251Ssam D1 and D2. Otherwise, return 1 (it may be that there is an RTL that 1321189251Ssam can match both or just that we couldn't prove there wasn't such an RTL). 1322189251Ssam 1323189251Ssam TOPLEVEL is nonzero if we are to only look at the top level and not 1324189251Ssam recursively descend. */ 1325189251Ssam 1326189251Ssamstatic int 1327189251Ssammaybe_both_true (struct decision *d1, struct decision *d2, 1328189251Ssam int toplevel) 1329189251Ssam{ 1330189251Ssam struct decision *p1, *p2; 1331189251Ssam int cmp; 1332189251Ssam 1333189251Ssam /* Don't compare strings on the different positions in insn. Doing so 1334189251Ssam is incorrect and results in false matches from constructs like 1335189251Ssam 1336189251Ssam [(set (subreg:HI (match_operand:SI "register_operand" "r") 0) 1337189251Ssam (subreg:HI (match_operand:SI "register_operand" "r") 0))] 1338189251Ssam vs 1339189251Ssam [(set (match_operand:HI "register_operand" "r") 1340189251Ssam (match_operand:HI "register_operand" "r"))] 1341189251Ssam 1342189251Ssam If we are presented with such, we are recursing through the remainder 1343189251Ssam of a node's success nodes (from the loop at the end of this function). 1344189251Ssam Skip forward until we come to a position that matches. 1345189251Ssam 1346189251Ssam Due to the way position strings are constructed, we know that iterating 1347189251Ssam forward from the lexically lower position (e.g. "00") will run into 1348189251Ssam the lexically higher position (e.g. "1") and not the other way around. 1349189251Ssam This saves a bit of effort. */ 1350189251Ssam 1351189251Ssam cmp = strcmp (d1->position, d2->position); 1352189251Ssam if (cmp != 0) 1353189251Ssam { 1354189251Ssam gcc_assert (!toplevel); 1355189251Ssam 1356189251Ssam /* If the d2->position was lexically lower, swap. */ 1357189251Ssam if (cmp > 0) 1358189251Ssam p1 = d1, d1 = d2, d2 = p1; 1359189251Ssam 1360189251Ssam if (d1->success.first == 0) 1361189251Ssam return 1; 1362189251Ssam for (p1 = d1->success.first; p1; p1 = p1->next) 1363189251Ssam if (maybe_both_true (p1, d2, 0)) 1364189251Ssam return 1; 1365189251Ssam 1366189251Ssam return 0; 1367189251Ssam } 1368189251Ssam 1369189251Ssam /* Test the current level. */ 1370189251Ssam cmp = maybe_both_true_1 (d1->tests, d2->tests); 1371189251Ssam if (cmp >= 0) 1372189251Ssam return cmp; 1373189251Ssam 1374189251Ssam /* We can't prove that D1 and D2 cannot both be true. If we are only 1375189251Ssam to check the top level, return 1. Otherwise, see if we can prove 1376189251Ssam that all choices in both successors are mutually exclusive. If 1377189251Ssam either does not have any successors, we can't prove they can't both 1378189251Ssam be true. */ 1379189251Ssam 1380189251Ssam if (toplevel || d1->success.first == 0 || d2->success.first == 0) 1381189251Ssam return 1; 1382189251Ssam 1383189251Ssam for (p1 = d1->success.first; p1; p1 = p1->next) 1384189251Ssam for (p2 = d2->success.first; p2; p2 = p2->next) 1385189251Ssam if (maybe_both_true (p1, p2, 0)) 1386189251Ssam return 1; 1387189251Ssam 1388189251Ssam return 0; 1389189251Ssam} 1390189251Ssam 1391189251Ssam/* A subroutine of nodes_identical. Examine two tests for equivalence. */ 1392189251Ssam 1393189251Ssamstatic int 1394189251Ssamnodes_identical_1 (struct decision_test *d1, struct decision_test *d2) 1395189251Ssam{ 1396189251Ssam switch (d1->type) 1397189251Ssam { 1398189251Ssam case DT_num_insns: 1399189251Ssam return d1->u.num_insns == d2->u.num_insns; 1400189251Ssam 1401189251Ssam case DT_mode: 1402189251Ssam return d1->u.mode == d2->u.mode; 1403189251Ssam 1404189251Ssam case DT_code: 1405189251Ssam return d1->u.code == d2->u.code; 1406189251Ssam 1407189251Ssam case DT_pred: 1408189251Ssam return (d1->u.pred.mode == d2->u.pred.mode 1409189251Ssam && strcmp (d1->u.pred.name, d2->u.pred.name) == 0); 1410189251Ssam 1411189251Ssam case DT_c_test: 1412189251Ssam return strcmp (d1->u.c_test, d2->u.c_test) == 0; 1413189251Ssam 1414189251Ssam case DT_veclen: 1415189251Ssam case DT_veclen_ge: 1416189251Ssam return d1->u.veclen == d2->u.veclen; 1417189251Ssam 1418189251Ssam case DT_dup: 1419189251Ssam return d1->u.dup == d2->u.dup; 1420189251Ssam 1421189251Ssam case DT_elt_zero_int: 1422189251Ssam case DT_elt_one_int: 1423189251Ssam case DT_elt_zero_wide: 1424189251Ssam case DT_elt_zero_wide_safe: 1425189251Ssam return d1->u.intval == d2->u.intval; 1426189251Ssam 1427189251Ssam case DT_accept_op: 1428189251Ssam return d1->u.opno == d2->u.opno; 1429189251Ssam 1430189251Ssam case DT_accept_insn: 1431189251Ssam /* Differences will be handled in merge_accept_insn. */ 1432189251Ssam return 1; 1433189251Ssam 1434189251Ssam default: 1435189251Ssam gcc_unreachable (); 1436189251Ssam } 1437189251Ssam} 1438189251Ssam 1439189251Ssam/* True iff the two nodes are identical (on one level only). Due 1440189251Ssam to the way these lists are constructed, we shouldn't have to 1441189251Ssam consider different orderings on the tests. */ 1442189251Ssam 1443189251Ssamstatic int 1444189251Ssamnodes_identical (struct decision *d1, struct decision *d2) 1445189251Ssam{ 1446189251Ssam struct decision_test *t1, *t2; 1447189251Ssam 1448189251Ssam for (t1 = d1->tests, t2 = d2->tests; t1 && t2; t1 = t1->next, t2 = t2->next) 1449189251Ssam { 1450189251Ssam if (t1->type != t2->type) 1451189251Ssam return 0; 1452189251Ssam if (! nodes_identical_1 (t1, t2)) 1453189251Ssam return 0; 1454189251Ssam } 1455189251Ssam 1456189251Ssam /* For success, they should now both be null. */ 1457189251Ssam if (t1 != t2) 1458189251Ssam return 0; 1459189251Ssam 1460189251Ssam /* Check that their subnodes are at the same position, as any one set 1461189251Ssam of sibling decisions must be at the same position. Allowing this 1462189251Ssam requires complications to find_afterward and when change_state is 1463189251Ssam invoked. */ 1464189251Ssam if (d1->success.first 1465252726Srpaulo && d2->success.first 1466252726Srpaulo && strcmp (d1->success.first->position, d2->success.first->position)) 1467189251Ssam return 0; 1468189251Ssam 1469189251Ssam return 1; 1470281806Srpaulo} 1471189251Ssam 1472252726Srpaulo/* A subroutine of merge_trees; given two nodes that have been declared 1473252726Srpaulo identical, cope with two insn accept states. If they differ in the 1474252726Srpaulo number of clobbers, then the conflict was created by make_insn_sequence 1475252726Srpaulo and we can drop the with-clobbers version on the floor. If both 1476252726Srpaulo nodes have no additional clobbers, we have found an ambiguity in the 1477189251Ssam source machine description. */ 1478189251Ssam 1479189251Ssamstatic void 1480189251Ssammerge_accept_insn (struct decision *oldd, struct decision *addd) 1481189251Ssam{ 1482189251Ssam struct decision_test *old, *add; 1483189251Ssam 1484189251Ssam for (old = oldd->tests; old; old = old->next) 1485189251Ssam if (old->type == DT_accept_insn) 1486189251Ssam break; 1487252726Srpaulo if (old == NULL) 1488189251Ssam return; 1489189251Ssam 1490189251Ssam for (add = addd->tests; add; add = add->next) 1491189251Ssam if (add->type == DT_accept_insn) 1492252726Srpaulo break; 1493252726Srpaulo if (add == NULL) 1494252726Srpaulo return; 1495252726Srpaulo 1496252726Srpaulo /* If one node is for a normal insn and the second is for the base 1497252726Srpaulo insn with clobbers stripped off, the second node should be ignored. */ 1498252726Srpaulo 1499252726Srpaulo if (old->u.insn.num_clobbers_to_add == 0 1500252726Srpaulo && add->u.insn.num_clobbers_to_add > 0) 1501252726Srpaulo { 1502252726Srpaulo /* Nothing to do here. */ 1503252726Srpaulo } 1504252726Srpaulo else if (old->u.insn.num_clobbers_to_add > 0 1505252726Srpaulo && add->u.insn.num_clobbers_to_add == 0) 1506281806Srpaulo { 1507281806Srpaulo /* In this case, replace OLD with ADD. */ 1508252726Srpaulo old->u.insn = add->u.insn; 1509252726Srpaulo } 1510252726Srpaulo else 1511252726Srpaulo { 1512252726Srpaulo message_with_line (add->u.insn.lineno, "`%s' matches `%s'", 1513252726Srpaulo get_insn_name (add->u.insn.code_number), 1514252726Srpaulo get_insn_name (old->u.insn.code_number)); 1515189251Ssam message_with_line (old->u.insn.lineno, "previous definition of `%s'", 1516189251Ssam get_insn_name (old->u.insn.code_number)); 1517189251Ssam error_count++; 1518252726Srpaulo } 1519189251Ssam} 1520189251Ssam 1521189251Ssam/* Merge two decision trees OLDH and ADDH, modifying OLDH destructively. */ 1522346981Scy 1523189251Ssamstatic void 1524189251Ssammerge_trees (struct decision_head *oldh, struct decision_head *addh) 1525189251Ssam{ 1526189251Ssam struct decision *next, *add; 1527189251Ssam 1528189251Ssam if (addh->first == 0) 1529189251Ssam return; 1530189251Ssam if (oldh->first == 0) 1531189251Ssam { 1532252726Srpaulo *oldh = *addh; 1533252726Srpaulo return; 1534252726Srpaulo } 1535252726Srpaulo 1536252726Srpaulo /* Trying to merge bits at different positions isn't possible. */ 1537346981Scy gcc_assert (!strcmp (oldh->first->position, addh->first->position)); 1538346981Scy 1539346981Scy for (add = addh->first; add ; add = next) 1540346981Scy { 1541346981Scy struct decision *old, *insert_before = NULL; 1542346981Scy 1543346981Scy next = add->next; 1544346981Scy 1545346981Scy /* The semantics of pattern matching state that the tests are 1546346981Scy done in the order given in the MD file so that if an insn 1547346981Scy matches two patterns, the first one will be used. However, 1548346981Scy in practice, most, if not all, patterns are unambiguous so 1549252726Srpaulo that their order is independent. In that case, we can merge 1550252726Srpaulo identical tests and group all similar modes and codes together. 1551252726Srpaulo 1552252726Srpaulo Scan starting from the end of OLDH until we reach a point 1553252726Srpaulo where we reach the head of the list or where we pass a 1554189251Ssam pattern that could also be true if NEW is true. If we find 1555189251Ssam an identical pattern, we can merge them. Also, record the 1556189251Ssam last node that tests the same code and mode and the last one 1557252726Srpaulo that tests just the same mode. 1558252726Srpaulo 1559252726Srpaulo If we have no match, place NEW after the closest match we found. */ 1560252726Srpaulo 1561252726Srpaulo for (old = oldh->last; old; old = old->prev) 1562252726Srpaulo { 1563189251Ssam if (nodes_identical (old, add)) 1564252726Srpaulo { 1565189251Ssam merge_accept_insn (old, add); 1566189251Ssam merge_trees (&old->success, &add->success); 1567189251Ssam goto merged_nodes; 1568189251Ssam } 1569189251Ssam 1570189251Ssam if (maybe_both_true (old, add, 0)) 1571189251Ssam break; 1572189251Ssam 1573189251Ssam /* Insert the nodes in DT test type order, which is roughly 1574189251Ssam how expensive/important the test is. Given that the tests 1575189251Ssam are also ordered within the list, examining the first is 1576189251Ssam sufficient. */ 1577252726Srpaulo if ((int) add->tests->type < (int) old->tests->type) 1578252726Srpaulo insert_before = old; 1579252726Srpaulo } 1580252726Srpaulo 1581252726Srpaulo if (insert_before == NULL) 1582252726Srpaulo { 1583252726Srpaulo add->next = NULL; 1584252726Srpaulo add->prev = oldh->last; 1585252726Srpaulo oldh->last->next = add; 1586252726Srpaulo oldh->last = add; 1587252726Srpaulo } 1588189251Ssam else 1589189251Ssam { 1590189251Ssam if ((add->prev = insert_before->prev) != NULL) 1591189251Ssam add->prev->next = add; 1592189251Ssam else 1593252726Srpaulo oldh->first = add; 1594189251Ssam add->next = insert_before; 1595189251Ssam insert_before->prev = add; 1596189251Ssam } 1597189251Ssam 1598189251Ssam merged_nodes:; 1599189251Ssam } 1600189251Ssam} 1601189251Ssam 1602189251Ssam/* Walk the tree looking for sub-nodes that perform common tests. 1603189251Ssam Factor out the common test into a new node. This enables us 1604189251Ssam (depending on the test type) to emit switch statements later. */ 1605189251Ssam 1606189251Ssamstatic void 1607189251Ssamfactor_tests (struct decision_head *head) 1608189251Ssam{ 1609189251Ssam struct decision *first, *next; 1610189251Ssam 1611189251Ssam for (first = head->first; first && first->next; first = next) 1612189251Ssam { 1613337817Scy enum decision_type type; 1614189251Ssam struct decision *new, *old_last; 1615189251Ssam 1616189251Ssam type = first->tests->type; 1617189251Ssam next = first->next; 1618189251Ssam 1619189251Ssam /* Want at least two compatible sequential nodes. */ 1620189251Ssam if (next->tests->type != type) 1621189251Ssam continue; 1622189251Ssam 1623337817Scy /* Don't want all node types, just those we can turn into 1624189251Ssam switch statements. */ 1625337817Scy if (type != DT_mode 1626189251Ssam && type != DT_code 1627189251Ssam && type != DT_veclen 1628189251Ssam && type != DT_elt_zero_int 1629189251Ssam && type != DT_elt_one_int 1630189251Ssam && type != DT_elt_zero_wide_safe) 1631189251Ssam continue; 1632189251Ssam 1633189251Ssam /* If we'd been performing more than one test, create a new node 1634189251Ssam below our first test. */ 1635189251Ssam if (first->tests->next != NULL) 1636189251Ssam { 1637189251Ssam new = new_decision (first->position, &first->success); 1638189251Ssam new->tests = first->tests->next; 1639189251Ssam first->tests->next = NULL; 1640189251Ssam } 1641189251Ssam 1642189251Ssam /* Crop the node tree off after our first test. */ 1643189251Ssam first->next = NULL; 1644189251Ssam old_last = head->last; 1645189251Ssam head->last = first; 1646189251Ssam 1647189251Ssam /* For each compatible test, adjust to perform only one test in 1648189251Ssam the top level node, then merge the node back into the tree. */ 1649189251Ssam do 1650189251Ssam { 1651189251Ssam struct decision_head h; 1652189251Ssam 1653189251Ssam if (next->tests->next != NULL) 1654189251Ssam { 1655189251Ssam new = new_decision (next->position, &next->success); 1656189251Ssam new->tests = next->tests->next; 1657189251Ssam next->tests->next = NULL; 1658189251Ssam } 1659189251Ssam new = next; 1660189251Ssam next = next->next; 1661189251Ssam new->next = NULL; 1662189251Ssam h.first = h.last = new; 1663189251Ssam 1664189251Ssam merge_trees (head, &h); 1665189251Ssam } 1666189251Ssam while (next && next->tests->type == type); 1667337817Scy 1668337817Scy /* After we run out of compatible tests, graft the remaining nodes 1669337817Scy back onto the tree. */ 1670189251Ssam if (next) 1671189251Ssam { 1672189251Ssam next->prev = head->last; 1673189251Ssam head->last->next = next; 1674337817Scy head->last = old_last; 1675337817Scy } 1676337817Scy } 1677337817Scy 1678189251Ssam /* Recurse. */ 1679189251Ssam for (first = head->first; first; first = first->next) 1680337817Scy factor_tests (&first->success); 1681337817Scy} 1682337817Scy 1683337817Scy/* After factoring, try to simplify the tests on any one node. 1684337817Scy Tests that are useful for switch statements are recognizable 1685337817Scy by having only a single test on a node -- we'll be manipulating 1686337817Scy nodes with multiple tests: 1687337817Scy 1688189251Ssam If we have mode tests or code tests that are redundant with 1689189251Ssam predicates, remove them. */ 1690189251Ssam 1691189251Ssamstatic void 1692189251Ssamsimplify_tests (struct decision_head *head) 1693189251Ssam{ 1694189251Ssam struct decision *tree; 1695189251Ssam 1696189251Ssam for (tree = head->first; tree; tree = tree->next) 1697189251Ssam { 1698189251Ssam struct decision_test *a, *b; 1699189251Ssam 1700189251Ssam a = tree->tests; 1701189251Ssam b = a->next; 1702189251Ssam if (b == NULL) 1703189251Ssam continue; 1704189251Ssam 1705189251Ssam /* Find a predicate node. */ 1706189251Ssam while (b && b->type != DT_pred) 1707189251Ssam b = b->next; 1708189251Ssam if (b) 1709189251Ssam { 1710189251Ssam /* Due to how these tests are constructed, we don't even need 1711189251Ssam to check that the mode and code are compatible -- they were 1712189251Ssam generated from the predicate in the first place. */ 1713189251Ssam while (a->type == DT_mode || a->type == DT_code) 1714189251Ssam a = a->next; 1715189251Ssam tree->tests = a; 1716189251Ssam } 1717189251Ssam } 1718189251Ssam 1719189251Ssam /* Recurse. */ 1720189251Ssam for (tree = head->first; tree; tree = tree->next) 1721189251Ssam simplify_tests (&tree->success); 1722189251Ssam} 1723189251Ssam 1724189251Ssam/* Count the number of subnodes of HEAD. If the number is high enough, 1725189251Ssam make the first node in HEAD start a separate subroutine in the C code 1726189251Ssam that is generated. */ 1727189251Ssam 1728189251Ssamstatic int 1729337817Scybreak_out_subroutines (struct decision_head *head, int initial) 1730337817Scy{ 1731189251Ssam int size = 0; 1732189251Ssam struct decision *sub; 1733189251Ssam 1734281806Srpaulo for (sub = head->first; sub; sub = sub->next) 1735281806Srpaulo size += 1 + break_out_subroutines (&sub->success, 0); 1736281806Srpaulo 1737281806Srpaulo if (size > SUBROUTINE_THRESHOLD && ! initial) 1738281806Srpaulo { 1739281806Srpaulo head->first->subroutine_number = ++next_subroutine_number; 1740281806Srpaulo size = 1; 1741281806Srpaulo } 1742281806Srpaulo return size; 1743281806Srpaulo} 1744281806Srpaulo 1745281806Srpaulo/* For each node p, find the next alternative that might be true 1746281806Srpaulo when p is true. */ 1747281806Srpaulo 1748281806Srpaulostatic void 1749281806Srpaulofind_afterward (struct decision_head *head, struct decision *real_afterward) 1750281806Srpaulo{ 1751281806Srpaulo struct decision *p, *q, *afterward; 1752281806Srpaulo 1753281806Srpaulo /* We can't propagate alternatives across subroutine boundaries. 1754281806Srpaulo This is not incorrect, merely a minor optimization loss. */ 1755281806Srpaulo 1756281806Srpaulo p = head->first; 1757281806Srpaulo afterward = (p->subroutine_number > 0 ? NULL : real_afterward); 1758281806Srpaulo 1759281806Srpaulo for ( ; p ; p = p->next) 1760281806Srpaulo { 1761281806Srpaulo /* Find the next node that might be true if this one fails. */ 1762281806Srpaulo for (q = p->next; q ; q = q->next) 1763281806Srpaulo if (maybe_both_true (p, q, 1)) 1764281806Srpaulo break; 1765281806Srpaulo 1766281806Srpaulo /* If we reached the end of the list without finding one, 1767281806Srpaulo use the incoming afterward position. */ 1768281806Srpaulo if (!q) 1769281806Srpaulo q = afterward; 1770281806Srpaulo p->afterward = q; 1771281806Srpaulo if (q) 1772281806Srpaulo q->need_label = 1; 1773281806Srpaulo } 1774346981Scy 1775281806Srpaulo /* Recurse. */ 1776281806Srpaulo for (p = head->first; p ; p = p->next) 1777281806Srpaulo if (p->success.first) 1778281806Srpaulo find_afterward (&p->success, p->afterward); 1779281806Srpaulo 1780281806Srpaulo /* When we are generating a subroutine, record the real afterward 1781281806Srpaulo position in the first node where write_tree can find it, and we 1782281806Srpaulo can do the right thing at the subroutine call site. */ 1783281806Srpaulo p = head->first; 1784281806Srpaulo if (p->subroutine_number > 0) 1785346981Scy p->afterward = real_afterward; 1786281806Srpaulo} 1787281806Srpaulo 1788281806Srpaulo/* Assuming that the state of argument is denoted by OLDPOS, take whatever 1789281806Srpaulo actions are necessary to move to NEWPOS. If we fail to move to the 1790281806Srpaulo new state, branch to node AFTERWARD if nonzero, otherwise return. 1791281806Srpaulo 1792281806Srpaulo Failure to move to the new state can only occur if we are trying to 1793281806Srpaulo match multiple insns and we try to step past the end of the stream. */ 1794281806Srpaulo 1795281806Srpaulostatic void 1796281806Srpaulochange_state (const char *oldpos, const char *newpos, const char *indent) 1797281806Srpaulo{ 1798281806Srpaulo int odepth = strlen (oldpos); 1799281806Srpaulo int ndepth = strlen (newpos); 1800281806Srpaulo int depth; 1801281806Srpaulo int old_has_insn, new_has_insn; 1802281806Srpaulo 1803281806Srpaulo /* Pop up as many levels as necessary. */ 1804281806Srpaulo for (depth = odepth; strncmp (oldpos, newpos, depth) != 0; --depth) 1805281806Srpaulo continue; 1806281806Srpaulo 1807281806Srpaulo /* Hunt for the last [A-Z] in both strings. */ 1808281806Srpaulo for (old_has_insn = odepth - 1; old_has_insn >= 0; --old_has_insn) 1809281806Srpaulo if (ISUPPER (oldpos[old_has_insn])) 1810281806Srpaulo break; 1811281806Srpaulo for (new_has_insn = ndepth - 1; new_has_insn >= 0; --new_has_insn) 1812281806Srpaulo if (ISUPPER (newpos[new_has_insn])) 1813281806Srpaulo break; 1814281806Srpaulo 1815281806Srpaulo /* Go down to desired level. */ 1816281806Srpaulo while (depth < ndepth) 1817281806Srpaulo { 1818281806Srpaulo /* It's a different insn from the first one. */ 1819281806Srpaulo if (ISUPPER (newpos[depth])) 1820281806Srpaulo { 1821281806Srpaulo printf ("%stem = peep2_next_insn (%d);\n", 1822281806Srpaulo indent, newpos[depth] - 'A'); 1823281806Srpaulo printf ("%sx%d = PATTERN (tem);\n", indent, depth + 1); 1824281806Srpaulo } 1825281806Srpaulo else if (ISLOWER (newpos[depth])) 1826281806Srpaulo printf ("%sx%d = XVECEXP (x%d, 0, %d);\n", 1827281806Srpaulo indent, depth + 1, depth, newpos[depth] - 'a'); 1828281806Srpaulo else 1829281806Srpaulo printf ("%sx%d = XEXP (x%d, %c);\n", 1830281806Srpaulo indent, depth + 1, depth, newpos[depth]); 1831281806Srpaulo ++depth; 1832281806Srpaulo } 1833281806Srpaulo} 1834281806Srpaulo 1835281806Srpaulo/* Print the enumerator constant for CODE -- the upcase version of 1836281806Srpaulo the name. */ 1837281806Srpaulo 1838281806Srpaulostatic void 1839281806Srpauloprint_code (enum rtx_code code) 1840281806Srpaulo{ 1841281806Srpaulo const char *p; 1842281806Srpaulo for (p = GET_RTX_NAME (code); *p; p++) 1843281806Srpaulo putchar (TOUPPER (*p)); 1844281806Srpaulo} 1845281806Srpaulo 1846281806Srpaulo/* Emit code to cross an afterward link -- change state and branch. */ 1847281806Srpaulo 1848281806Srpaulostatic void 1849281806Srpaulowrite_afterward (struct decision *start, struct decision *afterward, 1850281806Srpaulo const char *indent) 1851281806Srpaulo{ 1852281806Srpaulo if (!afterward || start->subroutine_number > 0) 1853281806Srpaulo printf("%sgoto ret0;\n", indent); 1854281806Srpaulo else 1855281806Srpaulo { 1856281806Srpaulo change_state (start->position, afterward->position, indent); 1857281806Srpaulo printf ("%sgoto L%d;\n", indent, afterward->number); 1858281806Srpaulo } 1859281806Srpaulo} 1860281806Srpaulo 1861281806Srpaulo/* Emit a HOST_WIDE_INT as an integer constant expression. We need to take 1862281806Srpaulo special care to avoid "decimal constant is so large that it is unsigned" 1863281806Srpaulo warnings in the resulting code. */ 1864281806Srpaulo 1865281806Srpaulostatic void 1866281806Srpauloprint_host_wide_int (HOST_WIDE_INT val) 1867281806Srpaulo{ 1868281806Srpaulo HOST_WIDE_INT min = (unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1); 1869281806Srpaulo if (val == min) 1870281806Srpaulo printf ("(" HOST_WIDE_INT_PRINT_DEC_C "-1)", val + 1); 1871281806Srpaulo else 1872281806Srpaulo printf (HOST_WIDE_INT_PRINT_DEC_C, val); 1873281806Srpaulo} 1874281806Srpaulo 1875281806Srpaulo/* Emit a switch statement, if possible, for an initial sequence of 1876281806Srpaulo nodes at START. Return the first node yet untested. */ 1877281806Srpaulo 1878281806Srpaulostatic struct decision * 1879281806Srpaulowrite_switch (struct decision *start, int depth) 1880281806Srpaulo{ 1881281806Srpaulo struct decision *p = start; 1882281806Srpaulo enum decision_type type = p->tests->type; 1883281806Srpaulo struct decision *needs_label = NULL; 1884281806Srpaulo 1885281806Srpaulo /* If we have two or more nodes in sequence that test the same one 1886281806Srpaulo thing, we may be able to use a switch statement. */ 1887281806Srpaulo 1888281806Srpaulo if (!p->next 1889281806Srpaulo || p->tests->next 1890281806Srpaulo || p->next->tests->type != type 1891281806Srpaulo || p->next->tests->next 1892281806Srpaulo || nodes_identical_1 (p->tests, p->next->tests)) 1893281806Srpaulo return p; 1894281806Srpaulo 1895281806Srpaulo /* DT_code is special in that we can do interesting things with 1896281806Srpaulo known predicates at the same time. */ 1897281806Srpaulo if (type == DT_code) 1898281806Srpaulo { 1899281806Srpaulo char codemap[NUM_RTX_CODE]; 1900281806Srpaulo struct decision *ret; 1901281806Srpaulo RTX_CODE code; 1902281806Srpaulo 1903281806Srpaulo memset (codemap, 0, sizeof(codemap)); 1904281806Srpaulo 1905281806Srpaulo printf (" switch (GET_CODE (x%d))\n {\n", depth); 1906281806Srpaulo code = p->tests->u.code; 1907281806Srpaulo do 1908281806Srpaulo { 1909281806Srpaulo if (p != start && p->need_label && needs_label == NULL) 1910281806Srpaulo needs_label = p; 1911281806Srpaulo 1912281806Srpaulo printf (" case "); 1913281806Srpaulo print_code (code); 1914281806Srpaulo printf (":\n goto L%d;\n", p->success.first->number); 1915281806Srpaulo p->success.first->need_label = 1; 1916281806Srpaulo 1917281806Srpaulo codemap[code] = 1; 1918281806Srpaulo p = p->next; 1919281806Srpaulo } 1920281806Srpaulo while (p 1921281806Srpaulo && ! p->tests->next 1922281806Srpaulo && p->tests->type == DT_code 1923281806Srpaulo && ! codemap[code = p->tests->u.code]); 1924281806Srpaulo 1925281806Srpaulo /* If P is testing a predicate that we know about and we haven't 1926281806Srpaulo seen any of the codes that are valid for the predicate, we can 1927281806Srpaulo write a series of "case" statement, one for each possible code. 1928281806Srpaulo Since we are already in a switch, these redundant tests are very 1929281806Srpaulo cheap and will reduce the number of predicates called. */ 1930281806Srpaulo 1931281806Srpaulo /* Note that while we write out cases for these predicates here, 1932281806Srpaulo we don't actually write the test here, as it gets kinda messy. 1933281806Srpaulo It is trivial to leave this to later by telling our caller that 1934281806Srpaulo we only processed the CODE tests. */ 1935281806Srpaulo if (needs_label != NULL) 1936281806Srpaulo ret = needs_label; 1937281806Srpaulo else 1938281806Srpaulo ret = p; 1939281806Srpaulo 1940281806Srpaulo while (p && p->tests->type == DT_pred && p->tests->u.pred.data) 1941281806Srpaulo { 1942281806Srpaulo const struct pred_data *data = p->tests->u.pred.data; 1943281806Srpaulo RTX_CODE c; 1944281806Srpaulo for (c = 0; c < NUM_RTX_CODE; c++) 1945281806Srpaulo if (codemap[c] && data->codes[c]) 1946189251Ssam goto pred_done; 1947189251Ssam 1948189251Ssam for (c = 0; c < NUM_RTX_CODE; c++) 1949189251Ssam if (data->codes[c]) 1950189251Ssam { 1951189251Ssam fputs (" case ", stdout); 1952189251Ssam print_code (c); 1953189251Ssam fputs (":\n", stdout); 1954189251Ssam codemap[c] = 1; 1955189251Ssam } 1956189251Ssam 1957189251Ssam printf (" goto L%d;\n", p->number); 1958189251Ssam p->need_label = 1; 1959189251Ssam p = p->next; 1960189251Ssam } 1961189251Ssam 1962189251Ssam pred_done: 1963189251Ssam /* Make the default case skip the predicates we managed to match. */ 1964189251Ssam 1965189251Ssam printf (" default:\n"); 1966189251Ssam if (p != ret) 1967189251Ssam { 1968189251Ssam if (p) 1969189251Ssam { 1970189251Ssam printf (" goto L%d;\n", p->number); 1971189251Ssam p->need_label = 1; 1972189251Ssam } 1973189251Ssam else 1974189251Ssam write_afterward (start, start->afterward, " "); 1975189251Ssam } 1976289549Srpaulo else 1977189251Ssam printf (" break;\n"); 1978189251Ssam printf (" }\n"); 1979189251Ssam 1980189251Ssam return ret; 1981189251Ssam } 1982189251Ssam else if (type == DT_mode 1983189251Ssam || type == DT_veclen 1984189251Ssam || type == DT_elt_zero_int 1985189251Ssam || type == DT_elt_one_int 1986189251Ssam || type == DT_elt_zero_wide_safe) 1987189251Ssam { 1988189251Ssam const char *indent = ""; 1989189251Ssam 1990189251Ssam /* We cast switch parameter to integer, so we must ensure that the value 1991189251Ssam fits. */ 1992189251Ssam if (type == DT_elt_zero_wide_safe) 1993189251Ssam { 1994189251Ssam indent = " "; 1995189251Ssam printf(" if ((int) XWINT (x%d, 0) == XWINT (x%d, 0))\n", depth, depth); 1996189251Ssam } 1997189251Ssam printf ("%s switch (", indent); 1998189251Ssam switch (type) 1999189251Ssam { 2000189251Ssam case DT_mode: 2001189251Ssam printf ("GET_MODE (x%d)", depth); 2002189251Ssam break; 2003189251Ssam case DT_veclen: 2004189251Ssam printf ("XVECLEN (x%d, 0)", depth); 2005189251Ssam break; 2006189251Ssam case DT_elt_zero_int: 2007189251Ssam printf ("XINT (x%d, 0)", depth); 2008189251Ssam break; 2009189251Ssam case DT_elt_one_int: 2010189251Ssam printf ("XINT (x%d, 1)", depth); 2011189251Ssam break; 2012189251Ssam case DT_elt_zero_wide_safe: 2013189251Ssam /* Convert result of XWINT to int for portability since some C 2014189251Ssam compilers won't do it and some will. */ 2015189251Ssam printf ("(int) XWINT (x%d, 0)", depth); 2016189251Ssam break; 2017189251Ssam default: 2018189251Ssam gcc_unreachable (); 2019189251Ssam } 2020189251Ssam printf (")\n%s {\n", indent); 2021189251Ssam 2022189251Ssam do 2023189251Ssam { 2024189251Ssam /* Merge trees will not unify identical nodes if their 2025189251Ssam sub-nodes are at different levels. Thus we must check 2026189251Ssam for duplicate cases. */ 2027189251Ssam struct decision *q; 2028189251Ssam for (q = start; q != p; q = q->next) 2029252726Srpaulo if (nodes_identical_1 (p->tests, q->tests)) 2030189251Ssam goto case_done; 2031189251Ssam 2032189251Ssam if (p != start && p->need_label && needs_label == NULL) 2033189251Ssam needs_label = p; 2034252726Srpaulo 2035346981Scy printf ("%s case ", indent); 2036346981Scy switch (type) 2037346981Scy { 2038346981Scy case DT_mode: 2039346981Scy printf ("%smode", GET_MODE_NAME (p->tests->u.mode)); 2040346981Scy break; 2041346981Scy case DT_veclen: 2042346981Scy printf ("%d", p->tests->u.veclen); 2043346981Scy break; 2044189251Ssam case DT_elt_zero_int: 2045189251Ssam case DT_elt_one_int: 2046281806Srpaulo case DT_elt_zero_wide: 2047281806Srpaulo case DT_elt_zero_wide_safe: 2048281806Srpaulo print_host_wide_int (p->tests->u.intval); 2049281806Srpaulo break; 2050281806Srpaulo default: 2051281806Srpaulo gcc_unreachable (); 2052189251Ssam } 2053189251Ssam printf (":\n%s goto L%d;\n", indent, p->success.first->number); 2054189251Ssam p->success.first->need_label = 1; 2055189251Ssam 2056189251Ssam p = p->next; 2057189251Ssam } 2058189251Ssam while (p && p->tests->type == type && !p->tests->next); 2059189251Ssam 2060214734Srpaulo case_done: 2061214734Srpaulo printf ("%s default:\n%s break;\n%s }\n", 2062214734Srpaulo indent, indent, indent); 2063214734Srpaulo 2064214734Srpaulo return needs_label != NULL ? needs_label : p; 2065214734Srpaulo } 2066214734Srpaulo else 2067252726Srpaulo { 2068252726Srpaulo /* None of the other tests are amenable. */ 2069252726Srpaulo return p; 2070337817Scy } 2071337817Scy} 2072337817Scy 2073337817Scy/* Emit code for one test. */ 2074337817Scy 2075252726Srpaulostatic void 2076214734Srpaulowrite_cond (struct decision_test *p, int depth, 2077214734Srpaulo enum routine_type subroutine_type) 2078214734Srpaulo{ 2079214734Srpaulo switch (p->type) 2080214734Srpaulo { 2081214734Srpaulo case DT_num_insns: 2082214734Srpaulo printf ("peep2_current_count >= %d", p->u.num_insns); 2083252726Srpaulo break; 2084252726Srpaulo 2085214734Srpaulo case DT_mode: 2086214734Srpaulo printf ("GET_MODE (x%d) == %smode", depth, GET_MODE_NAME (p->u.mode)); 2087252726Srpaulo break; 2088252726Srpaulo 2089252726Srpaulo case DT_code: 2090214734Srpaulo printf ("GET_CODE (x%d) == ", depth); 2091214734Srpaulo print_code (p->u.code); 2092214734Srpaulo break; 2093214734Srpaulo 2094214734Srpaulo case DT_veclen: 2095214734Srpaulo printf ("XVECLEN (x%d, 0) == %d", depth, p->u.veclen); 2096214734Srpaulo break; 2097214734Srpaulo 2098214734Srpaulo case DT_elt_zero_int: 2099214734Srpaulo printf ("XINT (x%d, 0) == %d", depth, (int) p->u.intval); 2100351611Scy break; 2101351611Scy 2102214734Srpaulo case DT_elt_one_int: 2103252726Srpaulo printf ("XINT (x%d, 1) == %d", depth, (int) p->u.intval); 2104252726Srpaulo break; 2105252726Srpaulo 2106252726Srpaulo case DT_elt_zero_wide: 2107252726Srpaulo case DT_elt_zero_wide_safe: 2108252726Srpaulo printf ("XWINT (x%d, 0) == ", depth); 2109252726Srpaulo print_host_wide_int (p->u.intval); 2110252726Srpaulo break; 2111214734Srpaulo 2112214734Srpaulo case DT_const_int: 2113214734Srpaulo printf ("x%d == const_int_rtx[MAX_SAVED_CONST_INT + (%d)]", 2114214734Srpaulo depth, (int) p->u.intval); 2115214734Srpaulo break; 2116214734Srpaulo 2117189251Ssam case DT_veclen_ge: 2118189251Ssam printf ("XVECLEN (x%d, 0) >= %d", depth, p->u.veclen); 2119189251Ssam break; 2120189251Ssam 2121189251Ssam case DT_dup: 2122189251Ssam printf ("rtx_equal_p (x%d, operands[%d])", depth, p->u.dup); 2123189251Ssam break; 2124189251Ssam 2125189251Ssam case DT_pred: 2126189251Ssam printf ("%s (x%d, %smode)", p->u.pred.name, depth, 2127189251Ssam GET_MODE_NAME (p->u.pred.mode)); 2128189251Ssam break; 2129189251Ssam 2130189251Ssam case DT_c_test: 2131189251Ssam print_c_condition (p->u.c_test); 2132289549Srpaulo break; 2133189251Ssam 2134189251Ssam case DT_accept_insn: 2135189251Ssam gcc_assert (subroutine_type == RECOG); 2136189251Ssam gcc_assert (p->u.insn.num_clobbers_to_add); 2137189251Ssam printf ("pnum_clobbers != NULL"); 2138189251Ssam break; 2139189251Ssam 2140189251Ssam default: 2141189251Ssam gcc_unreachable (); 2142189251Ssam } 2143189251Ssam} 2144252726Srpaulo 2145189251Ssam/* Emit code for one action. The previous tests have succeeded; 2146281806Srpaulo TEST is the last of the chain. In the normal case we simply 2147189251Ssam perform a state change. For the `accept' tests we must do more work. */ 2148189251Ssam 2149189251Ssamstatic void 2150189251Ssamwrite_action (struct decision *p, struct decision_test *test, 2151189251Ssam int depth, int uncond, struct decision *success, 2152281806Srpaulo enum routine_type subroutine_type) 2153214734Srpaulo{ 2154214734Srpaulo const char *indent; 2155214734Srpaulo int want_close = 0; 2156214734Srpaulo 2157214734Srpaulo if (uncond) 2158252726Srpaulo indent = " "; 2159189251Ssam else if (test->type == DT_accept_op || test->type == DT_accept_insn) 2160189251Ssam { 2161189251Ssam fputs (" {\n", stdout); 2162189251Ssam indent = " "; 2163189251Ssam want_close = 1; 2164189251Ssam } 2165189251Ssam else 2166189251Ssam indent = " "; 2167252726Srpaulo 2168252726Srpaulo if (test->type == DT_accept_op) 2169252726Srpaulo { 2170252726Srpaulo printf("%soperands[%d] = x%d;\n", indent, test->u.opno, depth); 2171252726Srpaulo 2172252726Srpaulo /* Only allow DT_accept_insn to follow. */ 2173252726Srpaulo if (test->next) 2174189251Ssam { 2175189251Ssam test = test->next; 2176189251Ssam gcc_assert (test->type == DT_accept_insn); 2177189251Ssam } 2178189251Ssam } 2179189251Ssam 2180189251Ssam /* Sanity check that we're now at the end of the list of tests. */ 2181189251Ssam gcc_assert (!test->next); 2182189251Ssam 2183189251Ssam if (test->type == DT_accept_insn) 2184189251Ssam { 2185189251Ssam switch (subroutine_type) 2186189251Ssam { 2187189251Ssam case RECOG: 2188189251Ssam if (test->u.insn.num_clobbers_to_add != 0) 2189189251Ssam printf ("%s*pnum_clobbers = %d;\n", 2190189251Ssam indent, test->u.insn.num_clobbers_to_add); 2191252726Srpaulo printf ("%sreturn %d; /* %s */\n", indent, 2192252726Srpaulo test->u.insn.code_number, 2193189251Ssam get_insn_name (test->u.insn.code_number)); 2194281806Srpaulo break; 2195189251Ssam 2196189251Ssam case SPLIT: 2197189251Ssam printf ("%sreturn gen_split_%d (insn, operands);\n", 2198189251Ssam indent, test->u.insn.code_number); 2199189251Ssam break; 2200189251Ssam 2201189251Ssam case PEEPHOLE2: 2202189251Ssam { 2203189251Ssam int match_len = 0, i; 2204189251Ssam 2205189251Ssam for (i = strlen (p->position) - 1; i >= 0; --i) 2206189251Ssam if (ISUPPER (p->position[i])) 2207189251Ssam { 2208189251Ssam match_len = p->position[i] - 'A'; 2209189251Ssam break; 2210189251Ssam } 2211189251Ssam printf ("%s*_pmatch_len = %d;\n", indent, match_len); 2212189251Ssam printf ("%stem = gen_peephole2_%d (insn, operands);\n", 2213189251Ssam indent, test->u.insn.code_number); 2214189251Ssam printf ("%sif (tem != 0)\n%s return tem;\n", indent, indent); 2215189251Ssam } 2216189251Ssam break; 2217189251Ssam 2218189251Ssam default: 2219189251Ssam gcc_unreachable (); 2220189251Ssam } 2221189251Ssam } 2222189251Ssam else 2223189251Ssam { 2224189251Ssam printf("%sgoto L%d;\n", indent, success->number); 2225189251Ssam success->need_label = 1; 2226189251Ssam } 2227189251Ssam 2228189251Ssam if (want_close) 2229189251Ssam fputs (" }\n", stdout); 2230189251Ssam} 2231189251Ssam 2232189251Ssam/* Return 1 if the test is always true and has no fallthru path. Return -1 2233189251Ssam if the test does have a fallthru path, but requires that the condition be 2234281806Srpaulo terminated. Otherwise return 0 for a normal test. */ 2235281806Srpaulo/* ??? is_unconditional is a stupid name for a tri-state function. */ 2236281806Srpaulo 2237189251Ssamstatic int 2238189251Ssamis_unconditional (struct decision_test *t, enum routine_type subroutine_type) 2239189251Ssam{ 2240189251Ssam if (t->type == DT_accept_op) 2241189251Ssam return 1; 2242189251Ssam 2243189251Ssam if (t->type == DT_accept_insn) 2244189251Ssam { 2245189251Ssam switch (subroutine_type) 2246189251Ssam { 2247189251Ssam case RECOG: 2248189251Ssam return (t->u.insn.num_clobbers_to_add == 0); 2249189251Ssam case SPLIT: 2250189251Ssam return 1; 2251189251Ssam case PEEPHOLE2: 2252189251Ssam return -1; 2253189251Ssam default: 2254189251Ssam gcc_unreachable (); 2255189251Ssam } 2256189251Ssam } 2257189251Ssam 2258189251Ssam return 0; 2259189251Ssam} 2260189251Ssam 2261189251Ssam/* Emit code for one node -- the conditional and the accompanying action. 2262189251Ssam Return true if there is no fallthru path. */ 2263189251Ssam 2264189251Ssamstatic int 2265189251Ssamwrite_node (struct decision *p, int depth, 2266189251Ssam enum routine_type subroutine_type) 2267189251Ssam{ 2268189251Ssam struct decision_test *test, *last_test; 2269189251Ssam int uncond; 2270189251Ssam 2271189251Ssam /* Scan the tests and simplify comparisons against small 2272189251Ssam constants. */ 2273189251Ssam for (test = p->tests; test; test = test->next) 2274189251Ssam { 2275189251Ssam if (test->type == DT_code 2276189251Ssam && test->u.code == CONST_INT 2277189251Ssam && test->next 2278189251Ssam && test->next->type == DT_elt_zero_wide_safe 2279189251Ssam && -MAX_SAVED_CONST_INT <= test->next->u.intval 2280189251Ssam && test->next->u.intval <= MAX_SAVED_CONST_INT) 2281189251Ssam { 2282189251Ssam test->type = DT_const_int; 2283189251Ssam test->u.intval = test->next->u.intval; 2284189251Ssam test->next = test->next->next; 2285189251Ssam } 2286189251Ssam } 2287189251Ssam 2288189251Ssam last_test = test = p->tests; 2289189251Ssam uncond = is_unconditional (test, subroutine_type); 2290189251Ssam if (uncond == 0) 2291189251Ssam { 2292189251Ssam printf (" if ("); 2293189251Ssam write_cond (test, depth, subroutine_type); 2294189251Ssam 2295189251Ssam while ((test = test->next) != NULL) 2296189251Ssam { 2297189251Ssam last_test = test; 2298189251Ssam if (is_unconditional (test, subroutine_type)) 2299189251Ssam break; 2300189251Ssam 2301189251Ssam printf ("\n && "); 2302189251Ssam write_cond (test, depth, subroutine_type); 2303189251Ssam } 2304189251Ssam 2305189251Ssam printf (")\n"); 2306189251Ssam } 2307189251Ssam 2308189251Ssam write_action (p, last_test, depth, uncond, p->success.first, subroutine_type); 2309189251Ssam 2310189251Ssam return uncond > 0; 2311189251Ssam} 2312189251Ssam 2313189251Ssam/* Emit code for all of the sibling nodes of HEAD. */ 2314189251Ssam 2315189251Ssamstatic void 2316189251Ssamwrite_tree_1 (struct decision_head *head, int depth, 2317189251Ssam enum routine_type subroutine_type) 2318189251Ssam{ 2319189251Ssam struct decision *p, *next; 2320189251Ssam int uncond = 0; 2321189251Ssam 2322189251Ssam for (p = head->first; p ; p = next) 2323189251Ssam { 2324189251Ssam /* The label for the first element was printed in write_tree. */ 2325189251Ssam if (p != head->first && p->need_label) 2326189251Ssam OUTPUT_LABEL (" ", p->number); 2327189251Ssam 2328189251Ssam /* Attempt to write a switch statement for a whole sequence. */ 2329189251Ssam next = write_switch (p, depth); 2330189251Ssam if (p != next) 2331189251Ssam uncond = 0; 2332189251Ssam else 2333189251Ssam { 2334189251Ssam /* Failed -- fall back and write one node. */ 2335189251Ssam uncond = write_node (p, depth, subroutine_type); 2336189251Ssam next = p->next; 2337189251Ssam } 2338189251Ssam } 2339189251Ssam 2340189251Ssam /* Finished with this chain. Close a fallthru path by branching 2341189251Ssam to the afterward node. */ 2342189251Ssam if (! uncond) 2343281806Srpaulo write_afterward (head->last, head->last->afterward, " "); 2344189251Ssam} 2345189251Ssam 2346189251Ssam/* Write out the decision tree starting at HEAD. PREVPOS is the 2347189251Ssam position at the node that branched to this node. */ 2348189251Ssam 2349189251Ssamstatic void 2350189251Ssamwrite_tree (struct decision_head *head, const char *prevpos, 2351189251Ssam enum routine_type type, int initial) 2352189251Ssam{ 2353189251Ssam struct decision *p = head->first; 2354189251Ssam 2355189251Ssam putchar ('\n'); 2356189251Ssam if (p->need_label) 2357189251Ssam OUTPUT_LABEL (" ", p->number); 2358189251Ssam 2359189251Ssam if (! initial && p->subroutine_number > 0) 2360189251Ssam { 2361189251Ssam static const char * const name_prefix[] = { 2362281806Srpaulo "recog", "split", "peephole2" 2363189251Ssam }; 2364189251Ssam 2365189251Ssam static const char * const call_suffix[] = { 2366189251Ssam ", pnum_clobbers", "", ", _pmatch_len" 2367189251Ssam }; 2368189251Ssam 2369189251Ssam /* This node has been broken out into a separate subroutine. 2370189251Ssam Call it, test the result, and branch accordingly. */ 2371189251Ssam 2372189251Ssam if (p->afterward) 2373189251Ssam { 2374189251Ssam printf (" tem = %s_%d (x0, insn%s);\n", 2375189251Ssam name_prefix[type], p->subroutine_number, call_suffix[type]); 2376189251Ssam if (IS_SPLIT (type)) 2377189251Ssam printf (" if (tem != 0)\n return tem;\n"); 2378189251Ssam else 2379189251Ssam printf (" if (tem >= 0)\n return tem;\n"); 2380189251Ssam 2381189251Ssam change_state (p->position, p->afterward->position, " "); 2382189251Ssam printf (" goto L%d;\n", p->afterward->number); 2383281806Srpaulo } 2384189251Ssam else 2385189251Ssam { 2386189251Ssam printf (" return %s_%d (x0, insn%s);\n", 2387189251Ssam name_prefix[type], p->subroutine_number, call_suffix[type]); 2388189251Ssam } 2389189251Ssam } 2390189251Ssam else 2391189251Ssam { 2392189251Ssam int depth = strlen (p->position); 2393252726Srpaulo 2394189251Ssam change_state (prevpos, p->position, " "); 2395189251Ssam write_tree_1 (head, depth, type); 2396337817Scy 2397189251Ssam for (p = head->first; p; p = p->next) 2398281806Srpaulo if (p->success.first) 2399281806Srpaulo write_tree (&p->success, p->position, type, 0); 2400189251Ssam } 2401189251Ssam} 2402189251Ssam 2403189251Ssam/* Write out a subroutine of type TYPE to do comparisons starting at 2404189251Ssam node TREE. */ 2405189251Ssam 2406189251Ssamstatic void 2407252726Srpaulowrite_subroutine (struct decision_head *head, enum routine_type type) 2408252726Srpaulo{ 2409189251Ssam int subfunction = head->first ? head->first->subroutine_number : 0; 2410189251Ssam const char *s_or_e; 2411252726Srpaulo char extension[32]; 2412189251Ssam int i; 2413189251Ssam 2414252726Srpaulo s_or_e = subfunction ? "static " : ""; 2415189251Ssam 2416189251Ssam if (subfunction) 2417252726Srpaulo sprintf (extension, "_%d", subfunction); 2418189251Ssam else if (type == RECOG) 2419189251Ssam extension[0] = '\0'; 2420252726Srpaulo else 2421189251Ssam strcpy (extension, "_insns"); 2422189251Ssam 2423189251Ssam switch (type) 2424189251Ssam { 2425189251Ssam case RECOG: 2426189251Ssam printf ("%sint\n\ 2427189251Ssamrecog%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *pnum_clobbers ATTRIBUTE_UNUSED)\n", s_or_e, extension); 2428189251Ssam break; 2429189251Ssam case SPLIT: 2430189251Ssam printf ("%srtx\n\ 2431189251Ssamsplit%s (rtx x0 ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)\n", 2432189251Ssam s_or_e, extension); 2433189251Ssam break; 2434189251Ssam case PEEPHOLE2: 2435189251Ssam printf ("%srtx\n\ 2436189251Ssampeephole2%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *_pmatch_len ATTRIBUTE_UNUSED)\n", 2437189251Ssam s_or_e, extension); 2438189251Ssam break; 2439252726Srpaulo } 2440189251Ssam 2441189251Ssam printf ("{\n rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];\n"); 2442281806Srpaulo for (i = 1; i <= max_depth; i++) 2443346981Scy printf (" rtx x%d ATTRIBUTE_UNUSED;\n", i); 2444281806Srpaulo 2445281806Srpaulo printf (" %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int"); 2446337817Scy 2447337817Scy if (!subfunction) 2448189251Ssam printf (" recog_data.insn = NULL_RTX;\n"); 2449189251Ssam 2450189251Ssam if (head->first) 2451189251Ssam write_tree (head, "", type, 1); 2452189251Ssam else 2453189251Ssam printf (" goto ret0;\n"); 2454337817Scy 2455189251Ssam printf (" ret0:\n return %d;\n}\n\n", IS_SPLIT (type) ? 0 : -1); 2456189251Ssam} 2457337817Scy 2458252726Srpaulo/* In break_out_subroutines, we discovered the boundaries for the 2459252726Srpaulo subroutines, but did not write them out. Do so now. */ 2460252726Srpaulo 2461252726Srpaulostatic void 2462252726Srpaulowrite_subroutines (struct decision_head *head, enum routine_type type) 2463252726Srpaulo{ 2464189251Ssam struct decision *p; 2465252726Srpaulo 2466189251Ssam for (p = head->first; p ; p = p->next) 2467189251Ssam if (p->success.first) 2468189251Ssam write_subroutines (&p->success, type); 2469189251Ssam 2470189251Ssam if (head->first->subroutine_number > 0) 2471189251Ssam write_subroutine (head, type); 2472189251Ssam} 2473189251Ssam 2474189251Ssam/* Begin the output file. */ 2475189251Ssam 2476189251Ssamstatic void 2477252726Srpaulowrite_header (void) 2478189251Ssam{ 2479189251Ssam puts ("\ 2480189251Ssam/* Generated automatically by the program `genrecog' from the target\n\ 2481189251Ssam machine description file. */\n\ 2482189251Ssam\n\ 2483189251Ssam#include \"config.h\"\n\ 2484189251Ssam#include \"system.h\"\n\ 2485189251Ssam#include \"coretypes.h\"\n\ 2486189251Ssam#include \"tm.h\"\n\ 2487189251Ssam#include \"rtl.h\"\n\ 2488189251Ssam#include \"tm_p.h\"\n\ 2489189251Ssam#include \"function.h\"\n\ 2490189251Ssam#include \"insn-config.h\"\n\ 2491189251Ssam#include \"recog.h\"\n\ 2492252726Srpaulo#include \"real.h\"\n\ 2493189251Ssam#include \"output.h\"\n\ 2494189251Ssam#include \"flags.h\"\n\ 2495189251Ssam#include \"hard-reg-set.h\"\n\ 2496189251Ssam#include \"resource.h\"\n\ 2497189251Ssam#include \"toplev.h\"\n\ 2498189251Ssam#include \"reload.h\"\n\ 2499189251Ssam#include \"tm-constrs.h\"\n\ 2500189251Ssam\n"); 2501189251Ssam 2502189251Ssam puts ("\n\ 2503189251Ssam/* `recog' contains a decision tree that recognizes whether the rtx\n\ 2504189251Ssam X0 is a valid instruction.\n\ 2505189251Ssam\n\ 2506189251Ssam recog returns -1 if the rtx is not valid. If the rtx is valid, recog\n\ 2507252726Srpaulo returns a nonnegative number which is the insn code number for the\n\ 2508189251Ssam pattern that matched. This is the same as the order in the machine\n\ 2509189251Ssam description of the entry that matched. This number can be used as an\n\ 2510189251Ssam index into `insn_data' and other tables.\n"); 2511189251Ssam puts ("\ 2512189251Ssam The third argument to recog is an optional pointer to an int. If\n\ 2513189251Ssam present, recog will accept a pattern if it matches except for missing\n\ 2514189251Ssam CLOBBER expressions at the end. In that case, the value pointed to by\n\ 2515189251Ssam the optional pointer will be set to the number of CLOBBERs that need\n\ 2516189251Ssam to be added (it should be initialized to zero by the caller). If it"); 2517189251Ssam puts ("\ 2518189251Ssam is set nonzero, the caller should allocate a PARALLEL of the\n\ 2519189251Ssam appropriate size, copy the initial entries, and call add_clobbers\n\ 2520189251Ssam (found in insn-emit.c) to fill in the CLOBBERs.\n\ 2521189251Ssam"); 2522252726Srpaulo 2523189251Ssam puts ("\n\ 2524189251Ssam The function split_insns returns 0 if the rtl could not\n\ 2525189251Ssam be split or the split rtl as an INSN list if it can be.\n\ 2526189251Ssam\n\ 2527189251Ssam The function peephole2_insns returns 0 if the rtl could not\n\ 2528189251Ssam be matched. If there was a match, the new rtl is returned in an INSN list,\n\ 2529189251Ssam and LAST_INSN will point to the last recognized insn in the old sequence.\n\ 2530189251Ssam*/\n\n"); 2531189251Ssam} 2532189251Ssam 2533189251Ssam 2534189251Ssam/* Construct and return a sequence of decisions 2535189251Ssam that will recognize INSN. 2536189251Ssam 2537189251Ssam TYPE says what type of routine we are recognizing (RECOG or SPLIT). */ 2538252726Srpaulo 2539189251Ssamstatic struct decision_head 2540189251Ssammake_insn_sequence (rtx insn, enum routine_type type) 2541189251Ssam{ 2542189251Ssam rtx x; 2543189251Ssam const char *c_test = XSTR (insn, type == RECOG ? 2 : 1); 2544189251Ssam int truth = maybe_eval_c_test (c_test); 2545189251Ssam struct decision *last; 2546189251Ssam struct decision_test *test, **place; 2547189251Ssam struct decision_head head; 2548189251Ssam char c_test_pos[2]; 2549189251Ssam 2550189251Ssam /* We should never see an insn whose C test is false at compile time. */ 2551189251Ssam gcc_assert (truth); 2552189251Ssam 2553252726Srpaulo c_test_pos[0] = '\0'; 2554189251Ssam if (type == PEEPHOLE2) 2555189251Ssam { 2556189251Ssam int i, j; 2557189251Ssam 2558281806Srpaulo /* peephole2 gets special treatment: 2559281806Srpaulo - X always gets an outer parallel even if it's only one entry 2560281806Srpaulo - we remove all traces of outer-level match_scratch and match_dup 2561281806Srpaulo expressions here. */ 2562281806Srpaulo x = rtx_alloc (PARALLEL); 2563281806Srpaulo PUT_MODE (x, VOIDmode); 2564281806Srpaulo XVEC (x, 0) = rtvec_alloc (XVECLEN (insn, 0)); 2565281806Srpaulo for (i = j = 0; i < XVECLEN (insn, 0); i++) 2566281806Srpaulo { 2567281806Srpaulo rtx tmp = XVECEXP (insn, 0, i); 2568281806Srpaulo if (GET_CODE (tmp) != MATCH_SCRATCH && GET_CODE (tmp) != MATCH_DUP) 2569189251Ssam { 2570189251Ssam XVECEXP (x, 0, j) = tmp; 2571189251Ssam j++; 2572189251Ssam } 2573189251Ssam } 2574189251Ssam XVECLEN (x, 0) = j; 2575189251Ssam 2576189251Ssam c_test_pos[0] = 'A' + j - 1; 2577189251Ssam c_test_pos[1] = '\0'; 2578189251Ssam } 2579189251Ssam else if (XVECLEN (insn, type == RECOG) == 1) 2580189251Ssam x = XVECEXP (insn, type == RECOG, 0); 2581189251Ssam else 2582189251Ssam { 2583189251Ssam x = rtx_alloc (PARALLEL); 2584189251Ssam XVEC (x, 0) = XVEC (insn, type == RECOG); 2585189251Ssam PUT_MODE (x, VOIDmode); 2586189251Ssam } 2587189251Ssam 2588189251Ssam validate_pattern (x, insn, NULL_RTX, 0); 2589189251Ssam 2590189251Ssam memset(&head, 0, sizeof(head)); 2591189251Ssam last = add_to_sequence (x, &head, "", type, 1); 2592189251Ssam 2593189251Ssam /* Find the end of the test chain on the last node. */ 2594189251Ssam for (test = last->tests; test->next; test = test->next) 2595189251Ssam continue; 2596189251Ssam place = &test->next; 2597189251Ssam 2598189251Ssam /* Skip the C test if it's known to be true at compile time. */ 2599189251Ssam if (truth == -1) 2600189251Ssam { 2601189251Ssam /* Need a new node if we have another test to add. */ 2602189251Ssam if (test->type == DT_accept_op) 2603189251Ssam { 2604189251Ssam last = new_decision (c_test_pos, &last->success); 2605189251Ssam place = &last->tests; 2606351611Scy } 2607189251Ssam test = new_decision_test (DT_c_test, &place); 2608189251Ssam test->u.c_test = c_test; 2609189251Ssam } 2610189251Ssam 2611189251Ssam test = new_decision_test (DT_accept_insn, &place); 2612189251Ssam test->u.insn.code_number = next_insn_code; 2613189251Ssam test->u.insn.lineno = pattern_lineno; 2614189251Ssam test->u.insn.num_clobbers_to_add = 0; 2615189251Ssam 2616189251Ssam switch (type) 2617189251Ssam { 2618189251Ssam case RECOG: 2619189251Ssam /* If this is a DEFINE_INSN and X is a PARALLEL, see if it ends 2620189251Ssam with a group of CLOBBERs of (hard) registers or MATCH_SCRATCHes. 2621189251Ssam If so, set up to recognize the pattern without these CLOBBERs. */ 2622189251Ssam 2623289549Srpaulo if (GET_CODE (x) == PARALLEL) 2624189251Ssam { 2625189251Ssam int i; 2626189251Ssam 2627189251Ssam /* Find the last non-clobber in the parallel. */ 2628189251Ssam for (i = XVECLEN (x, 0); i > 0; i--) 2629189251Ssam { 2630189251Ssam rtx y = XVECEXP (x, 0, i - 1); 2631189251Ssam if (GET_CODE (y) != CLOBBER 2632189251Ssam || (!REG_P (XEXP (y, 0)) 2633189251Ssam && GET_CODE (XEXP (y, 0)) != MATCH_SCRATCH)) 2634189251Ssam break; 2635189251Ssam } 2636189251Ssam 2637189251Ssam if (i != XVECLEN (x, 0)) 2638189251Ssam { 2639189251Ssam rtx new; 2640189251Ssam struct decision_head clobber_head; 2641189251Ssam 2642189251Ssam /* Build a similar insn without the clobbers. */ 2643189251Ssam if (i == 1) 2644189251Ssam new = XVECEXP (x, 0, 0); 2645189251Ssam else 2646189251Ssam { 2647189251Ssam int j; 2648189251Ssam 2649189251Ssam new = rtx_alloc (PARALLEL); 2650189251Ssam XVEC (new, 0) = rtvec_alloc (i); 2651189251Ssam for (j = i - 1; j >= 0; j--) 2652189251Ssam XVECEXP (new, 0, j) = XVECEXP (x, 0, j); 2653189251Ssam } 2654189251Ssam 2655189251Ssam /* Recognize it. */ 2656189251Ssam memset (&clobber_head, 0, sizeof(clobber_head)); 2657189251Ssam last = add_to_sequence (new, &clobber_head, "", type, 1); 2658189251Ssam 2659189251Ssam /* Find the end of the test chain on the last node. */ 2660189251Ssam for (test = last->tests; test->next; test = test->next) 2661189251Ssam continue; 2662189251Ssam 2663189251Ssam /* We definitely have a new test to add -- create a new 2664189251Ssam node if needed. */ 2665189251Ssam place = &test->next; 2666189251Ssam if (test->type == DT_accept_op) 2667189251Ssam { 2668189251Ssam last = new_decision ("", &last->success); 2669189251Ssam place = &last->tests; 2670189251Ssam } 2671189251Ssam 2672189251Ssam /* Skip the C test if it's known to be true at compile 2673189251Ssam time. */ 2674189251Ssam if (truth == -1) 2675189251Ssam { 2676189251Ssam test = new_decision_test (DT_c_test, &place); 2677189251Ssam test->u.c_test = c_test; 2678189251Ssam } 2679189251Ssam 2680189251Ssam test = new_decision_test (DT_accept_insn, &place); 2681189251Ssam test->u.insn.code_number = next_insn_code; 2682189251Ssam test->u.insn.lineno = pattern_lineno; 2683189251Ssam test->u.insn.num_clobbers_to_add = XVECLEN (x, 0) - i; 2684189251Ssam 2685189251Ssam merge_trees (&head, &clobber_head); 2686189251Ssam } 2687189251Ssam } 2688189251Ssam break; 2689189251Ssam 2690189251Ssam case SPLIT: 2691189251Ssam /* Define the subroutine we will call below and emit in genemit. */ 2692189251Ssam printf ("extern rtx gen_split_%d (rtx, rtx *);\n", next_insn_code); 2693189251Ssam break; 2694189251Ssam 2695189251Ssam case PEEPHOLE2: 2696189251Ssam /* Define the subroutine we will call below and emit in genemit. */ 2697189251Ssam printf ("extern rtx gen_peephole2_%d (rtx, rtx *);\n", 2698189251Ssam next_insn_code); 2699189251Ssam break; 2700189251Ssam } 2701189251Ssam 2702189251Ssam return head; 2703189251Ssam} 2704189251Ssam 2705189251Ssamstatic void 2706189251Ssamprocess_tree (struct decision_head *head, enum routine_type subroutine_type) 2707189251Ssam{ 2708189251Ssam if (head->first == NULL) 2709189251Ssam { 2710189251Ssam /* We can elide peephole2_insns, but not recog or split_insns. */ 2711189251Ssam if (subroutine_type == PEEPHOLE2) 2712189251Ssam return; 2713189251Ssam } 2714189251Ssam else 2715189251Ssam { 2716189251Ssam factor_tests (head); 2717189251Ssam 2718189251Ssam next_subroutine_number = 0; 2719189251Ssam break_out_subroutines (head, 1); 2720189251Ssam find_afterward (head, NULL); 2721189251Ssam 2722189251Ssam /* We run this after find_afterward, because find_afterward needs 2723189251Ssam the redundant DT_mode tests on predicates to determine whether 2724189251Ssam two tests can both be true or not. */ 2725189251Ssam simplify_tests(head); 2726189251Ssam 2727189251Ssam write_subroutines (head, subroutine_type); 2728189251Ssam } 2729189251Ssam 2730189251Ssam write_subroutine (head, subroutine_type); 2731252726Srpaulo} 2732252726Srpaulo 2733252726Srpauloextern int main (int, char **); 2734252726Srpaulo 2735252726Srpauloint 2736252726Srpaulomain (int argc, char **argv) 2737252726Srpaulo{ 2738252726Srpaulo rtx desc; 2739252726Srpaulo struct decision_head recog_tree, split_tree, peephole2_tree, h; 2740252726Srpaulo 2741252726Srpaulo progname = "genrecog"; 2742252726Srpaulo 2743252726Srpaulo memset (&recog_tree, 0, sizeof recog_tree); 2744252726Srpaulo memset (&split_tree, 0, sizeof split_tree); 2745252726Srpaulo memset (&peephole2_tree, 0, sizeof peephole2_tree); 2746252726Srpaulo 2747252726Srpaulo if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE) 2748252726Srpaulo return (FATAL_EXIT_CODE); 2749252726Srpaulo 2750252726Srpaulo next_insn_code = 0; 2751252726Srpaulo 2752189251Ssam write_header (); 2753189251Ssam 2754189251Ssam /* Read the machine description. */ 2755189251Ssam 2756189251Ssam while (1) 2757189251Ssam { 2758189251Ssam desc = read_md_rtx (&pattern_lineno, &next_insn_code); 2759189251Ssam if (desc == NULL) 2760189251Ssam break; 2761189251Ssam 2762189251Ssam switch (GET_CODE (desc)) 2763252726Srpaulo { 2764252726Srpaulo case DEFINE_PREDICATE: 2765252726Srpaulo case DEFINE_SPECIAL_PREDICATE: 2766252726Srpaulo process_define_predicate (desc); 2767252726Srpaulo break; 2768252726Srpaulo 2769252726Srpaulo case DEFINE_INSN: 2770252726Srpaulo h = make_insn_sequence (desc, RECOG); 2771189251Ssam merge_trees (&recog_tree, &h); 2772189251Ssam break; 2773189251Ssam 2774189251Ssam case DEFINE_SPLIT: 2775189251Ssam h = make_insn_sequence (desc, SPLIT); 2776189251Ssam merge_trees (&split_tree, &h); 2777189251Ssam break; 2778189251Ssam 2779189251Ssam case DEFINE_PEEPHOLE2: 2780189251Ssam h = make_insn_sequence (desc, PEEPHOLE2); 2781189251Ssam merge_trees (&peephole2_tree, &h); 2782189251Ssam 2783189251Ssam default: 2784189251Ssam /* do nothing */; 2785189251Ssam } 2786189251Ssam } 2787189251Ssam 2788189251Ssam if (error_count || have_error) 2789189251Ssam return FATAL_EXIT_CODE; 2790252726Srpaulo 2791252726Srpaulo puts ("\n\n"); 2792252726Srpaulo 2793252726Srpaulo process_tree (&recog_tree, RECOG); 2794281806Srpaulo process_tree (&split_tree, SPLIT); 2795281806Srpaulo process_tree (&peephole2_tree, PEEPHOLE2); 2796252726Srpaulo 2797252726Srpaulo fflush (stdout); 2798252726Srpaulo return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); 2799252726Srpaulo} 2800189251Ssam 2801189251Ssamstatic void 2802189251Ssamdebug_decision_2 (struct decision_test *test) 2803189251Ssam{ 2804189251Ssam switch (test->type) 2805189251Ssam { 2806189251Ssam case DT_num_insns: 2807189251Ssam fprintf (stderr, "num_insns=%d", test->u.num_insns); 2808189251Ssam break; 2809189251Ssam case DT_mode: 2810189251Ssam fprintf (stderr, "mode=%s", GET_MODE_NAME (test->u.mode)); 2811189251Ssam break; 2812189251Ssam case DT_code: 2813189251Ssam fprintf (stderr, "code=%s", GET_RTX_NAME (test->u.code)); 2814189251Ssam break; 2815189251Ssam case DT_veclen: 2816189251Ssam fprintf (stderr, "veclen=%d", test->u.veclen); 2817189251Ssam break; 2818189251Ssam case DT_elt_zero_int: 2819189251Ssam fprintf (stderr, "elt0_i=%d", (int) test->u.intval); 2820189251Ssam break; 2821189251Ssam case DT_elt_one_int: 2822189251Ssam fprintf (stderr, "elt1_i=%d", (int) test->u.intval); 2823189251Ssam break; 2824189251Ssam case DT_elt_zero_wide: 2825189251Ssam fprintf (stderr, "elt0_w=" HOST_WIDE_INT_PRINT_DEC, test->u.intval); 2826189251Ssam break; 2827189251Ssam case DT_elt_zero_wide_safe: 2828189251Ssam fprintf (stderr, "elt0_ws=" HOST_WIDE_INT_PRINT_DEC, test->u.intval); 2829189251Ssam break; 2830189251Ssam case DT_veclen_ge: 2831189251Ssam fprintf (stderr, "veclen>=%d", test->u.veclen); 2832189251Ssam break; 2833189251Ssam case DT_dup: 2834189251Ssam fprintf (stderr, "dup=%d", test->u.dup); 2835189251Ssam break; 2836189251Ssam case DT_pred: 2837189251Ssam fprintf (stderr, "pred=(%s,%s)", 2838189251Ssam test->u.pred.name, GET_MODE_NAME(test->u.pred.mode)); 2839189251Ssam break; 2840189251Ssam case DT_c_test: 2841189251Ssam { 2842189251Ssam char sub[16+4]; 2843189251Ssam strncpy (sub, test->u.c_test, sizeof(sub)); 2844189251Ssam memcpy (sub+16, "...", 4); 2845189251Ssam fprintf (stderr, "c_test=\"%s\"", sub); 2846189251Ssam } 2847189251Ssam break; 2848189251Ssam case DT_accept_op: 2849189251Ssam fprintf (stderr, "A_op=%d", test->u.opno); 2850189251Ssam break; 2851189251Ssam case DT_accept_insn: 2852189251Ssam fprintf (stderr, "A_insn=(%d,%d)", 2853189251Ssam test->u.insn.code_number, test->u.insn.num_clobbers_to_add); 2854189251Ssam break; 2855189251Ssam 2856189251Ssam default: 2857189251Ssam gcc_unreachable (); 2858189251Ssam } 2859189251Ssam} 2860189251Ssam 2861189251Ssamstatic void 2862189251Ssamdebug_decision_1 (struct decision *d, int indent) 2863189251Ssam{ 2864189251Ssam int i; 2865189251Ssam struct decision_test *test; 2866189251Ssam 2867189251Ssam if (d == NULL) 2868189251Ssam { 2869189251Ssam for (i = 0; i < indent; ++i) 2870189251Ssam putc (' ', stderr); 2871189251Ssam fputs ("(nil)\n", stderr); 2872189251Ssam return; 2873189251Ssam } 2874189251Ssam 2875189251Ssam for (i = 0; i < indent; ++i) 2876189251Ssam putc (' ', stderr); 2877189251Ssam 2878189251Ssam putc ('{', stderr); 2879189251Ssam test = d->tests; 2880189251Ssam if (test) 2881189251Ssam { 2882189251Ssam debug_decision_2 (test); 2883189251Ssam while ((test = test->next) != NULL) 2884189251Ssam { 2885189251Ssam fputs (" + ", stderr); 2886189251Ssam debug_decision_2 (test); 2887252726Srpaulo } 2888252726Srpaulo } 2889252726Srpaulo fprintf (stderr, "} %d n %d a %d\n", d->number, 2890252726Srpaulo (d->next ? d->next->number : -1), 2891252726Srpaulo (d->afterward ? d->afterward->number : -1)); 2892252726Srpaulo} 2893252726Srpaulo 2894252726Srpaulostatic void 2895252726Srpaulodebug_decision_0 (struct decision *d, int indent, int maxdepth) 2896189251Ssam{ 2897189251Ssam struct decision *n; 2898189251Ssam int i; 2899189251Ssam 2900189251Ssam if (maxdepth < 0) 2901189251Ssam return; 2902189251Ssam if (d == NULL) 2903189251Ssam { 2904189251Ssam for (i = 0; i < indent; ++i) 2905189251Ssam putc (' ', stderr); 2906189251Ssam fputs ("(nil)\n", stderr); 2907189251Ssam return; 2908189251Ssam } 2909189251Ssam 2910189251Ssam debug_decision_1 (d, indent); 2911189251Ssam for (n = d->success.first; n ; n = n->next) 2912189251Ssam debug_decision_0 (n, indent + 2, maxdepth - 1); 2913189251Ssam} 2914189251Ssam 2915189251Ssamvoid 2916189251Ssamdebug_decision (struct decision *d) 2917189251Ssam{ 2918189251Ssam debug_decision_0 (d, 0, 1000000); 2919189251Ssam} 2920189251Ssam 2921189251Ssamvoid 2922189251Ssamdebug_decision_list (struct decision *d) 2923189251Ssam{ 2924189251Ssam while (d) 2925189251Ssam { 2926189251Ssam debug_decision_0 (d, 0, 0); 2927189251Ssam d = d->next; 2928189251Ssam } 2929189251Ssam} 2930189251Ssam