This is the mail archive of the gcc-patches@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]

SH PIC far branches: alignment and SH1 problems


This started as a run-time error in a commercial test suite, that only
failed with -m1 -fPIC.  It turned out that we were emitting something
like:

        mov.l   .La, rn; braf rn
        nop
        .align 2
.La:
        .long   .Lt - .La

There was an implicit assumption here that .align 2 wouldn't introduce
any alignment.  If it does, we lose.

So I changed it so that we emit:

        mov.l   .La, rn; braf rn
        nop
.Lf:
        .align 2
.La:
        .long   .Lt - .Lf

so that, regardless of the alignment, we get the right base address
for the braf.

But then, I recalled SH1 doesn't support braf, so we shouldn't be
emitting it.  Unfortunately, we have at most one scratch register
available, and there's no guarantee that the PIC base register will be
set for us to use, say, .Lt@GOTOFF, and just add the PIC base register
to the scratch register.  So, I ended up taking the simpler approach
of pushing r0 (or r1, if r0 happens to be the scratch register), using
it to compute the target address, then popping it back.  It's ugly,
but at least now it doesn't use unavailable insns.

While looking for other potential mis-uses of braf, I noticed the use
in casesi_jump_2 wasn't properly guarded by TARGET_SH2, so I added the
condition.

I'm checking this in.

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* config/sh/sh.c (output_far_jump): Don't use braf on SH1.  Emit
	label before alignment to be used as the braf base address.
	* config/sh/sh.md (length): Use longer lengths for SH1 PIC far
	branches.
	(casesi_jump_2): Require at least TARGET_SH2.

Index: gcc/config/sh/sh.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/sh/sh.c,v
retrieving revision 1.88
diff -u -p -r1.88 sh.c
--- gcc/config/sh/sh.c 2001/01/19 22:31:21 1.88
+++ gcc/config/sh/sh.c 2001/02/02 18:02:18
@@ -715,6 +715,7 @@ output_far_jump (insn, op)
      rtx op;
 {
   struct { rtx lab, reg, op; } this;
+  rtx braf_base_lab;
   const char *jump;
   int far;
   int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
@@ -726,21 +727,28 @@ output_far_jump (insn, op)
       && offset - get_attr_length (insn) <= 32766)
     {
       far = 0;
-      jump = "mov.w	%O0,%1;braf	%1";
+      jump = "mov.w	%O0,%1; braf	%1";
     }
   else
     {
       far = 1;
       if (flag_pic)
-	jump = "mov.l	%O0,%1;braf	%1";
+	{
+	  if (TARGET_SH2)
+	    jump = "mov.l	%O0,%1; braf	%1";
+	  else
+	    jump = "mov.l	r0,@-r15; mova	%O0,r0; mov.l	@r0,%1; add	r0,%1; mov.l	@r15+,r0; jmp	@%1";
+	}
       else
-	jump = "mov.l	%O0,%1;jmp	@%1";
+	jump = "mov.l	%O0,%1; jmp	@%1";
     }
   /* If we have a scratch register available, use it.  */
   if (GET_CODE (PREV_INSN (insn)) == INSN
       && INSN_CODE (PREV_INSN (insn)) == CODE_FOR_indirect_jump_scratch)
     {
       this.reg = SET_DEST (PATTERN (PREV_INSN (insn)));
+      if (REGNO (this.reg) == R0_REG && flag_pic && ! TARGET_SH2)
+	jump = "mov.l	r1,@-r15; mova	%O0,r0; mov.l	@r0,r1; add	r1,r0; mov.l	@r15+,r1; jmp	@%1";
       output_asm_insn (jump, &this.lab);
       if (dbr_sequence_length ())
 	print_slot (final_sequence);
@@ -758,12 +766,22 @@ output_far_jump (insn, op)
       output_asm_insn (jump, &this.lab);
       output_asm_insn ("mov.l	@r15+,r13", 0);
     }
+  if (far && flag_pic && TARGET_SH2)
+    {
+      braf_base_lab = gen_label_rtx ();
+      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+				 CODE_LABEL_NUMBER (braf_base_lab));
+    }
   if (far)
     output_asm_insn (".align	2", 0);
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (this.lab));
   this.op = op;
   if (far && flag_pic)
-    output_asm_insn (".long	%O2-%O0", &this.lab);
+    {
+      if (TARGET_SH2)
+	this.lab = braf_base_lab;
+      output_asm_insn (".long	%O2-%O0", &this.lab);
+    }
   else
     output_asm_insn (far ? ".long	%O2" : ".word %O2-%O0", &this.lab);
   return "";
Index: gcc/config/sh/sh.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/sh/sh.md,v
retrieving revision 1.74
diff -u -p -r1.74 sh.md
--- gcc/config/sh/sh.md 2001/01/09 14:23:50 1.74
+++ gcc/config/sh/sh.md 2001/02/02 18:02:18
@@ -290,6 +290,8 @@
 ;; ??? using pc is not computed transitively.
 		(ne (match_dup 0) (match_dup 0))
 		(const_int 14)
+		(ne (symbol_ref ("flag_pic")) (const_int 0))
+		(const_int 24)
 		] (const_int 16))
 	 (eq_attr "type" "jump")
 	 (cond [(eq_attr "med_branch_p" "yes")
@@ -306,6 +308,8 @@
 ;; ??? using pc is not computed transitively.
 		(ne (match_dup 0) (match_dup 0))
 		(const_int 12)
+		(ne (symbol_ref ("flag_pic")) (const_int 0))
+		(const_int 22)
 		] (const_int 14))
 	 ] (const_int 2)))
 
@@ -3674,7 +3678,8 @@
   [(set (pc) (plus:SI (match_operand:SI 0 "register_operand" "r")
 		      (label_ref (match_operand 1 "" ""))))
    (use (label_ref (match_operand 2 "" "")))]
-  "! INSN_UID (operands[1]) || prev_real_insn (operands[1]) == insn"
+  "TARGET_SH2
+   && (! INSN_UID (operands[1]) || prev_real_insn (operands[1]) == insn)"
   "braf	%0%#"
   [(set_attr "needs_delay_slot" "yes")
    (set_attr "type" "jump_ind")])

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                  aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist    *Please* write to mailing lists, not to me

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