read-rtl.c (map_value, [...]): New structures.
authorRichard Sandiford <rsandifo@redhat.com>
Mon, 23 Aug 2004 05:55:50 +0000 (05:55 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Mon, 23 Aug 2004 05:55:50 +0000 (05:55 +0000)
* read-rtl.c (map_value, mapping, macro_group): New structures.
(BELLWETHER_CODE): New macro.
(modes, codes, bellwether_codes): New variables.
(find_mode, uses_mode_macro_p, apply_mode_macro, find_code)
(uses_code_macro_p, apply_code_macro, apply_macro_to_string)
(apply_macro_to_rtx, uses_macro_p, add_condition_to_string)
(add_condition_to_rtx, apply_macro_traverse, add_mapping)
(add_map_value, initialize_macros): New functions.
(def_hash, def_hash_eq_p): Generalize to anything that points to,
or starts with, a char * field.
(find_macro, read_mapping, check_code_macro): New functions.
(read_rtx_1): New, split out from read_rtx.  Handle the new
define_{mode,code}_{macro,attr} constructs.  Use find_macro
to parse the name of a code or mode.  Use BELLWETHER_CODE to
extract the format and to choose a suitable code for rtx_alloc.
Modify recursive invocations to use read_rtx_1.
(read_rtx): Call initialize_macros.  Apply code and mode macros
to the rtx returned by read_rtx_1.  Cache everything after the
first macro expansion for subsequent read_rtx calls.
* doc/md.texi: Document new .md constructs.
* config/mips/mips.md (GPR): New mode macro.
(d, si8_di5): New mode attributes.
(any_cond): New code macro.
(add[sd]i3): Redefine using :GPR.
(*add[sd]i3): Likewise, renaming from add[sd]i3_internal.
(*add[sd]i3_sp[12], *add<mode>3_mips16): Redefine using :GPR, naming
previously unnamed MIPS16 patterns.
(*addsi3_extended): Renamed from addsi3_internal_2.  Fix overly long
lines.  Don't match (plus (const_int 0) ...).
(*addsi3_extended_mips16): Name previously unnamed MIPS16 pattern.
Use a define_split to generate the addition.
(sub[sd]i3): Redefine using :GPR.  Turn subsi3 into a define_insn.
(subsi3_internal): Delete.
(*subsi3_extended): Renamed from subsi3_internal_2.
(bunordered, bordered, bunlt, bunge, buneq, bltgt, bunle, bungt)
(beq, bne, bgt, bge, blt, ble, bgtu, bgeu, bltu, bleu): Redefine
using an any_cond template.

From-SVN: r86404

gcc/ChangeLog
gcc/config/mips/mips.md
gcc/doc/md.texi
gcc/read-rtl.c

index c442371f6579272ad25554000affb18de551448c..25da5351e72b7011f4fffc3dee2576959d3d4a42 100644 (file)
@@ -1,3 +1,43 @@
+2004-08-23  Richard Sandiford  <rsandifo@redhat.com>
+
+       * read-rtl.c (map_value, mapping, macro_group): New structures.
+       (BELLWETHER_CODE): New macro.
+       (modes, codes, bellwether_codes): New variables.
+       (find_mode, uses_mode_macro_p, apply_mode_macro, find_code)
+       (uses_code_macro_p, apply_code_macro, apply_macro_to_string)
+       (apply_macro_to_rtx, uses_macro_p, add_condition_to_string)
+       (add_condition_to_rtx, apply_macro_traverse, add_mapping)
+       (add_map_value, initialize_macros): New functions.
+       (def_hash, def_hash_eq_p): Generalize to anything that points to,
+       or starts with, a char * field.
+       (find_macro, read_mapping, check_code_macro): New functions.
+       (read_rtx_1): New, split out from read_rtx.  Handle the new
+       define_{mode,code}_{macro,attr} constructs.  Use find_macro
+       to parse the name of a code or mode.  Use BELLWETHER_CODE to
+       extract the format and to choose a suitable code for rtx_alloc.
+       Modify recursive invocations to use read_rtx_1.
+       (read_rtx): Call initialize_macros.  Apply code and mode macros
+       to the rtx returned by read_rtx_1.  Cache everything after the
+       first macro expansion for subsequent read_rtx calls.
+       * doc/md.texi: Document new .md constructs.
+       * config/mips/mips.md (GPR): New mode macro.
+       (d, si8_di5): New mode attributes.
+       (any_cond): New code macro.
+       (add[sd]i3): Redefine using :GPR.
+       (*add[sd]i3): Likewise, renaming from add[sd]i3_internal.
+       (*add[sd]i3_sp[12], *add<mode>3_mips16): Redefine using :GPR, naming
+       previously unnamed MIPS16 patterns.
+       (*addsi3_extended): Renamed from addsi3_internal_2.  Fix overly long
+       lines.  Don't match (plus (const_int 0) ...).
+       (*addsi3_extended_mips16): Name previously unnamed MIPS16 pattern.
+       Use a define_split to generate the addition.
+       (sub[sd]i3): Redefine using :GPR.  Turn subsi3 into a define_insn.
+       (subsi3_internal): Delete.
+       (*subsi3_extended): Renamed from subsi3_internal_2.
+       (bunordered, bordered, bunlt, bunge, buneq, bltgt, bunle, bungt)
+       (beq, bne, bgt, bge, blt, ble, bgtu, bgeu, bltu, bleu): Redefine
+       using an any_cond template.
+
 2004-08-23  Richard Sandiford  <rsandifo@redhat.com>
 
        * read-rtl.c (read_rtx): Tidy use of format_ptr.
index 603a6b9d18c02388d67220e646c416816cea9b6a..a1226f8d2fc03fee381c3cdaa66b32e980b85ef7 100644 (file)
 (define_asm_attributes
   [(set_attr "type" "multi")])
 \f
+;; This mode macro allows 32-bit and 64-bit GPR patterns to be generated
+;; from the same template.
+(define_mode_macro GPR [SI (DI "TARGET_64BIT")])
+
+;; In GPR templates, a string like "<d>subu" will expand to "subu" in the
+;; 32-bit version and "dsubu" in the 64-bit version.
+(define_mode_attr d [(SI "") (DI "d")])
+
+;; The unextended ranges of the MIPS16 addiu and daddiu instructions
+;; are different.  Some forms of unextended addiu have an 8-bit immediate
+;; field but the equivalent daddiu has only a 5-bit field.
+(define_mode_attr si8_di5 [(SI "8") (DI "5")])
+
+;; This code macro allows all branch instructions to be generated from
+;; a single define_expand template.
+(define_code_macro any_cond [unordered ordered unlt unge uneq ltgt unle ungt
+                            eq ne gt ge lt le gtu geu ltu leu])
+\f
 ;; .........................
 ;;
 ;;     Branch, call and jump delay slots
   [(set_attr "type"    "fadd")
    (set_attr "mode"    "SF")])
 
