diff options
author | ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-05-12 09:56:46 +0000 |
---|---|---|
committer | ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-05-12 09:56:46 +0000 |
commit | 0f56938bd9293d210ef6a365eadcd122836c3bfd (patch) | |
tree | 43c42f7af9755f290377e17a4c95ed428514cfc4 /gcc/config/arm | |
parent | 9fa8e4680c4ffce826ae73b3c5acb13691988ecd (diff) | |
download | gcc-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.c | 19 |
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); |