summaryrefslogtreecommitdiff
path: root/gcc/config/arm
diff options
context:
space:
mode:
authorktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>2016-05-12 09:56:46 +0000
committerktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4>2016-05-12 09:56:46 +0000
commit0f56938bd9293d210ef6a365eadcd122836c3bfd (patch)
tree43c42f7af9755f290377e17a4c95ed428514cfc4 /gcc/config/arm
parent9fa8e4680c4ffce826ae73b3c5acb13691988ecd (diff)
downloadgcc-0f56938bd9293d210ef6a365eadcd122836c3bfd.tar.gz
[ARM] PR target/70830: Avoid POP-{reglist}^ when returning from interrupt handlers
PR target/70830 * config/arm/arm.c (arm_output_multireg_pop): Avoid POP instruction when popping the PC and within an interrupt handler routine. Add missing tab to output of "ldmfd". (output_return_instruction): Output LDMFD with SP update rather than POP when returning from interrupt handler. * gcc.target/arm/interrupt-1.c: Change dg-compile to dg-assemble. Add -save-temps to dg-options. Scan for ldmfd rather than pop instruction. * gcc.target/arm/interrupt-2.c: Likewise. * gcc.target/arm/pr70830.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@236169 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/arm')
-rw-r--r--gcc/config/arm/arm.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 71b51439dc7..58b04322d18 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -17755,6 +17755,7 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse,
int num_saves = XVECLEN (operands[0], 0);
unsigned int regno;
unsigned int regno_base = REGNO (operands[1]);
+ bool interrupt_p = IS_INTERRUPT (arm_current_func_type ());
offset = 0;
offset += update ? 1 : 0;
@@ -17772,7 +17773,8 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse,
}
conditional = reverse ? "%?%D0" : "%?%d0";
- if ((regno_base == SP_REGNUM) && update)
+ /* Can't use POP if returning from an interrupt. */
+ if ((regno_base == SP_REGNUM) && !(interrupt_p && return_pc))
{
sprintf (pattern, "pop%s\t{", conditional);
}
@@ -17781,11 +17783,8 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse,
/* Output ldmfd when the base register is SP, otherwise output ldmia.
It's just a convention, their semantics are identical. */
if (regno_base == SP_REGNUM)
- /* update is never true here, hence there is no need to handle
- pop here. */
- sprintf (pattern, "ldmfd%s", conditional);
-
- if (update)
+ sprintf (pattern, "ldmfd%s\t", conditional);
+ else if (update)
sprintf (pattern, "ldmia%s\t", conditional);
else
sprintf (pattern, "ldm%s\t", conditional);
@@ -17811,7 +17810,7 @@ arm_output_multireg_pop (rtx *operands, bool return_pc, rtx cond, bool reverse,
strcat (pattern, "}");
- if (IS_INTERRUPT (arm_current_func_type ()) && return_pc)
+ if (interrupt_p && return_pc)
strcat (pattern, "^");
output_asm_insn (pattern, &cond);
@@ -19622,8 +19621,12 @@ output_return_instruction (rtx operand, bool really_return, bool reverse,
sprintf (instr, "ldmfd%s\t%%|sp, {", conditional);
}
}
+ /* For interrupt returns we have to use an LDM rather than
+ a POP so that we can use the exception return variant. */
+ else if (IS_INTERRUPT (func_type))
+ sprintf (instr, "ldmfd%s\t%%|sp!, {", conditional);
else
- sprintf (instr, "pop%s\t{", conditional);
+ sprintf (instr, "pop%s\t{", conditional);
p = instr + strlen (instr);