diff options
| -rw-r--r-- | gcc/config/msp430/msp430-protos.h | 5 | ||||
| -rw-r--r-- | gcc/config/msp430/msp430.c | 162 | ||||
| -rw-r--r-- | gcc/config/msp430/msp430.h | 10 | ||||
| -rw-r--r-- | gcc/config/msp430/msp430.md | 437 | ||||
| -rw-r--r-- | gcc/config/msp430/predicates.md | 13 |
5 files changed, 506 insertions, 121 deletions
diff --git a/gcc/config/msp430/msp430-protos.h b/gcc/config/msp430/msp430-protos.h index 0b4d9a4..33ad1ad 100644 --- a/gcc/config/msp430/msp430-protos.h +++ b/gcc/config/msp430/msp430-protos.h @@ -26,7 +26,7 @@ void msp430_expand_eh_return (rtx); void msp430_expand_epilogue (int); void msp430_expand_helper (rtx *operands, const char *, bool); void msp430_expand_prologue (void); -const char * msp430x_extendhisi (rtx *); +int msp430x_extendhisi (rtx *, bool); void msp430_fixup_compare_operands (machine_mode, rtx *); int msp430_hard_regno_nregs_has_padding (int, machine_mode); int msp430_hard_regno_nregs_with_padding (int, machine_mode); @@ -49,10 +49,11 @@ rtx msp430_subreg (machine_mode, rtx, machine_mode, int); bool msp430_use_f5_series_hwmult (void); bool msp430_has_hwmult (void); bool msp430_op_not_in_high_mem (rtx op); +bool msp430x_insn_required (rtx op); #ifdef RTX_CODE int msp430_expand_shift (enum rtx_code code, machine_mode mode, rtx *operands); -const char * msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, rtx *operands); +int msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, rtx *operands, bool); #endif #endif /* GCC_MSP430_PROTOS_H */ diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index 9f76351..cc3472e 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -3520,18 +3520,22 @@ msp430_expand_shift (enum rtx_code code, machine_mode mode, rtx *operands) For 430X it is inneficient to do so for any modes except SI and DI, since we can make use of R*M insns or RPT with 430X insns, so this function is only used for SImode in that case. */ -const char * +int msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, - rtx *operands) + rtx *operands, bool return_length) { int i; int amt; int max_shift = GET_MODE_BITSIZE (mode) - 1; + int length = 0; + gcc_assert (CONST_INT_P (operands[2])); amt = INTVAL (operands[2]); if (amt == 0 || amt > max_shift) { + if (return_length) + return 0; switch (code) { case ASHIFT: @@ -3549,17 +3553,28 @@ msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, default: gcc_unreachable (); } - return ""; + return 0; } if (code == ASHIFT) { if (!msp430x && mode == HImode) - for (i = 0; i < amt; i++) - output_asm_insn ("RLA.W\t%0", operands); + { + if (return_length) + length = 2 + (MEM_P (operands[0]) ? 2 : 0); + else + for (i = 0; i < amt; i++) + output_asm_insn ("RLA.W\t%0", operands); + } else if (mode == SImode) - for (i = 0; i < amt; i++) - output_asm_insn ("RLA%X0.W\t%L0 { RLC%X0.W\t%H0", operands); + { + if (return_length) + length = 4 + (MEM_P (operands[0]) ? 4 : 0) + + (4 * msp430x_insn_required (operands[0])); + else + for (i = 0; i < amt; i++) + output_asm_insn ("RLA%X0.W\t%L0 { RLC%X0.W\t%H0", operands); + } else /* Catch unhandled cases. */ gcc_unreachable (); @@ -3567,33 +3582,61 @@ msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, else if (code == ASHIFTRT) { if (!msp430x && mode == HImode) - for (i = 0; i < amt; i++) - output_asm_insn ("RRA.W\t%0", operands); + { + if (return_length) + length = 2 + (MEM_P (operands[0]) ? 2 : 0); + else + for (i = 0; i < amt; i++) + output_asm_insn ("RRA.W\t%0", operands); + } else if (mode == SImode) - for (i = 0; i < amt; i++) - output_asm_insn ("RRA%X0.W\t%H0 { RRC%X0.W\t%L0", operands); + { + if (return_length) + length = 4 + (MEM_P (operands[0]) ? 4 : 0) + + (4 * msp430x_insn_required (operands[0])); + else + for (i = 0; i < amt; i++) + output_asm_insn ("RRA%X0.W\t%H0 { RRC%X0.W\t%L0", operands); + } else gcc_unreachable (); } else if (code == LSHIFTRT) { if (!msp430x && mode == HImode) - for (i = 0; i < amt; i++) - output_asm_insn ("CLRC { RRC.W\t%0", operands); + { + if (return_length) + length = 4 + (MEM_P (operands[0]) ? 2 : 0); + else + for (i = 0; i < amt; i++) + output_asm_insn ("CLRC { RRC.W\t%0", operands); + } else if (mode == SImode) - for (i = 0; i < amt; i++) - output_asm_insn ("CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0", operands); + { + if (return_length) + length = 6 + (MEM_P (operands[0]) ? 4 : 0) + + (4 * msp430x_insn_required (operands[0])); + else + for (i = 0; i < amt; i++) + output_asm_insn ("CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0", + operands); + } /* FIXME: Why doesn't "RRUX.W\t%H0 { RRC%X0.W\t%L0" work for msp430x? It causes execution timeouts e.g. pr41963.c. */ #if 0 else if (msp430x && mode == SImode) - for (i = 0; i < amt; i++) - output_asm_insn ("RRUX.W\t%H0 { RRC%X0.W\t%L0", operands); + { + if (return_length) + length = 2; + else + for (i = 0; i < amt; i++) + output_asm_insn ("RRUX.W\t%H0 { RRC%X0.W\t%L0", operands); + } #endif else gcc_unreachable (); } - return ""; + return length * amt; } /* Called by cbranch<mode>4 to coerce operands into usable forms. */ @@ -4115,6 +4158,20 @@ msp430_op_not_in_high_mem (rtx op) return false; } +/* Based on the operand OP, is a 430X insn required to handle it? + There are only 3 conditions for which a 430X insn is required: + - PSImode operand + - memory reference to a symbol which could be in upper memory + (so its address is > 0xFFFF) + - absolute address which has VOIDmode, i.e. (mem:HI (const_int)) + Use a 430 insn if none of these conditions are true. */ +bool +msp430x_insn_required (rtx op) +{ + return (GET_MODE (op) == PSImode + || !msp430_op_not_in_high_mem (op)); +} + #undef TARGET_PRINT_OPERAND #define TARGET_PRINT_OPERAND msp430_print_operand @@ -4455,35 +4512,52 @@ msp430_register_pre_includes (const char *sysroot ATTRIBUTE_UNUSED, /* Generate a sequence of instructions to sign-extend an HI value into an SI value. Handles the tricky case where - we are overwriting the destination. */ - -const char * -msp430x_extendhisi (rtx * operands) + we are overwriting the destination. + Return the number of bytes used by the emitted instructions. + If RETURN_LENGTH is true then do not emit the assembly instruction + sequence. */ +int +msp430x_extendhisi (rtx * operands, bool return_length) { if (REGNO (operands[0]) == REGNO (operands[1])) - /* Low word of dest == source word. 8-byte sequence. */ - return "BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0"; - - if (! msp430x) - /* Note: This sequence is approximately the same length as invoking a helper - function to perform the sign-extension, as in: - - MOV.W %1, %L0 - MOV.W %1, r12 - CALL __mspabi_srai_15 - MOV.W r12, %H0 - - but this version does not involve any function calls or using argument - registers, so it reduces register pressure. 10-byte sequence. */ - return "MOV.W\t%1, %L0 { BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 " - "{ INV.W\t%H0, %H0"; - - if (REGNO (operands[0]) + 1 == REGNO (operands[1])) - /* High word of dest == source word. 6-byte sequence. */ - return "MOV.W\t%1, %L0 { RPT\t#15 { RRAX.W\t%H0"; + { + /* Low word of dest == source word. */ + if (!return_length) + output_asm_insn ("BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0", + operands); + return 8; + } + else if (! msp430x) + { + /* Note: This sequence is approximately the same length as invoking a + helper function to perform the sign-extension, as in: + + MOV.W %1, %L0 + MOV.W %1, r12 + CALL __mspabi_srai_15 + MOV.W r12, %H0 + + but this version does not involve any function calls or using argument + registers, so it reduces register pressure. */ + if (!return_length) + output_asm_insn ("MOV.W\t%1, %L0 { BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0", + operands); + return 10; + } + else if (REGNO (operands[0]) + 1 == REGNO (operands[1])) + { + /* High word of dest == source word. */ + if (!return_length) + output_asm_insn ("MOV.W\t%1, %L0 { RPT\t#15 { RRAX.W\t%H0", + operands); + return 6; + } - /* No overlap between dest and source. 8-byte sequence. */ - return "MOV.W\t%1, %L0 { MOV.W\t%1, %H0 { RPT\t#15 { RRAX.W\t%H0"; + /* No overlap between dest and source. */ + if (!return_length) + output_asm_insn ("MOV.W\t%1, %L0 { MOV.W\t%1, %H0 { RPT\t#15 { RRAX.W\t%H0", + operands); + return 8; } /* Stop GCC from thinking that it can eliminate (SUBREG:PSI (SI)). */ diff --git a/gcc/config/msp430/msp430.h b/gcc/config/msp430/msp430.h index 2500771..c2fcaef 100644 --- a/gcc/config/msp430/msp430.h +++ b/gcc/config/msp430/msp430.h @@ -530,3 +530,13 @@ void msp430_register_pre_includes (const char *sysroot ATTRIBUTE_UNUSED, #define SYMBOL_FLAG_LOW_MEM (SYMBOL_FLAG_MACH_DEP << 0) + +#define ADJUST_INSN_LENGTH(insn, length) \ + do \ + { \ + if (recog_memoized (insn) >= 0) \ + { \ + length += get_attr_extra_length (insn); \ + length *= get_attr_length_multiplier (insn); \ + } \ + } while (0) diff --git a/gcc/config/msp430/msp430.md b/gcc/config/msp430/msp430.md index ad244bb..65e9517 100644 --- a/gcc/config/msp430/msp430.md +++ b/gcc/config/msp430/msp430.md @@ -58,8 +58,100 @@ UNS_DELAY_END ]) -;; This is an approximation. -(define_attr "length" "" (const_int 4)) +;; Instruction length is calculated by examining the type and number of +;; operands. +;; Whether the insn uses the 430X extension word, or is a 430X address +;; instruction also has an effect. +;; "Cheap" source operands do not contribute to the overall length of the insn +;; and are register (Rn), indirect post-increment (@Rn+) and indirect register +;; (@Rn). +;; The lengths of instructions in bytes are: +;; Single-op 430: Cheap op == 2 +;; (also CALLA) Other op == 4 +;; Double-op 430: Source is not cheap == 2 +;; (also MOVA, Dest is register == 2 +;; CMPA, ADDA, Dest is not a register == 4 +;; SUBA) (sum the source and dest cost) +;; Single-op 430X: For insn names ending in 'X' add 2 to single-op 430 cost. +;; Double-op 430X: Insn name ends in 'M' == 2 +;; Others have the same cost as double-op 430 but add 2. +;; +;; The insn type describes whether it is a single or double operand MSP430 +;; instruction (some single-operand GCC instructions are actually +;; double-operand on the target). +;; "triple" and "cmp" types use the costs of a double operand type but +;; instead assume that the src operand is in op2, and also cmp types assume the +;; dst operand is in op1. +;; This attribute also describes which operands are safe to examine +;; when calculating the length or extension. GCC will segfault trying to +;; examine a non-existant operand of an insn. +(define_attr "type" "none,single,double,triple,cmp" (const_string "none")) + +;; The M extension is for instructions like RRAM - they always +;; only, and the operand must be a register. +(define_attr "extension" "none,x,a,m" + (cond [(eq_attr "type" "none") + (const_string "none") + (match_operand 0 "msp430_high_memory_operand" "") + (const_string "x") + (and (eq_attr "type" "double") + (match_operand 1 "msp430_high_memory_operand" "")) + (const_string "x") + (and (ior (eq_attr "type" "triple") (eq_attr "type" "cmp")) + (ior (match_operand 1 "msp430_high_memory_operand" "") + (match_operand 2 "msp430_high_memory_operand" ""))) + (const_string "x")] + (const_string "none"))) + +;; Multiply the default length by this constant value. +(define_attr "length_multiplier" "" (const_int 1)) + +;; Add an additional amount to the total length of the insn. +(define_attr "extra_length" "" (const_int 0)) + +;; FIXME for some reason if we move the addition of 2 for extension == x to +;; ADJUST_INSN_LENGTH, codesize gets much worse. +(define_attr "length" "" + (cond [(eq_attr "extension" "m") + (const_int 2) + (eq_attr "type" "single") + (plus (if_then_else (match_operand 0 "msp430_cheap_operand" "") + (const_int 2) + (const_int 4)) + (if_then_else (eq_attr "extension" "x") + (const_int 2) + (const_int 0))) + (eq_attr "type" "double") + (plus (plus (if_then_else (match_operand 0 "register_operand" "") + (const_int 2) + (const_int 4)) + (if_then_else (match_operand 1 "msp430_cheap_operand" "") + (const_int 0) + (const_int 2))) + (if_then_else (eq_attr "extension" "x") + (const_int 2) + (const_int 0))) + (eq_attr "type" "triple") + (plus (plus (if_then_else (match_operand 0 "register_operand" "") + (const_int 2) + (const_int 4)) + (if_then_else (match_operand 2 "msp430_cheap_operand" "") + (const_int 0) + (const_int 2))) + (if_then_else (eq_attr "extension" "x") + (const_int 2) + (const_int 0))) + (eq_attr "type" "cmp") + (plus (plus (if_then_else (match_operand 1 "register_operand" "") + (const_int 2) + (const_int 4)) + (if_then_else (match_operand 2 "msp430_cheap_operand" "") + (const_int 0) + (const_int 2))) + (if_then_else (eq_attr "extension" "x") + (const_int 2) + (const_int 0)))] + (const_int 2))) (include "predicates.md") (include "constraints.md") @@ -97,35 +189,43 @@ (match_operand:HI 0 "register_operand" "r"))] "" "PUSH\t%0" - ) + [(set_attr "type" "single")] +) (define_insn "pusha" [(set (mem:PSI (pre_dec:PSI (reg:PSI SP_REGNO))) (match_operand:PSI 0 "register_operand" "r"))] "TARGET_LARGE" "PUSHX.A\t%0" - ) + [(set_attr "type" "single") + (set_attr "extension" "x")] +) (define_insn "pushm" [(unspec_volatile [(match_operand 0 "register_operand" "r") (match_operand 1 "immediate_operand" "n")] UNS_PUSHM)] "" "PUSHM%b0\t%1, %0" - ) + [(set_attr "type" "single") + (set_attr "extension" "m")] +) (define_insn "pop" [(set (match_operand:HI 0 "register_operand" "=r") (mem:HI (post_inc:HI (reg:HI SP_REGNO))))] "" "POP\t%0" - ) + [(set_attr "type" "single")] +) (define_insn "popa" [(set (match_operand:PSI 0 "register_operand" "=r") (mem:PSI (post_inc:PSI (reg:PSI SP_REGNO))))] "TARGET_LARGE" "POPX.A\t%0" - ) + [(set_attr "type" "single") + (set_attr "extension" "x")] +) ;; This is nasty. Operand0 is bogus. It is only there so that we can get a ;; mode for the %b0 to work. We should use operand1 for this, but that does @@ -144,7 +244,9 @@ (match_operand 2 "immediate_operand" "i")] UNS_POPM)] "" "POPM%b0\t%2, r%J1" - ) + [(set_attr "type" "single") + (set_attr "extension" "m")] +) ;; The next two patterns are here to support a "feature" of how GCC implements ;; varargs. When a function uses varargs and the *second* to last named @@ -170,6 +272,10 @@ return \"SUBA\t#2, r1 { MOVX.A\t2(r1), 0(r1)\"; return \"SUB\t#2, r1 { MOV.W\t2(r1), 0(r1)\"; " + [(set (attr "length") + (if_then_else (match_test "TARGET_LARGE") + (const_int 8) + (const_int 6)))] ) (define_insn "swap_and_shrink" @@ -178,7 +284,12 @@ "* return TARGET_LARGE ? \"MOVX.A\t0(r1), 2(r1) { ADDA\t#2, SP\" : \"MOV.W\t0(r1), 2(r1) { ADD\t#2, SP\"; - ") + " + [(set (attr "length") + (if_then_else (match_test "TARGET_LARGE") + (const_int 10) + (const_int 8)))] +) ; I set LOAD_EXTEND_OP and WORD_REGISTER_OPERATIONS, but gcc puts in a ; zero_extend anyway. Catch it here. @@ -189,6 +300,7 @@ "@ MOV.B\t%1, %0 MOV%X1.B\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "movqi_topbyte" @@ -196,6 +308,8 @@ (subreg:QI (match_operand:PSI 1 "msp430_general_operand" "r") 2))] "msp430x" "PUSHM.A\t#1,%1 { POPM.W\t#1,%0 { POPM.W\t#1,%0" + [(set_attr "length" "6") + (set_attr "type" "double")] ) (define_insn "movqi" @@ -205,6 +319,7 @@ "@ MOV.B\t%1, %0 MOVX.B\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "movhi" @@ -215,6 +330,7 @@ MOV.B\t%1, %0 MOV.W\t%1, %0 MOVX.W\t%1, %0" + [(set_attr "type" "double")] ) (define_expand "movsi" @@ -222,7 +338,7 @@ (match_operand:SI 1 "general_operand"))] "" "" - ) +) (define_insn_and_split "movsi_s" [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") @@ -235,7 +351,8 @@ (set (match_operand:HI 3 "msp430_general_dst_nonv_operand") (match_operand:HI 5 "general_operand"))] "msp430_split_movsi (operands);" - ) + [(set_attr "type" "double")] +) (define_insn_and_split "movsi_x" [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=rm") @@ -248,6 +365,7 @@ (set (match_operand:HI 3 "msp430_general_dst_nonv_operand") (match_operand:HI 5 "general_operand"))] "msp430_split_movsi (operands);" + [(set_attr "type" "double")] ) ;; FIXME: Some MOVX.A cases can be done with MOVA, this is only a few of them. @@ -260,7 +378,10 @@ MOV.W\t%1, %0 MOVA\t%1, %0 MOVA\t%1, %0 - MOVX.A\t%1, %0") + MOVX.A\t%1, %0" + [(set_attr "extension" "none,none,a,a,x") + (set_attr "type" "double")] +) ; This pattern is identical to the truncsipsi2 pattern except ; that it uses a SUBREG instead of a TRUNC. It is needed in @@ -274,6 +395,8 @@ (subreg:PSI (match_operand:SI 1 "register_operand" "r") 0))] "msp430x" "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A #1, %0 ; Move reg-pair %L1:%H1 into pointer %0" + [(set_attr "length" "6") + (set_attr "type" "double")] ) ;; Produced when converting a pointer to an integer via a union, eg gcc.dg/pr47201.c. @@ -282,6 +405,8 @@ (subreg:HI (match_operand:PSI 1 "msp430_symbol_operand" "i") 0))] "msp430x" "MOVA\t%1, %0" + [(set_attr "extension" "a") + (set_attr "type" "double")] ) ;;------------------------------------------------------------ @@ -295,6 +420,8 @@ "@ ADDA\t%2, %0 ADDX.A\t%2, %0" + [(set_attr "extension" "a,x") + (set_attr "type" "triple")] ) (define_insn "addqi3" @@ -305,6 +432,7 @@ "@ ADD.B\t%2, %0 ADDX.B\t%2, %0" + [(set_attr "type" "triple")] ) (define_insn "addhi3" @@ -315,6 +443,7 @@ "@ ADD.W\t%2, %0 ADDX.W\t%2, %0" + [(set_attr "type" "triple")] ) ; This pattern is needed in order to avoid reload problems. @@ -327,6 +456,13 @@ (match_operand 2 "general_operand" "rmi")))] "" "ADD%X2.W\t%L2, %L0 { ADDC%X2.W\t%H2, %H0 { PUSH.W\t%H0 { PUSH.W\t%L0 { POPM.A\t#1, %0" + [(set (attr "length") + (if_then_else (match_operand 2 "register_operand" "") + (const_int 10) + (if_then_else (match_operand 2 "msp430_high_memory_operand" "") + (const_int 18) + (const_int 14)))) + (set_attr "type" "triple")] ) (define_insn "addsi3" @@ -337,6 +473,8 @@ "@ ADD\t%L2, %L0 { ADDC\t%H2, %H0 ADDX\t%L2, %L0 { ADDCX\t%H2, %H0" + [(set_attr "length_multiplier" "2") + (set_attr "type" "triple")] ) ; Version of addhi that exposes the carry operations, for SImode adds. @@ -382,7 +520,8 @@ "@ ADD\t%2, %1 ; cy ADDX\t%2, %1 ; cy" - ) + [(set_attr "type" "triple")] +) (define_insn "addhi3_cy_i" [(set (match_operand:HI 0 "msp430_general_dst_nonv_operand" "=r,rm") @@ -397,7 +536,8 @@ "@ ADD\t%2, %1 ; cy ADD%X0\t%2, %1 ; cy" - ) + [(set_attr "type" "triple")] +) ; Version of addhi that adds the carry, for SImode adds. (define_insn "addchi4_cy" @@ -410,7 +550,8 @@ "@ ADDC\t%2, %1 ADDCX\t%2, %1" - ) + [(set_attr "type" "triple")] +) ; Split an SImode add into two HImode adds, keeping track of the carry ; so that gcc knows when it can and can't optimize away the two @@ -440,7 +581,7 @@ if (msp430_split_addsi (operands)) FAIL; " - ) +) ;; Alternatives 2 and 3 are to handle cases generated by reload. @@ -454,6 +595,9 @@ SUBX.A\t%2, %0 MOVX.A\t%1, %0 { SUBX.A\t%2, %0 MOVX.A\t%1, %0 { SUBA\t%2, %0" + [(set_attr "type" "triple") + (set_attr "extension" "a,x,x,x") + (set_attr "length_multiplier" "1,1,2,2")] ) ;; Alternatives 2 and 3 are to handle cases generated by reload. @@ -467,6 +611,8 @@ SUBX.B\t%2, %0 MOV%X2.B\t%1, %0 { SUB%X2.B\t%2, %0 MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0" + [(set_attr "length_multiplier" "1,1,2,2") + (set_attr "type" "triple")] ) ;; Alternatives 2 and 3 are to handle cases generated by reload. @@ -480,6 +626,8 @@ SUBX.W\t%2, %0 MOV%X2.W\t%1, %0 { SUB%X2.W\t%2, %0 MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0" + [(set_attr "length_multiplier" "1,1,2,2") + (set_attr "type" "triple")] ) (define_insn "subsi3" @@ -490,6 +638,8 @@ "@ SUB\t%L2, %L0 { SUBC\t%H2, %H0 SUBX\t%L2, %L0 { SUBCX\t%H2, %H0" + [(set_attr "length_multiplier" "2") + (set_attr "type" "triple")] ) (define_insn "*bic<mode>_cg" @@ -500,6 +650,8 @@ "@ BIC%x0%b0\t#%I2, %0 BIC%X0%b0\t#%I2, %0" + [(set_attr "length" "2") ; Smaller length achieved by using constant generator + (set_attr "type" "double")] ) (define_insn "bic<mode>3" @@ -510,6 +662,7 @@ "@ BIC%x0%b0\t%1, %0 BICX%b0\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "and<mode>3" @@ -521,6 +674,7 @@ AND%x0.B\t%2, %0 AND%x0%b0\t%2, %0 ANDX%b0\t%2, %0" + [(set_attr "type" "triple")] ) (define_insn "ior<mode>3" @@ -531,6 +685,7 @@ "@ BIS%x0%b0\t%2, %0 BISX%b0\t%2, %0" + [(set_attr "type" "triple")] ) (define_insn "xor<mode>3" @@ -541,6 +696,7 @@ "@ XOR%x0%b0\t%2, %0 XORX%b0\t%2, %0" + [(set_attr "type" "triple")] ) ;; Macro : XOR #~0, %0 @@ -551,6 +707,7 @@ "@ INV%x0%b0\t%0 INV%X0%b0\t%0" + [(set_attr "type" "double")] ) (define_insn "extendqihi2" @@ -560,6 +717,7 @@ "@ SXT%X0\t%0 SXT%X0\t%0" + [(set_attr "type" "single")] ) (define_insn "extendqipsi2" @@ -569,6 +727,8 @@ "@ SXT\t%0 SXTX.A\t%0" + [(set_attr "type" "single") + (set_attr "extension" "none,x")] ) ;; ------------------------ @@ -590,6 +750,7 @@ MOV.B\t%1, %0 MOV%X1.B\t%1, %0 AND%X0\t#0xff, %0" + [(set_attr "type" "double")] ) (define_insn "zero_extendqipsi2" @@ -599,6 +760,7 @@ "@ MOV.B\t%1, %0 MOV%X1.B\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "zero_extendqisi2" @@ -608,6 +770,9 @@ "@ CLR\t%H0 MOV%X1.B\t%1,%L0 { CLR\t%H0" + [(set_attr "extra_length" "2") + (set_attr "length_multiplier" "1,2") + (set_attr "type" "double")] ) (define_insn "zero_extendhipsi2" @@ -618,6 +783,7 @@ MOV.W\t%1, %0 MOV%X1\t%1, %0 MOVX.A\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "zero_extendhisi2" @@ -627,6 +793,8 @@ "@ MOV%X0.W\t#0,%H0 MOV.W\t%1,%L0 { MOV.W\t#0,%H0" + [(set_attr "length_multiplier" "1,2") + (set_attr "type" "double")] ) (define_insn "zero_extendhisipsi2" @@ -636,6 +804,8 @@ "@ AND.W\t#-1,%0 MOV.W\t%1,%0" + [(set_attr "length" "4,2") + (set_attr "type" "double")] ) ; Nasty - we are sign-extending a 20-bit PSI value in one register into @@ -671,6 +841,13 @@ else \ return \"PUSHM.A\t#1, %1 { POPX.W\t%L0 { POPX.W\t%H0 ; move pointer in %1 into reg-pair %L0:%H0\"; MOVX.A %1, %0" + [(set (attr "length") + (cond [(match_test "REGNO (operands[1]) == SP_REGNO") + (const_int 18) + (eq_attr "alternative" "1") + (const_int 6)] + (const_int 10))) + (set_attr "type" "double")] ) ;; Below are unnamed insn patterns to catch pointer manipulation insns @@ -687,6 +864,7 @@ (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0)))] "msp430x" "MOV%X1.B\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "" @@ -696,6 +874,7 @@ "@ MOV.B\t%1, %0 MOV%X1.B\t%1, %0" + [(set_attr "type" "double")] ) ;; The next three insns emit identical assembly code. @@ -711,6 +890,9 @@ RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" + [(set_attr "length" "4,*,*") + (set_attr "extra_length" "0,4,6") + (set_attr "type" "double")] ) (define_insn "" @@ -722,6 +904,9 @@ RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" + [(set_attr "length" "4,*,*") + (set_attr "extra_length" "0,4,6") + (set_attr "type" "double")] ) ;; Same as above but with a NOP sign_extend round the subreg @@ -734,6 +919,9 @@ RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RLAM.W %2, %L0 { CLR %H0 MOV%X1.B %1, %L0 { RPT %2 { RLAX.W %L0 { CLR %H0" + [(set_attr "length" "4,*,*") + (set_attr "extra_length" "0,4,6") + (set_attr "type" "double")] ) (define_insn "" @@ -741,6 +929,8 @@ (zero_extend:SI (sign_extend:PSI (subreg:HI (match_operand:QI 1 "general_operand" "rm") 0))))] "msp430x" "MOV%X1.B %1, %L0 { CLR %H0" + [(set_attr "extra_length" "4") + (set_attr "type" "double")] ) (define_insn "" @@ -752,6 +942,9 @@ RLAM.W %2, %0 MOV%X1.B %1, %0 { RLAM.W %2, %0 MOV%X1.B %1, %0 { RPT %2 { RLAX.A %0" + [(set_attr "length" "2,*,*") + (set_attr "extra_length" "0,2,4") + (set_attr "type" "double")] ) ;; END msp430 pointer manipulation combine insn patterns @@ -771,13 +964,18 @@ (truncate:HI (match_operand:PSI 1 "register_operand" "r")))] "" "MOVX\t%1, %0" + [(set_attr "extension" "m") + (set_attr "type" "double")] ) (define_insn "extendhisi2" [(set (match_operand:SI 0 "msp430_general_dst_nonv_operand" "=r") (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))] "" - { return msp430x_extendhisi (operands); } + { msp430x_extendhisi (operands, 0); return ""; } + [(set (attr "length") + (symbol_ref "msp430x_extendhisi (operands, 1)")) + (set_attr "type" "double")] ) (define_insn "extendhipsi2" @@ -785,6 +983,9 @@ (subreg:PSI (sign_extend:SI (match_operand:HI 1 "general_operand" "0")) 0))] "msp430x" "RLAM.A #4, %0 { RRAM.A #4, %0" + [(set_attr "length_multiplier" "2") + (set_attr "extension" "m") + (set_attr "type" "double")] ) ;; Look for cases where integer/pointer conversions are suboptimal due @@ -798,6 +999,9 @@ (const_int 1)))] "msp430x" "RLAM.A #4, %0 { RRAM.A #3, %0" + [(set_attr "length_multiplier" "2") + (set_attr "extension" "m") + (set_attr "type" "double")] ) (define_insn "extend_and_shift2_hipsi2" @@ -806,6 +1010,9 @@ (const_int 2)))] "msp430x" "RLAM.A #4, %0 { RRAM.A #2, %0" + [(set_attr "length_multiplier" "2") + (set_attr "extension" "m") + (set_attr "type" "double")] ) ;; We also need to be able to sign-extend pointer types (eg ptrdiff_t). @@ -827,6 +1034,8 @@ else return \"MOV.W\t%1, %L0 { MOVX.A\t%1, %H0 { RPT\t#16 { RRAX.A\t%H0 ; sign extend pointer in %1 into %L0:%H0\"; " + [(set_attr "length" "10") + (set_attr "type" "double")] ) ; See the movsipsi2 pattern above for another way that GCC performs this @@ -836,6 +1045,8 @@ (truncate:PSI (match_operand:SI 1 "register_operand" "r")))] "" "PUSH.W\t%H1 { PUSH.W\t%L1 { POPM.A\t#1, %L0" + [(set_attr "length" "6") + (set_attr "type" "single")] ) ;;------------------------------------------------------------ @@ -886,7 +1097,10 @@ (any_shift:HI (match_operand:HI 1 "general_operand" "0") (match_operand:HI 2 "const_int_operand" "n")))] "!msp430x" - "* return msp430_output_asm_shift_insns (<CODE>, HImode, operands);" + "* msp430_output_asm_shift_insns (<CODE>, HImode, operands, false); return \"\";" + [(set (attr "length") + (symbol_ref "msp430_output_asm_shift_insns (<CODE>, HImode, operands, true)")) + (set_attr "type" "single")] ) ;; All 430 and 430X SImode constant shifts @@ -895,7 +1109,10 @@ (any_shift:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "const_int_operand" "n")))] "" - "* return msp430_output_asm_shift_insns (<CODE>, SImode, operands);" + "* msp430_output_asm_shift_insns (<CODE>, SImode, operands, false); return \"\";" + [(set (attr "length") + (symbol_ref "msp430_output_asm_shift_insns (<CODE>, SImode, operands, true)")) + (set_attr "type" "single")] ) (define_insn "ashl<mode>3_430x" @@ -908,6 +1125,8 @@ RPT\t%2 { RLAX%b0\t%0 RPT\t#16 { RLAX%b0\t%0 { RPT\t%W2 { RLAX%b0\t%0 # undefined behavior left shift of %1 by %2" + [(set_attr "length" "2,4,8,0") + (set_attr "type" "single")] ) (define_insn "ashr<mode>3_430x" @@ -920,6 +1139,8 @@ RPT\t%2 { RRAX%b0\t%0 RPT\t#16 { RRAX%b0\t%0 { RPT\t%W2 { RRAX%b0\t%0 # undefined behavior arithmetic right shift of %1 by %2" + [(set_attr "length" "2,4,8,0") + (set_attr "type" "single")] ) (define_insn "lshr<mode>3_430x" @@ -932,6 +1153,8 @@ RPT\t%2 { RRUX%b0\t%0 RPT\t#16 { RRUX%b0\t%0 { RPT\t%W2 { RRUX%b0\t%0 # undefined behavior logical right shift of %1 by %2" + [(set_attr "length" "2,4,8,0") + (set_attr "type" "single")] ) ;;------------------------------------------------------------ @@ -941,39 +1164,43 @@ [(const_int 0)] "" "msp430_expand_prologue (); DONE;" - ) +) (define_expand "epilogue" [(const_int 0)] "" "msp430_expand_epilogue (0); DONE;" - ) +) (define_insn "epilogue_helper" [(set (pc) - (unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)) + (unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)) (return)] - "" + "!msp430x" "BR%Q0\t#__mspabi_func_epilog_%J0" - ) + [(set_attr "length" "2")] +) (define_insn "prologue_start_marker" [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)] "" "; start of prologue" - ) + [(set_attr "length" "0")] +) (define_insn "prologue_end_marker" [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)] "" "; end of prologue" - ) + [(set_attr "length" "0")] +) (define_insn "epilogue_start_marker" [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)] "" "; start of epilogue" - ) + [(set_attr "length" "0")] +) ;; This makes the linker add a call to exit() after the call to main() ;; in crt0 @@ -981,7 +1208,8 @@ [(unspec_volatile [(const_int 0)] UNS_REFSYM_NEED_EXIT)] "" ".refsym\t__crt0_call_exit" - ) + [(set_attr "length" "0")] +) ;;------------------------------------------------------------ ;; Jumps @@ -998,6 +1226,8 @@ (match_operand 1 ""))] "" "CALL%Q0\t%0" + [(set_attr "extension" "none") + (set_attr "type" "single")] ) (define_expand "call_value" @@ -1014,12 +1244,15 @@ (match_operand 2 "")))] "" "CALL%Q0\t%1" + [(set_attr "extension" "none") + (set_attr "type" "single")] ) (define_insn "msp430_return" [(return)] "" { return msp430_is_interrupt_func () ? "RETI" : (TARGET_LARGE ? "RETA" : "RET"); } + [(set_attr "length" "2")] ) ;; This pattern is NOT, as expected, a return pattern. It's called @@ -1045,13 +1278,15 @@ "reload_completed" [(const_int 0)] "msp430_expand_epilogue (1); DONE;" - ) + [(set_attr "length" "40")] +) (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" "BR%Q0\t#%l0" + [(set_attr "length" "4")] ) ;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs @@ -1061,6 +1296,10 @@ (match_operand 0 "nonimmediate_operand" "rYl"))] "" "BR%Q0\t%0" + [(set (attr "length") + (if_then_else (match_operand 0 "register_operand" "") + (const_int 2) + (const_int 4)))] ) ;;------------------------------------------------------------ @@ -1077,14 +1316,14 @@ )] "" "msp430_fixup_compare_operands (<MODE>mode, operands);" - ) +) (define_insn "cbranchpsi4_real" [(set (pc) (if_then_else (match_operator 0 "msp430_cmp_operator" [(match_operand:PSI 1 "msp430_general_dst_nonv_operand" "r,rYs,rm") (match_operand:PSI 2 "general_operand" "rLs,rYsi,rmi")]) - (label_ref (match_operand 3 "" "")) + (label_ref (match_operand 3 "" "")) (pc))) (clobber (reg:BI CARRY)) ] @@ -1093,7 +1332,9 @@ CMP%Q0\t%2, %1 { J%0\t%l3 CMPX.A\t%2, %1 { J%0\t%l3 CMPX.A\t%2, %1 { J%0\t%l3" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] +) (define_insn "cbranchqi4_real" [(set (pc) (if_then_else @@ -1108,7 +1349,9 @@ "@ CMP.B\t%2, %1 { J%0\t%l3 CMPX.B\t%2, %1 { J%0\t%l3" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] +) (define_insn "cbranchhi4_real" [(set (pc) (if_then_else @@ -1123,6 +1366,8 @@ "@ CMP.W\t%2, %1 { J%0\t%l3 CMPX.W\t%2, %1 { J%0\t%l3" + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] ) (define_insn "cbranchpsi4_reversed" @@ -1139,7 +1384,9 @@ CMP%Q0\t%1, %2 { J%R0\t%l3 CMPX.A\t%1, %2 { J%R0\t%l3 CMPX.A\t%1, %2 { J%R0\t%l3" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] +) (define_insn "cbranchqi4_reversed" [(set (pc) (if_then_else @@ -1154,7 +1401,9 @@ "@ CMP.B\t%1, %2 { J%R0\t%l3 CMPX.B\t%1, %2 { J%R0\t%l3" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] +) (define_insn "cbranchhi4_reversed" [(set (pc) (if_then_else @@ -1169,14 +1418,16 @@ "@ CMP.W\t%1, %2 { J%R0\t%l3 CMPX.W\t%1, %2 { J%R0\t%l3" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "cmp")] +) (define_insn "*bitbranch<mode>4" [(set (pc) (if_then_else (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) (const_int 0)) - (label_ref (match_operand 2 "" "")) + (label_ref (match_operand 2 "" "")) (pc))) (clobber (reg:BI CARRY)) ] @@ -1184,14 +1435,16 @@ "@ BIT%x0%b0\t%1, %0 { JNE\t%l2 BITX%b0\t%1, %0 { JNE\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch<mode>4" [(set (pc) (if_then_else (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) (const_int 0)) - (label_ref (match_operand 2 "" "")) + (label_ref (match_operand 2 "" "")) (pc))) (clobber (reg:BI CARRY)) ] @@ -1199,14 +1452,16 @@ "@ BIT%x0%b0\t%1, %0 { JEQ\t%l2 BITX%b0\t%1, %0 { JEQ\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch<mode>4" [(set (pc) (if_then_else (eq (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) (const_int 0)) - (pc) + (pc) (label_ref (match_operand 2 "" "")))) (clobber (reg:BI CARRY)) ] @@ -1214,14 +1469,16 @@ "@ BIT%x0%b0\t%1, %0 { JNE\t%l2 BITX%b0\t%1, %0 { JNE\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch<mode>4" [(set (pc) (if_then_else (ne (and:QHI (match_operand:QHI 0 "msp430_general_dst_operand" "rYsYx,rm") (match_operand:QHI 1 "msp430_general_operand" "rYsYxi,rmi")) (const_int 0)) - (pc) + (pc) (label_ref (match_operand 2 "" "")))) (clobber (reg:BI CARRY)) ] @@ -1229,7 +1486,9 @@ "@ BIT%x0%b0\t%1, %0 { JEQ\t%l2 BITX%b0\t%1, %0 { JEQ\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) ;;------------------------------------------------------------ ;; zero-extract versions of the above @@ -1240,7 +1499,7 @@ (const_int 1) (match_operand 1 "const_0_to_15_operand" "i,i")) (const_int 0)) - (label_ref (match_operand 2 "" "")) + (label_ref (match_operand 2 "" "")) (pc))) (clobber (reg:BI CARRY)) ] @@ -1248,7 +1507,9 @@ "@ BIT%x0%b0\t%p1, %0 { JNE\t%l2 BIT%X0%b0\t%p1, %0 { JNE\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch<mode>4_z" [(set (pc) (if_then_else @@ -1256,13 +1517,15 @@ (const_int 1) (match_operand 1 "const_0_to_15_operand" "i")) (const_int 0)) - (label_ref (match_operand 2 "" "")) + (label_ref (match_operand 2 "" "")) (pc))) (clobber (reg:BI CARRY)) ] "" "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch<mode>4_z" [(set (pc) (if_then_else @@ -1270,13 +1533,15 @@ (const_int 1) (match_operand 1 "const_0_to_15_operand" "i")) (const_int 0)) - (pc) + (pc) (label_ref (match_operand 2 "" "")))) (clobber (reg:BI CARRY)) ] "" "BIT%X0%b0\t%p1, %0 { JNE\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) (define_insn "*bitbranch<mode>4_z" [(set (pc) (if_then_else @@ -1284,13 +1549,15 @@ (const_int 1) (match_operand 1 "const_0_to_15_operand" "i")) (const_int 0)) - (pc) + (pc) (label_ref (match_operand 2 "" "")))) (clobber (reg:BI CARRY)) ] "" "BIT%X0%b0\t%p1, %0 { JEQ\t%l2" - ) + [(set_attr "extra_length" "2") + (set_attr "type" "double")] +) ;;------------------------------------------------------------ ;; Misc @@ -1299,31 +1566,36 @@ [(const_int 0)] "1" "NOP" + [(set_attr "length" "2")] ) (define_insn "disable_interrupts" [(unspec_volatile [(const_int 0)] UNS_DINT)] "" "DINT \; NOP" - ) + [(set_attr "length" "2")] +) (define_insn "enable_interrupts" [(unspec_volatile [(const_int 0)] UNS_EINT)] "" "EINT" - ) + [(set_attr "length" "2")] +) (define_insn "push_intr_state" [(unspec_volatile [(const_int 0)] UNS_PUSH_INTR)] "" "PUSH\tSR" - ) + [(set_attr "length" "2")] +) (define_insn "pop_intr_state" [(unspec_volatile [(const_int 0)] UNS_POP_INTR)] "" "POP\tSR" - ) + [(set_attr "length" "2")] +) ;; Clear bits in the copy of the status register that is currently ;; saved on the stack at the top of the interrupt handler. @@ -1331,7 +1603,9 @@ [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIC_SR)] "" "BIC.W\t%0, %O0(SP)" - ) + [(set_attr "type" "single") + (set_attr "extra_length" "2")] +) ;; Set bits in the copy of the status register that is currently ;; saved on the stack at the top of the interrupt handler. @@ -1339,30 +1613,33 @@ [(unspec_volatile [(match_operand 0 "nonmemory_operand" "ir")] UNS_BIS_SR)] "" "BIS.W\t%0, %O0(SP)" - ) + [(set_attr "type" "single") + (set_attr "extra_length" "2")] +) ;; For some reason GCC is generating (set (reg) (and (neg (reg)) (int))) ;; very late on in the compilation and not splitting it into separate ;; instructions, so we provide a pattern to support it here. (define_insn "andneghi3" - [(set (match_operand:HI 0 "register_operand" "=r") - (and:HI (neg:HI (match_operand:HI 1 "general_operand" "rm")) - (match_operand 2 "immediate_operand" "n")))] + [(set (match_operand:HI 0 "register_operand" "=r,r") + (and:HI (neg:HI (match_operand:HI 1 "general_operand" "0,rm")) + (match_operand 2 "immediate_operand" "n,n")))] "" - "* - if (REGNO (operands[0]) != REGNO (operands[1])) - return \"MOV%X1.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; - else - return \"INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0\"; - " - ) + "@ + INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0 + MOV%X1.W\t%1, %0 { INV.W\t%0 { INC.W\t%0 { AND.W\t%2, %0" + [(set_attr "length" "12,14") + (set_attr "type" "double")] +) + (define_insn "delay_cycles_start" [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_DELAY_START)] "" "; Begin %J0 cycle delay" - ) + [(set_attr "length" "0")] +) (define_insn "delay_cycles_end" [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] @@ -1387,7 +1664,8 @@ JNE 1b POP r14 POP r13" - ) + [(set_attr "length" "32")] +) (define_insn "delay_cycles_32x" [(unspec_volatile [(match_operand 0 "immediate_operand" "i") @@ -1403,7 +1681,8 @@ TST.W r13 JNE 1b POPM.A #2,r14" - ) + [(set_attr "length" "28")] +) (define_insn "delay_cycles_16" [(unspec_volatile [(match_operand 0 "immediate_operand" "i") @@ -1415,7 +1694,8 @@ 1: SUB.W #1, r13 JNE 1b POP r13" - ) + [(set_attr "length" "14")] +) (define_insn "delay_cycles_16x" [(unspec_volatile [(match_operand 0 "immediate_operand" "i") @@ -1427,19 +1707,22 @@ 1: SUB.W #1, r13 JNE 1b POPM.A #1,r13" - ) + [(set_attr "length" "14")] +) (define_insn "delay_cycles_2" [(unspec_volatile [(const_int 0) ] UNS_DELAY_2)] "" "JMP .+2" - ) + [(set_attr "length" "2")] +) (define_insn "delay_cycles_1" [(unspec_volatile [(const_int 0) ] UNS_DELAY_1)] "" "NOP" - ) + [(set_attr "length" "2")] +) ; libgcc helper functions for widening multiplication aren't currently ; generated by gcc, so we can't catch them later and map them to the mspabi @@ -1494,6 +1777,7 @@ else return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x0132 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\"; " + [(set_attr "length" "24")] ) (define_insn "*umulhisi3_inline" @@ -1507,6 +1791,7 @@ else return \"PUSH.W sr { DINT { NOP { MOV.W %1, &0x0130 { MOV.W %2, &0x0138 { MOV.W &0x013A, %L0 { MOV.W &0x013C, %H0 { POP.W sr\"; " + [(set_attr "length" "24")] ) (define_insn "mulsidi3" @@ -1520,6 +1805,7 @@ else return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x0144 { MOV.W %H1, &0x0146 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0 { POP.W sr\"; " + [(set_attr "length" "40")] ) (define_insn "umulsidi3" @@ -1533,4 +1819,5 @@ else return \"PUSH.W sr { DINT { NOP { MOV.W %L1, &0x0140 { MOV.W %H1, &0x0142 { MOV.W %L2, &0x0150 { MOV.W %H2, &0x0152 { MOV.W &0x0154, %A0 { MOV.W &0x0156, %B0 { MOV.W &0x0158, %C0 { MOV.W &0x015A, %D0 { POP.W sr\"; " + [(set_attr "length" "40")] ) diff --git a/gcc/config/msp430/predicates.md b/gcc/config/msp430/predicates.md index 4bfa0c0..eb1f61d 100644 --- a/gcc/config/msp430/predicates.md +++ b/gcc/config/msp430/predicates.md @@ -131,3 +131,16 @@ (define_predicate "msp430_symbol_operand" (match_code "symbol_ref") ) + +; Used in length attribute tests - if a source operand is a reg, +; (mem (post_inc)), or (mem (reg)) then it is cheap compared to other operand +; types. +(define_predicate "msp430_cheap_operand" + (ior (match_code "reg") + (and (match_code "mem") + (ior (match_code "reg" "0") + (match_code "post_inc" "0"))))) + +; Used for insn attributes only. For insn patterns themselves, use constraints. +(define_predicate "msp430_high_memory_operand" + (match_test "msp430x_insn_required (op)")) |
