Skip to content

Commit 546c8f9

Browse files
committed
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.
1 parent f62dd39 commit 546c8f9

File tree

5 files changed

+506
-121
lines changed

5 files changed

+506
-121
lines changed

gcc/config/msp430/msp430-protos.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ void msp430_expand_eh_return (rtx);
2626
void msp430_expand_epilogue (int);
2727
void msp430_expand_helper (rtx *operands, const char *, bool);
2828
void msp430_expand_prologue (void);
29-
const char * msp430x_extendhisi (rtx *);
29+
int msp430x_extendhisi (rtx *, bool);
3030
void msp430_fixup_compare_operands (machine_mode, rtx *);
3131
int msp430_hard_regno_nregs_has_padding (int, machine_mode);
3232
int msp430_hard_regno_nregs_with_padding (int, machine_mode);
@@ -49,10 +49,11 @@ rtx msp430_subreg (machine_mode, rtx, machine_mode, int);
4949
bool msp430_use_f5_series_hwmult (void);
5050
bool msp430_has_hwmult (void);
5151
bool msp430_op_not_in_high_mem (rtx op);
52+
bool msp430x_insn_required (rtx op);
5253

5354
#ifdef RTX_CODE
5455
int msp430_expand_shift (enum rtx_code code, machine_mode mode, rtx *operands);
55-
const char * msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, rtx *operands);
56+
int msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode, rtx *operands, bool);
5657
#endif
5758

5859
#endif /* GCC_MSP430_PROTOS_H */

gcc/config/msp430/msp430.c

