This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] SH optimization -O3 corrupts registers in interrupt function


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]