OSDN Git Service

* genpreds.c: Add capability to generate predicate bodies as
authorzack <zack@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 12 Aug 2004 07:49:00 +0000 (07:49 +0000)
committerzack <zack@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 12 Aug 2004 07:49:00 +0000 (07:49 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@85855 138bc75d-0d04-0410-961f-82ee72b054a4

14 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/config/ia64/ia64.c
gcc/config/ia64/ia64.h
gcc/config/ia64/ia64.md
gcc/doc/md.texi
gcc/doc/tm.texi
gcc/dummy-conditions.c
gcc/genpreds.c
gcc/genrecog.c
gcc/gensupport.c
gcc/gensupport.h
gcc/recog.h
gcc/rtl.def

index b0e986b..7de4f0b 100644 (file)
@@ -1,3 +1,75 @@
+2004-08-12  Zack Weinberg  <zack@codesourcery.com>
+
+       * 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  <rth@redhat.com>
 
        * c-common.h (STATEMENT_LIST_HAS_LABEL): New.
@@ -8,7 +80,7 @@
 2004-08-12  Richard Henderson  <rth@redhat.com>
 
        * 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  <rth@redhat.com>
        (LINK_SPEC): Same.
        * doc/invoke.texi (Darwin Options): Document -dead_strip and
        -no_dead_strip_inits_and_terms.
-       
+
 2004-08-11  Paul Brook  <paul@codesourcery.com>
 
        * config/arm/arm-protos.h (arm_finalize_pic) Rename ...
        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,
        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,
index c51760a..e58a3a2 100644 (file)
@@ -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)
index 66e51ea..ce48d3f 100644 (file)
@@ -418,513 +418,6 @@ static const struct attribute_spec ia64_attribute_table[] =
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
-/* 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));
-}
-\f
 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)
index 96b559b..58304a9 100644 (file)
@@ -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.  */
 
index 04eda40..31af3bb 100644 (file)
 \f
 ;; ::::::::::::::::::::
 ;; ::
+;; :: 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);
+})
+
+\f
+;; ::::::::::::::::::::
+;; ::
 ;; :: Attributes
 ;; ::
 ;; ::::::::::::::::::::
index 0e35053..6b85836 100644 (file)
@@ -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
index 06c08f9..2910730 100644 (file)
@@ -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
index eb3fb41..95db257 100644 (file)
@@ -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.
 
    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 <stddef.h>  /* 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;
index b560120..833d47f 100644 (file)
@@ -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;
+}
index f1bce6c..f3c052c 100644 (file)
@@ -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;
 \f
-/* 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
 
+\f
 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");
index 2acfc8a..618e1a2 100644 (file)
@@ -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);
 \f
 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;
+    }
+}
index ea78b24..90f866a 100644 (file)
@@ -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 */
index 28db9aa..eae37fb 100644 (file)
@@ -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);
index fd23963..300d9d5 100644 (file)
@@ -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.