Lines changed: 118 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3520,18 +3520,22 @@ msp430_expand_shift (enum rtx_code code, machine_mode mode, rtx *operands)
35203520
For 430X it is inneficient to do so for any modes except SI and DI, since we
35213521
can make use of R*M insns or RPT with 430X insns, so this function is only
35223522
used for SImode in that case. */
3523-
const char *
3523+
int
35243524
msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode,
3525-
rtx *operands)
3525+
rtx *operands, bool return_length)
35263526
{
35273527
int i;
35283528
int amt;
35293529
int max_shift = GET_MODE_BITSIZE (mode) - 1;
3530+
int length = 0;
3531+
35303532
gcc_assert (CONST_INT_P (operands[2]));
35313533
amt = INTVAL (operands[2]);
35323534

35333535
if (amt == 0 || amt > max_shift)
35343536
{
3537+
if (return_length)
3538+
return 0;
35353539
switch (code)
35363540
{
35373541
case ASHIFT:
@@ -3549,51 +3553,90 @@ msp430_output_asm_shift_insns (enum rtx_code code, machine_mode mode,
35493553
default:
35503554
gcc_unreachable ();
35513555
}
3552-
return "";
3556+
return 0;
35533557
}
35543558

35553559
if (code == ASHIFT)
35563560
{
35573561
if (!msp430x && mode == HImode)
3558-
for (i = 0; i < amt; i++)
3559-
output_asm_insn ("RLA.W\t%0", operands);
3562+
{
3563+
if (return_length)
3564+
length = 2 + (MEM_P (operands[0]) ? 2 : 0);
3565+
else
3566+
for (i = 0; i < amt; i++)
3567+
output_asm_insn ("RLA.W\t%0", operands);
3568+
}
35603569
else if (mode == SImode)
3561-
for (i = 0; i < amt; i++)
3562-
output_asm_insn ("RLA%X0.W\t%L0 { RLC%X0.W\t%H0", operands);
3570+
{
3571+
if (return_length)
3572+
length = 4 + (MEM_P (operands[0]) ? 4 : 0)
3573+
+ (4 * msp430x_insn_required (operands[0]));
3574+
else
3575+
for (i = 0; i < amt; i++)
3576+
output_asm_insn ("RLA%X0.W\t%L0 { RLC%X0.W\t%H0", operands);
3577+
}
35633578
else
35643579
/* Catch unhandled cases. */
35653580
gcc_unreachable ();
35663581
}
35673582
else if (code == ASHIFTRT)
35683583
{
35693584
if (!msp430x && mode == HImode)
3570-
for (i = 0; i < amt; i++)
3571-
output_asm_insn ("RRA.W\t%0", operands);
3585+
{
3586+
if (return_length)
3587+
length = 2 + (MEM_P (operands[0]) ? 2 : 0);
3588+
else
3589+
for (i = 0; i < amt; i++)
3590+
output_asm_insn ("RRA.W\t%0", operands);
3591+
}
35723592
else if (mode == SImode)
3573-
for (i = 0; i < amt; i++)
3574-
output_asm_insn ("RRA%X0.W\t%H0 { RRC%X0.W\t%L0", operands);
3593+
{
3594+
if (return_length)
3595+
length = 4 + (MEM_P (operands[0]) ? 4 : 0)
3596+
+ (4 * msp430x_insn_required (operands[0]));
3597+
else
3598+
for (i = 0; i < amt; i++)
3599+
output_asm_insn ("RRA%X0.W\t%H0 { RRC%X0.W\t%L0", operands);
3600+
}
35753601
else
35763602
gcc_unreachable ();
35773603
}
35783604
else if (code == LSHIFTRT)
35793605
{
35803606
if (!msp430x && mode == HImode)
3581-
for (i = 0; i < amt; i++)
3582-
output_asm_insn ("CLRC { RRC.W\t%0", operands);
3607+
{
3608+
if (return_length)
3609+
length = 4 + (MEM_P (operands[0]) ? 2 : 0);
3610+
else
3611+
for (i = 0; i < amt; i++)
3612+
output_asm_insn ("CLRC { RRC.W\t%0", operands);
3613+
}
35833614
else if (mode == SImode)
3584-
for (i = 0; i < amt; i++)
3585-
output_asm_insn ("CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0", operands);
3615+
{
3616+
if (return_length)
3617+
length = 6 + (MEM_P (operands[0]) ? 4 : 0)
3618+
+ (4 * msp430x_insn_required (operands[0]));
3619+
else
3620+
for (i = 0; i < amt; i++)
3621+
output_asm_insn ("CLRC { RRC%X0.W\t%H0 { RRC%X0.W\t%L0",
3622+
operands);
3623+
}
35863624
/* FIXME: Why doesn't "RRUX.W\t%H0 { RRC%X0.W\t%L0" work for msp430x?
35873625
It causes execution timeouts e.g. pr41963.c. */
35883626
#if 0
35893627
else if (msp430x && mode == SImode)
3590-
for (i = 0; i < amt; i++)
3591-
output_asm_insn ("RRUX.W\t%H0 { RRC%X0.W\t%L0", operands);
3628+
{
3629+
if (return_length)
3630+
length = 2;
3631+
else
3632+
for (i = 0; i < amt; i++)
3633+
output_asm_insn ("RRUX.W\t%H0 { RRC%X0.W\t%L0", operands);
3634+
}
35923635
#endif
35933636
else
35943637
gcc_unreachable ();
35953638
}
3596-
return "";
3639+
return length * amt;
35973640
}
35983641

35993642
/* Called by cbranch<mode>4 to coerce operands into usable forms. */
@@ -4115,6 +4158,20 @@ msp430_op_not_in_high_mem (rtx op)
41154158
return false;
41164159
}
41174160

4161+
/* Based on the operand OP, is a 430X insn required to handle it?
4162+
There are only 3 conditions for which a 430X insn is required:
4163+
- PSImode operand
4164+
- memory reference to a symbol which could be in upper memory
4165+
(so its address is > 0xFFFF)
4166+
- absolute address which has VOIDmode, i.e. (mem:HI (const_int))
4167+
Use a 430 insn if none of these conditions are true. */
4168+
bool
4169+
msp430x_insn_required (rtx op)
4170+
{
4171+
return (GET_MODE (op) == PSImode
4172+
|| !msp430_op_not_in_high_mem (op));
4173+
}
4174+
41184175
#undef TARGET_PRINT_OPERAND
41194176
#define TARGET_PRINT_OPERAND msp430_print_operand
41204177

