From e543e219eb1865d4230278c3db3d2bedd60b1de0 Mon Sep 17 00:00:00 2001 From: Zack Weinberg Date: Thu, 12 Aug 2004 07:49:00 +0000 Subject: [PATCH] genpreds.c: Add capability to generate predicate bodies as well as function prototypes. * genpreds.c: Add capability to generate predicate bodies as well as function prototypes. Write function prototypes for the generic predicates too. (process_define_predicate, write_tm_preds_h, write_insn_preds_c) (write_predicate_subfunction, mark_mode_tests, add_mode_tests) (write_match_code, write_predicate_expr, write_one_predicate_function) (parse_option): New functions. (output_predicate_decls): Delete. (main): Read the machine description, process DEFINE_PREDICATE or DEFINE_SPECIAL_PREDICATE patterns, write tm-preds.h or insn-preds.c as appropriate. * genrecog.c (struct decision_test): Replace index with struct pred_data pointer. (next_index): Remove, unused. (pred_table, preds, special_mode_pred_table): Delete. (compute_predicate_codes, process_define_predicate): New functions. (validate_pattern, add_to_sequence, write_switch): Update for new data structures. (main): Handle DEFINE_PREDICATE and DEFINE_SPECIAL_PREDICATE. Check both error_count and have_error. * gensupport.c (in_fname, first_predicate): New globals. (define_pred_queue, define_pred_tail): New RTL-pattern queue. (predicate_table, last_predicate, old_pred_table) (old_special_pred_table): New statics. (hash_struct_pred_data, eq_struct_pred_data, lookup_predicate) (add_predicate, init_predicate_table): New functions. (process_rtx): Handle DEFINE_PREDICATE and DEFINE_SPECIAL_PREDICATE. (init_md_reader_args_cb): Use the global in_fname. No need to zero it or max_include_len. Call init_predicate_table. (read_rtx): Run the predicate queue after the attribute queue but before all the others. * gensupport.h (in_fname, struct pred_data, first_predicate) (lookup_predicate, add_predicate, FOR_ALL_PREDICATES): Declare. * rtl.def (MATCH_CODE, MATCH_TEST, DEFINE_PREDICATE) (DEFINE_SPECIAL_PREDICATE): New RTL codes. * dummy-conditions.c: Don't include bconfig.h, system.h, coretypes.h, tm.h, or system.h. Do include stddef.h. Duplicate declaration of struct c_test from gensupport.h. * Makefile.in (OBJS-common): Add insn-preds.o. (STAGESTUFF, .PRECIOUS): Add insn-preds.c. (insn-preds.c, insn-preds.o): New rules. (s-preds): Also generate insn-preds.c. (dummy-conditions.o, genpreds$(build_exeext), genpreds.o): Update dependencies. (print-rtl.o, print-rtl1.o): Correct dependencies. * recog.h: Delete prototypes of predicate functions. * doc/md.texi (Predicates): New section with complete documentation of operand/operator predicates. Remove some incomplete documentation of predicates from other places. * doc/tm.texi (Misc): Move SPECIAL_MODE_PREDICATES next to PREDICATE_CODES; indicate that both are deprecated in favor of define_predicate/define_special_predicate. * config/ia64/ia64.c: All predicate function definitions moved to ia64.md, except (small_addr_symbolic_operand, tls_symbolic_operand): Delete. (ia64_expand_load_address, ia64_expand_move): Check SYMBOL_REF_TLS_MODEL directly, don't use tls_symbolic_operand. * config/ia64/ia64.md: All predicates now defined here. (symbolic_operand): Is now a special predicate. * config/ia64/ia64.h: Declare ia64_section_threshold. (PREDICATE_CODES): Delete. From-SVN: r85855 --- gcc/ChangeLog | 84 ++++++- gcc/Makefile.in | 37 +-- gcc/config/ia64/ia64.c | 512 +--------------------------------------- gcc/config/ia64/ia64.h | 51 +--- gcc/config/ia64/ia64.md | 336 ++++++++++++++++++++++++++ gcc/doc/md.texi | 381 +++++++++++++++++++++++++++--- gcc/doc/tm.texi | 40 ++-- gcc/dummy-conditions.c | 18 +- gcc/genpreds.c | 475 ++++++++++++++++++++++++++++++++++--- gcc/genrecog.c | 486 ++++++++++++++++++++++---------------- gcc/gensupport.c | 168 ++++++++++++- gcc/gensupport.h | 26 ++ gcc/recog.h | 16 -- gcc/rtl.def | 28 +++ 14 files changed, 1777 insertions(+), 881 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b0e986be8fc..7de4f0b0fb9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,75 @@ +2004-08-12 Zack Weinberg + + * genpreds.c: Add capability to generate predicate bodies as + well as function prototypes. Write function prototypes for + the generic predicates too. + (process_define_predicate, write_tm_preds_h, write_insn_preds_c) + (write_predicate_subfunction, mark_mode_tests, add_mode_tests) + (write_match_code, write_predicate_expr, write_one_predicate_function) + (parse_option): New functions. + (output_predicate_decls): Delete. + (main): Read the machine description, process DEFINE_PREDICATE or + DEFINE_SPECIAL_PREDICATE patterns, write tm-preds.h or insn-preds.c + as appropriate. + + * genrecog.c (struct decision_test): Replace index with + struct pred_data pointer. + (next_index): Remove, unused. + (pred_table, preds, special_mode_pred_table): Delete. + (compute_predicate_codes, process_define_predicate): New functions. + (validate_pattern, add_to_sequence, write_switch): Update for + new data structures. + (main): Handle DEFINE_PREDICATE and DEFINE_SPECIAL_PREDICATE. + Check both error_count and have_error. + + * gensupport.c (in_fname, first_predicate): New globals. + (define_pred_queue, define_pred_tail): New RTL-pattern queue. + (predicate_table, last_predicate, old_pred_table) + (old_special_pred_table): New statics. + (hash_struct_pred_data, eq_struct_pred_data, lookup_predicate) + (add_predicate, init_predicate_table): New functions. + (process_rtx): Handle DEFINE_PREDICATE and DEFINE_SPECIAL_PREDICATE. + (init_md_reader_args_cb): Use the global in_fname. No need to zero + it or max_include_len. Call init_predicate_table. + (read_rtx): Run the predicate queue after the attribute queue + but before all the others. + * gensupport.h (in_fname, struct pred_data, first_predicate) + (lookup_predicate, add_predicate, FOR_ALL_PREDICATES): Declare. + * rtl.def (MATCH_CODE, MATCH_TEST, DEFINE_PREDICATE) + (DEFINE_SPECIAL_PREDICATE): New RTL codes. + * dummy-conditions.c: Don't include bconfig.h, system.h, + coretypes.h, tm.h, or system.h. Do include stddef.h. + Duplicate declaration of struct c_test from gensupport.h. + + * Makefile.in (OBJS-common): Add insn-preds.o. + (STAGESTUFF, .PRECIOUS): Add insn-preds.c. + (insn-preds.c, insn-preds.o): New rules. + (s-preds): Also generate insn-preds.c. + (dummy-conditions.o, genpreds$(build_exeext), genpreds.o): + Update dependencies. + (print-rtl.o, print-rtl1.o): Correct dependencies. + + * recog.h: Delete prototypes of predicate functions. + + * doc/md.texi (Predicates): New section with complete + documentation of operand/operator predicates. Remove some + incomplete documentation of predicates from other places. + * doc/tm.texi (Misc): Move SPECIAL_MODE_PREDICATES next to + PREDICATE_CODES; indicate that both are deprecated in favor + of define_predicate/define_special_predicate. + + * config/ia64/ia64.c: All predicate function definitions moved + to ia64.md, except + (small_addr_symbolic_operand, tls_symbolic_operand): Delete. + (ia64_expand_load_address, ia64_expand_move): + Check SYMBOL_REF_TLS_MODEL directly, don't use tls_symbolic_operand. + + * config/ia64/ia64.md: All predicates now defined here. + (symbolic_operand): Is now a special predicate. + + * config/ia64/ia64.h: Declare ia64_section_threshold. + (PREDICATE_CODES): Delete. + 2004-08-12 Richard Henderson * c-common.h (STATEMENT_LIST_HAS_LABEL): New. @@ -8,7 +80,7 @@ 2004-08-12 Richard Henderson * stor-layout.c (round_up, round_down): Move ... - * fold-const.c (round_up, round_down): ... here. Use + * fold-const.c (round_up, round_down): ... here. Use multiple_of_p to avoid any arithmetic at all. 2004-08-12 Richard Henderson @@ -56,7 +128,7 @@ (LINK_SPEC): Same. * doc/invoke.texi (Darwin Options): Document -dead_strip and -no_dead_strip_inits_and_terms. - + 2004-08-11 Paul Brook * config/arm/arm-protos.h (arm_finalize_pic) Rename ... @@ -102,15 +174,15 @@ get_vuse_ops,get_v_must_def_ops): Add operand structure reference. (get_v_may_def_result_ptr, get_v_may_def_op_ptr): New access struct. (start_ssa_stmt_operands): Delete. - * tree-flow.h (struct stmt_ann_d): Replace operand vectors with new + * tree-flow.h (struct stmt_ann_d): Replace operand vectors with new struct stmt_operands_d. (build_ssa_operands): New extern entry point. - * tree-ssa-dom.c (record_equivalences_from_stmt): Remove operand + * tree-ssa-dom.c (record_equivalences_from_stmt): Remove operand building code, replace with create_ssa_artficial_load_stmt(). * tree-ssa-operands.c (struct voperands_d): Delete. (allocate_v_may_def_optype): Allocate v_may_def_operand_type_t vector. (allocate_v_must_def_optype): Use sizeof (tree), not sizeof (tree *). - (free_uses, free_defs, free_vuses, free_v_may_defs, + (free_uses, free_defs, free_vuses, free_v_may_defs, free_v_must_defs): Remove dealloc parameter. (remove_vuses, remove_v_may_def, remove_v_must_defs): Delete. (finalize_ssa_defs, finalize_ssa_uses, finalize_ssa_v_may_defs, @@ -125,7 +197,7 @@ duplicates and simple accumulation. (free_ssa_operands): Free vectors in a stmt_operand structure. (build_ssa_operands): New. Create a new stmt_operand structure from - a stmt and an old set of stmt_operands. + a stmt and an old set of stmt_operands. (get_stmt_operands): Simplify and call build_ssa_operands. (get_expr_operands, get_asm_expr_operands, get_indirect_ref_operands, get_call_expr_operands, add_stmt_operand, add_call_clobber_ops, diff --git a/gcc/Makefile.in b/gcc/Makefile.in index c51760a0697..e58a3a2141b 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -910,8 +910,8 @@ OBJS-common = \ genrtl.o ggc-common.o global.o graph.o gtype-desc.o \ haifa-sched.o hooks.o ifcvt.o insn-attrtab.o insn-emit.o insn-modes.o \ insn-extract.o insn-opinit.o insn-output.o insn-peep.o insn-recog.o \ - integrate.o intl.o jump.o langhooks.o lcm.o lists.o local-alloc.o \ - loop.o modulo-sched.o \ + insn-preds.o integrate.o intl.o jump.o langhooks.o lcm.o lists.o \ + local-alloc.o loop.o modulo-sched.o \ optabs.o options.o opts.o params.o postreload.o predict.o \ print-rtl.o print-tree.o value-prof.o var-tracking.o \ profile.o ra.o ra-build.o ra-colorize.o ra-debug.o ra-rewrite.o \ @@ -937,7 +937,8 @@ BACKEND = main.o @TREEBROWSER@ libbackend.a $(CPPLIB) # Files to be copied away after each stage in building. STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \ insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \ - insn-attr.h insn-attrtab.c insn-opinit.c insn-constants.h tm-preds.h \ + insn-attr.h insn-attrtab.c insn-opinit.c insn-preds.c insn-constants.h \ + tm-preds.h \ tree-check.h insn-conditions.c min-insn-modes.c insn-modes.c insn-modes.h \ s-flags s-config s-codes s-mlib s-genrtl s-modes s-gtype gtyp-gen.h \ s-gtyp-gen s-output s-recog s-emit s-extract s-peep s-check s-conditions \ @@ -1796,7 +1797,7 @@ rtl.o : rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) $(RTL_H) real.h \ $(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) print-rtl.o : print-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(RTL_H) $(TREE_H) hard-reg-set.h $(BASIC_BLOCK_H) real.h + $(RTL_H) $(TREE_H) hard-reg-set.h $(BASIC_BLOCK_H) real.h $(FLAGS_H) rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h \ $(RTL_H) hard-reg-set.h $(TM_P_H) insn-config.h $(RECOG_H) real.h $(FLAGS_H) \ $(BASIC_BLOCK_H) $(REGS_H) output.h target.h function.h @@ -2166,7 +2167,7 @@ libbackend.o : $(OBJS-common:.o=.c) $(out_file) \ .PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \ insn-emit.c insn-recog.c insn-extract.c insn-output.c insn-peep.c \ - insn-attr.h insn-attrtab.c + insn-attr.h insn-attrtab.c insn-preds.c # The following pair of rules has this effect: # genconfig is run only if the md has changed since genconfig was last run; @@ -2205,8 +2206,7 @@ insn-conditions.o : insn-conditions.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ insn-constants.h $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) insn-conditions.c -dummy-conditions.o : dummy-conditions.c $(BCONFIG_H) $(SYSTEM_H) \ - coretypes.h $(GTM_H) gensupport.h +dummy-conditions.o : dummy-conditions.c insn-flags.h: s-flags ; @true s-flags : $(md_file) genflags$(build_exeext) @@ -2340,13 +2340,19 @@ s-modes: genmodes$(build_exeext) $(SHELL) $(srcdir)/../move-if-change tmp-modes.c insn-modes.c $(STAMP) s-modes -tm-preds.h: s-preds; @true +insn-preds.c tm-preds.h: s-preds; @true -s-preds: genpreds$(build_exeext) - $(RUN_GEN) ./genpreds$(build_exeext) > tmp-preds.h +s-preds: $(md_file) genpreds$(build_exeext) + $(RUN_GEN) ./genpreds$(build_exeext) -h $(md_file) > tmp-preds.h $(SHELL) $(srcdir)/../move-if-change tmp-preds.h tm-preds.h + $(RUN_GEN) ./genpreds$(build_exeext) $(md_file) > tmp-preds.c + $(SHELL) $(srcdir)/../move-if-change tmp-preds.c insn-preds.c $(STAMP) s-preds +insn-preds.o : insn-preds.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) insn-config.h $(RECOG_H) real.h output.h $(FLAGS_H) function.h \ + hard-reg-set.h $(RESOURCE_H) $(TM_P_H) toplev.h reload.h + GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \ $(CPP_ID_DATA_H) $(host_xm_file_list) \ $(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) $(srcdir)/bitmap.h \ @@ -2539,11 +2545,14 @@ genmodes$(build_exeext) : genmodes.o $(BUILD_ERRORS) $(BUILD_LIBDEPS) genmodes.o : genmodes.c $(BCONFIG_H) $(SYSTEM_H) errors.h $(HASHTAB_H) \ machmode.def $(extra_modes_file) -genpreds$(build_exeext) : genpreds.o $(BUILD_LIBDEPS) +genpreds$(build_exeext) : genpreds.o $(BUILD_RTL) $(BUILD_EARLY_SUPPORT) \ + $(BUILD_PRINT) $(BUILD_ERRORS) $(BUILD_LIBDEPS) $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \ - genpreds.o $(BUILD_LIBS) + genpreds.o $(BUILD_RTL) $(BUILD_EARLY_SUPPORT) $(BUILD_PRINT) \ + $(BUILD_ERRORS) $(BUILD_LIBS) -genpreds.o : genpreds.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H) +genpreds.o : genpreds.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ + $(GTM_H) errors.h gensupport.h $(OBSTACK_H) gengtype$(build_exeext) : gengtype.o gengtype-lex.o gengtype-yacc.o \ $(BUILD_LIBDEPS) @@ -2593,7 +2602,7 @@ $(BUILD_PREFIX_1)rtl.o: $(srcdir)/rtl.c $(BCONFIG_H) coretypes.h $(GTM_H) $(SYST $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) $(BUILD_PREFIX)rtl.c $(OUTPUT_OPTION) print-rtl1.o: $(srcdir)/print-rtl.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ - $(GTM_H) $(RTL_H) $(TREE_H) hard-reg-set.h $(BASIC_BLOCK_H) + $(GTM_H) $(RTL_BASE_H) $(TREE_H) $(FLAGS_H) hard-reg-set.h $(BASIC_BLOCK_H) rm -f print-rtl1.c sed -e 's/config[.]h/bconfig.h/' $(srcdir)/print-rtl.c > print-rtl1.c $(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) print-rtl1.c $(OUTPUT_OPTION) diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 66e51ea8081..ce48d3fe644 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -418,513 +418,6 @@ static const struct attribute_spec ia64_attribute_table[] = struct gcc_target targetm = TARGET_INITIALIZER; -/* Return 1 if OP is a valid operand for the MEM of a CALL insn. */ - -int -call_operand (rtx op, enum machine_mode mode) -{ - if (mode != GET_MODE (op) && mode != VOIDmode) - return 0; - - return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG - || (GET_CODE (op) == SUBREG && GET_CODE (XEXP (op, 0)) == REG)); -} - -/* Return 1 if OP refers to a symbol in the sdata section. */ - -int -sdata_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - switch (GET_CODE (op)) - { - case CONST: - if (GET_CODE (XEXP (op, 0)) != PLUS - || GET_CODE (XEXP (XEXP (op, 0), 0)) != SYMBOL_REF) - break; - op = XEXP (XEXP (op, 0), 0); - /* FALLTHRU */ - - case SYMBOL_REF: - if (CONSTANT_POOL_ADDRESS_P (op)) - return GET_MODE_SIZE (get_pool_mode (op)) <= ia64_section_threshold; - else - return SYMBOL_REF_LOCAL_P (op) && SYMBOL_REF_SMALL_P (op); - - default: - break; - } - - return 0; -} - -int -small_addr_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return SYMBOL_REF_SMALL_ADDR_P (op); -} - -/* Return 1 if OP refers to a symbol, and is appropriate for a GOT load. */ - -int -got_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - switch (GET_CODE (op)) - { - case CONST: - /* Accept only (plus (symbol_ref) (const_int)). */ - op = XEXP (op, 0); - if (GET_CODE (op) != PLUS) - return 0; - if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF) - return 0; - op = XEXP (op, 1); - if (GET_CODE (op) != CONST_INT) - return 0; - - /* Ok if we're not using GOT entries at all. */ - if (TARGET_NO_PIC || TARGET_AUTO_PIC) - return 1; - - /* The low 14 bits of the constant have been forced to zero - by ia64_expand_load_address, so that we do not use up so - many GOT entries. Prevent cse from undoing this. */ - return (INTVAL (op) & 0x3fff) == 0; - - case SYMBOL_REF: - /* This sort of load should not be used for things in sdata. */ - return !SYMBOL_REF_SMALL_ADDR_P (op); - - case LABEL_REF: - return 1; - - default: - break; - } - return 0; -} - -/* Return 1 if OP refers to a symbol. */ - -int -symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - switch (GET_CODE (op)) - { - case CONST: - case SYMBOL_REF: - case LABEL_REF: - return 1; - - default: - break; - } - return 0; -} - -/* Return tls_model if OP refers to a TLS symbol. */ - -int -tls_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - if (GET_CODE (op) != SYMBOL_REF) - return 0; - return SYMBOL_REF_TLS_MODEL (op); -} - - -/* Return 1 if OP refers to a function. */ - -int -function_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - if (GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (op)) - return 1; - else - return 0; -} - -/* Return 1 if OP is a general operand, excluding tls symbolic operands. */ - -int -move_operand (rtx op, enum machine_mode mode) -{ - return general_operand (op, mode) && !tls_symbolic_operand (op, mode); -} - -/* Return 1 if OP is a register operand that is (or could be) a GR reg. */ - -int -gr_register_operand (rtx op, enum machine_mode mode) -{ - if (! register_operand (op, mode)) - return 0; - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - if (GET_CODE (op) == REG) - { - unsigned int regno = REGNO (op); - if (regno < FIRST_PSEUDO_REGISTER) - return GENERAL_REGNO_P (regno); - } - return 1; -} - -/* Return 1 if OP is a register operand that is (or could be) an FR reg. */ - -int -fr_register_operand (rtx op, enum machine_mode mode) -{ - if (! register_operand (op, mode)) - return 0; - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - if (GET_CODE (op) == REG) - { - unsigned int regno = REGNO (op); - if (regno < FIRST_PSEUDO_REGISTER) - return FR_REGNO_P (regno); - } - return 1; -} - -/* Return 1 if OP is a register operand that is (or could be) a GR/FR reg. */ - -int -grfr_register_operand (rtx op, enum machine_mode mode) -{ - if (! register_operand (op, mode)) - return 0; - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - if (GET_CODE (op) == REG) - { - unsigned int regno = REGNO (op); - if (regno < FIRST_PSEUDO_REGISTER) - return GENERAL_REGNO_P (regno) || FR_REGNO_P (regno); - } - return 1; -} - -/* Return 1 if OP is a nonimmediate operand that is (or could be) a GR reg. */ - -int -gr_nonimmediate_operand (rtx op, enum machine_mode mode) -{ - if (! nonimmediate_operand (op, mode)) - return 0; - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - if (GET_CODE (op) == REG) - { - unsigned int regno = REGNO (op); - if (regno < FIRST_PSEUDO_REGISTER) - return GENERAL_REGNO_P (regno); - } - return 1; -} - -/* Return 1 if OP is a nonimmediate operand that is (or could be) a FR reg. */ - -int -fr_nonimmediate_operand (rtx op, enum machine_mode mode) -{ - if (! nonimmediate_operand (op, mode)) - return 0; - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - if (GET_CODE (op) == REG) - { - unsigned int regno = REGNO (op); - if (regno < FIRST_PSEUDO_REGISTER) - return FR_REGNO_P (regno); - } - return 1; -} - -/* Return 1 if OP is a nonimmediate operand that is a GR/FR reg. */ - -int -grfr_nonimmediate_operand (rtx op, enum machine_mode mode) -{ - if (! nonimmediate_operand (op, mode)) - return 0; - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - if (GET_CODE (op) == REG) - { - unsigned int regno = REGNO (op); - if (regno < FIRST_PSEUDO_REGISTER) - return GENERAL_REGNO_P (regno) || FR_REGNO_P (regno); - } - return 1; -} - -/* Return 1 if OP is a GR register operand, or zero. */ - -int -gr_reg_or_0_operand (rtx op, enum machine_mode mode) -{ - return (op == const0_rtx || gr_register_operand (op, mode)); -} - -/* Return 1 if OP is a GR register operand, or a 5 bit immediate operand. */ - -int -gr_reg_or_5bit_operand (rtx op, enum machine_mode mode) -{ - return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) < 32) - || gr_register_operand (op, mode)); -} - -/* Return 1 if OP is a GR register operand, or a 6 bit immediate operand. */ - -int -gr_reg_or_6bit_operand (rtx op, enum machine_mode mode) -{ - return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_M (INTVAL (op))) - || gr_register_operand (op, mode)); -} - -/* Return 1 if OP is a GR register operand, or an 8 bit immediate operand. */ - -int -gr_reg_or_8bit_operand (rtx op, enum machine_mode mode) -{ - return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op))) - || gr_register_operand (op, mode)); -} - -/* Return 1 if OP is a GR/FR register operand, or an 8 bit immediate. */ - -int -grfr_reg_or_8bit_operand (rtx op, enum machine_mode mode) -{ - return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op))) - || grfr_register_operand (op, mode)); -} - -/* Return 1 if OP is a register operand, or an 8 bit adjusted immediate - operand. */ - -int -gr_reg_or_8bit_adjusted_operand (rtx op, enum machine_mode mode) -{ - return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_L (INTVAL (op))) - || gr_register_operand (op, mode)); -} - -/* Return 1 if OP is a register operand, or is valid for both an 8 bit - immediate and an 8 bit adjusted immediate operand. This is necessary - because when we emit a compare, we don't know what the condition will be, - so we need the union of the immediates accepted by GT and LT. */ - -int -gr_reg_or_8bit_and_adjusted_operand (rtx op, enum machine_mode mode) -{ - return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op)) - && CONST_OK_FOR_L (INTVAL (op))) - || gr_register_operand (op, mode)); -} - -/* Return 1 if OP is a register operand, or a 14 bit immediate operand. */ - -int -gr_reg_or_14bit_operand (rtx op, enum machine_mode mode) -{ - return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_I (INTVAL (op))) - || gr_register_operand (op, mode)); -} - -/* Return 1 if OP is a register operand, or a 22 bit immediate operand. */ - -int -gr_reg_or_22bit_operand (rtx op, enum machine_mode mode) -{ - return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_J (INTVAL (op))) - || gr_register_operand (op, mode)); -} - -/* Return 1 if OP is a 6 bit immediate operand. */ - -int -shift_count_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == CONST_INT && CONST_OK_FOR_M (INTVAL (op))); -} - -/* Return 1 if OP is a 5 bit immediate operand. */ - -int -shift_32bit_count_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == CONST_INT - && (INTVAL (op) >= 0 && INTVAL (op) < 32)); -} - -/* Return 1 if OP is a 2, 4, 8, or 16 immediate operand. */ - -int -shladd_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == CONST_INT - && (INTVAL (op) == 2 || INTVAL (op) == 4 - || INTVAL (op) == 8 || INTVAL (op) == 16)); -} - -/* Return 1 if OP is a -16, -8, -4, -1, 1, 4, 8, or 16 immediate operand. */ - -int -fetchadd_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == CONST_INT - && (INTVAL (op) == -16 || INTVAL (op) == -8 || - INTVAL (op) == -4 || INTVAL (op) == -1 || - INTVAL (op) == 1 || INTVAL (op) == 4 || - INTVAL (op) == 8 || INTVAL (op) == 16)); -} - -/* Return 1 if OP is a floating-point constant zero, one, or a register. */ - -int -fr_reg_or_fp01_operand (rtx op, enum machine_mode mode) -{ - return ((GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (op)) - || fr_register_operand (op, mode)); -} - -/* Like nonimmediate_operand, but don't allow MEMs that try to use a - POST_MODIFY with a REG as displacement. */ - -int -destination_operand (rtx op, enum machine_mode mode) -{ - if (! nonimmediate_operand (op, mode)) - return 0; - if (GET_CODE (op) == MEM - && GET_CODE (XEXP (op, 0)) == POST_MODIFY - && GET_CODE (XEXP (XEXP (XEXP (op, 0), 1), 1)) == REG) - return 0; - return 1; -} - -/* Like memory_operand, but don't allow post-increments. */ - -int -not_postinc_memory_operand (rtx op, enum machine_mode mode) -{ - return (memory_operand (op, mode) - && GET_RTX_CLASS (GET_CODE (XEXP (op, 0))) != RTX_AUTOINC); -} - -/* Return 1 if this is a comparison operator, which accepts a normal 8-bit - signed immediate operand. */ - -int -normal_comparison_operator (register rtx op, enum machine_mode mode) -{ - enum rtx_code code = GET_CODE (op); - return ((mode == VOIDmode || GET_MODE (op) == mode) - && (code == EQ || code == NE - || code == GT || code == LE || code == GTU || code == LEU)); -} - -/* Return 1 if this is a comparison operator, which accepts an adjusted 8-bit - signed immediate operand. */ - -int -adjusted_comparison_operator (register rtx op, enum machine_mode mode) -{ - enum rtx_code code = GET_CODE (op); - return ((mode == VOIDmode || GET_MODE (op) == mode) - && (code == LT || code == GE || code == LTU || code == GEU)); -} - -/* Return 1 if this is a signed inequality operator. */ - -int -signed_inequality_operator (register rtx op, enum machine_mode mode) -{ - enum rtx_code code = GET_CODE (op); - return ((mode == VOIDmode || GET_MODE (op) == mode) - && (code == GE || code == GT - || code == LE || code == LT)); -} - -/* Return 1 if this operator is valid for predication. */ - -int -predicate_operator (register rtx op, enum machine_mode mode) -{ - enum rtx_code code = GET_CODE (op); - return ((GET_MODE (op) == mode || mode == VOIDmode) - && (code == EQ || code == NE)); -} - -/* Return 1 if this operator can be used in a conditional operation. */ - -int -condop_operator (register rtx op, enum machine_mode mode) -{ - enum rtx_code code = GET_CODE (op); - return ((GET_MODE (op) == mode || mode == VOIDmode) - && (code == PLUS || code == MINUS || code == AND - || code == IOR || code == XOR)); -} - -/* Return 1 if this is the ar.lc register. */ - -int -ar_lc_reg_operand (register rtx op, enum machine_mode mode) -{ - return (GET_MODE (op) == DImode - && (mode == DImode || mode == VOIDmode) - && GET_CODE (op) == REG - && REGNO (op) == AR_LC_REGNUM); -} - -/* Return 1 if this is the ar.ccv register. */ - -int -ar_ccv_reg_operand (register rtx op, enum machine_mode mode) -{ - return ((GET_MODE (op) == mode || mode == VOIDmode) - && GET_CODE (op) == REG - && REGNO (op) == AR_CCV_REGNUM); -} - -/* Return 1 if this is the ar.pfs register. */ - -int -ar_pfs_reg_operand (register rtx op, enum machine_mode mode) -{ - return ((GET_MODE (op) == mode || mode == VOIDmode) - && GET_CODE (op) == REG - && REGNO (op) == AR_PFS_REGNUM); -} - -/* Similarly. */ - -int -xfreg_or_fp01_operand (rtx op, enum machine_mode mode) -{ - if (GET_CODE (op) == SUBREG) - return 0; - return fr_reg_or_fp01_operand (op, mode); -} - -/* Return 1 if OP is valid as a base register in a reg + offset address. */ - -int -basereg_operand (rtx op, enum machine_mode mode) -{ - /* ??? Should I copy the flag_omit_frame_pointer and cse_not_expected - checks from pa.c basereg_operand as well? Seems to be OK without them - in test runs. */ - - return (register_operand (op, mode) && - REG_POINTER ((GET_CODE (op) == SUBREG) ? SUBREG_REG (op) : op)); -} - typedef enum { ADDR_AREA_NORMAL, /* normal address area */ @@ -1099,7 +592,7 @@ ia64_depz_field_mask (rtx rop, rtx rshift) void ia64_expand_load_address (rtx dest, rtx src) { - if (tls_symbolic_operand (src, VOIDmode)) + if (GET_CODE (src) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (src)) abort (); if (GET_CODE (dest) != REG) abort (); @@ -1299,7 +792,8 @@ ia64_expand_move (rtx op0, rtx op1) if ((mode == Pmode || mode == ptr_mode) && symbolic_operand (op1, VOIDmode)) { enum tls_model tls_kind; - if ((tls_kind = tls_symbolic_operand (op1, VOIDmode))) + if (GET_CODE (op1) == SYMBOL_REF + && (tls_kind = SYMBOL_REF_TLS_MODEL (op1))) return ia64_expand_tls_address (tls_kind, op0, op1); if (!TARGET_NO_PIC && reload_completed) diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h index 96b559b4d12..58304a9b366 100644 --- a/gcc/config/ia64/ia64.h +++ b/gcc/config/ia64/ia64.h @@ -146,6 +146,10 @@ extern int target_flags; #define TARGET_DWARF2_ASM (target_flags & MASK_DWARF2_ASM) +/* Variables which are this size or smaller are put in the sdata/sbss + sections. */ +extern unsigned int ia64_section_threshold; + /* If the assembler supports thread-local storage, assume that the system does as well. If a particular target system has an assembler that supports TLS -- but the rest of the system does not @@ -2140,53 +2144,6 @@ do { \ #define SYMBOL_REF_SMALL_ADDR_P(X) \ ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_SMALL_ADDR) != 0) -/* Define this if you have defined special-purpose predicates in the file - `MACHINE.c'. For each predicate, list all rtl codes that can be in - expressions matched by the predicate. */ - -#define PREDICATE_CODES \ -{ "call_operand", {SUBREG, REG, SYMBOL_REF}}, \ -{ "got_symbolic_operand", {SYMBOL_REF, CONST, LABEL_REF}}, \ -{ "sdata_symbolic_operand", {SYMBOL_REF, CONST}}, \ -{ "small_addr_symbolic_operand", {SYMBOL_REF}}, \ -{ "symbolic_operand", {SYMBOL_REF, CONST, LABEL_REF}}, \ -{ "tls_symbolic_operand", {SYMBOL_REF}}, \ -{ "function_operand", {SYMBOL_REF}}, \ -{ "destination_operand", {SUBREG, REG, MEM}}, \ -{ "not_postinc_memory_operand", {MEM}}, \ -{ "move_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \ - SYMBOL_REF, CONST, LABEL_REF}}, \ -{ "gr_register_operand", {SUBREG, REG}}, \ -{ "fr_register_operand", {SUBREG, REG}}, \ -{ "grfr_register_operand", {SUBREG, REG}}, \ -{ "gr_nonimmediate_operand", {SUBREG, REG, MEM}}, \ -{ "fr_nonimmediate_operand", {SUBREG, REG, MEM}}, \ -{ "grfr_nonimmediate_operand", {SUBREG, REG, MEM}}, \ -{ "gr_reg_or_0_operand", {SUBREG, REG, CONST_INT}}, \ -{ "gr_reg_or_5bit_operand", {SUBREG, REG, CONST_INT}}, \ -{ "gr_reg_or_6bit_operand", {SUBREG, REG, CONST_INT}}, \ -{ "gr_reg_or_8bit_operand", {SUBREG, REG, CONST_INT}}, \ -{ "grfr_reg_or_8bit_operand", {SUBREG, REG, CONST_INT}}, \ -{ "gr_reg_or_8bit_adjusted_operand", {SUBREG, REG, CONST_INT}}, \ -{ "gr_reg_or_8bit_and_adjusted_operand", {SUBREG, REG, CONST_INT}}, \ -{ "gr_reg_or_14bit_operand", {SUBREG, REG, CONST_INT}}, \ -{ "gr_reg_or_22bit_operand", {SUBREG, REG, CONST_INT}}, \ -{ "shift_count_operand", {SUBREG, REG, CONST_INT}}, \ -{ "shift_32bit_count_operand", {SUBREG, REG, CONST_INT}}, \ -{ "shladd_operand", {CONST_INT}}, \ -{ "fetchadd_operand", {CONST_INT}}, \ -{ "fr_reg_or_fp01_operand", {SUBREG, REG, CONST_DOUBLE}}, \ -{ "normal_comparison_operator", {EQ, NE, GT, LE, GTU, LEU}}, \ -{ "adjusted_comparison_operator", {LT, GE, LTU, GEU}}, \ -{ "signed_inequality_operator", {GE, GT, LE, LT}}, \ -{ "predicate_operator", {NE, EQ}}, \ -{ "condop_operator", {PLUS, MINUS, IOR, XOR, AND}}, \ -{ "ar_lc_reg_operand", {REG}}, \ -{ "ar_ccv_reg_operand", {REG}}, \ -{ "ar_pfs_reg_operand", {REG}}, \ -{ "xfreg_or_fp01_operand", {REG, CONST_DOUBLE}}, \ -{ "basereg_operand", {SUBREG, REG}}, - /* An alias for a machine mode name. This is the machine mode that elements of a jump-table should have. */ diff --git a/gcc/config/ia64/ia64.md b/gcc/config/ia64/ia64.md index 04eda406a4f..31af3bbd534 100644 --- a/gcc/config/ia64/ia64.md +++ b/gcc/config/ia64/ia64.md @@ -89,6 +89,342 @@ (UNSPECV_PSAC_NORMAL 6) (UNSPECV_SETJMP_RECEIVER 7) ]) + +;; :::::::::::::::::::: +;; :: +;; :: Predicates +;; :: +;; :::::::::::::::::::: + +;; True if OP is a valid operand for the MEM of a CALL insn. +(define_predicate "call_operand" + (ior (match_code "symbol_ref") + (match_operand 0 "register_operand"))) + +;; True if OP refers to any kind of symbol. +;; For roughly the same reasons that pmode_register_operand exists, this +;; predicate ignores its mode argument. +(define_special_predicate "symbolic_operand" + (match_code "symbol_ref,const,label_ref")) + +;; True if OP is a SYMBOL_REF which refers to a function. +(define_predicate "function_operand" + (and (match_code "symbol_ref") + (match_test "SYMBOL_REF_FUNCTION_P (op)"))) + +;; True if OP refers to a symbol, and is appropriate for a GOT load. +(define_predicate "got_symbolic_operand" + (match_operand 0 "symbolic_operand" "") +{ + switch (GET_CODE (op)) + { + case LABEL_REF: + return true; + + case SYMBOL_REF: + /* This sort of load should not be used for things in sdata. */ + return !SYMBOL_REF_SMALL_ADDR_P (op); + + case CONST: + /* Accept only (plus (symbol_ref) (const_int)). */ + op = XEXP (op, 0); + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 0)) != SYMBOL_REF + || GET_CODE (XEXP (op, 1)) != CONST_INT) + return false; + + /* Ok if we're not using GOT entries at all. */ + if (TARGET_NO_PIC || TARGET_AUTO_PIC) + return true; + + /* The low 14 bits of the constant have been forced to zero + by ia64_expand_load_address, so that we do not use up so + many GOT entries. Prevent cse from undoing this. */ + op = XEXP (op, 1); + return (INTVAL (op) & 0x3fff) == 0; + + default: + abort (); + } +}) + +;; True if OP refers to a symbol in the sdata section. +(define_predicate "sdata_symbolic_operand" + (match_code "symbol_ref,const") +{ + switch (GET_CODE (op)) + { + case CONST: + op = XEXP (op, 0); + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 0)) != SYMBOL_REF) + return false; + op = XEXP (op, 0); + /* FALLTHRU */ + + case SYMBOL_REF: + if (CONSTANT_POOL_ADDRESS_P (op)) + return GET_MODE_SIZE (get_pool_mode (op)) <= ia64_section_threshold; + else + return SYMBOL_REF_LOCAL_P (op) && SYMBOL_REF_SMALL_P (op); + + default: + abort (); + } +}) + +;; Like nonimmediate_operand, but don't allow MEMs that try to use a +;; POST_MODIFY with a REG as displacement. +(define_predicate "destination_operand" + (and (match_operand 0 "nonimmediate_operand") + (match_test "GET_CODE (op) != MEM + || GET_CODE (XEXP (op, 0)) != POST_MODIFY + || GET_CODE (XEXP (XEXP (XEXP (op, 0), 1), 1)) != REG"))) + +;; Like memory_operand, but don't allow post-increments. +(define_predicate "not_postinc_memory_operand" + (and (match_operand 0 "memory_operand") + (match_test "GET_RTX_CLASS (GET_CODE (XEXP (op, 0))) != RTX_AUTOINC"))) + +;; True if OP is a general operand, excluding tls symbolic operands. +(define_predicate "move_operand" + (and (match_operand 0 "general_operand") + (not (match_test + "GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (op)")))) + +;; True if OP is a register operand that is (or could be) a GR reg. +(define_predicate "gr_register_operand" + (match_operand 0 "register_operand") +{ + unsigned int regno; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + regno = REGNO (op); + return (regno >= FIRST_PSEUDO_REGISTER || GENERAL_REGNO_P (regno)); +}) + +;; True if OP is a register operand that is (or could be) an FR reg. +(define_predicate "fr_register_operand" + (match_operand 0 "register_operand") +{ + unsigned int regno; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + regno = REGNO (op); + return (regno >= FIRST_PSEUDO_REGISTER || FR_REGNO_P (regno)); +}) + +;; True if OP is a register operand that is (or could be) a GR/FR reg. +(define_predicate "grfr_register_operand" + (match_operand 0 "register_operand") +{ + unsigned int regno; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + regno = REGNO (op); + return (regno >= FIRST_PSEUDO_REGISTER + || GENERAL_REGNO_P (regno) + || FR_REGNO_P (regno)); +}) + +;; True if OP is a nonimmediate operand that is (or could be) a GR reg. +(define_predicate "gr_nonimmediate_operand" + (match_operand 0 "nonimmediate_operand") +{ + unsigned int regno; + + if (GET_CODE (op) == MEM) + return true; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + regno = REGNO (op); + return (regno >= FIRST_PSEUDO_REGISTER || GENERAL_REGNO_P (regno)); +}) + +;; True if OP is a nonimmediate operand that is (or could be) a FR reg. +(define_predicate "fr_nonimmediate_operand" + (match_operand 0 "nonimmediate_operand") +{ + unsigned int regno; + + if (GET_CODE (op) == MEM) + return true; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + regno = REGNO (op); + return (regno >= FIRST_PSEUDO_REGISTER || FR_REGNO_P (regno)); +}) + +;; True if OP is a nonimmediate operand that is (or could be) a GR/FR reg. +(define_predicate "grfr_nonimmediate_operand" + (match_operand 0 "nonimmediate_operand") +{ + unsigned int regno; + + if (GET_CODE (op) == MEM) + return true; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + regno = REGNO (op); + return (regno >= FIRST_PSEUDO_REGISTER + || GENERAL_REGNO_P (regno) + || FR_REGNO_P (regno)); +}) + +;; True if OP is a GR register operand, or zero. +(define_predicate "gr_reg_or_0_operand" + (ior (match_operand 0 "gr_register_operand") + (and (match_code "const_int") + (match_test "op == const0_rtx")))) + +;; True if OP is a GR register operand, or a 5 bit immediate operand. +(define_predicate "gr_reg_or_5bit_operand" + (ior (match_operand 0 "gr_register_operand") + (and (match_code "const_int") + (match_test "INTVAL (op) >= 0 && INTVAL (op) < 32")))) + +;; True if OP is a GR register operand, or a 6 bit immediate operand. +(define_predicate "gr_reg_or_6bit_operand" + (ior (match_operand 0 "gr_register_operand") + (and (match_code "const_int") + (match_test "CONST_OK_FOR_M (INTVAL (op))")))) + +;; True if OP is a GR register operand, or an 8 bit immediate operand. +(define_predicate "gr_reg_or_8bit_operand" + (ior (match_operand 0 "gr_register_operand") + (and (match_code "const_int") + (match_test "CONST_OK_FOR_K (INTVAL (op))")))) + +;; True if OP is a GR/FR register operand, or an 8 bit immediate operand. +(define_predicate "grfr_reg_or_8bit_operand" + (ior (match_operand 0 "grfr_register_operand") + (and (match_code "const_int") + (match_test "CONST_OK_FOR_K (INTVAL (op))")))) + +;; True if OP is a register operand, or an 8 bit adjusted immediate operand. +(define_predicate "gr_reg_or_8bit_adjusted_operand" + (ior (match_operand 0 "gr_register_operand") + (and (match_code "const_int") + (match_test "CONST_OK_FOR_L (INTVAL (op))")))) + +;; True if OP is a register operand, or is valid for both an 8 bit +;; immediate and an 8 bit adjusted immediate operand. This is necessary +;; because when we emit a compare, we don't know what the condition will be, +;; so we need the union of the immediates accepted by GT and LT. +(define_predicate "gr_reg_or_8bit_and_adjusted_operand" + (ior (match_operand 0 "gr_register_operand") + (and (match_code "const_int") + (match_test "CONST_OK_FOR_K (INTVAL (op)) + && CONST_OK_FOR_L (INTVAL (op))")))) + +;; True if OP is a register operand, or a 14 bit immediate operand. +(define_predicate "gr_reg_or_14bit_operand" + (ior (match_operand 0 "gr_register_operand") + (and (match_code "const_int") + (match_test "CONST_OK_FOR_I (INTVAL (op))")))) + +;; True if OP is a register operand, or a 22 bit immediate operand. +(define_predicate "gr_reg_or_22bit_operand" + (ior (match_operand 0 "gr_register_operand") + (and (match_code "const_int") + (match_test "CONST_OK_FOR_J (INTVAL (op))")))) + +;; True if OP is a 6 bit immediate operand. +(define_predicate "shift_count_operand" + (and (match_code "const_int") + (match_test "CONST_OK_FOR_M (INTVAL (op))"))) + +;; True if OP is a 5 bit immediate operand. +(define_predicate "shift_32bit_count_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) >= 0 && INTVAL (op) < 32"))) + +;; True if OP is one of the immediate valuse 2, 4, 8, or 16. +(define_predicate "shladd_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) == 2 || INTVAL (op) == 4 || + INTVAL (op) == 8 || INTVAL (op) == 16"))) + +;; True if OP is one of the immediate values -16, -8, -4, -1, 1, 4, 8, 16. +(define_predicate "fetchadd_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) == -16 || INTVAL (op) == -8 || + INTVAL (op) == -4 || INTVAL (op) == -1 || + INTVAL (op) == 1 || INTVAL (op) == 4 || + INTVAL (op) == 8 || INTVAL (op) == 16"))) + + +;; True if OP is a floating-point constant zero, one, or a register. +(define_predicate "fr_reg_or_fp01_operand" + (ior (match_operand 0 "fr_register_operand") + (and (match_code "const_double") + (match_test "CONST_DOUBLE_OK_FOR_G (op)")))) + +;; Like fr_reg_or_fp01_operand, but don't allow any SUBREGs. +(define_predicate "xfreg_or_fp01_operand" + (and (match_operand 0 "fr_reg_or_fp01_operand") + (not (match_code "subreg")))) + +;; True if this is a comparison operator, which accepts a normal 8-bit +;; signed immediate operand. +(define_predicate "normal_comparison_operator" + (match_code "eq,ne,gt,le,gtu,leu")) + +;; True if this is a comparison operator, which accepts an adjusted 8-bit +;; signed immediate operand. +(define_predicate "adjusted_comparison_operator" + (match_code "lt,ge,ltu,geu")) + +;; True if this is a signed inequality operator. +(define_predicate "signed_inequality_operator" + (match_code "ge,gt,le,lt")) + +;; True if this operator is valid for predication. +(define_predicate "predicate_operator" + (match_code "eq,ne")) + +;; True if this operator can be used in a conditional operation. +(define_predicate "condop_operator" + (match_code "plus,minus,ior,xor,and")) + +;; These three are hardware registers that can only be addressed in +;; DImode. It's not strictly necessary to test mode == DImode here, +;; but it makes decent insurance against someone writing a +;; match_operand wrong. + +;; True if this is the ar.lc register. +(define_predicate "ar_lc_reg_operand" + (and (match_code "reg") + (match_test "mode == DImode && REGNO (op) == AR_LC_REGNUM"))) + +;; True if this is the ar.ccv register. +(define_predicate "ar_ccv_reg_operand" + (and (match_code "reg") + (match_test "mode == DImode && REGNO (op) == AR_CCV_REGNUM"))) + +;; True if this is the ar.pfs register. +(define_predicate "ar_pfs_reg_operand" + (and (match_code "reg") + (match_test "mode == DImode && REGNO (op) == AR_PFS_REGNUM"))) + +;; True if OP is valid as a base register in a reg + offset address. +;; ??? Should I copy the flag_omit_frame_pointer and cse_not_expected +;; checks from pa.c basereg_operand as well? Seems to be OK without them +;; in test runs. +(define_predicate "basereg_operand" + (match_operand 0 "register_operand") +{ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + return REG_POINTER (op); +}) + ;; :::::::::::::::::::: ;; :: diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 0e35053aaad..6b85836cb0f 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -28,7 +28,9 @@ See the next chapter for information on the C header file. from such an insn. * Output Statement:: For more generality, write C code to output the assembler code. -* Constraints:: When not all operands are general operands. +* Predicates:: Controlling what kinds of operands can be used + for an insn. +* Constraints:: Fine-tuning operand selection. * Standard Names:: Names mark patterns to use for code generation. * Pattern Ordering:: When the order of patterns makes a difference. * Dependent Patterns:: Having one pattern may make you need another. @@ -258,14 +260,16 @@ expressions. In the case of a @code{define_expand}, any operand numbers used only in @code{match_dup} expressions have higher values than all other operand numbers. -@var{predicate} is a string that is the name of a C function that accepts two -arguments, an expression and a machine mode. During matching, the -function will be called with the putative operand as the expression and -@var{m} as the mode argument (if @var{m} is not specified, -@code{VOIDmode} will be used, which normally causes @var{predicate} to accept -any mode). If it returns zero, this instruction pattern fails to match. -@var{predicate} may be an empty string; then it means no test is to be done -on the operand, so anything which occurs in this position is valid. +@var{predicate} is a string that is the name of a function that +accepts two arguments, an expression and a machine mode. +@xref{Predicates}. During matching, the function will be called with +the putative operand as the expression and @var{m} as the mode +argument (if @var{m} is not specified, @code{VOIDmode} will be used, +which normally causes @var{predicate} to accept any mode). If it +returns zero, this instruction pattern fails to match. +@var{predicate} may be an empty string; then it means no test is to be +done on the operand, so anything which occurs in this position is +valid. Most of the time, @var{predicate} will reject modes other than @var{m}---but not always. For example, the predicate @code{address_operand} uses @@ -275,36 +279,13 @@ Many predicates accept @code{const_int} nodes even though their mode is @var{constraint} controls reloading and the choice of the best register class to use for a value, as explained later (@pxref{Constraints}). +If the constraint would be an empty string, it can be omitted. People are often unclear on the difference between the constraint and the predicate. The predicate helps decide whether a given insn matches the pattern. The constraint plays no role in this decision; instead, it controls various decisions in the case of an insn which does match. -@findex general_operand -On CISC machines, the most common @var{predicate} is -@code{"general_operand"}. This function checks that the putative -operand is either a constant, a register or a memory reference, and that -it is valid for mode @var{m}. - -@findex register_operand -For an operand that must be a register, @var{predicate} should be -@code{"register_operand"}. Using @code{"general_operand"} would be -valid, since the reload pass would copy any non-register operands -through registers, but this would make GCC do extra work, it would -prevent invariant operands (such as constant) from being removed from -loops, and it would prevent the register allocator from doing the best -possible job. On RISC machines, it is usually most efficient to allow -@var{predicate} to accept only objects that the constraints allow. - -@findex immediate_operand -For an operand that must be a constant, you must be sure to either use -@code{"immediate_operand"} for @var{predicate}, or make the instruction -pattern's extra condition require a constant, or both. You cannot -expect the constraints to do this work! If the constraints allow only -constants, but the predicate allows something else, the compiler will -crash when that case arises. - @findex match_scratch @item (match_scratch:@var{m} @var{n} @var{constraint}) This expression is also a placeholder for operand number @var{n} @@ -681,6 +662,333 @@ as follows, having the output control string start with a @samp{@@}: clrmem %0") @end group @end smallexample + +@node Predicates +@section Predicates +@cindex predicates +@cindex operand predicates +@cindex operator predicates + +A predicate determines whether a @code{match_operand} or +@code{match_operator} expression matches, and therefore whether the +surrounding instruction pattern will be used for that combination of +operands. GCC has a number of machine-independent predicates, and you +can define machine-specific predicates as needed. By convention, +predicates used with @code{match_operand} have names that end in +@samp{_operand}, and those used with @code{match_operator} have names +that end in @samp{_operator}. + +All predicates are Boolean functions (in the mathematical sense) of +two arguments: the RTL expression that is being considered at that +position in the instruction pattern, and the machine mode that the +@code{match_operand} or @code{match_operator} specifies. In this +section, the first argument is called @var{op} and the second argument +@var{mode}. Predicates can be called from C as ordinary two-argument +functions; this can be useful in output templates or other +machine-specific code. + +Operand predicates can allow operands that are not actually acceptable +to the hardware, as long as the constraints give reload the ability to +fix them up (@pxref{Constraints}). However, GCC will usually generate +better code if the predicates specify the requirements of the machine +instructions as closely as possible. Reload cannot fix up operands +that must be constants (``immediate operands''); you must use a +predicate that allows only constants, or else enforce the requirement +in the extra condition. + +@cindex predicates and machine modes +@cindex normal predicates +@cindex special predicates +Most predicates handle their @var{mode} argument in a uniform manner. +If @var{mode} is @code{VOIDmode} (unspecified), then @var{op} can have +any mode. If @var{mode} is anything else, then @var{op} must have the +same mode, unless @var{op} is a @code{CONST_INT} or integer +@code{CONST_DOUBLE}. These RTL expressions always have +@code{VOIDmode}, so it would be counterproductive to check that their +mode matches. Instead, predicates that accept @code{CONST_INT} and/or +integer @code{CONST_DOUBLE} check that the value stored in the +constant will fit in the requested mode. + +Predicates with this behavior are called @dfn{normal}. +@command{genrecog} can optimize the instruction recognizer based on +knowledge of how normal predicates treat modes. It can also diagnose +certain kinds of common errors in the use of normal predicates; for +instance, it is almost always an error to use a normal predicate +without specifying a mode. + +Predicates that do something different with their @var{mode} argument +are called @dfn{special}. The generic predicates +@code{address_operand} and @code{pmode_register_operand} are special +predicates. @command{genrecog} does not do any optimizations or +diagnosis when special predicates are used. + +@menu +* Machine-Independent Predicates:: Predicates available to all back ends. +* Defining Predicates:: How to write machine-specific predicate + functions. +@end menu + +@node Machine-Independent Predicates +@subsection Machine-Independent Predicates +@cindex machine-independent predicates +@cindex generic predicates + +These are the generic predicates available to all back ends. They are +defined in @file{recog.c}. The first category of predicates allow +only constant, or @dfn{immediate}, operands. + +@defun immediate_operand +This predicate allows any sort of constant that fits in @var{mode}. +It is an appropriate choice for instructions that take operands that +must be constant. +@end defun + +@defun const_int_operand +This predicate allows any @code{CONST_INT} expression that fits in +@var{mode}. It is an appropriate choice for an immediate operand that +does not allow a symbol or label. +@end defun + +@defun const_double_operand +This predicate accepts any @code{CONST_DOUBLE} expression that has +exactly @var{mode}. If @var{mode} is @code{VOIDmode}, it will also +accept @code{CONST_INT}. It is intended for immediate floating point +constants. +@end defun + +@noindent +The second category of predicates allow only some kind of machine +register. + +@defun register_operand +This predicate allows any @code{REG} or @code{SUBREG} expression that +is valid for @var{mode}. It is often suitable for arithmetic +instruction operands on a RISC machine. +@end defun + +@defun pmode_register_operand +This is a slight variant on @code{register_operand} which works around +a limitation in the machine-description reader. + +@example +(match_operand @var{n} "pmode_register_operand" @var{constraint}) +@end example + +@noindent +means exactly what + +@example +(match_operand:P @var{n} "register_operand" @var{constraint}) +@end example + +@noindent +would mean, if the machine-description reader accepted @samp{:P} +mode suffixes. Unfortunately, it cannot, because @code{Pmode} is an +alias for some other mode, and might vary with machine-specific +options. @xref{Misc}. +@end defun + +@defun scratch_operand +This predicate allows hard registers and @code{SCRATCH} expressions, +but not pseudo-registers. It is used internally by @code{match_scratch}; +it should not be used directly. +@end defun + +@noindent +The third category of predicates allow only some kind of memory reference. + +@defun memory_operand +This predicate allows any valid reference to a quantity of mode +@var{mode} in memory, as determined by the weak form of +@code{GO_IF_LEGITIMATE_ADDRESS} (@pxref{Addressing Modes}). +@end defun + +@defun address_operand +This predicate is a little unusual; it allows any operand that is a +valid expression for the @emph{address} of a quantity of mode +@var{mode}, again determined by the weak form of +@code{GO_IF_LEGITIMATE_ADDRESS}. To first order, if +@samp{@w{(mem:@var{mode} (@var{exp}))}} is acceptable to +@code{memory_operand}, then @var{exp} is acceptable to +@code{address_operand}. Note that @var{exp} does not necessarily have +the mode @var{mode}. +@end defun + +@defun indirect_operand +This is a stricter form of @code{memory_operand} which allows only +memory references with a @code{general_operand} as the address +expression. New uses of this predicate are discouraged, because +@code{general_operand} is very permissive, so it's hard to tell what +an @code{indirect_operand} does or does not allow. If a target has +different requirements for memory operands for different instructions, +it is better to define target-specific predicates which enforce the +hardware's requirements explicitly. +@end defun + +@defun push_operand +This predicate allows a memory reference suitable for pushing a value +onto the stack. This will be a @code{MEM} which refers to +@code{stack_pointer_rtx}, with a side-effect in its address expression +(@pxref{Incdec}); which one is determined by the +@code{STACK_PUSH_CODE} macro (@pxref{Frame Layout}). +@end defun + +@defun pop_operand +This predicate allows a memory reference suitable for popping a value +off the stack. Again, this will be a @code{MEM} referring to +@code{stack_pointer_rtx}, with a side-effect in its address +expression. However, this time @code{STACK_POP_CODE} is expected. +@end defun + +@noindent +The fourth category of predicates allow some combination of the above +operands. + +@defun nonmemory_operand +This predicate allows any immediate or register operand valid for @var{mode}. +@end defun + +@defun nonimmediate_operand +This predicate allows any register or memory operand valid for @var{mode}. +@end defun + +@defun general_operand +This predicate allows any immediate, register, or memory operand +valid for @var{mode}. +@end defun + +@noindent +Finally, there is one generic operator predicate. + +@defun comparison_operator +This predicate matches any expression which performs an arithmetic +comparison in @var{mode}; that is, @code{COMPARISON_P} is true for the +expression code. +@end defun + +@node Defining Predicates +@subsection Defining Machine-Specific Predicates +@cindex defining predicates +@findex define_predicate +@findex define_special_predicate + +Many machines have requirements for their operands that cannot be +expressed precisely using the generic predicates. You can define +additional predicates using @code{define_predicate} and +@code{define_special_predicate} expressions. These expressions have +three operands: + +@itemize @bullet +@item +The name of the predicate, as it will be referred to in +@code{match_operand} or @code{match_operator} expressions. + +@item +An RTL expression which evaluates to true if the predicate allows the +operand @var{op}, false if it does not. This expression can only use +the following RTL codes: + +@table @code +@item MATCH_OPERAND +When written inside a predicate expression, a @code{MATCH_OPERAND} +expression evaluates to true if the predicate it names would allow +@var{op}. The operand number and constraint are ignored. Due to +limitations in @command{genrecog}, you can only refer to generic +predicates and predicates that have already been defined. + +@item MATCH_CODE +This expression has one operand, a string constant containing a +comma-separated list of RTX code names (in lower case). It evaluates +to true if @var{op} has any of the listed codes. + +@item MATCH_TEST +This expression has one operand, a string constant containing a C +expression. The predicate's arguments, @var{op} and @var{mode}, are +available with those names in the C expression. The @code{MATCH_TEST} +evaluates to true if the C expression evaluates to a nonzero value. +@code{MATCH_TEST} expressions must not have side effects. + +@item AND +@itemx IOR +@itemx NOT +@itemx IF_THEN_ELSE +The basic @samp{MATCH_} expressions can be combined using these +logical operators, which have the semantics of the C operators +@samp{&&}, @samp{||}, @samp{!}, and @samp{@w{? :}} respectively. +@end table + +@item +An optional block of C code, which should execute +@samp{@w{return true}} if the predicate is found to match and +@samp{@w{return false}} if it does not. It must not have any side +effects. The predicate arguments, @var{op} and @var{mode}, are +available with those names. + +If a code block is present in a predicate definition, then the RTL +expression must evaluate to true @emph{and} the code block must +execute @samp{@w{return true}} for the predicate to allow the operand. +The RTL expression is evaluated first; do not re-check anything in the +code block that was checked in the RTL expression. +@end itemize + +The program @command{genrecog} scans @code{define_predicate} and +@code{define_special_predicate} expressions to determine which RTX +codes are possibly allowed. You should always make this explicit in +the RTL predicate expression, using @code{MATCH_OPERAND} and +@code{MATCH_CODE}. + +Here is an example of a simple predicate definition, from the IA64 +machine description: + +@smallexample +@group +;; @r{True if @var{op} is a @code{SYMBOL_REF} which refers to the sdata section.} +(define_predicate "small_addr_symbolic_operand" + (and (match_code "symbol_ref") + (match_test "SYMBOL_REF_SMALL_ADDR_P (op)"))) +@end group +@end smallexample + +@noindent +And here is another, showing the use of the C block. + +@smallexample +@group +;; @r{True if @var{op} is a register operand that is (or could be) a GR reg.} +(define_predicate "gr_register_operand" + (match_operand 0 "register_operand") +@{ + unsigned int regno; + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + regno = REGNO (op); + return (regno >= FIRST_PSEUDO_REGISTER || GENERAL_REGNO_P (regno)); +@}) +@end group +@end smallexample + +Predicates written with @code{define_predicate} automatically include +a test that @var{mode} is @code{VOIDmode}, or @var{op} has the same +mode as @var{mode}, or @var{op} is a @code{CONST_INT} or +@code{CONST_DOUBLE}. They do @emph{not} check specifically for +integer @code{CONST_DOUBLE}, nor do they test that the value of either +kind of constant fits in the requested mode. This is because +target-specific predicates that take constants usually have to do more +stringent value checks anyway. If you need the exact same treatment +of @code{CONST_INT} or @code{CONST_DOUBLE} that the generic predicates +provide, use a @code{MATCH_OPERAND} subexpression to call +@code{const_int_operand}, @code{const_double_operand}, or +@code{immediate_operand}. + +Predicates written with @code{define_special_predicate} do not get any +automatic mode checks, and are treated as having special mode handling +by @command{genrecog}. + +The program @command{genpreds} is responsible for generating code to +test predicates. It also writes a header file containing function +declarations for all machine-specific predicates. It is not necessary +to declare these predicates in @file{@var{cpu}-protos.h}. @end ifset @c Most of this node appears by itself (in a different place) even @@ -692,8 +1000,11 @@ as follows, having the output control string start with a @samp{@@}: @cindex operand constraints @cindex constraints -Each @code{match_operand} in an instruction pattern can specify a -constraint for the type of operands allowed. +Each @code{match_operand} in an instruction pattern can specify +constraints for the operands allowed. The constraints allow you to +fine-tune matching within the set of operands allowed by the +predicate. + @end ifset @ifclear INTERNALS @node Constraints diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 06c08f99c45..29107308793 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -8539,24 +8539,9 @@ patterns. For each predicate function named in @code{PREDICATE_CODES}, a declaration will be generated in @file{insn-codes.h}. -@end defmac - -@defmac HAS_LONG_COND_BRANCH -Define this boolean macro to indicate whether or not your architecture -has conditional branches that can span all of memory. It is used in -conjunction with an optimization that partitions hot and cold basic -blocks into separate sections of the executable. If this macro is -set to false, gcc will convert any conditional branches that attempt -to cross between sections into unconditional branches or indirect jumps. -@end defmac -@defmac HAS_LONG_UNCOND_BRANCH -Define this boolean macro to indicate whether or not your architecture -has unconditional branches that can span all of memory. It is used in -conjunction with an optimization that partitions hot and cold basic -blocks into separate sections of the executable. If this macro is -set to false, gcc will convert any unconditional branches that attempt -to cross between sections into indirect jumps. +Use of this macro is deprecated; use @code{define_predicate} instead. +@xref{Defining Predicates}. @end defmac @defmac SPECIAL_MODE_PREDICATES @@ -8574,6 +8559,27 @@ for a byte extraction from @code{%ah} etc.). #define SPECIAL_MODE_PREDICATES \ "ext_register_operand", @end smallexample + +Use of this macro is deprecated; use @code{define_special_predicate} +instead. @xref{Defining Predicates}. +@end defmac + +@defmac HAS_LONG_COND_BRANCH +Define this boolean macro to indicate whether or not your architecture +has conditional branches that can span all of memory. It is used in +conjunction with an optimization that partitions hot and cold basic +blocks into separate sections of the executable. If this macro is +set to false, gcc will convert any conditional branches that attempt +to cross between sections into unconditional branches or indirect jumps. +@end defmac + +@defmac HAS_LONG_UNCOND_BRANCH +Define this boolean macro to indicate whether or not your architecture +has unconditional branches that can span all of memory. It is used in +conjunction with an optimization that partitions hot and cold basic +blocks into separate sections of the executable. If this macro is +set to false, gcc will convert any unconditional branches that attempt +to cross between sections into indirect jumps. @end defmac @defmac CASE_VECTOR_MODE diff --git a/gcc/dummy-conditions.c b/gcc/dummy-conditions.c index eb3fb417314..95db257bd09 100644 --- a/gcc/dummy-conditions.c +++ b/gcc/dummy-conditions.c @@ -1,5 +1,5 @@ /* Support for calculating constant conditions. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -18,16 +18,22 @@ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "bconfig.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "gensupport.h" +#include /* for size_t */ /* MD generators that are run before insn-conditions.c exists should link against this file instead. Currently that is genconditions and genconstants. */ +/* In order to avoid dragging in all the headers that are needed to + declare things that gensupport.h uses, we duplicate the declaration + of struct c_test here. (In particular we do not want to have to + include tm.h nor rtl.h in this file.) */ +struct c_test +{ + const char *expr; + int value; +}; + /* Empty conditions table to prevent link errors. */ const struct c_test insn_conditions[1] = { { 0, 0 } }; const size_t n_insn_conditions = 0; diff --git a/gcc/genpreds.c b/gcc/genpreds.c index b5601208df8..833d47f907b 100644 --- a/gcc/genpreds.c +++ b/gcc/genpreds.c @@ -1,8 +1,8 @@ /* Generate from machine description: - - some macros CODE_FOR_... giving the insn_code_number value - for each of the defined standard insn names. - Copyright (C) 1987, 1991, 1995, 1998, - 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + - prototype declarations for operand predicates (tm-preds.h) + - function definitions of operand predicates, if defined new-style + (insn-preds.c) + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -26,40 +26,461 @@ Boston, MA 02111-1307, USA. */ #include "coretypes.h" #include "tm.h" #include "rtl.h" +#include "errors.h" +#include "gensupport.h" +#include "obstack.h" +/* The new way to declare predicates is with (define_predicate) or + (define_special_predicate) expressions in the machine description. + This provides a function body as well as a name. */ static void -output_predicate_decls (void) +process_define_predicate (rtx defn) { -#ifdef PREDICATE_CODES - static const struct { - const char *const name; - const RTX_CODE codes[NUM_RTX_CODE]; - } predicate[] = { - PREDICATE_CODES - }; - size_t i; - - puts ("#ifdef RTX_CODE\n"); - for (i = 0; i < ARRAY_SIZE (predicate); i++) - printf ("extern int %s (rtx, enum machine_mode);\n", - predicate[i].name); - puts ("\n#endif /* RTX_CODE */\n"); -#endif + struct pred_data *pred; + if (XEXP (defn, 1) == 0) + { + error ("%s: must give a predicate expression", XSTR (defn, 0)); + return; + } + + pred = xcalloc (sizeof (struct pred_data), 1); + pred->name = XSTR (defn, 0); + pred->exp = XEXP (defn, 1); + pred->c_block = XSTR (defn, 2); + + if (GET_CODE (defn) == DEFINE_SPECIAL_PREDICATE) + pred->special = true; + + add_predicate (pred); +} + +/* Write tm-preds.h. Unfortunately, it is impossible to forward-declare + an enumeration in portable C, so we have to condition all these + prototypes on HAVE_MACHINE_MODES. */ +static void +write_tm_preds_h (void) +{ + struct pred_data *p; + + printf ("\ +/* Generated automatically by the program '%s'\n\ + from the machine description file '%s'. */\n\n", progname, in_fname); + + puts ("\ +#ifndef GCC_TM_PREDS_H\n\ +#define GCC_TM_PREDS_H\n\ +\n\ +#ifdef HAVE_MACHINE_MODES"); + + FOR_ALL_PREDICATES (p) + printf ("extern int %s (rtx, enum machine_mode);\n", p->name); + + puts ("\ +#endif /* HAVE_MACHINE_MODES */\n\ +#endif /* tm-preds.h */"); +} + +/* Given a predicate, if it has an embedded C block, write the block + out as a static inline subroutine, and augment the RTL test with a + match_test that calls that subroutine. For instance, + + (define_predicate "basereg_operand" + (match_operand 0 "register_operand") + { + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + return REG_POINTER (op); + }) + + becomes + + static inline int basereg_operand_1(rtx op, enum machine_mode mode) + { + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + return REG_POINTER (op); + } + + (define_predicate "basereg_operand" + (and (match_operand 0 "register_operand") + (match_test "basereg_operand_1 (op, mode)"))) + + The only wart is that there's no way to insist on a { } string in + an RTL template, so we have to handle "" strings. */ + + +static void +write_predicate_subfunction (struct pred_data *p) +{ + const char *match_test_str; + rtx match_test_exp, and_exp; + + if (p->c_block[0] == '\0') + return; + + /* Construct the function-call expression. */ + obstack_grow (rtl_obstack, p->name, strlen (p->name)); + obstack_grow (rtl_obstack, "_1 (op, mode)", + sizeof "_1 (op, mode)"); + match_test_str = obstack_finish (rtl_obstack); + + /* Add the function-call expression to the complete expression to be + evaluated. */ + match_test_exp = rtx_alloc (MATCH_TEST); + XSTR (match_test_exp, 0) = match_test_str; + + and_exp = rtx_alloc (AND); + XEXP (and_exp, 0) = p->exp; + XEXP (and_exp, 1) = match_test_exp; + + p->exp = and_exp; + + printf ("static inline int\n" + "%s_1 (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n", + p->name); + if (p->c_block[0] == '{') + fputs (p->c_block, stdout); + else + printf ("{\n %s\n}", p->c_block); + fputs ("\n\n", stdout); +} + +/* Given an RTL expression EXP, find all subexpressions which we may + assume to perform mode tests. Normal MATCH_OPERAND does; + MATCH_CODE does if and only if it accepts CONST_INT or + CONST_DOUBLE; and we have to assume that MATCH_TEST does not. + These combine in almost-boolean fashion - the only exception is + that (not X) must be assumed not to perform a mode test, whether or + not X does. + + The mark is the RTL /v flag, which is true for subexpressions which + do *not* perform mode tests. +*/ +#define NO_MODE_TEST(EXP) RTX_FLAG (EXP, volatil) +static void +mark_mode_tests (rtx exp) +{ + switch (GET_CODE (exp)) + { + case MATCH_OPERAND: + { + struct pred_data *p = lookup_predicate (XSTR (exp, 1)); + if (!p) + error ("reference to undefined predicate '%s'", XSTR (exp, 1)); + else if (p->special) + NO_MODE_TEST (exp) = 1; + } + break; + + case MATCH_CODE: + if (!strstr (XSTR (exp, 0), "const_int") + && !strstr (XSTR (exp, 0), "const_double")) + NO_MODE_TEST (exp) = 1; + break; + + case MATCH_TEST: + case NOT: + NO_MODE_TEST (exp) = 1; + break; + + case AND: + mark_mode_tests (XEXP (exp, 0)); + mark_mode_tests (XEXP (exp, 1)); + + NO_MODE_TEST (exp) = (NO_MODE_TEST (XEXP (exp, 0)) + && NO_MODE_TEST (XEXP (exp, 1))); + break; + + case IOR: + mark_mode_tests (XEXP (exp, 0)); + mark_mode_tests (XEXP (exp, 1)); + + NO_MODE_TEST (exp) = (NO_MODE_TEST (XEXP (exp, 0)) + || NO_MODE_TEST (XEXP (exp, 1))); + break; + + case IF_THEN_ELSE: + /* A ? B : C does a mode test if (one of A and B) does a mode + test, and C does too. */ + mark_mode_tests (XEXP (exp, 0)); + mark_mode_tests (XEXP (exp, 1)); + mark_mode_tests (XEXP (exp, 2)); + + NO_MODE_TEST (exp) = ((NO_MODE_TEST (XEXP (exp, 0)) + && NO_MODE_TEST (XEXP (exp, 1))) + || NO_MODE_TEST (XEXP (exp, 2))); + break; + + default: + error ("'%s' cannot be used in a define_predicate expression", + GET_RTX_NAME (GET_CODE (exp))); + } +} + +/* Given a predicate, work out where in its RTL expression to add + tests for proper modes. Special predicates do not get any such + tests. We try to avoid adding tests when we don't have to; in + particular, other normal predicates can be counted on to do it for + us. */ + +static void +add_mode_tests (struct pred_data *p) +{ + rtx match_test_exp, and_exp; + rtx *pos; + + /* Don't touch special predicates. */ + if (p->special) + return; + + mark_mode_tests (p->exp); + + /* If the whole expression already tests the mode, we're done. */ + if (!NO_MODE_TEST (p->exp)) + return; + + match_test_exp = rtx_alloc (MATCH_TEST); + XSTR (match_test_exp, 0) = "mode == VOIDmode || GET_MODE (op) == mode"; + and_exp = rtx_alloc (AND); + XEXP (and_exp, 1) = match_test_exp; + + /* It is always correct to rewrite p->exp as + + (and (...) (match_test "mode == VOIDmode || GET_MODE (op) == mode")) + + but there are a couple forms where we can do better. If the + top-level pattern is an IOR, and one of the two branches does test + the mode, we can wrap just the branch that doesn't. Likewise, if + we have an IF_THEN_ELSE, and one side of it tests the mode, we can + wrap just the side that doesn't. And, of course, we can repeat this + descent as many times as it works. */ + + pos = &p->exp; + for (;;) + { + rtx subexp = *pos; + if (GET_CODE (subexp) == IOR) + { + if (NO_MODE_TEST (XEXP (subexp, 0)) + && NO_MODE_TEST (XEXP (subexp, 1))) + break; + else if (NO_MODE_TEST (XEXP (subexp, 0))) + pos = &XEXP (subexp, 0); + else if (NO_MODE_TEST (XEXP (subexp, 1))) + pos = &XEXP (subexp, 1); + else + abort (); + } + else if (GET_CODE (subexp) == IF_THEN_ELSE) + { + if (NO_MODE_TEST (XEXP (subexp, 0)) + && NO_MODE_TEST (XEXP (subexp, 1)) + && NO_MODE_TEST (XEXP (subexp, 2))) + break; + else if (NO_MODE_TEST (XEXP (subexp, 0)) + && NO_MODE_TEST (XEXP (subexp, 1))) + /* Must put it on the dependent clause, not the controlling + expression, or we change the meaning of the test. */ + pos = &XEXP (subexp, 1); + else if (NO_MODE_TEST (XEXP (subexp, 2))) + pos = &XEXP (subexp, 2); + else + abort (); + } + else + break; + } + + XEXP (and_exp, 0) = *pos; + *pos = and_exp; +} + + +/* CODES is a list of RTX codes. Write out an expression which + determines whether the operand has one of those codes. */ +static void +write_match_code (const char *codes) +{ + const char *code; + + while ((code = scan_comma_elt (&codes)) != 0) + { + fputs ("GET_CODE (op) == ", stdout); + while (code < codes) + { + putchar (TOUPPER (*code)); + code++; + } + + if (*codes == ',') + fputs (" || ", stdout); + } +} + +/* EXP is an RTL (sub)expression for a predicate. Recursively + descend the expression and write out an equivalent C expression. */ +static void +write_predicate_expr (const char *name, rtx exp) +{ + switch (GET_CODE (exp)) + { + case AND: + putchar ('('); + write_predicate_expr (name, XEXP (exp, 0)); + fputs (") && (", stdout); + write_predicate_expr (name, XEXP (exp, 1)); + putchar (')'); + break; + + case IOR: + putchar ('('); + write_predicate_expr (name, XEXP (exp, 0)); + fputs (") || (", stdout); + write_predicate_expr (name, XEXP (exp, 1)); + putchar (')'); + break; + + case NOT: + fputs ("!(", stdout); + write_predicate_expr (name, XEXP (exp, 0)); + putchar (')'); + break; + + case IF_THEN_ELSE: + putchar ('('); + write_predicate_expr (name, XEXP (exp, 0)); + fputs (") ? (", stdout); + write_predicate_expr (name, XEXP (exp, 1)); + fputs (") : (", stdout); + write_predicate_expr (name, XEXP (exp, 2)); + putchar (')'); + break; + + case MATCH_OPERAND: + printf ("%s (op, mode)", XSTR (exp, 1)); + break; + + case MATCH_CODE: + write_match_code (XSTR (exp, 0)); + break; + + case MATCH_TEST: + fputs (XSTR (exp, 0), stdout); + break; + + default: + error ("%s: cannot use '%s' in a predicate expression", + name, GET_RTX_NAME (GET_CODE (exp))); + putchar ('0'); + } +} + +/* Given a predicate, write out a complete C function to compute it. */ +static void +write_one_predicate_function (struct pred_data *p) +{ + if (!p->exp) + return; + + write_predicate_subfunction (p); + add_mode_tests (p); + + /* A normal predicate can legitimately not look at enum machine_mode + if it accepts only CONST_INTs and/or CONST_DOUBLEs. */ + printf ("int\n%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n" + "{\n return ", + p->name); + write_predicate_expr (p->name, p->exp); + fputs (";\n}\n\n", stdout); } +/* Write insn-preds.c. + N.B. the list of headers to include was copied from genrecog; it + may not be ideal. + + FUTURE: Write #line markers referring back to the machine + description. (Can't practically do this now since we don't know + the line number of the C block - just the line number of the enclosing + expression.) */ +static void +write_insn_preds_c (void) +{ + struct pred_data *p; + + printf ("\ +/* Generated automatically by the program '%s'\n\ + from the machine description file '%s'. */\n\n", progname, in_fname); + + puts ("\ +#include \"config.h\"\n\ +#include \"system.h\"\n\ +#include \"coretypes.h\"\n\ +#include \"tm.h\"\n\ +#include \"rtl.h\"\n\ +#include \"tm_p.h\"\n\ +#include \"function.h\"\n\ +#include \"insn-config.h\"\n\ +#include \"recog.h\"\n\ +#include \"real.h\"\n\ +#include \"output.h\"\n\ +#include \"flags.h\"\n\ +#include \"hard-reg-set.h\"\n\ +#include \"resource.h\"\n\ +#include \"toplev.h\"\n\ +#include \"reload.h\"\n"); + + FOR_ALL_PREDICATES (p) + write_one_predicate_function (p); +} + +/* Argument parsing. */ +static bool gen_header; +static bool +parse_option (const char *opt) +{ + if (!strcmp (opt, "-h")) + { + gen_header = true; + return 1; + } + else + return 0; +} + +/* Master control. */ int -main (void) +main (int argc, char **argv) { - puts ("/* Generated automatically by the program `genpreds'. */\n"); - puts ("#ifndef GCC_TM_PREDS_H"); - puts ("#define GCC_TM_PREDS_H\n"); + rtx defn; + int pattern_lineno, next_insn_code = 0; - output_predicate_decls (); + progname = argv[0]; + if (argc <= 1) + fatal ("no input file name"); + if (init_md_reader_args_cb (argc, argv, parse_option) != SUCCESS_EXIT_CODE) + return FATAL_EXIT_CODE; + + while ((defn = read_md_rtx (&pattern_lineno, &next_insn_code)) != 0) + { + if (GET_CODE (defn) == DEFINE_PREDICATE + || GET_CODE (defn) == DEFINE_SPECIAL_PREDICATE) + process_define_predicate (defn); + } - puts ("#endif /* GCC_TM_PREDS_H */"); + if (gen_header) + write_tm_preds_h (); + else + write_insn_preds_c (); - if (ferror (stdout) || fflush (stdout) || fclose (stdout)) + if (have_error || ferror (stdout) || fflush (stdout) || fclose (stdout)) return FATAL_EXIT_CODE; return SUCCESS_EXIT_CODE; } + +/* Dummy for debugging purposes. */ +const char * +get_insn_name (int code ATTRIBUTE_UNUSED) +{ + return 0; +} diff --git a/gcc/genrecog.c b/gcc/genrecog.c index f1bce6c78a5..f3c052c4fbe 100644 --- a/gcc/genrecog.c +++ b/gcc/genrecog.c @@ -58,7 +58,6 @@ #include "errors.h" #include "gensupport.h" - #define OUTPUT_LABEL(INDENT_STRING, LABEL_NUMBER) \ printf("%sL%d: ATTRIBUTE_UNUSED_LABEL\n", (INDENT_STRING), (LABEL_NUMBER)) @@ -103,7 +102,8 @@ struct decision_test struct { const char *name; /* Predicate to call. */ - int index; /* Index into `preds' or -1. */ + const struct pred_data *data; + /* Optimization hints for this predicate. */ enum machine_mode mode; /* Machine mode for node. */ } pred; @@ -162,11 +162,6 @@ static int next_number; static int next_insn_code; -/* Similar, but counts all expressions in the MD file; used for - error messages. */ - -static int next_index; - /* Record the highest depth we ever have so we know how many variables to allocate in each subroutine we make. */ @@ -178,55 +173,213 @@ static int pattern_lineno; /* Count of errors. */ static int error_count; -/* This table contains a list of the rtl codes that can possibly match a - predicate defined in recog.c. The function `maybe_both_true' uses it to - deduce that there are no expressions that can be matches by certain pairs - of tree nodes. Also, if a predicate can match only one code, we can - hardwire that code into the node testing the predicate. */ +/* Predicate handling. + + We construct from the machine description a table mapping each + predicate to a list of the rtl codes it can possibly match. The + function 'maybe_both_true' uses it to deduce that there are no + expressions that can be matches by certain pairs of tree nodes. + Also, if a predicate can match only one code, we can hardwire that + code into the node testing the predicate. + + Some predicates are flagged as special. validate_pattern will not + warn about modeless match_operand expressions if they have a + special predicate. Predicates that allow only constants are also + treated as special, for this purpose. + + validate_pattern will warn about predicates that allow non-lvalues + when they appear in destination operands. + + Calculating the set of rtx codes that can possibly be accepted by a + predicate expression EXP requires a three-state logic: any given + subexpression may definitively accept a code C (Y), definitively + reject a code C (N), or may have an indeterminate effect (I). N + and I is N; Y or I is Y; Y and I, N or I are both I. Here are full + truth tables. + + a b a&b a|b + Y Y Y Y + N Y N Y + N N N N + I Y I Y + I N N I + I I I I + + We represent Y with 1, N with 0, I with 2. If any code is left in + an I state by the complete expression, we must assume that that + code can be accepted. */ + +#define N 0 +#define Y 1 +#define I 2 + +#define TRISTATE_AND(a,b) \ + ((a) == I ? ((b) == N ? N : I) : \ + (b) == I ? ((a) == N ? N : I) : \ + (a) && (b)) + +#define TRISTATE_OR(a,b) \ + ((a) == I ? ((b) == Y ? Y : I) : \ + (b) == I ? ((a) == Y ? Y : I) : \ + (a) || (b)) + +#define TRISTATE_NOT(a) \ + ((a) == I ? I : !(a)) + +/* Recursively calculate the set of rtx codes accepted by the + predicate expression EXP, writing the result to CODES. */ +static void +compute_predicate_codes (rtx exp, char codes[NUM_RTX_CODE]) +{ + char op0_codes[NUM_RTX_CODE]; + char op1_codes[NUM_RTX_CODE]; + char op2_codes[NUM_RTX_CODE]; + int i; + + switch (GET_CODE (exp)) + { + case AND: + compute_predicate_codes (XEXP (exp, 0), op0_codes); + compute_predicate_codes (XEXP (exp, 1), op1_codes); + for (i = 0; i < NUM_RTX_CODE; i++) + codes[i] = TRISTATE_AND (op0_codes[i], op1_codes[i]); + break; + + case IOR: + compute_predicate_codes (XEXP (exp, 0), op0_codes); + compute_predicate_codes (XEXP (exp, 1), op1_codes); + for (i = 0; i < NUM_RTX_CODE; i++) + codes[i] = TRISTATE_OR (op0_codes[i], op1_codes[i]); + break; + case NOT: + compute_predicate_codes (XEXP (exp, 0), op0_codes); + for (i = 0; i < NUM_RTX_CODE; i++) + codes[i] = TRISTATE_NOT (codes[i]); + break; + + case IF_THEN_ELSE: + /* a ? b : c accepts the same codes as (a & b) | (!a & c). */ + compute_predicate_codes (XEXP (exp, 0), op0_codes); + compute_predicate_codes (XEXP (exp, 1), op1_codes); + compute_predicate_codes (XEXP (exp, 2), op2_codes); + for (i = 0; i < NUM_RTX_CODE; i++) + codes[i] = TRISTATE_OR (TRISTATE_AND (op0_codes[i], op1_codes[i]), + TRISTATE_AND (TRISTATE_NOT (op0_codes[i]), + op2_codes[i])); + break; + + case MATCH_CODE: + /* MATCH_CODE allows a specified list of codes. */ + memset (codes, N, NUM_RTX_CODE); + { + const char *next_code = XSTR (exp, 0); + const char *code; -static const struct pred_table + if (*next_code == '\0') + { + message_with_line (pattern_lineno, "empty match_code expression"); + error_count++; + break; + } + + while ((code = scan_comma_elt (&next_code)) != 0) + { + size_t n = next_code - code; + + for (i = 0; i < NUM_RTX_CODE; i++) + if (!strncmp (code, GET_RTX_NAME (i), n) + && GET_RTX_NAME (i)[n] == '\0') + { + codes[i] = Y; + break; + } + } + } + break; + + case MATCH_OPERAND: + /* MATCH_OPERAND disallows the set of codes that the named predicate + disallows, and is indeterminate for the codes that it does allow. */ + { + struct pred_data *p = lookup_predicate (XSTR (exp, 1)); + if (!p) + { + message_with_line (pattern_lineno, + "reference to unknown predicate '%s'", + XSTR (exp, 1)); + error_count++; + break; + } + for (i = 0; i < NUM_RTX_CODE; i++) + codes[i] = p->codes[i] ? I : N; + } + break; + + + case MATCH_TEST: + /* (match_test WHATEVER) is completely indeterminate. */ + memset (codes, I, NUM_RTX_CODE); + break; + + default: + message_with_line (pattern_lineno, + "'%s' cannot be used in a define_predicate expression", + GET_RTX_NAME (GET_CODE (exp))); + error_count++; + memset (codes, I, NUM_RTX_CODE); + break; + } +} + +#undef TRISTATE_OR +#undef TRISTATE_AND +#undef TRISTATE_NOT + +/* Process a define_predicate expression: compute the set of predicates + that can be matched, and record this as a known predicate. */ +static void +process_define_predicate (rtx desc) { - const char *const name; - const RTX_CODE codes[NUM_RTX_CODE]; -} preds[] = { - {"general_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF, SUBREG, REG, MEM }}, -#ifdef PREDICATE_CODES - PREDICATE_CODES -#endif - {"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF, SUBREG, REG, MEM, - PLUS, MINUS, MULT}}, - {"register_operand", {SUBREG, REG}}, - {"pmode_register_operand", {SUBREG, REG}}, - {"scratch_operand", {SCRATCH, REG}}, - {"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF}}, - {"const_int_operand", {CONST_INT}}, - {"const_double_operand", {CONST_INT, CONST_DOUBLE}}, - {"nonimmediate_operand", {SUBREG, REG, MEM}}, - {"nonmemory_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, - LABEL_REF, SUBREG, REG}}, - {"push_operand", {MEM}}, - {"pop_operand", {MEM}}, - {"memory_operand", {SUBREG, MEM}}, - {"indirect_operand", {SUBREG, MEM}}, - {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU, - UNORDERED, ORDERED, UNEQ, UNGE, UNGT, UNLE, - UNLT, LTGT}} -}; + struct pred_data *pred = xcalloc (sizeof (struct pred_data), 1); + char codes[NUM_RTX_CODE]; + bool seen_one = false; + int i; -#define NUM_KNOWN_PREDS ARRAY_SIZE (preds) + pred->name = XSTR (desc, 0); + if (GET_CODE (desc) == DEFINE_SPECIAL_PREDICATE) + pred->special = 1; -static const char *const special_mode_pred_table[] = { -#ifdef SPECIAL_MODE_PREDICATES - SPECIAL_MODE_PREDICATES -#endif - "pmode_register_operand" -}; + compute_predicate_codes (XEXP (desc, 1), codes); -#define NUM_SPECIAL_MODE_PREDS ARRAY_SIZE (special_mode_pred_table) + for (i = 0; i < NUM_RTX_CODE; i++) + if (codes[i] != N) + { + pred->codes[i] = true; + if (GET_RTX_CLASS (i) != RTX_CONST_OBJ) + pred->allows_non_const = true; + if (i != REG + && i != SUBREG + && i != MEM + && i != CONCAT + && i != PARALLEL + && i != STRICT_LOW_PART) + pred->allows_non_lvalue = true; + + if (seen_one) + pred->singleton = UNKNOWN; + else + { + pred->singleton = i; + seen_one = true; + } + } + add_predicate (pred); +} +#undef I +#undef N +#undef Y + static struct decision *new_decision (const char *, struct decision_head *); static struct decision_test *new_decision_test @@ -485,8 +638,7 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code) case MATCH_OPERATOR: { const char *pred_name = XSTR (pattern, 1); - int allows_non_lvalue = 1, allows_non_const = 1; - int special_mode_pred = 0; + const struct pred_data *pred; const char *c_test; if (GET_CODE (insn) == DEFINE_INSN) @@ -496,53 +648,14 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code) if (pred_name[0] != 0) { - for (i = 0; i < NUM_KNOWN_PREDS; i++) - if (! strcmp (preds[i].name, pred_name)) - break; - - if (i < NUM_KNOWN_PREDS) - { - int j; - - allows_non_lvalue = allows_non_const = 0; - for (j = 0; preds[i].codes[j] != 0; j++) - { - RTX_CODE c = preds[i].codes[j]; - if (c != LABEL_REF - && c != SYMBOL_REF - && c != CONST_INT - && c != CONST_DOUBLE - && c != CONST - && c != HIGH) - allows_non_const = 1; - - if (c != REG - && c != SUBREG - && c != MEM - && c != CONCAT - && c != PARALLEL - && c != STRICT_LOW_PART) - allows_non_lvalue = 1; - } - } - else - { -#ifdef PREDICATE_CODES - /* If the port has a list of the predicates it uses but - omits one, warn. */ - message_with_line (pattern_lineno, - "warning: `%s' not in PREDICATE_CODES", - pred_name); -#endif - } - - for (i = 0; i < NUM_SPECIAL_MODE_PREDS; ++i) - if (strcmp (pred_name, special_mode_pred_table[i]) == 0) - { - special_mode_pred = 1; - break; - } + pred = lookup_predicate (pred_name); + if (!pred) + message_with_line (pattern_lineno, + "warning: unknown predicate '%s'", + pred_name); } + else + pred = 0; if (code == MATCH_OPERAND) { @@ -595,39 +708,33 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code) /* Allowing non-lvalues in destinations -- particularly CONST_INT -- while not likely to occur at runtime, results in less efficient code from insn-recog.c. */ - if (set - && pred_name[0] != '\0' - && allows_non_lvalue) - { - message_with_line (pattern_lineno, - "warning: destination operand %d allows non-lvalue", - XINT (pattern, 0)); - } + if (set && pred && pred->allows_non_lvalue) + message_with_line (pattern_lineno, + "warning: destination operand %d " + "allows non-lvalue", + XINT (pattern, 0)); - /* A modeless MATCH_OPERAND can be handy when we can - check for multiple modes in the c_test. In most other cases, - it is a mistake. Only DEFINE_INSN is eligible, since SPLIT - and PEEP2 can FAIL within the output pattern. Exclude - address_operand, since its mode is related to the mode of - the memory not the operand. Exclude the SET_DEST of a call - instruction, as that is a common idiom. */ + /* A modeless MATCH_OPERAND can be handy when we can check for + multiple modes in the c_test. In most other cases, it is a + mistake. Only DEFINE_INSN is eligible, since SPLIT and + PEEP2 can FAIL within the output pattern. Exclude special + predicates, which check the mode themselves. Also exclude + predicates that allow only constants. Exclude the SET_DEST + of a call instruction, as that is a common idiom. */ if (GET_MODE (pattern) == VOIDmode && code == MATCH_OPERAND && GET_CODE (insn) == DEFINE_INSN - && allows_non_const - && ! special_mode_pred - && pred_name[0] != '\0' - && strcmp (pred_name, "address_operand") != 0 + && pred + && !pred->special + && pred->allows_non_const && strstr (c_test, "operands") == NULL && ! (set && GET_CODE (set) == SET && GET_CODE (SET_SRC (set)) == CALL)) - { - message_with_line (pattern_lineno, - "warning: operand %d missing mode?", - XINT (pattern, 0)); - } + message_with_line (pattern_lineno, + "warning: operand %d missing mode?", + XINT (pattern, 0)); return; } @@ -829,9 +936,9 @@ add_to_sequence (rtx pattern, struct decision_head *last, const char *position, case MATCH_SCRATCH: case MATCH_OPERATOR: { - const char *pred_name; RTX_CODE was_code = code; - int allows_const_int = 1; + const char *pred_name; + bool allows_const_int = true; if (code == MATCH_SCRATCH) { @@ -849,44 +956,26 @@ add_to_sequence (rtx pattern, struct decision_head *last, const char *position, if (pred_name[0] != 0) { + const struct pred_data *pred; + test = new_decision_test (DT_pred, &place); test->u.pred.name = pred_name; test->u.pred.mode = mode; - /* See if we know about this predicate and save its number. - If we do, and it only accepts one code, note that fact. - - If we know that the predicate does not allow CONST_INT, - we know that the only way the predicate can match is if - the modes match (here we use the kludge of relying on the - fact that "address_operand" accepts CONST_INT; otherwise, - it would have to be a special case), so we can test the - mode (but we need not). This fact should considerably - simplify the generated code. */ - - for (i = 0; i < NUM_KNOWN_PREDS; i++) - if (! strcmp (preds[i].name, pred_name)) - break; + /* See if we know about this predicate. + If we do, remember it for use below. - if (i < NUM_KNOWN_PREDS) + We can optimize the generated code a little if either + (a) the predicate only accepts one code, or (b) the + predicate does not allow CONST_INT, in which case it + can match only if the modes match. */ + pred = lookup_predicate (pred_name); + if (pred) { - int j; - - test->u.pred.index = i; - - if (preds[i].codes[1] == 0 && code == UNKNOWN) - code = preds[i].codes[0]; - - allows_const_int = 0; - for (j = 0; preds[i].codes[j] != 0; j++) - if (preds[i].codes[j] == CONST_INT) - { - allows_const_int = 1; - break; - } + test->u.pred.data = pred; + allows_const_int = pred->codes[CONST_INT]; + code = pred->singleton; } - else - test->u.pred.index = -1; } /* Can't enforce a mode if we allow const_int. */ @@ -1109,39 +1198,28 @@ maybe_both_true_2 (struct decision_test *d1, struct decision_test *d2) separate DT_mode that will make maybe_both_true_1 return 0. */ } - if (d1->u.pred.index >= 0) + if (d1->u.pred.data) { /* If D2 tests a code, see if it is in the list of valid codes for D1's predicate. */ if (d2->type == DT_code) { - const RTX_CODE *c = &preds[d1->u.pred.index].codes[0]; - while (*c != 0) - { - if (*c == d2->u.code) - break; - ++c; - } - if (*c == 0) + if (!d1->u.pred.data->codes[d2->u.code]) return 0; } /* Otherwise see if the predicates have any codes in common. */ - else if (d2->type == DT_pred && d2->u.pred.index >= 0) + else if (d2->type == DT_pred && d2->u.pred.data) { - const RTX_CODE *c1 = &preds[d1->u.pred.index].codes[0]; - int common = 0; + bool common = false; + enum rtx_code c; - while (*c1 != 0 && !common) - { - const RTX_CODE *c2 = &preds[d2->u.pred.index].codes[0]; - while (*c2 != 0 && !common) - { - common = (*c1 == *c2); - ++c2; - } - ++c1; - } + for (c = 0; c < NUM_RTX_CODE; c++) + if (d1->u.pred.data->codes[c] && d2->u.pred.data->codes[c]) + { + common = true; + break; + } if (!common) return 0; @@ -1823,22 +1901,22 @@ write_switch (struct decision *start, int depth) else ret = p; - while (p && p->tests->type == DT_pred - && p->tests->u.pred.index >= 0) + while (p && p->tests->type == DT_pred && p->tests->u.pred.data) { - const RTX_CODE *c; - - for (c = &preds[p->tests->u.pred.index].codes[0]; *c ; ++c) - if (codemap[(int) *c] != 0) + const struct pred_data *data = p->tests->u.pred.data; + RTX_CODE c; + for (c = 0; c < NUM_RTX_CODE; c++) + if (codemap[c] && data->codes[c]) goto pred_done; - for (c = &preds[p->tests->u.pred.index].codes[0]; *c ; ++c) - { - printf (" case "); - print_code (*c); - printf (":\n"); - codemap[(int) *c] = 1; - } + for (c = 0; c < NUM_RTX_CODE; c++) + if (data->codes[c]) + { + fputs (" case ", stdout); + print_code (c); + fputs (":\n", stdout); + codemap[c] = 1; + } printf (" goto L%d;\n", p->number); p->need_label = 1; @@ -2640,7 +2718,6 @@ main (int argc, char **argv) return (FATAL_EXIT_CODE); next_insn_code = 0; - next_index = 0; write_header (); @@ -2652,26 +2729,33 @@ main (int argc, char **argv) if (desc == NULL) break; - if (GET_CODE (desc) == DEFINE_INSN) + switch (GET_CODE (desc)) { + case DEFINE_PREDICATE: + case DEFINE_SPECIAL_PREDICATE: + process_define_predicate (desc); + break; + + case DEFINE_INSN: h = make_insn_sequence (desc, RECOG); merge_trees (&recog_tree, &h); - } - else if (GET_CODE (desc) == DEFINE_SPLIT) - { + break; + + case DEFINE_SPLIT: h = make_insn_sequence (desc, SPLIT); merge_trees (&split_tree, &h); - } - else if (GET_CODE (desc) == DEFINE_PEEPHOLE2) - { + break; + + case DEFINE_PEEPHOLE2: h = make_insn_sequence (desc, PEEPHOLE2); merge_trees (&peephole2_tree, &h); - } - next_index++; + default: + /* do nothing */; + } } - if (error_count) + if (error_count || have_error) return FATAL_EXIT_CODE; puts ("\n\n"); diff --git a/gcc/gensupport.c b/gcc/gensupport.c index 2acfc8a3efd..618e1a271a5 100644 --- a/gcc/gensupport.c +++ b/gcc/gensupport.c @@ -35,6 +35,8 @@ int target_flags; int insn_elision = 1; +const char *in_fname; + static struct obstack obstack; struct obstack *rtl_obstack = &obstack; @@ -65,6 +67,8 @@ struct queue_elem static struct queue_elem *define_attr_queue; static struct queue_elem **define_attr_tail = &define_attr_queue; +static struct queue_elem *define_pred_queue; +static struct queue_elem **define_pred_tail = &define_pred_queue; static struct queue_elem *define_insn_queue; static struct queue_elem **define_insn_tail = &define_insn_queue; static struct queue_elem *define_cond_exec_queue; @@ -109,6 +113,7 @@ static void process_one_cond_exec (struct queue_elem *); static void process_define_cond_exec (void); static void process_include (rtx, int); static char *save_string (const char *, int); +static void init_predicate_table (void); void message_with_line (int lineno, const char *msg, ...) @@ -284,6 +289,11 @@ process_rtx (rtx desc, int lineno) queue_pattern (desc, &define_attr_tail, read_rtx_filename, lineno); break; + case DEFINE_PREDICATE: + case DEFINE_SPECIAL_PREDICATE: + queue_pattern (desc, &define_pred_tail, read_rtx_filename, lineno); + break; + case INCLUDE: process_include (desc, lineno); break; @@ -904,10 +914,7 @@ init_md_reader_args_cb (int argc, char **argv, bool (*parse_opt)(const char *)) int i; size_t ix; char *lastsl; - const char *in_fname; - max_include_len = 0; - in_fname = NULL; for (i = 1; i < argc; i++) { if (argv[i][0] != '-') @@ -977,6 +984,8 @@ init_md_reader_args_cb (int argc, char **argv, bool (*parse_opt)(const char *)) *(htab_find_slot (condition_table, &insn_conditions[ix], INSERT)) = (void *) &insn_conditions[ix]; + init_predicate_table (); + obstack_init (rtl_obstack); errors = 0; sequence_num = 0; @@ -1025,6 +1034,8 @@ read_md_rtx (int *lineno, int *seqnr) /* Read all patterns from a given queue before moving on to the next. */ if (define_attr_queue != NULL) queue = &define_attr_queue; + else if (define_pred_queue != NULL) + queue = &define_pred_queue; else if (define_insn_queue != NULL) queue = &define_insn_queue; else if (other_queue != NULL) @@ -1181,3 +1192,154 @@ scan_comma_elt (const char **pstr) *pstr = p; return start; } + +/* Helper functions for define_predicate and define_special_predicate + processing. Shared between genrecog.c and genpreds.c. */ + +static htab_t predicate_table; +struct pred_data *first_predicate; +static struct pred_data **last_predicate = &first_predicate; + +static hashval_t +hash_struct_pred_data (const void *ptr) +{ + return htab_hash_string (((const struct pred_data *)ptr)->name); +} + +static int +eq_struct_pred_data (const void *a, const void *b) +{ + return !strcmp (((const struct pred_data *)a)->name, + ((const struct pred_data *)b)->name); +} + +struct pred_data * +lookup_predicate (const char *name) +{ + struct pred_data key; + key.name = name; + return htab_find (predicate_table, &key); +} + +void +add_predicate (struct pred_data *pred) +{ + void **slot = htab_find_slot (predicate_table, pred, INSERT); + if (*slot) + { + error ("duplicate predicate definition for '%s'", pred->name); + return; + } + *slot = pred; + *last_predicate = pred; + last_predicate = &pred->next; +} + +/* This array gives the initial content of the predicate table. It + has entries for all predicates defined in recog.c. The back end + can define PREDICATE_CODES to give additional entries for the + table; this is considered an obsolete mechanism (use + define_predicate instead). */ + +struct old_pred_table +{ + const char *name; + RTX_CODE codes[NUM_RTX_CODE]; +}; + +static const struct old_pred_table old_preds[] = { + {"general_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, + LABEL_REF, SUBREG, REG, MEM }}, + {"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, + LABEL_REF, SUBREG, REG, MEM, + PLUS, MINUS, MULT}}, + {"register_operand", {SUBREG, REG}}, + {"pmode_register_operand", {SUBREG, REG}}, + {"scratch_operand", {SCRATCH, REG}}, + {"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, + LABEL_REF}}, + {"const_int_operand", {CONST_INT}}, + {"const_double_operand", {CONST_INT, CONST_DOUBLE}}, + {"nonimmediate_operand", {SUBREG, REG, MEM}}, + {"nonmemory_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, + LABEL_REF, SUBREG, REG}}, + {"push_operand", {MEM}}, + {"pop_operand", {MEM}}, + {"memory_operand", {SUBREG, MEM}}, + {"indirect_operand", {SUBREG, MEM}}, + {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU, + UNORDERED, ORDERED, UNEQ, UNGE, UNGT, UNLE, + UNLT, LTGT}}, +#ifdef PREDICATE_CODES + PREDICATE_CODES +#endif +}; +#define NUM_KNOWN_OLD_PREDS ARRAY_SIZE (old_preds) + +/* This table gives the initial set of special predicates. It has + entries for all special predicates defined in recog.c. The back + end can define SPECIAL_MODE_PREDICATES to give additional entries + for the table; this is considered an obsolete mechanism (use + define_special_predicate instead). */ +static const char *const old_special_pred_table[] = { + "address_operand", + "pmode_register_operand", +#ifdef SPECIAL_MODE_PREDICATES + SPECIAL_MODE_PREDICATES +#endif +}; + +#define NUM_OLD_SPECIAL_MODE_PREDS ARRAY_SIZE (old_special_pred_table) + +/* Initialize the table of predicate definitions, starting with + the information we have on generic predicates, and the old-style + PREDICATE_CODES definitions. */ + +static void +init_predicate_table (void) +{ + size_t i, j; + struct pred_data *pred; + + predicate_table = htab_create_alloc (37, hash_struct_pred_data, + eq_struct_pred_data, 0, + xcalloc, free); + + for (i = 0; i < NUM_KNOWN_OLD_PREDS; i++) + { + pred = xcalloc (sizeof (struct pred_data), 1); + pred->name = old_preds[i].name; + + for (j = 0; old_preds[i].codes[j] != 0; j++) + { + enum rtx_code code = old_preds[i].codes[j]; + + pred->codes[code] = true; + if (GET_RTX_CLASS (code) != RTX_CONST_OBJ) + pred->allows_non_const = true; + if (code != REG + && code != SUBREG + && code != MEM + && code != CONCAT + && code != PARALLEL + && code != STRICT_LOW_PART) + pred->allows_non_lvalue = true; + } + if (j == 1) + pred->singleton = old_preds[i].codes[0]; + + add_predicate (pred); + } + + for (i = 0; i < NUM_OLD_SPECIAL_MODE_PREDS; i++) + { + pred = lookup_predicate (old_special_pred_table[i]); + if (!pred) + { + error ("old-style special predicate list refers " + "to unknown predicate '%s'", old_special_pred_table[i]); + continue; + } + pred->special = true; + } +} diff --git a/gcc/gensupport.h b/gcc/gensupport.h index ea78b247d5d..90f866a2f56 100644 --- a/gcc/gensupport.h +++ b/gcc/gensupport.h @@ -23,6 +23,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA struct obstack; extern struct obstack *rtl_obstack; +extern const char *in_fname; extern int init_md_reader_args_cb (int, char **, bool (*)(const char *)); extern int init_md_reader_args (int, char **); @@ -66,4 +67,29 @@ extern int cmp_c_test (const void *, const void *); extern int n_comma_elts (const char *); extern const char *scan_comma_elt (const char **); +/* Predicate handling: helper functions and data structures. */ + +struct pred_data +{ + struct pred_data *next; /* for iterating over the set of all preds */ + const char *name; /* predicate name */ + bool special; /* special handling of modes? */ + + /* data used primarily by genpreds.c */ + const char *c_block; /* C test block */ + rtx exp; /* RTL test expression */ + + /* data used primarily by genrecog.c */ + enum rtx_code singleton; /* if pred takes only one code, that code */ + bool allows_non_lvalue; /* if pred allows non-lvalue expressions */ + bool allows_non_const; /* if pred allows non-const expressions */ + bool codes[NUM_RTX_CODE]; /* set of codes accepted */ +}; + +extern struct pred_data *first_predicate; +extern struct pred_data *lookup_predicate (const char *); +extern void add_predicate (struct pred_data *); + +#define FOR_ALL_PREDICATES(p) for (p = first_predicate; p; p = p->next) + #endif /* GCC_GENSUPPORT_H */ diff --git a/gcc/recog.h b/gcc/recog.h index 28db9aa07f4..eae37fb4442 100644 --- a/gcc/recog.h +++ b/gcc/recog.h @@ -96,22 +96,6 @@ extern int next_insn_tests_no_inequality (rtx); extern int reg_fits_class_p (rtx, enum reg_class, int, enum machine_mode); extern rtx *find_single_use (rtx, rtx, rtx *); -extern int general_operand (rtx, enum machine_mode); -extern int address_operand (rtx, enum machine_mode); -extern int register_operand (rtx, enum machine_mode); -extern int pmode_register_operand (rtx, enum machine_mode); -extern int scratch_operand (rtx, enum machine_mode); -extern int immediate_operand (rtx, enum machine_mode); -extern int const_int_operand (rtx, enum machine_mode); -extern int const_double_operand (rtx, enum machine_mode); -extern int nonimmediate_operand (rtx, enum machine_mode); -extern int nonmemory_operand (rtx, enum machine_mode); -extern int push_operand (rtx, enum machine_mode); -extern int pop_operand (rtx, enum machine_mode); -extern int memory_operand (rtx, enum machine_mode); -extern int indirect_operand (rtx, enum machine_mode); -extern int comparison_operator (rtx, enum machine_mode); - extern int offsettable_memref_p (rtx); extern int offsettable_nonstrict_memref_p (rtx); extern int offsettable_address_p (int, enum machine_mode, rtx); diff --git a/gcc/rtl.def b/gcc/rtl.def index fd23963597c..300d9d50267 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -182,6 +182,17 @@ DEF_RTL_EXPR(MATCH_OP_DUP, "match_op_dup", "iE", RTX_MATCH) at the index specified by the argument. For MATCH_PARALLEL. */ DEF_RTL_EXPR(MATCH_PAR_DUP, "match_par_dup", "iE", RTX_MATCH) +/* Appears only in define_predicate/define_special predicate + expressions in a machine description. Evaluates true only if the + operand has an RTX code from the set given by the argument (a + comma-separated list). */ +DEF_RTL_EXPR(MATCH_CODE, "match_code", "s", RTX_MATCH) + +/* Appears only in define_predicate/define_special_predicate expressions + in a machine description. The argument is a C expression to be injected + at this point in the predicate formula. */ +DEF_RTL_EXPR(MATCH_TEST, "match_test", "s", RTX_MATCH) + /* Appears only in machine descriptions. Defines the pattern for one kind of instruction. Operand: @@ -297,6 +308,23 @@ DEF_RTL_EXPR(DEFINE_ASM_ATTRIBUTES, "define_asm_attributes", "V", RTX_EXTRA) 2: A template or C code to produce assembler output. */ DEF_RTL_EXPR(DEFINE_COND_EXEC, "define_cond_exec", "Ess", RTX_EXTRA) +/* Definition of an operand predicate. The difference between + DEFINE_PREDICATE and DEFINE_SPECIAL_PREDICATE is that genrecog will + not warn about a match_operand with no mode if it has a predicate + defined with DEFINE_SPECIAL_PREDICATE. + + Operand: + 0: The name of the predicate. + 1: A boolean expression which computes whether or not the predicate + matches. This expression can use IOR, AND, NOT, MATCH_OPERAND, + MATCH_CODE, and MATCH_TEST. It must be specific enough that genrecog + can calculate the set of RTX codes that can possibly match. + 2: A C function body which must return true for the predicate to match. + Optional. Use this when the test is too complicated to fit into a + match_test expression. */ +DEF_RTL_EXPR(DEFINE_PREDICATE, "define_predicate", "ses", RTX_EXTRA) +DEF_RTL_EXPR(DEFINE_SPECIAL_PREDICATE, "define_special_predicate", "ses", RTX_EXTRA) + /* SEQUENCE appears in the result of a `gen_...' function for a DEFINE_EXPAND that wants to make several insns. Its elements are the bodies of the insns that should be made. -- 2.30.2