aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/config/msp430/msp430-protos.h5
-rw-r--r--gcc/config/msp430/msp430.c162
-rw-r--r--gcc/config/msp430/msp430.h10
-rw-r--r--gcc/config/msp430/msp430.md437
-rw-r--r--gcc/config/msp430/predicates.md13
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)"))