@@ -4455,35 +4512,52 @@ msp430_register_pre_includes (const char *sysroot ATTRIBUTE_UNUSED,
44554512

44564513
/* Generate a sequence of instructions to sign-extend an HI
44574514
value into an SI value. Handles the tricky case where
4458-
we are overwriting the destination. */
4459-
4460-
const char *
4461-
msp430x_extendhisi (rtx * operands)
4515+
we are overwriting the destination.
4516+
Return the number of bytes used by the emitted instructions.
4517+
If RETURN_LENGTH is true then do not emit the assembly instruction
4518+
sequence. */
4519+
int
4520+
msp430x_extendhisi (rtx * operands, bool return_length)
44624521
{
44634522
if (REGNO (operands[0]) == REGNO (operands[1]))
4464-
/* Low word of dest == source word. 8-byte sequence. */
4465-
return "BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0";
4466-
4467-
if (! msp430x)
4468-
/* Note: This sequence is approximately the same length as invoking a helper
4469-
function to perform the sign-extension, as in:
4470-
4471-
MOV.W %1, %L0
4472-
MOV.W %1, r12
4473-
CALL __mspabi_srai_15
4474-
MOV.W r12, %H0
4475-
4476-
but this version does not involve any function calls or using argument
4477-
registers, so it reduces register pressure. 10-byte sequence. */
4478-
return "MOV.W\t%1, %L0 { BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 "
4479-
"{ INV.W\t%H0, %H0";
4480-
4481-
if (REGNO (operands[0]) + 1 == REGNO (operands[1]))
4482-
/* High word of dest == source word. 6-byte sequence. */
4483-
return "MOV.W\t%1, %L0 { RPT\t#15 { RRAX.W\t%H0";
4523+
{
4524+
/* Low word of dest == source word. */
4525+
if (!return_length)
4526+
output_asm_insn ("BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0",
4527+
operands);
4528+
return 8;
4529+
}
4530+
else if (! msp430x)
4531+
{
4532+
/* Note: This sequence is approximately the same length as invoking a
4533+
helper function to perform the sign-extension, as in:
4534+
4535+
MOV.W %1, %L0
4536+
MOV.W %1, r12
4537+
CALL __mspabi_srai_15
4538+
MOV.W r12, %H0
4539+
4540+
but this version does not involve any function calls or using argument
4541+
registers, so it reduces register pressure. */
4542+
if (!return_length)
4543+
output_asm_insn ("MOV.W\t%1, %L0 { BIT.W\t#0x8000, %L0 { SUBC.W\t%H0, %H0 { INV.W\t%H0, %H0",
4544+
operands);
4545+
return 10;
4546+
}
4547+
else if (REGNO (operands[0]) + 1 == REGNO (operands[1]))
4548+
{
4549+
/* High word of dest == source word. */
4550+
if (!return_length)
4551+
output_asm_insn ("MOV.W\t%1, %L0 { RPT\t#15 { RRAX.W\t%H0",
4552+
operands);
4553+
return 6;
4554+
}
44844555

4485-
/* No overlap between dest and source. 8-byte sequence. */
4486-
return "MOV.W\t%1, %L0 { MOV.W\t%1, %H0 { RPT\t#15 { RRAX.W\t%H0";
4556+
/* No overlap between dest and source. */
4557+
if (!return_length)
4558+
output_asm_insn ("MOV.W\t%1, %L0 { MOV.W\t%1, %H0 { RPT\t#15 { RRAX.W\t%H0",
4559+
operands);
4560+
return 8;
44874561
}
44884562

44894563
/* Stop GCC from thinking that it can eliminate (SUBREG:PSI (SI)). */

gcc/config/msp430/msp430.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,3 +530,13 @@ void msp430_register_pre_includes (const char *sysroot ATTRIBUTE_UNUSED,
530530

531531

532532
#define SYMBOL_FLAG_LOW_MEM (SYMBOL_FLAG_MACH_DEP << 0)
533+
534+
#define ADJUST_INSN_LENGTH(insn, length) \
535+
do \
536+
{ \
537+
if (recog_memoized (insn) >= 0) \
538+
{ \
539+
length += get_attr_extra_length (insn); \
540+
length *= get_attr_length_multiplier (insn); \
541+
} \
542+
} while (0)

0 commit comments

Comments
 (0)