-(define_expand "addsi3"
-  [(set (match_operand:SI 0 "register_operand")
-       (plus:SI (match_operand:SI 1 "reg_or_0_operand")
-                (match_operand:SI 2 "arith_operand")))]
+(define_expand "add<mode>3"
+  [(set (match_operand:GPR 0 "register_operand")
+       (plus:GPR (match_operand:GPR 1 "register_operand")
+                 (match_operand:GPR 2 "arith_operand")))]
   "")
 
-(define_insn "addsi3_internal"
-  [(set (match_operand:SI 0 "register_operand" "=d,d")
-       (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ,dJ")
-                (match_operand:SI 2 "arith_operand" "d,Q")))]
+(define_insn "*add<mode>3"
+  [(set (match_operand:GPR 0 "register_operand" "=d,d")
+       (plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
+                 (match_operand:GPR 2 "arith_operand" "d,Q")))]
   "!TARGET_MIPS16"
   "@
-    addu\t%0,%z1,%2
-    addiu\t%0,%z1,%2"
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "SI")])
+    <d>addu\t%0,%1,%2
+    <d>addiu\t%0,%1,%2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")])
 
-;; For the mips16, we need to recognize stack pointer additions
-;; explicitly, since we don't have a constraint for $sp.  These insns
-;; will be generated by the save_restore_insns functions.
+;; We need to recognize MIPS16 stack pointer additions explicitly, since
+;; we don't have a constraint for $sp.  These insns will be generated by
+;; the save_restore_insns functions.
 
-(define_insn ""
-  [(set (reg:SI 29)
-       (plus:SI (reg:SI 29)
-                (match_operand:SI 0 "const_arith_operand" "")))]
+(define_insn "*add<mode>3_sp1"
+  [(set (reg:GPR 29)
+       (plus:GPR (reg:GPR 29)
+                 (match_operand:GPR 0 "const_arith_operand" "")))]
   "TARGET_MIPS16"
-  "addu\t%$,%$,%0"
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "SI")
-   (set (attr "length")        (if_then_else (match_operand:VOID 0 "m16_simm8_8")
+  "<d>addiu\t%$,%$,%0"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")
+   (set (attr "length") (if_then_else (match_operand 0 "m16_simm8_8")
                                      (const_int 4)
                                      (const_int 8)))])
 
-(define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "=d")
-       (plus:SI (reg:SI 29)
-                (match_operand:SI 1 "const_arith_operand" "")))]
+(define_insn "*add<mode>3_sp2"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+       (plus:GPR (reg:GPR 29)
+                 (match_operand:GPR 1 "const_arith_operand" "")))]
   "TARGET_MIPS16"
-  "addu\t%0,%$,%1"
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "SI")
-   (set (attr "length")        (if_then_else (match_operand:VOID 1 "m16_uimm8_4")
+  "<d>addiu\t%0,%$,%1"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")
+   (set (attr "length") (if_then_else (match_operand 1 "m16_uimm<si8_di5>_4")
                                      (const_int 4)
                                      (const_int 8)))])
 
-(define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
-       (plus:SI (match_operand:SI 1 "register_operand" "0,d,d")
-                (match_operand:SI 2 "arith_operand" "Q,O,d")))]
+(define_insn "*add<mode>3_mips16"
+  [(set (match_operand:GPR 0 "register_operand" "=d,d,d")
+       (plus:GPR (match_operand:GPR 1 "register_operand" "0,d,d")
+                 (match_operand:GPR 2 "arith_operand" "Q,O,d")))]
   "TARGET_MIPS16"
-{
-  if (REGNO (operands[0]) == REGNO (operands[1]))
-    return "addu\t%0,%2";
-  else
-    return "addu\t%0,%1,%2";
-}
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "SI")
+  "@
+    <d>addiu\t%0,%2
+    <d>addiu\t%0,%1,%2
+    <d>addu\t%0,%1,%2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")
    (set_attr_alternative "length"
-               [(if_then_else (match_operand:VOID 2 "m16_simm8_1")
+               [(if_then_else (match_operand 2 "m16_simm<si8_di5>_1")
                               (const_int 4)
                               (const_int 8))
-                (if_then_else (match_operand:VOID 2 "m16_simm4_1")
+                (if_then_else (match_operand 2 "m16_simm4_1")
                               (const_int 4)
                               (const_int 8))
                 (const_int 4)])])
     }
 })
 
-(define_expand "adddi3"
-  [(set (match_operand:DI 0 "register_operand")
-       (plus:DI (match_operand:DI 1 "register_operand")
-                (match_operand:DI 2 "arith_operand")))]
-  "TARGET_64BIT")
-
-(define_insn "adddi3_internal"
-  [(set (match_operand:DI 0 "register_operand" "=d,d")
-       (plus:DI (match_operand:DI 1 "reg_or_0_operand" "dJ,dJ")
-                (match_operand:DI 2 "arith_operand" "d,Q")))]
-  "TARGET_64BIT && !TARGET_MIPS16"
-  "@
-    daddu\t%0,%z1,%2
-    daddiu\t%0,%z1,%2"
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "DI")])
-
-;; For the mips16, we need to recognize stack pointer additions
-;; explicitly, since we don't have a constraint for $sp.  These insns
-;; will be generated by the save_restore_insns functions.
-
-(define_insn ""
-  [(set (reg:DI 29)
-       (plus:DI (reg:DI 29)
-                (match_operand:DI 0 "const_arith_operand" "")))]
-  "TARGET_MIPS16 && TARGET_64BIT"
-  "daddu\t%$,%$,%0"
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "DI")
-   (set (attr "length")        (if_then_else (match_operand:VOID 0 "m16_simm8_8")
-                                     (const_int 4)
-                                     (const_int 8)))])
-
-(define_insn ""
-  [(set (match_operand:DI 0 "register_operand" "=d")
-       (plus:DI (reg:DI 29)
-                (match_operand:DI 1 "const_arith_operand" "")))]
-  "TARGET_MIPS16 && TARGET_64BIT"
-  "daddu\t%0,%$,%1"
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "DI")
-   (set (attr "length")        (if_then_else (match_operand:VOID 0 "m16_uimm5_4")
-                                     (const_int 4)
-                                     (const_int 8)))])
-
-(define_insn ""
-  [(set (match_operand:DI 0 "register_operand" "=d,d,d")
-       (plus:DI (match_operand:DI 1 "register_operand" "0,d,d")
-                (match_operand:DI 2 "arith_operand" "Q,O,d")))]
-  "TARGET_MIPS16 && TARGET_64BIT"
-{
-  if (REGNO (operands[0]) == REGNO (operands[1]))
-    return "daddu\t%0,%2";
-  else
-    return "daddu\t%0,%1,%2";
-}
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "DI")
-   (set_attr_alternative "length"
-               [(if_then_else (match_operand:VOID 2 "m16_simm5_1")
-                              (const_int 4)
-                              (const_int 8))
-                (if_then_else (match_operand:VOID 2 "m16_simm4_1")
-                              (const_int 4)
-                              (const_int 8))
-                (const_int 4)])])
-
-
-;; On the mips16, we can sometimes split an add of a constant which is
-;; a 4 byte instruction into two adds which are both 2 byte
-;; instructions.  There are two cases: one where we are adding a
-;; constant plus a register to another register, and one where we are
-;; simply adding a constant to a register.
-
 (define_split
   [(set (match_operand:DI 0 "register_operand")
        (plus:DI (match_dup 0)
     }
 })
 
-(define_insn "addsi3_internal_2"
+(define_insn "*addsi3_extended"
   [(set (match_operand:DI 0 "register_operand" "=d,d")
-       (sign_extend:DI (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ,dJ")
-                                (match_operand:SI 2 "arith_operand" "d,Q"))))]
+       (sign_extend:DI
+            (plus:SI (match_operand:SI 1 "register_operand" "d,d")
+                     (match_operand:SI 2 "arith_operand" "d,Q"))))]
   "TARGET_64BIT && !TARGET_MIPS16"
   "@
-    addu\t%0,%z1,%2
-    addiu\t%0,%z1,%2"
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "SI")])
+    addu\t%0,%1,%2
+    addiu\t%0,%1,%2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
 
