Commit e3281ffc by Nick Clifton Committed by Nick Clifton

Do not move register a4 into lr if lr already contains the return address.

  CVS: ----------------------------------------------------------------------

From-SVN: r22002
parent 6b7e236f
Wed Aug 26 09:30:59 1998 Nick Clifton <nickc@cygnus.com>
* config/arm/thumb.c (thumb_exit): Do not move a4 into lr if it
already contains the return address.
Wed Aug 26 12:57:09 1998 Jeffrey A Law (law@cygnus.com) Wed Aug 26 12:57:09 1998 Jeffrey A Law (law@cygnus.com)
* mn10300.h (RTX_COSTS): Handle UDIV and UMOD too. * mn10300.h (RTX_COSTS): Handle UDIV and UMOD too.
......
...@@ -603,7 +603,6 @@ number_of_first_bit_set (mask) ...@@ -603,7 +603,6 @@ number_of_first_bit_set (mask)
/* Generate code to return from a thumb function. If /* Generate code to return from a thumb function. If
'reg_containing_return_addr' is -1, then the return address is 'reg_containing_return_addr' is -1, then the return address is
actually on the stack, at the stack pointer. */ actually on the stack, at the stack pointer. */
static void static void
thumb_exit (f, reg_containing_return_addr) thumb_exit (f, reg_containing_return_addr)
FILE * f; FILE * f;
...@@ -620,7 +619,6 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -620,7 +619,6 @@ thumb_exit (f, reg_containing_return_addr)
int restore_a4 = FALSE; int restore_a4 = FALSE;
/* Compute the registers we need to pop. */ /* Compute the registers we need to pop. */
regs_to_pop = 0; regs_to_pop = 0;
pops_needed = 0; pops_needed = 0;
...@@ -633,16 +631,14 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -633,16 +631,14 @@ thumb_exit (f, reg_containing_return_addr)
if (TARGET_BACKTRACE) if (TARGET_BACKTRACE)
{ {
/* Restore frame pointer and stack pointer. */ /* Restore frame pointer and stack pointer. */
regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER); regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER);
pops_needed += 2; pops_needed += 2;
} }
/* If there is nothing to pop then just emit the BX instruction and return. */ /* If there is nothing to pop then just emit the BX instruction and return.*/
if (pops_needed == 0) if (pops_needed == 0)
{ {
asm_fprintf (f, "\tbx\t%s\n", reg_names[ reg_containing_return_addr ]); asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]);
return; return;
} }
...@@ -650,7 +646,6 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -650,7 +646,6 @@ thumb_exit (f, reg_containing_return_addr)
/* Otherwise if we are not supporting interworking and we have not created /* Otherwise if we are not supporting interworking and we have not created
a backtrace structure and the function was not entered in ARM mode then a backtrace structure and the function was not entered in ARM mode then
just pop the return address straight into the PC. */ just pop the return address straight into the PC. */
else if ( ! TARGET_THUMB_INTERWORK else if ( ! TARGET_THUMB_INTERWORK
&& ! TARGET_BACKTRACE && ! TARGET_BACKTRACE
&& ! is_called_in_ARM_mode (current_function_decl)) && ! is_called_in_ARM_mode (current_function_decl))
...@@ -661,7 +656,6 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -661,7 +656,6 @@ thumb_exit (f, reg_containing_return_addr)
} }
/* Find out how many of the (return) argument registers we can corrupt. */ /* Find out how many of the (return) argument registers we can corrupt. */
regs_available_for_popping = 0; regs_available_for_popping = 0;
#ifdef RTX_CODE #ifdef RTX_CODE
...@@ -671,14 +665,10 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -671,14 +665,10 @@ thumb_exit (f, reg_containing_return_addr)
the register is used to hold a return value. */ the register is used to hold a return value. */
if (current_function_return_rtx != 0) if (current_function_return_rtx != 0)
{
mode = GET_MODE (current_function_return_rtx); mode = GET_MODE (current_function_return_rtx);
}
else else
#endif #endif
{
mode = DECL_MODE (DECL_RESULT (current_function_decl)); mode = DECL_MODE (DECL_RESULT (current_function_decl));
}
size = GET_MODE_SIZE (mode); size = GET_MODE_SIZE (mode);
...@@ -687,17 +677,23 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -687,17 +677,23 @@ thumb_exit (f, reg_containing_return_addr)
/* In a void function we can use any argument register. /* In a void function we can use any argument register.
In a function that returns a structure on the stack In a function that returns a structure on the stack
we can use the second and third argument registers. */ we can use the second and third argument registers. */
if (mode == VOIDmode) if (mode == VOIDmode)
regs_available_for_popping = (1 << ARG_1_REGISTER) | (1 << ARG_2_REGISTER) | (1 << ARG_3_REGISTER); regs_available_for_popping =
(1 << ARG_1_REGISTER)
| (1 << ARG_2_REGISTER)
| (1 << ARG_3_REGISTER);
else else
regs_available_for_popping = (1 << ARG_2_REGISTER) | (1 << ARG_3_REGISTER); regs_available_for_popping =
(1 << ARG_2_REGISTER)
| (1 << ARG_3_REGISTER);
} }
else if (size <= 4) regs_available_for_popping = (1 << ARG_2_REGISTER) | (1 << ARG_3_REGISTER); else if (size <= 4) regs_available_for_popping =
else if (size <= 8) regs_available_for_popping = (1 << ARG_3_REGISTER); (1 << ARG_2_REGISTER)
| (1 << ARG_3_REGISTER);
else if (size <= 8) regs_available_for_popping =
(1 << ARG_3_REGISTER);
/* Match registers to be popped with registers into which we pop them. */ /* Match registers to be popped with registers into which we pop them. */
for (available = regs_available_for_popping, for (available = regs_available_for_popping,
required = regs_to_pop; required = regs_to_pop;
required != 0 && available != 0; required != 0 && available != 0;
...@@ -706,41 +702,35 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -706,41 +702,35 @@ thumb_exit (f, reg_containing_return_addr)
-- pops_needed; -- pops_needed;
/* If we have any popping registers left over, remove them. */ /* If we have any popping registers left over, remove them. */
if (available > 0) if (available > 0)
regs_available_for_popping &= ~ available; regs_available_for_popping &= ~ available;
/* Otherwise if we need another popping register we can use /* Otherwise if we need another popping register we can use
the fourth argument register. */ the fourth argument register. */
else if (pops_needed) else if (pops_needed)
{ {
/* If we have not found any free argument registers and /* If we have not found any free argument registers and
reg a4 contains the return address, we must move it. */ reg a4 contains the return address, we must move it. */
if (regs_available_for_popping == 0
if (regs_available_for_popping == 0 && reg_containing_return_addr == ARG_4_REGISTER) && reg_containing_return_addr == ARG_4_REGISTER)
{ {
asm_fprintf (f, "\tmov\t%s, %s\n", asm_fprintf (f, "\tmov\t%s, %s\n",
reg_names[ LINK_REGISTER ], reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]);
reg_names[ ARG_4_REGISTER ]);
reg_containing_return_addr = LINK_REGISTER; reg_containing_return_addr = LINK_REGISTER;
} }
else if (size > 12) else if (size > 12)
{ {
/* Register a4 is being used to hold part of the return value, /* Register a4 is being used to hold part of the return value,
but we have dire need of a free, low register. */ but we have dire need of a free, low register. */
restore_a4 = TRUE; restore_a4 = TRUE;
asm_fprintf (f, "\tmov\t%s, %s\n", asm_fprintf (f, "\tmov\t%s, %s\n",
reg_names[ IP_REGISTER ], reg_names [IP_REGISTER], reg_names [ARG_4_REGISTER]);
reg_names[ ARG_4_REGISTER ]);
} }
if (reg_containing_return_addr != ARG_4_REGISTER) if (reg_containing_return_addr != ARG_4_REGISTER)
{ {
/* The fourth argument register is available. */ /* The fourth argument register is available. */
regs_available_for_popping |= 1 << ARG_4_REGISTER; regs_available_for_popping |= 1 << ARG_4_REGISTER;
-- pops_needed; -- pops_needed;
...@@ -748,41 +738,34 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -748,41 +738,34 @@ thumb_exit (f, reg_containing_return_addr)
} }
/* Pop as many registers as we can. */ /* Pop as many registers as we can. */
thumb_pushpop (f, regs_available_for_popping, FALSE);
thumb_pushpop (f, regs_available_for_popping, FALSE );
/* Process the registers we popped. */ /* Process the registers we popped. */
if (reg_containing_return_addr == -1) if (reg_containing_return_addr == -1)
{ {
/* The return address was popped into the lowest numbered register. */ /* The return address was popped into the lowest numbered register. */
regs_to_pop &= ~ (1 << LINK_REGISTER); regs_to_pop &= ~ (1 << LINK_REGISTER);
reg_containing_return_addr = number_of_first_bit_set (regs_available_for_popping); reg_containing_return_addr =
number_of_first_bit_set (regs_available_for_popping);
/* Remove this register for the mask of available registers, so that /* Remove this register for the mask of available registers, so that
the return address will not be corrupted by futher pops. */ the return address will not be corrupted by futher pops. */
regs_available_for_popping &= ~ (1 << reg_containing_return_addr); regs_available_for_popping &= ~ (1 << reg_containing_return_addr);
} }
/* If we popped other registers then handle them here. */ /* If we popped other registers then handle them here. */
if (regs_available_for_popping) if (regs_available_for_popping)
{ {
int frame_pointer; int frame_pointer;
/* Work out which register currently contains the frame pointer. */ /* Work out which register currently contains the frame pointer. */
frame_pointer = number_of_first_bit_set (regs_available_for_popping); frame_pointer = number_of_first_bit_set (regs_available_for_popping);
/* Move it into the correct place. */ /* Move it into the correct place. */
asm_fprintf (f, "\tmov\tfp, %s\n", reg_names [frame_pointer]);
asm_fprintf (f, "\tmov\tfp, %s\n", reg_names[ frame_pointer ]);
/* (Temporarily) remove it from the mask of popped registers. */ /* (Temporarily) remove it from the mask of popped registers. */
regs_available_for_popping &= ~ (1 << frame_pointer); regs_available_for_popping &= ~ (1 << frame_pointer);
regs_to_pop &= ~ (1 << FRAME_POINTER); regs_to_pop &= ~ (1 << FRAME_POINTER);
...@@ -790,20 +773,19 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -790,20 +773,19 @@ thumb_exit (f, reg_containing_return_addr)
{ {
int stack_pointer; int stack_pointer;
/* We popped the stack pointer as well, find the register that contains it. */ /* We popped the stack pointer as well, find the register that
contains it.*/
stack_pointer = number_of_first_bit_set (regs_available_for_popping); stack_pointer = number_of_first_bit_set (regs_available_for_popping);
/* Move it into the stack register. */ /* Move it into the stack register. */
asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [stack_pointer]);
asm_fprintf (f, "\tmov\tsp, %s\n", reg_names[ stack_pointer ]);
/* At this point we have popped all necessary registers, so /* At this point we have popped all necessary registers, so
do not worry about restoring regs_available_for_popping do not worry about restoring regs_available_for_popping
to its correct value: to its correct value:
assert (pops_needed == 0) assert (pops_needed == 0)
assert (regs_available_for_popping == (1 << stack_frame_pointer)) assert (regs_available_for_popping == (1 << frame_pointer))
assert (regs_to_pop == (1 << STACK_POINTER)) */ assert (regs_to_pop == (1 << STACK_POINTER)) */
} }
else else
...@@ -811,44 +793,27 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -811,44 +793,27 @@ thumb_exit (f, reg_containing_return_addr)
/* Since we have just move the popped value into the frame /* Since we have just move the popped value into the frame
pointer, the popping register is available for reuse, and pointer, the popping register is available for reuse, and
we know that we still have the stack pointer left to pop. */ we know that we still have the stack pointer left to pop. */
regs_available_for_popping |= (1 << frame_pointer); regs_available_for_popping |= (1 << frame_pointer);
} }
} }
/* If we still have registers left on the stack, but we no longer /* If we still have registers left on the stack, but we no longer have
have any registers into which we can pop them, then we must any registers into which we can pop them, then we must move the return
move the return address into the link register and make address into the link register and make available the register that
available the register that contained it. */ contained it. */
if (regs_available_for_popping == 0 && pops_needed > 0) if (regs_available_for_popping == 0 && pops_needed > 0)
{ {
regs_available_for_popping |= 1 << reg_containing_return_addr; regs_available_for_popping |= 1 << reg_containing_return_addr;
asm_fprintf (f, "\tmov\t%s, %s\n", asm_fprintf (f, "\tmov\t%s, %s\n",
reg_names[ LINK_REGISTER ], reg_names [LINK_REGISTER],
reg_names[ reg_containing_return_addr ]); reg_names [reg_containing_return_addr]);
reg_containing_return_addr = LINK_REGISTER; reg_containing_return_addr = LINK_REGISTER;
} }
/* If we have registers left on the stack then pop some more. /* If we have registers left on the stack then pop some more.
We know that we will only be popping one register here for We know that at most we will want to pop FP and SP. */
the following reasons:
1. We know that at most we want to pop LR, FP and SP.
2. We have already popped at least one register.
3. If there were 3 registers available for popping then
we have already popped all three of the registers.
4. If there were 2 registers available for popping then
we have already popped LR and FP, so there can only
be one register left on the stack: SP. And since we
had two registers available for popping we will have
left the LR in one of those registers and leaving
only one register left for popping the SP.
5. If there was only 1 register available for popping
then we can only be popping one register here. */
if (pops_needed > 0) if (pops_needed > 0)
{ {
int popped_into; int popped_into;
...@@ -856,23 +821,21 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -856,23 +821,21 @@ thumb_exit (f, reg_containing_return_addr)
thumb_pushpop (f, regs_available_for_popping, FALSE); thumb_pushpop (f, regs_available_for_popping, FALSE);
/* We have popped either FP or SP. Move whichever one /* We have popped either FP or SP.
it is into the correct register. */ Move whichever one it is into the correct register. */
popped_into = number_of_first_bit_set (regs_available_for_popping); popped_into = number_of_first_bit_set (regs_available_for_popping);
move_to = number_of_first_bit_set (regs_to_pop); move_to = number_of_first_bit_set (regs_to_pop);
asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[ move_to ], reg_names[ popped_into ]); asm_fprintf (f, "\tmov\t%s, %s\n",
reg_names [move_to], reg_names [popped_into]);
regs_to_pop &= ~ (1 << move_to); regs_to_pop &= ~ (1 << move_to);
-- pops_needed; -- pops_needed;
} }
/* If we still have not popped everything then we must have
only had one register available to us and we are now
popping the SP. */
/* If we still have not popped everything then we must have only
had one register available to us and we are now popping the SP. */
if (pops_needed > 0) if (pops_needed > 0)
{ {
int popped_into; int popped_into;
...@@ -881,7 +844,7 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -881,7 +844,7 @@ thumb_exit (f, reg_containing_return_addr)
popped_into = number_of_first_bit_set (regs_available_for_popping); popped_into = number_of_first_bit_set (regs_available_for_popping);
asm_fprintf (f, "\tmov\tsp, %s\n", reg_names[ popped_into ]); asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]);
/* /*
assert (regs_to_pop == (1 << STACK_POINTER)) assert (regs_to_pop == (1 << STACK_POINTER))
...@@ -892,21 +855,25 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -892,21 +855,25 @@ thumb_exit (f, reg_containing_return_addr)
/* If necessary restore the a4 register. */ /* If necessary restore the a4 register. */
if (restore_a4) if (restore_a4)
{ {
asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[ LINK_REGISTER ], reg_names[ ARG_4_REGISTER ]); if (reg_containing_return_addr != LINK_REGISTER)
asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[ ARG_4_REGISTER ], reg_names[ IP_REGISTER ]); {
reg_containing_return_addr = LINK_REGISTER; asm_fprintf (f, "\tmov\t%s, %s\n",
} reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]);
reg_containing_return_addr = LINK_REGISTER;
}
/* Return to caller. */ asm_fprintf (f, "\tmov\t%s, %s\n",
reg_names [ARG_4_REGISTER], reg_names [IP_REGISTER]);
}
asm_fprintf (f, "\tbx\t%s\n", reg_names[ reg_containing_return_addr ]); /* Return to caller. */
asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]);
} }
/* Emit code to push or pop registers to or from the stack. */ /* Emit code to push or pop registers to or from the stack. */
static void static void
thumb_pushpop (f, mask, push) thumb_pushpop (f, mask, push)
FILE *f; FILE * f;
int mask; int mask;
int push; int push;
{ {
...@@ -915,7 +882,8 @@ thumb_pushpop (f, mask, push) ...@@ -915,7 +882,8 @@ thumb_pushpop (f, mask, push)
if (lo_mask == 0 && ! push && (mask & (1 << 15))) if (lo_mask == 0 && ! push && (mask & (1 << 15)))
{ {
/* Special case. Do not generate a POP PC statement here, do it in thumb_exit() */ /* Special case. Do not generate a POP PC statement here, do it in
thumb_exit() */
thumb_exit (f, -1); thumb_exit (f, -1);
return; return;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment