[PATCH] SH optimization -O3 corrupts registers in interrupt function
Dhananjay R. Deshpande
dhananjayd@kpit.com
Thu Jun 13 03:22:00 GMT 2002
Hi,
If following code is compiled with sh-elf-gcc -O3 -S , register r0 is used
without saving it on stack.( gcc-3.1 )
extern int iTemp ;
#pragma interrupt
void isr(void)
{
iTemp = 0x3648732 ;
}
Asembly output -
.file "isr.c"
.data
.text
.align 2
.global _isr
_isr:
mov.l r1,@-r15
mov.l r2,@-r15
mov.l L2,r1
mov.l L3,r0 --------------------------> R0 is not saved on stack and gets corrupt.
mov.l r14,@-r15
mov.l r1,@r0
mov r15,r14
mov r14,r15
mov.l @r15+,r14
mov.l @r15+,r2
mov.l @r15+,r1
rte
nop
L4:
.align 2
L2:
.long 56919858
L3:
.long _iTemp
.ident "GCC: (GNU) 3.1"
This is due to rename-register optimization. For interrupt functions, rename
register optimization should not rename to registers which are not saved on
stack.
Following patch fixes this problem.
Some text for Changelog -
sh.h: Define HARD_REGNO_RENAME_OK
sh.c: sh_hard_regno_rename_ok() New. If current function has
interrupt_handler attribute, only registers saved on stack are
OK.
sh-protos.h: Declare sh_hard_regno_rename_ok()
===========================================================================
--- sh.h.orig Thu Jun 13 14:11:25 2002
+++ sh.h Thu Jun 13 14:13:03 2002
@@ -892,6 +892,12 @@
&& (GET_MODE_SIZE (MODE2) <= 4)) \
: ((MODE1) != SFmode && (MODE2) != SFmode))))
+/* A C expression that is nonzero if hard register NEW_REG can be
+ considered for use as a rename register for OLD_REG register */
+
+#define HARD_REGNO_RENAME_OK(OLD_REG, NEW_REG) \
+ sh_hard_regno_rename_ok (OLD_REG, NEW_REG)
+
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
===========================================================================
--- sh.c.orig Thu Jun 13 14:11:33 2002
+++ sh.c Thu Jun 13 14:14:11 2002
@@ -6632,6 +6632,26 @@
}
#endif /* ! OBJECT_FORMAT_ELF */
+/* Return non-zero if register old_reg can be renamed to register new_reg. */
+int
+sh_hard_regno_rename_ok (old_reg, new_reg)
+ unsigned int old_reg ATTRIBUTE_UNUSED;
+ unsigned int new_reg;
+{
+
+/* Interrupt functions can only use registers that have already been
+ saved by the prologue, even if they would normally be
+ call-clobbered. */
+
+ if ((lookup_attribute ("interrupt_handler",
+ DECL_ATTRIBUTES (current_function_decl))
+ != NULL_TREE)
+ && !regs_ever_live[new_reg])
+ return 0;
+
+ return 1;
+}
+
/* A C statement (sans semicolon) to update the integer variable COST
based on the relationship between INSN that is dependent on
DEP_INSN through the dependence LINK. The default is to make no
===========================================================================
--- sh-protos.h.orig Thu Jun 13 14:11:44 2002
+++ sh-protos.h Thu Jun 13 14:09:31 2002
@@ -122,6 +122,7 @@
extern int initial_elimination_offset PARAMS ((int, int));
extern int fldi_ok PARAMS ((void));
extern int sh_pr_n_sets PARAMS ((void));
+extern int sh_hard_regno_rename_ok PARAMS ((unsigned int, unsigned int));
#ifdef HARD_CONST
extern void fpscr_set_from_mem PARAMS ((int, HARD_REG_SET));
===========================================================================
Assembly output after applying the above patch.
.file "isr.c"
.data
.text
.align 2
.global _isr
_isr:
mov.l r1,@-r15
mov.l r2,@-r15
mov.l L2,r1
mov.l L3,r2
mov.l r14,@-r15
mov.l r2,@r1
mov r15,r14
mov r14,r15
mov.l @r15+,r14
mov.l @r15+,r2
mov.l @r15+,r1
rte
nop
L4:
.align 2
L2:
.long _iTemp
L3:
.long 56919858
.ident "GCC: (GNU) 3.1"
Regards,
Dhananjay
More information about the Gcc-patches
mailing list