-(define_insn ""
+;; Split this insn so that the addiu splitters can have a crack at it.
+;; Use a conservative length estimate until the split.
+(define_insn_and_split "*addsi3_extended_mips16"
   [(set (match_operand:DI 0 "register_operand" "=d,d,d")
-       (sign_extend:DI (plus:SI (match_operand:SI 1 "register_operand" "0,d,d")
-                                (match_operand:SI 2 "arith_operand" "Q,O,d"))))]
-  "TARGET_MIPS16 && TARGET_64BIT"
-{
-  if (REGNO (operands[0]) == REGNO (operands[1]))
-    return "addu\t%0,%2";
-  else
-    return "addu\t%0,%1,%2";
-}
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "SI")
-   (set_attr_alternative "length"
-               [(if_then_else (match_operand:VOID 2 "m16_simm8_1")
-                              (const_int 4)
-                              (const_int 8))
-                (if_then_else (match_operand:VOID 2 "m16_simm4_1")
-                              (const_int 4)
-                              (const_int 8))
-                (const_int 4)])])
+       (sign_extend:DI
+            (plus:SI (match_operand:SI 1 "register_operand" "0,d,d")
+                     (match_operand:SI 2 "arith_operand" "Q,O,d"))))]
+  "TARGET_64BIT && TARGET_MIPS16"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 3) (plus:SI (match_dup 1) (match_dup 2)))]
+  { operands[3] = gen_lowpart (SImode, operands[0]); }
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")
+   (set_attr "extended_mips16" "yes")])
 \f
 ;;
 ;;  ....................
   [(set_attr "type"    "fadd")
    (set_attr "mode"    "SF")])
 
-(define_expand "subsi3"
-  [(set (match_operand:SI 0 "register_operand")
-       (minus:SI (match_operand:SI 1 "register_operand")
-                 (match_operand:SI 2 "register_operand")))]
-  ""
-  "")
-
-(define_insn "subsi3_internal"
-  [(set (match_operand:SI 0 "register_operand" "=d")
-       (minus:SI (match_operand:SI 1 "register_operand" "d")
-                 (match_operand:SI 2 "register_operand" "d")))]
+(define_insn "sub<mode>3"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+       (minus:GPR (match_operand:GPR 1 "register_operand" "d")
+                  (match_operand:GPR 2 "register_operand" "d")))]
   ""
-  "subu\t%0,%z1,%2"
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "SI")])
-
-(define_insn "subdi3"
-  [(set (match_operand:DI 0 "register_operand" "=d")
-       (minus:DI (match_operand:DI 1 "register_operand" "d")
-                 (match_operand:DI 2 "register_operand" "d")))]
-  "TARGET_64BIT"
-  "dsubu\t%0,%1,%2"
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "DI")])
+  "<d>subu\t%0,%1,%2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")])
 
-(define_insn "subsi3_internal_2"
+(define_insn "*subsi3_extended"
   [(set (match_operand:DI 0 "register_operand" "=d")
        (sign_extend:DI
            (minus:SI (match_operand:SI 1 "register_operand" "d")
                      (match_operand:SI 2 "register_operand" "d"))))]
   "TARGET_64BIT"
   "subu\t%0,%1,%2"
-  [(set_attr "type"    "arith")
-   (set_attr "mode"    "DI")])
+  [(set_attr "type" "arith")
+   (set_attr "mode" "DI")])
 \f
 ;;
 ;;  ....................
@@ -5810,219 +5731,15 @@ dsrl\t%3,%3,1\n\
    (set_attr "mode"    "none")
    (set_attr "length"  "8")])
 
-(define_expand "bunordered"
-  [(set (pc)
-       (if_then_else (unordered:CC (cc0)
-                                   (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, UNORDERED);
-  DONE;
-})
-
-(define_expand "bordered"
-  [(set (pc)
-       (if_then_else (ordered:CC (cc0)
-                                 (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, ORDERED);
-  DONE;
-})
-
-(define_expand "bunlt"
-  [(set (pc)
-       (if_then_else (unlt:CC (cc0)
-                              (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, UNLT);
-  DONE;
-})
-
-(define_expand "bunge"
-  [(set (pc)
-       (if_then_else (unge:CC (cc0)
-                              (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, UNGE);
-  DONE;
-})
-
-(define_expand "buneq"
-  [(set (pc)
-       (if_then_else (uneq:CC (cc0)
-                              (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, UNEQ);
-  DONE;
-})
-
-(define_expand "bltgt"
-  [(set (pc)
-       (if_then_else (ltgt:CC (cc0)
-                              (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, LTGT);
-  DONE;
-})
-
-(define_expand "bunle"
-  [(set (pc)
-       (if_then_else (unle:CC (cc0)
-                              (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, UNLE);
-  DONE;
-})
-
-(define_expand "bungt"
-  [(set (pc)
-       (if_then_else (ungt:CC (cc0)
-                              (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, UNGT);
-  DONE;
-})
-
-(define_expand "beq"
-  [(set (pc)
-       (if_then_else (eq:CC (cc0)
-                            (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, EQ);
-  DONE;
-})
-
-(define_expand "bne"
-  [(set (pc)
-       (if_then_else (ne:CC (cc0)
-                            (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, NE);
-  DONE;
-})
-
-(define_expand "bgt"
-  [(set (pc)
-       (if_then_else (gt:CC (cc0)
-                            (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, GT);
-  DONE;
-})
-
-(define_expand "bge"
-  [(set (pc)
-       (if_then_else (ge:CC (cc0)
-                            (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, GE);
-  DONE;
-})
-
-(define_expand "blt"
-  [(set (pc)
-       (if_then_else (lt:CC (cc0)
-                            (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, LT);
-  DONE;
-})
-
-(define_expand "ble"
-  [(set (pc)
-       (if_then_else (le:CC (cc0)
-                            (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, LE);
-  DONE;
-})
-
-(define_expand "bgtu"
-  [(set (pc)
-       (if_then_else (gtu:CC (cc0)
-                             (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, GTU);
-  DONE;
-})
-
-(define_expand "bgeu"
-  [(set (pc)
-       (if_then_else (geu:CC (cc0)
-                             (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, GEU);
-  DONE;
-})
-
-(define_expand "bltu"
-  [(set (pc)
-       (if_then_else (ltu:CC (cc0)
-                             (const_int 0))
-                     (label_ref (match_operand 0 ""))
-                     (pc)))]
-  ""
-{
-  gen_conditional_branch (operands, LTU);
-  DONE;
-})
-
-(define_expand "bleu"
+(define_expand "b<code>"
   [(set (pc)
-       (if_then_else (leu:CC (cc0)
-                             (const_int 0))
+       (if_then_else (any_cond:CC (cc0)
+                                  (const_int 0))
                      (label_ref (match_operand 0 ""))
                      (pc)))]
   ""
 {
-  gen_conditional_branch (operands, LEU);
+  gen_conditional_branch (operands, <CODE>);
   DONE;
 })
 \f
index 6b85836cb0fc28b727353c0d6c6111a21c82f7b1..8404707db27757a0148a8d54c652a78c2d37975e 100644 (file)
@@ -47,6 +47,7 @@ See the next chapter for information on the C header file.
                            predication.
 * Constant Definitions::Defining symbolic constants that can be used in the
                         md file.
+* Macros::              Using macros to generate patterns from a template.
 @end menu
 
 @node Overview
@@ -6420,3 +6421,272 @@ You could write:
 The constants that are defined with a define_constant are also output
 in the insn-codes.h header file as #defines.
 @end ifset
+@ifset INTERNALS
+@node Macros
+@section Macros
+@cindex macros in @file{.md} files
+
+Ports often need to define similar patterns for more than one machine
+mode or for more than one rtx code.  GCC provides some simple macro
+facilities to make this process easier.
+
+@menu
+* Mode Macros::         Generating variations of patterns for different modes.
+* Code Macros::         Doing the same for codes.
+@end menu
+
+@node Mode Macros
+@subsection Mode Macros
+@cindex mode macros in @file{.md} files
+
+Ports often need to define similar patterns for two or more different modes.
+For example:
+
+@itemize @bullet
+@item
+If a processor has hardware support for both single and double
+floating-point arithmetic, the @code{SFmode} patterns tend to be
+very similar to the @code{DFmode} ones.
+
+@item
+If a port uses @code{SImode} pointers in one configuration and
+@code{DImode} pointers in another, it will usually have very similar
+@code{SImode} and @code{DImode} patterns for manipulating pointers.
+@end itemize
+
+Mode macros allow several patterns to be instantiated from one
+@file{.md} file template.  They can be used with any type of
+rtx-based construct, such as a @code{define_insn},
+@code{define_split}, or @code{define_peephole2}.
+
+@menu
+* Defining Mode Macros:: Defining a new mode macro.
+* String Substitutions:: Combining mode macros with string substitutions
+* Examples::             Examples
+@end menu
+
+@node Defining Mode Macros
+@subsubsection Defining Mode Macros
+@findex define_mode_macro
+
+The syntax for defining a mode macro is:
+
+@smallexample
+(define_mode_macro @var{name} [(@var{mode1} "@var{cond1}") ... (@var{moden} "@var{condn}")])
+@end smallexample
+
+This allows subsequent @file{.md} file constructs to use the mode suffix
+@code{:@var{name}}.  Every construct that does so will be expanded
+@var{n} times, once with every use of @code{:@var{name}} replaced by
+@code{:@var{mode1}}, once with every use replaced by @code{:@var{mode2}},
+and so on.  In the expansion for a particular @var{modei}, every
+C condition will also require that @var{condi} be true.
+
+For example:
+
+@smallexample
+(define_mode_macro P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
+@end smallexample
+
+defines a new mode suffix @code{:P}.  Every construct that uses
+@code{:P} will be expanded twice, once with every @code{:P} replaced
+by @code{:SI} and once with every @code{:P} replaced by @code{:DI}.
+The @code{:SI} version will only apply if @code{Pmode == SImode} and
+the @code{:DI} version will only apply if @code{Pmode == DImode}.
+
+As with other @file{.md} conditions, an empty string is treated
+as ``always true''.  @code{(@var{mode} "")} can also be abbreviated
+to @code{@var{mode}}.  For example:
+
+@smallexample
+(define_mode_macro GPR [SI (DI "TARGET_64BIT")])
+@end smallexample
+
+means that the @code{:DI} expansion only applies if @code{TARGET_64BIT}
+but that the @code{:SI} expansion has no such constraint.
+
+Macros are applied in the order they are defined.  This can be
+significant if two macros are used in a construct that requires
+string substitutions.  @xref{String Substitutions}.
+
+@node String Substitutions
+@subsubsection String Substitution in Mode Macros
+@findex define_mode_attr
+
+If an @file{.md} file construct uses mode macros, each version of the
+construct will often need slightly different strings.  For example:
+
+@itemize @bullet
+@item
+When a @code{define_expand} defines several @code{add@var{m}3} patterns
+(@pxref{Standard Names}), each expander will need to use the
+appropriate mode name for @var{m}.
+
+@item
+When a @code{define_insn} defines several instruction patterns,
+each instruction will often use a different assembler mnemonic.
+@end itemize
+
+GCC supports such variations through a system of ``mode attributes''.
+There are two standard attributes: @code{mode}, which is the name of
+the mode in lower case, and @code{MODE}, which is the same thing in
+upper case.  You can define other attributes using:
+
+@smallexample
+(define_mode_attr @var{name} [(@var{mode1} "@var{value1}") ... (@var{moden} "@var{valuen}")])
+@end smallexample
+
+where @var{name} is the name of the attribute and @var{valuei}
+is the value associated with @var{modei}.
+
+When GCC replaces some @var{:macro} with @var{:mode}, it will
+scan each string in the pattern for sequences of the form
+@code{<@var{macro}:@var{attr}>}, where @var{attr} is the name of
+a mode attribute.  If the attribute is defined for @var{mode}, the
+whole @code{<...>} sequence will be replaced by the appropriate
+attribute value.
+
+For example, suppose an @file{.md} file has:
+
+@smallexample
+(define_mode_macro P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
+(define_mode_attr load [(SI "lw") (DI "ld")])
+@end smallexample
+
+If one of the patterns that uses @code{:P} contains the string
+@code{"<P:load>\t%0,%1"}, the @code{SI} version of that pattern
+will use @code{"lw\t%0,%1"} and the @code{DI} version will use
+@code{"ld\t%0,%1"}.
+
+The @code{@var{macro}:} prefix may be omitted, in which case the
+substitution will be attempted for every macro expansion.
+
+@node Examples
+@subsubsection Mode Macro Examples
+
+Here is an example from the MIPS port.  It defines the following
+modes and attributes (among others):
+
+@smallexample
+(define_mode_macro GPR [SI (DI "TARGET_64BIT")])
+(define_mode_attr d [(SI "") (DI "d")])
+@end smallexample
+
+and uses the following template to define both @code{subsi3}
+and @code{subdi3}:
+
+@smallexample
+(define_insn "sub<mode>3"
+  [(set (match_operand:GPR 0 "register_operand" "=d")
+        (minus:GPR (match_operand:GPR 1 "register_operand" "d")
+                   (match_operand:GPR 2 "register_operand" "d")))]
+  ""
+  "<d>subu\t%0,%1,%2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "<MODE>")])
+@end smallexample
+
+This is exactly equivalent to:
+
+@smallexample
+(define_insn "subsi3"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (minus:SI (match_operand:SI 1 "register_operand" "d")
+                  (match_operand:SI 2 "register_operand" "d")))]
+  ""
+  "subu\t%0,%1,%2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "SI")])
+
+(define_insn "subdi3"
+  [(set (match_operand:DI 0 "register_operand" "=d")
+        (minus:DI (match_operand:DI 1 "register_operand" "d")
+                  (match_operand:DI 2 "register_operand" "d")))]
+  ""
+  "dsubu\t%0,%1,%2"
+  [(set_attr "type" "arith")
+   (set_attr "mode" "DI")])
+@end smallexample
+
+@node Code Macros
+@subsection Code Macros
+@cindex code macros in @file{.md} files
+@findex define_code_macro
+@findex define_code_attr
+
+Code macros operate in a similar way to mode macros.  @xref{Mode Macros}.
+
+The construct:
+
+@smallexample
+(define_code_macro @var{name} [(@var{code1} "@var{cond1}") ... (@var{coden} "@var{condn}")])
+@end smallexample
+
+defines a pseudo rtx code @var{name} that can be instantiated as
+@var{codei} if condition @var{condi} is true.  Each @var{codei}
+must have the same rtx format.  @xref{RTL Classes}.
+
+As with mode macros, each pattern that uses @var{name} will be
+expanded @var{n} times, once with all uses of @var{name} replaced by
+@var{code1}, once with all uses replaced by @var{code2}, and so on.
+@xref{Defining Mode Macros}.
+
+It is possible to define attributes for codes as well as for modes.
+There are two standard code attributes: @code{code}, the name of the
+code in lower case, and @code{CODE}, the name of the code in upper case.
+Other attributes are defined using:
+
+@smallexample
+(define_code_attr @var{name} [(@var{code1} "@var{value1}") ... (@var{coden} "@var{valuen}")])
+@end smallexample
+
+Here's an example of code macros in action, taken from the MIPS port:
+
+@smallexample
+(define_code_macro any_cond [unordered ordered unlt unge uneq ltgt unle ungt
+                             eq ne gt ge lt le gtu geu ltu leu])
+
+(define_expand "b<code>"
+  [(set (pc)
+        (if_then_else (any_cond:CC (cc0)
+                                   (const_int 0))
+                      (label_ref (match_operand 0 ""))
+                      (pc)))]
+  ""
+@{
+  gen_conditional_branch (operands, <CODE>);
+  DONE;
+@})
+@end smallexample
+
+This is equivalent to:
+
+@smallexample
+(define_expand "bunordered"
+  [(set (pc)
+        (if_then_else (unordered:CC (cc0)
+                                    (const_int 0))
+                      (label_ref (match_operand 0 ""))
+                      (pc)))]
+  ""
+@{
+  gen_conditional_branch (operands, UNORDERED);
+  DONE;
+@})
+
+(define_expand "bordered"
+  [(set (pc)
+        (if_then_else (ordered:CC (cc0)
+                                  (const_int 0))
+                      (label_ref (match_operand 0 ""))
+                      (pc)))]
+  ""
+@{
+  gen_conditional_branch (operands, ORDERED);
+  DONE;
+@})
+
+...
+@end smallexample
+
+@end ifset
index 2b9bd915d23ac279a95ed1e888bcb743d6cda228..fe0c7a4044ae56efe466cd5f24b44c6a61b67353 100644 (file)
@@ -30,9 +30,76 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 static htab_t md_constants;
 
+/* One element in a singly-linked list of (integer, string) pairs.  */
+struct map_value {
+  struct map_value *next;
+  int number;
+  const char *string;
+};
+
+/* Maps a macro or attribute name to a list of (integer, string) pairs.
+   The integers are mode or code values; the strings are either C conditions
+   or attribute values.  */
+struct mapping {
+  /* The name of the macro or attribute.  */
+  const char *name;
+
+  /* The group (modes or codes) to which the macro or attribute belongs.  */
+  struct macro_group *group;
+
+  /* Gives a unique number to the attribute or macro.  Numbers are
+     allocated consecutively, starting at 0.  */
+  int index;
+
+  /* The list of (integer, string) pairs.  */
+  struct map_value *values;
+};
+
+/* A structure for abstracting the common parts of code and mode macros.  */
+struct macro_group {
+  /* Tables of "mapping" structures, one for attributes and one for macros.  */
+  htab_t attrs, macros;
+
+  /* The number of "real" modes or codes (and by extension, the first
+     number available for use as a macro placeholder).  */
+  int num_builtins;
+
+  /* Treat the given string as the name of a standard mode or code and
+     return its integer value.  Use the given file for error reporting.  */
+  int (*find_builtin) (const char *, FILE *);
+
+  /* Return true if the given rtx uses the given mode or code.  */
+  bool (*uses_macro_p) (rtx, int);
+
+  /* Make the given rtx use the given mode or code.  */
+  void (*apply_macro) (rtx, int);
+};
+
+/* If CODE is the number of a code macro, return a real rtx code that
+   has the same format.  Return CODE otherwise.  */
+#define BELLWETHER_CODE(CODE) \
+  ((CODE) < NUM_RTX_CODE ? CODE : bellwether_codes[CODE - NUM_RTX_CODE])
+
 static void fatal_with_file_and_line (FILE *, const char *, ...)
   ATTRIBUTE_PRINTF_2 ATTRIBUTE_NORETURN;
 static void fatal_expected_char (FILE *, int, int) ATTRIBUTE_NORETURN;
+static int find_mode (const char *, FILE *);
+static bool uses_mode_macro_p (rtx, int);
+static void apply_mode_macro (rtx, int);
+static int find_code (const char *, FILE *);
+static bool uses_code_macro_p (rtx, int);
+static void apply_code_macro (rtx, int);
+static const char *apply_macro_to_string (const char *, struct mapping *, int);
+static rtx apply_macro_to_rtx (rtx, struct mapping *, int);
+static bool uses_macro_p (rtx, struct mapping *);
+static const char *add_condition_to_string (const char *, const char *);
+static void add_condition_to_rtx (rtx, const char *);
+static int apply_macro_traverse (void **, void *);
+static struct mapping *add_mapping (struct macro_group *, htab_t t,
+                                   const char *, FILE *);
+static struct map_value **add_map_value (struct map_value **,
+                                        int, const char *);
+static void initialize_macros (void);
 static void read_name (char *, FILE *);
 static char *read_string (FILE *, int);
 static char *read_quoted_string (FILE *);
@@ -42,6 +109,16 @@ static hashval_t def_hash (const void *);
 static int def_name_eq_p (const void *, const void *);
 static void read_constants (FILE *infile, char *tmp_char);
 static void validate_const_int (FILE *, const char *);
+static int find_macro (struct macro_group *, const char *, FILE *);
+static struct mapping *read_mapping (struct macro_group *, htab_t, FILE *);
+static void check_code_macro (struct mapping *, FILE *);
+static rtx read_rtx_1 (FILE *);
+
+/* The mode and code macro structures.  */
+static struct macro_group modes, codes;
+
+/* Index I is the value of BELLWETHER_CODE (I + NUM_RTX_CODE).  */
+static enum rtx_code *bellwether_codes;
 
 /* Obstack used for allocating RTL strings.  */
 static struct obstack string_obstack;
@@ -97,6 +174,393 @@ fatal_expected_char (FILE *infile, int expected_c, int actual_c)
                            expected_c, actual_c);
 }
 
+/* Implementations of the macro_group callbacks for modes.  */
+
+static int
+find_mode (const char *name, FILE *infile)
+{
+  int i;
+
+  for (i = 0; i < NUM_MACHINE_MODES; i++)
+    if (strcmp (GET_MODE_NAME (i), name) == 0)
+      return i;
+
+  fatal_with_file_and_line (infile, "unknown mode `%s'", name);
+}
+
+static bool
+uses_mode_macro_p (rtx x, int mode)
+{
+  return (int) GET_MODE (x) == mode;
+}
+
+static void
+apply_mode_macro (rtx x, int mode)
+{
+  PUT_MODE (x, mode);
+}
+
+/* Implementations of the macro_group callbacks for codes.  */
+
+static int
+find_code (const char *name, FILE *infile)
+{
+  int i;
+
+  for (i = 0; i < NUM_RTX_CODE; i++)
+    if (strcmp (GET_RTX_NAME (i), name) == 0)
+      return i;
+
+  fatal_with_file_and_line (infile, "unknown rtx code `%s'", name);
+}
+
+static bool
+uses_code_macro_p (rtx x, int code)
+{
+  return (int) GET_CODE (x) == code;
+}
+
+static void
+apply_code_macro (rtx x, int code)
+{
+  PUT_CODE (x, code);
+}
+
+/* Given that MACRO is being expanded as VALUE, apply the appropriate
+   string substitutions to STRING.  Return the new string if any changes
+   were needed, otherwise return STRING itself.  */
+
+static const char *
+apply_macro_to_string (const char *string, struct mapping *macro, int value)
+{
+  char *base, *copy, *p, *attr, *start, *end;
+  struct mapping *m;
+  struct map_value *v;
+
+  if (string == 0)
+    return string;
+
+  base = p = copy = ASTRDUP (string);
+  while ((start = index (p, '<')) && (end = index (start, '>')))
+    {
+      p = start + 1;
+
+      /* If there's a "macro:" prefix, check whether the macro name matches.
+        Set ATTR to the start of the attribute name.  */
+      attr = index (p, ':');
+      if (attr == 0 || attr > end)
+       attr = p;
+      else
+       {
+         if (strncmp (p, macro->name, attr - p) != 0
+             || macro->name[attr - p] != 0)
+           continue;
+         attr++;
+       }
+
+      /* Find the attribute specification.  */
+      *end = 0;
+      m = (struct mapping *) htab_find (macro->group->attrs, &attr);
+      *end = '>';
+      if (m == 0)
+       continue;
+
+      /* Find the attribute value for VALUE.  */
+      for (v = m->values; v != 0; v = v->next)
+       if (v->number == value)
+         break;
+      if (v == 0)
+       continue;
+
+      /* Add everything between the last copied byte and the '<',
+        then add in the attribute value.  */
+      obstack_grow (&string_obstack, base, start - base);
+      obstack_grow (&string_obstack, v->string, strlen (v->string));
+      base = end + 1;
+    }
+  if (base != copy)
+    {
+      obstack_grow (&string_obstack, base, strlen (base) + 1);
+      return (char *) obstack_finish (&string_obstack);
+    }
+  return string;
+}
+
+/* Return a copy of ORIGINAL in which all uses of MACRO have been
+   replaced by VALUE.  */
+
+static rtx
+apply_macro_to_rtx (rtx original, struct mapping *macro, int value)
+{
+  struct macro_group *group;
+  const char *format_ptr;
+  int i, j;
+  rtx x;
+  enum rtx_code bellwether_code;
+
+  if (original == 0)
+    return original;
+
+  /* Create a shallow copy of ORIGINAL.  */
+  bellwether_code = BELLWETHER_CODE (GET_CODE (original));
+  x = rtx_alloc (bellwether_code);
+  memcpy (x, original, RTX_SIZE (bellwether_code));
+
+  /* Change the mode or code itself.  */
+  group = macro->group;
+  if (group->uses_macro_p (x, macro->index + group->num_builtins))
+    group->apply_macro (x, value);
+
+  /* Change each string and recursively change each rtx.  */
+  format_ptr = GET_RTX_FORMAT (bellwether_code);
+  for (i = 0; format_ptr[i] != 0; i++)
+    switch (format_ptr[i])
+      {
+      case 'S':
+      case 'T':
+      case 's':
+       XSTR (x, i) = apply_macro_to_string (XSTR (x, i), macro, value);
+       break;
+
+      case 'e':
+       XEXP (x, i) = apply_macro_to_rtx (XEXP (x, i), macro, value);
+       break;
+
+      case 'V':
+      case 'E':
+       if (XVEC (original, i))
+         {
+           XVEC (x, i) = rtvec_alloc (XVECLEN (original, i));
+           for (j = 0; j < XVECLEN (x, i); j++)
+             XVECEXP (x, i, j) = apply_macro_to_rtx (XVECEXP (original, i, j),
+                                                     macro, value);
+         }
+       break;
+
+      default:
+       break;
+      }
+  return x;
+}
+
+/* Return true if X (or some subexpression of X) uses macro MACRO.  */
+
+static bool
+uses_macro_p (rtx x, struct mapping *macro)
+{
+  struct macro_group *group;
+  const char *format_ptr;
+  int i, j;
+
+  if (x == 0)
+    return false;
+
+  group = macro->group;
+  if (group->uses_macro_p (x, macro->index + group->num_builtins))
+    return true;
+
+  format_ptr = GET_RTX_FORMAT (BELLWETHER_CODE (GET_CODE (x)));
+  for (i = 0; format_ptr[i] != 0; i++)
+    switch (format_ptr[i])
+      {
+      case 'e':
+       if (uses_macro_p (XEXP (x, i), macro))
+         return true;
+       break;
+
+      case 'V':
+      case 'E':
+       if (XVEC (x, i))
+         for (j = 0; j < XVECLEN (x, i); j++)
+           if (uses_macro_p (XVECEXP (x, i, j), macro))
+             return true;
+       break;
+
+      default:
+       break;
+      }
+  return false;
+}
+
+/* Return a condition that must satisfy both ORIGINAL and EXTRA.  If ORIGINAL
+   has the form "&& ..." (as used in define_insn_and_splits), assume that
+   EXTRA is already satisfied.  Empty strings are treated like "true".  */
+
+static const char *
+add_condition_to_string (const char *original, const char *extra)
+{
+  char *result;
+
+  if (original == 0 || original[0] == 0)
+    return extra;
+
+  if ((original[0] == '&' && original[1] == '&') || extra[0] == 0)
+    return original;
+
+  asprintf (&result, "(%s) && (%s)", original, extra);
+  return result;
+}
+
+/* Like add_condition, but applied to all conditions in rtx X.  */
+
+static void
+add_condition_to_rtx (rtx x, const char *extra)
+{
+  switch (GET_CODE (x))
+    {
+    case DEFINE_INSN:
+    case DEFINE_EXPAND:
+      XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra);
+      break;
+
+    case DEFINE_SPLIT:
+    case DEFINE_PEEPHOLE:
+    case DEFINE_PEEPHOLE2:
+    case DEFINE_COND_EXEC:
+      XSTR (x, 1) = add_condition_to_string (XSTR (x, 1), extra);
+      break;
+
+    case DEFINE_INSN_AND_SPLIT:
+      XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra);
+      XSTR (x, 4) = add_condition_to_string (XSTR (x, 4), extra);
+      break;
+
+    default:
+      break;
+    }
+}
+
+/* A htab_traverse callback.  Search the EXPR_LIST given by DATA
+   for rtxes that use the macro in *SLOT.  Replace each such rtx
+   with a list of expansions.  */
+
+static int
+apply_macro_traverse (void **slot, void *data)
+{
+  struct mapping *macro;
+  struct map_value *v;
+  rtx elem, new_elem, original, x;
+
+  macro = (struct mapping *) *slot;
+  for (elem = (rtx) data; elem != 0; elem = XEXP (elem, 1))
+    if (uses_macro_p (XEXP (elem, 0), macro))
+      {
+       original = XEXP (elem, 0);
+       for (v = macro->values; v != 0; v = v->next)
+         {
+           x = apply_macro_to_rtx (original, macro, v->number);
+           add_condition_to_rtx (x, v->string);
+           if (v != macro->values)
+             {
+               /* Insert a new EXPR_LIST node after ELEM and put the
+                  new expansion there.  */
+               new_elem = rtx_alloc (EXPR_LIST);
+               XEXP (new_elem, 1) = XEXP (elem, 1);
+               XEXP (elem, 1) = new_elem;
+               elem = new_elem;
+             }
+           XEXP (elem, 0) = x;
+         }
+    }
+  return 1;
+}
+
+/* Add a new "mapping" structure to hashtable TABLE.  NAME is the name
+   of the mapping, GROUP is the group to which it belongs, and INFILE
+   is the file that defined the mapping.  */
+
+static struct mapping *
+add_mapping (struct macro_group *group, htab_t table,
+            const char *name, FILE *infile)
+{
+  struct mapping *m;
+  void **slot;
+
+  m = XNEW (struct mapping);
+  m->name = xstrdup (name);
+  m->group = group;
+  m->index = htab_elements (table);
+  m->values = 0;
+
+  slot = htab_find_slot (table, m, INSERT);
+  if (*slot != 0)
+    fatal_with_file_and_line (infile, "`%s' already defined", name);
+
+  *slot = m;
+  return m;
+}
+
+/* Add the pair (NUMBER, STRING) to a list of map_value structures.
+   END_PTR points to the current null terminator for the list; return
+   a pointer the new null terminator.  */
+
+static struct map_value **
+add_map_value (struct map_value **end_ptr, int number, const char *string)
+{
+  struct map_value *value;
+
+  value = XNEW (struct map_value);
+  value->next = 0;
+  value->number = number;
+  value->string = string;
+
+  *end_ptr = value;
+  return &value->next;
+}
+
+/* Do one-time initialization of the mode and code attributes.  */
+
+static void
+initialize_macros (void)
+{
+  struct mapping *lower, *upper;
+  struct map_value **lower_ptr, **upper_ptr;
+  char *copy, *p;
+  int i;
+
+  modes.attrs = htab_create (13, def_hash, def_name_eq_p, 0);
+  modes.macros = htab_create (13, def_hash, def_name_eq_p, 0);
+  modes.num_builtins = MAX_MACHINE_MODE;
+  modes.find_builtin = find_mode;
+  modes.uses_macro_p = uses_mode_macro_p;
+  modes.apply_macro = apply_mode_macro;
+
+  codes.attrs = htab_create (13, def_hash, def_name_eq_p, 0);
+  codes.macros = htab_create (13, def_hash, def_name_eq_p, 0);
+  codes.num_builtins = NUM_RTX_CODE;
+  codes.find_builtin = find_code;
+  codes.uses_macro_p = uses_code_macro_p;
+  codes.apply_macro = apply_code_macro;
+
+  lower = add_mapping (&modes, modes.attrs, "mode", 0);
+  upper = add_mapping (&modes, modes.attrs, "MODE", 0);
+  lower_ptr = &lower->values;
+  upper_ptr = &upper->values;
+  for (i = 0; i < MAX_MACHINE_MODE; i++)
+    {
+      copy = xstrdup (GET_MODE_NAME (i));
+      for (p = copy; *p != 0; p++)
+       *p = TOLOWER (*p);
+
+      upper_ptr = add_map_value (upper_ptr, i, GET_MODE_NAME (i));
+      lower_ptr = add_map_value (lower_ptr, i, copy);
+    }
+
+  lower = add_mapping (&codes, codes.attrs, "code", 0);
+  upper = add_mapping (&codes, codes.attrs, "CODE", 0);
+  lower_ptr = &lower->values;
+  upper_ptr = &upper->values;
+  for (i = 0; i < NUM_RTX_CODE; i++)
+    {
+      copy = xstrdup (GET_RTX_NAME (i));
+      for (p = copy; *p != 0; p++)
+       *p = TOUPPER (*p);
+
+      lower_ptr = add_map_value (lower_ptr, i, GET_RTX_NAME (i));
+      upper_ptr = add_map_value (upper_ptr, i, copy);
+    }
+}
+
 /* Read chars from INFILE until a non-whitespace char
    and return that.  Comments, both Lisp style and C style,
    are treated as whitespace.
@@ -398,24 +862,26 @@ atoll (const char *p)
 }
 #endif
 
-/* Given a constant definition, return a hash code for its name.  */
+/* Given an object that starts with a char * name field, return a hash
+   code for its name.  */
 static hashval_t
 def_hash (const void *def)
 {
   unsigned result, i;
-  const char *string = ((const struct md_constant *) def)->name;
+  const char *string = *(const char *const *) def;
 
-  for (result = i = 0;*string++ != '\0'; i++)
+  for (result = i = 0; *string++ != '\0'; i++)
     result += ((unsigned char) *string << (i % CHAR_BIT));
   return result;
 }
 
-/* Given two constant definitions, return true if they have the same name.  */
+/* Given two objects that start with char * name fields, return true if
+   they have the same name.  */
 static int
 def_name_eq_p (const void *def1, const void *def2)
 {
-  return ! strcmp (((const struct md_constant *) def1)->name,
-                  ((const struct md_constant *) def2)->name);
+  return ! strcmp (*(const char *const *) def1,
+                  *(const char *const *) def2);
 }
 
 /* INFILE is a FILE pointer to read text from.  TMP_CHAR is a buffer suitable
@@ -504,6 +970,102 @@ validate_const_int (FILE *infile, const char *string)
     fatal_with_file_and_line (infile, "invalid decimal constant \"%s\"\n", string);
 }
 
+/* Search GROUP for a mode or code called NAME and return its numerical
+   identifier.  INFILE is the file that contained NAME.  */
+
+static int
+find_macro (struct macro_group *group, const char *name, FILE *infile)
+{
+  struct mapping *m;
+
+  m = (struct mapping *) htab_find (group->macros, &name);
+  if (m != 0)
+    return m->index + group->num_builtins;
+  return group->find_builtin (name, infile);
+}
+
+/* Finish reading a declaration of the form:
+
+       (define... <name> [<value1> ... <valuen>])
+
+   from INFILE, where each <valuei> is either a bare symbol name or a
+   "(<name> <string>)" pair.  The "(define..." part has already been read.
+
+   Represent the declaration as a "mapping" structure; add it to TABLE
+   (which belongs to GROUP) and return it.  */
+
+static struct mapping *
+read_mapping (struct macro_group *group, htab_t table, FILE *infile)
+{
+  char tmp_char[256];
+  struct mapping *m;
+  struct map_value **end_ptr;
+  const char *string;
+  int number, c;
+
+  /* Read the mapping name and create a structure for it.  */
+  read_name (tmp_char, infile);
+  m = add_mapping (group, table, tmp_char, infile);
+
+  c = read_skip_spaces (infile);
+  if (c != '[')
+    fatal_expected_char (infile, '[', c);
+
+  /* Read each value.  */
+  end_ptr = &m->values;
+  c = read_skip_spaces (infile);
+  do
+    {
+      if (c != '(')
+       {
+         /* A bare symbol name that is implicitly paired to an
+            empty string.  */
+         ungetc (c, infile);
+         read_name (tmp_char, infile);
+         string = "";
+       }
+      else
+       {
+         /* A "(name string)" pair.  */
+         read_name (tmp_char, infile);
+         string = read_string (infile, false);
+         c = read_skip_spaces (infile);
+         if (c != ')')
+           fatal_expected_char (infile, ')', c);
+       }
+      number = group->find_builtin (tmp_char, infile);
+      end_ptr = add_map_value (end_ptr, number, string);
+      c = read_skip_spaces (infile);
+    }
+  while (c != ']');
+
+  c = read_skip_spaces (infile);
+  if (c != ')')
+    fatal_expected_char (infile, ')', c);
+
+  return m;
+}
+
+/* Check newly-created code macro MACRO to see whether every code has the
+   same format.  Initialize the macro's entry in bellwether_codes.  */
+
+static void
+check_code_macro (struct mapping *macro, FILE *infile)
+{
+  struct map_value *v;
+  enum rtx_code bellwether;
+
+  bellwether = macro->values->number;
+  for (v = macro->values->next; v != 0; v = v->next)
+    if (strcmp (GET_RTX_FORMAT (bellwether), GET_RTX_FORMAT (v->number)) != 0)
+      fatal_with_file_and_line (infile, "code macro `%s' combines "
+                               "different rtx formats", macro->name);
+
+  bellwether_codes = XRESIZEVEC (enum rtx_code, bellwether_codes,
+                                macro->index + 1);
+  bellwether_codes[macro->index] = bellwether;
+}
+
 /* Read an rtx in printed representation from INFILE
    and return an actual rtx in core constructed accordingly.
    read_rtx is not used in the compiler proper, but rather in
@@ -512,8 +1074,42 @@ validate_const_int (FILE *infile, const char *string)
 rtx
 read_rtx (FILE *infile)
 {
-  int i, j;
-  RTX_CODE tmp_code;
+  static rtx queue_head, queue_next;
+  rtx return_rtx;
+
+  /* Do one-time initialization.  */
+  if (queue_head == 0)
+    {
+      initialize_macros ();
+      obstack_init (&string_obstack);
+      queue_head = rtx_alloc (EXPR_LIST);
+    }
+
+  if (queue_next == 0)
+    {
+      queue_next = queue_head;
+
+      XEXP (queue_next, 0) = read_rtx_1 (infile);
+      XEXP (queue_next, 1) = 0;
+
+      htab_traverse (modes.macros, apply_macro_traverse, queue_next);
+      htab_traverse (codes.macros, apply_macro_traverse, queue_next);
+    }
+
+  return_rtx = XEXP (queue_next, 0);
+  queue_next = XEXP (queue_next, 1);
+
+  return return_rtx;
+}
+
+/* Subroutine of read_rtx that reads one construct from INFILE but
+   doesn't apply any macros.  */
+
+static rtx
+read_rtx_1 (FILE *infile)
+{
+  int i;
+  RTX_CODE real_code, bellwether_code;
   const char *format_ptr;
   /* tmp_char is a buffer used for reading decimal integers
      and names of rtx types and machine modes.
@@ -524,8 +1120,6 @@ read_rtx (FILE *infile)
   int tmp_int;
   HOST_WIDE_INT tmp_wide;
 
-  static int initialized;
-
   /* Linked list structure for making RTXs: */
   struct rtx_list
     {
@@ -533,51 +1127,52 @@ read_rtx (FILE *infile)
       rtx value;               /* Value of this node.  */
     };
 
-  if (!initialized)
-    {
-      obstack_init (&string_obstack);
-      initialized = 1;
-    }
-
-again:
+ again:
   c = read_skip_spaces (infile); /* Should be open paren.  */
   if (c != '(')
     fatal_expected_char (infile, '(', c);
 
   read_name (tmp_char, infile);
-
-  tmp_code = UNKNOWN;
-  for (i = 0; i < NUM_RTX_CODE; i++)
-    if (! strcmp (tmp_char, GET_RTX_NAME (i)))
-      {
-       tmp_code = (RTX_CODE) i;        /* get value for name */
-       break;
-      }
-
-  if (tmp_code == UNKNOWN)
+  if (strcmp (tmp_char, "nil") == 0)
     {
       /* (nil) stands for an expression that isn't there.  */
-      if (! strcmp (tmp_char, "nil"))
-       {
-         /* Discard the closeparen.  */
-         c = read_skip_spaces (infile);
-         if (c != ')')
-           fatal_expected_char (infile, ')', c);
-         return 0;
-       }
-      /* (define_constants ...) has special syntax.  */
-      else if (! strcmp (tmp_char, "define_constants"))
-       {
-         read_constants (infile, tmp_char);
-         goto again;
-       }
-      else 
-       fatal_with_file_and_line (infile, "unknown rtx code `%s'", tmp_char);
+      c = read_skip_spaces (infile);
+      if (c != ')')
+       fatal_expected_char (infile, ')', c);
+      return 0;
+    }
+  if (strcmp (tmp_char, "define_constants") == 0)
+    {
+      read_constants (infile, tmp_char);
+      goto again;
+    }
+  if (strcmp (tmp_char, "define_mode_attr") == 0)
+    {
+      read_mapping (&modes, modes.attrs, infile);
+      goto again;
+    }
+  if (strcmp (tmp_char, "define_mode_macro") == 0)
+    {
+      read_mapping (&modes, modes.macros, infile);
+      goto again;
+    }
+  if (strcmp (tmp_char, "define_code_attr") == 0)
+    {
+      read_mapping (&codes, codes.attrs, infile);
+      goto again;
+    }
+  if (strcmp (tmp_char, "define_code_macro") == 0)
+    {
+      check_code_macro (read_mapping (&codes, codes.macros, infile), infile);
+      goto again;
     }
+  real_code = find_macro (&codes, tmp_char, infile);
+  bellwether_code = BELLWETHER_CODE (real_code);
 
   /* If we end up with an insn expression then we free this space below.  */
-  return_rtx = rtx_alloc (tmp_code);
-  format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx));
+  return_rtx = rtx_alloc (bellwether_code);
+  format_ptr = GET_RTX_FORMAT (bellwether_code);
+  PUT_CODE (return_rtx, real_code);
 
   /* If what follows is `: mode ', read it and
      store the mode in the rtx.  */
@@ -586,14 +1181,7 @@ again:
   if (i == ':')
     {
       read_name (tmp_char, infile);
-      for (j = 0; j < NUM_MACHINE_MODES; j++)
-       if (! strcmp (GET_MODE_NAME (j), tmp_char))
-         break;
-
-      if (j == MAX_MACHINE_MODE)
-       fatal_with_file_and_line (infile, "unknown mode `%s'", tmp_char);
-
-      PUT_MODE (return_rtx, (enum machine_mode) j);
+      PUT_MODE (return_rtx, find_macro (&modes, tmp_char, infile));
     }
   else
     ungetc (i, infile);
@@ -608,7 +1196,7 @@ again:
 
       case 'e':
       case 'u':
-       XEXP (return_rtx, i) = read_rtx (infile);
+       XEXP (return_rtx, i) = read_rtx_1 (infile);
        break;
 
       case 'V':
@@ -640,7 +1228,7 @@ again:
            {
              ungetc (c, infile);
              list_counter++;
-             obstack_ptr_grow (&vector_stack, read_rtx (infile));
+             obstack_ptr_grow (&vector_stack, read_rtx_1 (infile));
            }
          if (list_counter > 0)
            {