Commit 1768c26f by Philip Blundell Committed by Phil Blundell

arm.c (arm_compute_save_reg_mask): Fix typo in comment.

2002-02-18 Philip Blundell <pb@nexus.co.uk>

	* config/arm/arm.c (arm_compute_save_reg_mask): Fix typo in
	comment.
	(output_return_instruction): Allow use of LDR to unstack
	return addresss even for interrupt handlers or when
	interworking.  If compiling for ARMv5, use interworking-safe
	return instructions by default.  Remove duplicated code and
	lengthy "strcat" sequences.

From-SVN: r49845
parent ccd84f51
2002-02-18 Philip Blundell <pb@nexus.co.uk>
* config/arm/arm.c (arm_compute_save_reg_mask): Fix typo in
comment.
(output_return_instruction): Allow use of LDR to unstack
return addresss even for interrupt handlers or when
interworking. If compiling for ARMv5, use interworking-safe
return instructions by default. Remove duplicated code and
lengthy "strcat" sequences.
2002-02-18 Franz Sirl <Franz.Sirl-kernel@lauterbach.com> 2002-02-18 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
* config/rs6000/sysv4.h (STARTFILE_SPEC): Use crtbeginT.o for -static. * config/rs6000/sysv4.h (STARTFILE_SPEC): Use crtbeginT.o for -static.
......
...@@ -7136,7 +7136,7 @@ arm_compute_save_reg_mask () ...@@ -7136,7 +7136,7 @@ arm_compute_save_reg_mask ()
/* Decide if we need to save the link register. /* Decide if we need to save the link register.
Interrupt routines have their own banked link register, Interrupt routines have their own banked link register,
so they never need to save it. so they never need to save it.
Otheriwse if we do not use the link register we do not need to save Otherwise if we do not use the link register we do not need to save
it. If we are pushing other registers onto the stack however, we it. If we are pushing other registers onto the stack however, we
can save an instruction in the epilogue by pushing the link register can save an instruction in the epilogue by pushing the link register
now and then popping it back into the PC. This incurs extra memory now and then popping it back into the PC. This incurs extra memory
...@@ -7204,21 +7204,20 @@ output_return_instruction (operand, really_return, reverse) ...@@ -7204,21 +7204,20 @@ output_return_instruction (operand, really_return, reverse)
live_regs_mask = arm_compute_save_reg_mask (); live_regs_mask = arm_compute_save_reg_mask ();
/* On some ARM architectures it is faster to use LDR rather than LDM to if (live_regs_mask)
load a single register. On other architectures, the cost is the same.
In 26 bit mode we have to use LDM in order to be able to restore the CPSR. */
if ((live_regs_mask == (1 << LR_REGNUM))
&& ! TARGET_INTERWORK
&& ! IS_INTERRUPT (func_type)
&& (! really_return || TARGET_APCS_32))
{ {
if (! really_return) const char * return_reg;
sprintf (instr, "ldr%s\t%%|lr, [%%|sp], #4", conditional);
/* If we do not have any special requirements for function exit
(eg interworking, or ISR) then we can load the return address
directly into the PC. Otherwise we must load it into LR. */
if (really_return
&& ! IS_INTERRUPT (func_type)
&& ! TARGET_INTERWORK)
return_reg = reg_names[PC_REGNUM];
else else
sprintf (instr, "ldr%s\t%%|pc, [%%|sp], #4", conditional); return_reg = reg_names[LR_REGNUM];
}
else if (live_regs_mask)
{
if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM)) if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
/* There are two possible reasons for the IP register being saved. /* There are two possible reasons for the IP register being saved.
Either a stack frame was created, in which case IP contains the Either a stack frame was created, in which case IP contains the
...@@ -7230,47 +7229,66 @@ output_return_instruction (operand, really_return, reverse) ...@@ -7230,47 +7229,66 @@ output_return_instruction (operand, really_return, reverse)
live_regs_mask |= (1 << SP_REGNUM); live_regs_mask |= (1 << SP_REGNUM);
} }
/* Generate the load multiple instruction to restore the registers. */ /* On some ARM architectures it is faster to use LDR rather than LDM to
if (frame_pointer_needed) load a single register. On other architectures, the cost is the same.
sprintf (instr, "ldm%sea\t%%|fp, {", conditional); In 26 bit mode we have to use LDM in order to be able to restore the
else CPSR. */
sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional); if ((live_regs_mask == (1 << LR_REGNUM))
&& (! really_return || TARGET_APCS_32))
for (reg = 0; reg <= SP_REGNUM; reg++)
if (live_regs_mask & (1 << reg))
{
strcat (instr, "%|");
strcat (instr, reg_names[reg]);
strcat (instr, ", ");
}
if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
{ {
/* If we are not restoring the LR register then we will sprintf (instr, "ldr%s\t%%|%s, [%%|sp], #4", conditional, return_reg);
have added one too many commas to the list above.
Replace it with a closing brace. */
instr [strlen (instr) - 2] = '}';
} }
else else
{ {
strcat (instr, "%|"); char *p;
int first = 1;
/* At this point there should only be one or two registers left in /* Generate the load multiple instruction to restore the registers. */
live_regs_mask: always LR, and possibly PC if we created a stack if (frame_pointer_needed)
frame. LR contains the return address. If we do not have any sprintf (instr, "ldm%sea\t%%|fp, {", conditional);
special requirements for function exit (eg interworking, or ISR)
then we can load this value directly into the PC and save an
instruction. */
if (! TARGET_INTERWORK
&& ! IS_INTERRUPT (func_type)
&& really_return)
strcat (instr, reg_names [PC_REGNUM]);
else else
strcat (instr, reg_names [LR_REGNUM]); sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
p = instr + strlen (instr);
for (reg = 0; reg <= SP_REGNUM; reg++)
if (live_regs_mask & (1 << reg))
{
int l = strlen (reg_names[reg]);
if (first)
first = 0;
else
{
memcpy (p, ", ", 2);
p += 2;
}
memcpy (p, "%|", 2);
memcpy (p + 2, reg_names[reg], l);
p += l + 2;
}
if (live_regs_mask & (1 << LR_REGNUM))
{
int l = strlen (return_reg);
if (! first)
{
memcpy (p, ", ", 2);
p += 2;
}
strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^"); memcpy (p, "%|", 2);
memcpy (p + 2, return_reg, l);
strcpy (p + 2 + l, (TARGET_APCS_32 || !really_return) ? "}" : "}^");
}
else
strcpy (p, "}");
} }
output_asm_insn (instr, & operand);
if (really_return) if (really_return)
{ {
/* See if we need to generate an extra instruction to /* See if we need to generate an extra instruction to
...@@ -7279,47 +7297,22 @@ output_return_instruction (operand, really_return, reverse) ...@@ -7279,47 +7297,22 @@ output_return_instruction (operand, really_return, reverse)
{ {
case ARM_FT_ISR: case ARM_FT_ISR:
case ARM_FT_FIQ: case ARM_FT_FIQ:
output_asm_insn (instr, & operand);
strcpy (instr, "sub");
strcat (instr, conditional);
strcat (instr, "s\t%|pc, %|lr, #4");
break;
case ARM_FT_EXCEPTION: case ARM_FT_EXCEPTION:
output_asm_insn (instr, & operand);
strcpy (instr, "mov");
strcat (instr, conditional);
strcat (instr, "s\t%|pc, %|lr");
break;
case ARM_FT_INTERWORKED: case ARM_FT_INTERWORKED:
output_asm_insn (instr, & operand); /* A separate return instruction is always needed. */
strcpy (instr, "bx");
strcat (instr, conditional);
strcat (instr, "\t%|lr");
break; break;
default: default:
/* The return has already been handled /* The return may have already been handled
by loading the LR into the PC. */ by loading the LR into the PC. */
if ((live_regs_mask & (1 << LR_REGNUM)) == 0) if ((live_regs_mask & (1 << LR_REGNUM)) != 0)
{ really_return = 0;
output_asm_insn (instr, & operand);
strcpy (instr, "mov");
strcat (instr, conditional);
if (! TARGET_APCS_32)
strcat (instr, "s");
strcat (instr, "\t%|pc, %|lr");
}
break; break;
} }
} }
} }
else if (really_return)
if (really_return)
{ {
switch ((int) ARM_FUNC_TYPE (func_type)) switch ((int) ARM_FUNC_TYPE (func_type))
{ {
...@@ -7337,18 +7330,19 @@ output_return_instruction (operand, really_return, reverse) ...@@ -7337,18 +7330,19 @@ output_return_instruction (operand, really_return, reverse)
break; break;
default: default:
sprintf (instr, "mov%s%s\t%%|pc, %%|lr", /* ARMv5 implementations always provide BX, so interworking
conditional, TARGET_APCS_32 ? "" : "s"); is the default unless APCS-26 is in use. */
if ((insn_flags & FL_ARCH5) != 0 && TARGET_APCS_32)
sprintf (instr, "bx%s\t%%|lr", conditional);
else
sprintf (instr, "mov%s%s\t%%|pc, %%|lr",
conditional, TARGET_APCS_32 ? "" : "s");
break; break;
} }
output_asm_insn (instr, & operand);
} }
else
/* Nothing to load off the stack, and
no return instruction to generate. */
return "";
output_asm_insn (instr, & operand);
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