From 032e83482b77e6d7fcc933640bc3fd17448d74a2 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 23 Aug 2004 05:55:50 +0000 Subject: [PATCH] read-rtl.c (map_value, [...]): New structures. * 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], *add3_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 | 40 +++ gcc/config/mips/mips.md | 477 ++++++--------------------- gcc/doc/md.texi | 270 ++++++++++++++++ gcc/read-rtl.c | 698 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 1050 insertions(+), 435 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c442371f657..25da5351e72 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,43 @@ +2004-08-23 Richard Sandiford + + * 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], *add3_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 * read-rtl.c (read_rtx): Tidy use of format_ptr. diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 603a6b9d18c..a1226f8d2fc 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -289,6 +289,24 @@ (define_asm_attributes [(set_attr "type" "multi")]) +;; 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 "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]) + ;; ......................... ;; ;; Branch, call and jump delay slots @@ -425,69 +443,67 @@ [(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 "add3" + [(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 "*add3" + [(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")]) + addu\t%0,%1,%2 + addiu\t%0,%1,%2" + [(set_attr "type" "arith") + (set_attr "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 "*add3_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") + "addiu\t%$,%$,%0" + [(set_attr "type" "arith") + (set_attr "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 "*add3_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") + "addiu\t%0,%$,%1" + [(set_attr "type" "arith") + (set_attr "mode" "") + (set (attr "length") (if_then_else (match_operand 1 "m16_uimm_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 "*add3_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") + "@ + addiu\t%0,%2 + addiu\t%0,%1,%2 + addu\t%0,%1,%2" + [(set_attr "type" "arith") + (set_attr "mode" "") (set_attr_alternative "length" - [(if_then_else (match_operand:VOID 2 "m16_simm8_1") + [(if_then_else (match_operand 2 "m16_simm_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)])]) @@ -560,80 +576,6 @@ } }) -(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) @@ -695,38 +637,33 @@ } }) -(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")]) ;; ;; .................... @@ -754,40 +691,24 @@ [(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 "sub3" + [(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")]) + "subu\t%0,%1,%2" + [(set_attr "type" "arith") + (set_attr "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")]) ;; ;; .................... @@ -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" [(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, ); DONE; }) diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 6b85836cb0f..8404707db27 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -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{"\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 "sub3" + [(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,%1,%2" + [(set_attr "type" "arith") + (set_attr "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" + [(set (pc) + (if_then_else (any_cond:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "")) + (pc)))] + "" +@{ + gen_conditional_branch (operands, ); + 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 diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c index 2b9bd915d23..fe0c7a4044a 100644 --- a/gcc/read-rtl.c +++ b/gcc/read-rtl.c @@ -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... [ ... ]) + + from INFILE, where each is either a bare symbol name or a + "( )" 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) { -- 2.30.2