From 546c8f955804ad74b0382b012f64e621a02eebde Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz Date: Fri, 13 Nov 2020 15:35:47 +0000 Subject: [PATCH] MSP430: Add defaulting to the insn length attribute The length of MSP430 instructions is mostly just a function of the type and number of operands. Setting the "type" attribute on all insns describes the number of operands, and the position of the source and destination operands. In most cases, defaulting in the "length" and "extension" attribute definitions can then be used to calculate the total length of the instruction by using the value of the "type" attribute to examine the operands. gcc/ChangeLog: * config/msp430/msp430-protos.h (msp430x_extendhisi): Return int instead of char *. (msp430_output_asm_shift_insns): Likewise. Add new return_length argument. (msp430x_insn_required): Add prototype. * config/msp430/msp430.c (msp430_output_asm_shift_insns): Return the total length, in bytes, of the emitted instructions. (msp430x_insn_required): New function. (msp430x_extendhisi): Return the total length, in bytes, of the emitted instructions. * config/msp430/msp430.h (ADJUST_INSN_LENGTH): Define. * config/msp430/msp430.md: New define_attr "type". New define_attr "extension". New define_attr "length_multiplier". New define_attr "extra_length". Rewrite define_attr "length". Set type, extension, length, length_multiplier or extra_length insn attributes on all insns, as appropriate. (andneghi3): Rewrite using constraints instead of C code to decide output insns. * config/msp430/predicates.md (msp430_cheap_operand): New predicate. (msp430_high_memory_operand): New predicate. --- gcc/config/msp430/msp430-protos.h | 5 +- gcc/config/msp430/msp430.c | 162 ++++++++--- gcc/config/msp430/msp430.h | 10 + gcc/config/msp430/msp430.md | 437 +++++++++++++++++++++++++----- 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 0b4d9a42b41..33ad1adc61f 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 9f7635118b1..cc3472e853d 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 cbranch4 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 25007716d24..c2fcaef6c50 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 ad244bb0f33..65e951774b1 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_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 "bic3" @@ -510,6 +662,7 @@ "@ BIC%x0%b0\t%1, %0 BICX%b0\t%1, %0" + [(set_attr "type" "double")] ) (define_insn "and3" @@ -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 "ior3" @@ -531,6 +685,7 @@ "@ BIS%x0%b0\t%2, %0 BISX%b0\t%2, %0" + [(set_attr "type" "triple")] ) (define_insn "xor3" @@ -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 (, HImode, operands);" + "* msp430_output_asm_shift_insns (, HImode, operands, false); return \"\";" + [(set (attr "length") + (symbol_ref "msp430_output_asm_shift_insns (, 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 (, SImode, operands);" + "* msp430_output_asm_shift_insns (, SImode, operands, false); return \"\";" + [(set (attr "length") + (symbol_ref "msp430_output_asm_shift_insns (, SImode, operands, true)")) + (set_attr "type" "single")] ) (define_insn "ashl3_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 "ashr3_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 "lshr3_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, 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 "*bitbranch4" [(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 "*bitbranch4" [(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 "*bitbranch4" [(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 "*bitbranch4" [(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 "*bitbranch4_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 "*bitbranch4_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 "*bitbranch4_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 4bfa0c0f2d5..eb1f61df780 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)")) -- 2.30.2