c/2898: Illegal function return in ARM code when compiling with -mthumb-interwork -O2
Philip Blundell
philb@gnu.org
Tue Sep 18 01:46:00 GMT 2001
Did you have any further thoughts on this?
p.
--
From: Philip Blundell <philb@gnu.org>
Date: Tue, 29 May 2001 20:34:44 +0100
To: Richard.Earnshaw@arm.com
Cc: gcc-patches@gcc.gnu.org
Subject: Re: c/2898: Illegal function return in ARM code when compiling with -mthumb-interwork -O2
>I realise this is what the old code did, but it's a truly horrible hack,
>particularly since it leaves a trailing space. Any chance the code could
>be reworked to avoid the need for this? BTW, repeated use of strcat is
>horribly inefficient.
Well, here's another version (in `diff -c' form for your viewing pleasure).
It abolishes most of the repeated strcats; in terms of ugly code this cure is
in danger of being worse than the original disease, but you can judge for
yourself.
p.
Index: arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.146
diff -u -p -c -r1.146 arm.c
*** arm.c 2001/05/24 21:09:05 1.146
--- arm.c 2001/05/29 19:28:25
*************** output_return_instruction (operand, real
*** 7033,7053 ****
live_regs_mask = arm_compute_save_reg_mask ();
! /* On some ARM architectures it is faster to use LDR rather than LDM to
! 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)
! sprintf (instr, "ldr%s\t%%|lr, [%%|sp], #4", conditional);
else
! sprintf (instr, "ldr%s\t%%|pc, [%%|sp], #4", conditional);
! }
! else if (live_regs_mask)
! {
if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
/* There are two possible reasons for the IP register being saved.
Either a stack frame was created, in which case IP contains the
--- 7050,7069 ----
live_regs_mask = arm_compute_save_reg_mask ();
! if (live_regs_mask)
{
! const char * return_reg;
!
! /* 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 (! TARGET_INTERWORK
! && ! IS_INTERRUPT (func_type)
! && really_return)
! return_reg = reg_names[PC_REGNUM];
else
! return_reg = reg_names[LR_REGNUM];
!
if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
/* There are two possible reasons for the IP register being saved.
Either a stack frame was created, in which case IP contains the
*************** output_return_instruction (operand, real
*** 7058,7103 ****
live_regs_mask &= ~ (1 << IP_REGNUM);
live_regs_mask |= (1 << SP_REGNUM);
}
-
- /* Generate the load multiple instruction to restore the registers. */
- if (frame_pointer_needed)
- sprintf (instr, "ldm%sea\t%%|fp, {", conditional);
- else
- sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
! 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
! have added one too many commas to the list above.
! Replace it with a closing brace. */
! instr [strlen (instr) - 2] = '}';
}
else
{
! strcat (instr, "%|");
! /* At this point there should only be one or two registers left in
! live_regs_mask: always LR, and possibly PC if we created a stack
! frame. LR contains the return address. If we do not have any
! 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
! strcat (instr, reg_names [LR_REGNUM]);
! strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^");
}
if (really_return)
--- 7074,7135 ----
live_regs_mask &= ~ (1 << IP_REGNUM);
live_regs_mask |= (1 << SP_REGNUM);
}
! /* On some ARM architectures it is faster to use LDR rather than LDM to
! 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))
! && (! really_return || TARGET_APCS_32))
{
! sprintf (instr, "ldr%s\t%%|%s, [%%|sp], #4", conditional, return_reg);
}
else
{
! char *p;
! int first = 1;
! /* Generate the load multiple instruction to restore the registers. */
! if (frame_pointer_needed)
! sprintf (instr, "ldm%sea\t%%|fp, {", conditional);
else
! 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;
! }
!
! memcpy (p, "%|", 2);
! memcpy (p + 2, return_reg, l);
! strcpy (p + 2 + l, (TARGET_APCS_32 || !really_return) ? "}" : "}^");
! }
! else
! strcpy (p, "}");
}
if (really_return)
--
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.5 (GNU/Linux)
Comment: Exmh version 2.1.1 10/15/1999 (debian)
iD8DBQE7pwnKVTLPJe9CT30RAkaCAJ9vmW+tbIrK1kk6ETavYtl+fURvogCePbIi
0ESbm+vijgprItufGLUf3BA=
=8uaa
-----END PGP SIGNATURE-----
More information about the Gcc-patches
mailing list