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]
Other format: [Raw text]

[again] switch() statements on ARM/Thumb


Ok, it's been christmas and everything... and afaics nobody has looked
into it since, so here is my slightly revised edition.

Without the patch, code generation for switch statements with -fpic
-mthumb produces just wrong code, so this is certainly an improvement...

On Mon, 2001-12-03 at 18:38, Richard Earnshaw wrote:

> 2001-11-22  Adrian von Bidder   <avbidder@acter.ch>
> 
>         * arm.h (CASE_VECTOR_PC_RELATIVE, ASM_OUTPUT_ADDR_DIFF_ELT): define
> 
> ASM_OUTPUT_ADDR_DIFF_ELT is already defined in arm/aout.h and arm/aof.h; 
> re-defining in arm.h is wrong, since it is incompatible with support for 
> AOF object formats.

So where should it go? elf.h? But this includes aout.h as well (which I
find somewhat confusing).
 
> CASE_VECTOR_PC_RELATIVE isn't required for ARM; GCC always uses an 
> ADDR_DIFF format for PIC.

Ok, deleted that.

The changes in arm.md:
 - immediate subtract for thumb
 - casesi pattern for thumb
 - pattern to take the address of a label_ref

I'm not really happy with the solution right now, especially the last
one, but at least it produces code that seems to be working. And using
32 bit values in the jump table instead of branch instructions gets rid
of the 'branch target out of range' errors I get when compiling long
switch() statements with the unmodified compiler as well.

greets from Zürich
-- vbi
 
Index: gcc/config/arm/arm.h
===================================================================
RCS file: /home/acter/Software/cvsroot/TOOLS/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.1.1.2
retrieving revision 1.6
diff -u -r1.1.1.2 -r1.6
--- gcc/config/arm/arm.h	2002/01/03 08:59:34	1.1.1.2
+++ gcc/config/arm/arm.h	2002/01/08 15:29:37	1.6
@@ -2679,6 +2680,14 @@
       ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM);		\
     }								\
   while (0)
+
+/* for pc relative jump tables when using pic code: */
+#undef ASM_OUTPUT_ADDR_DIFF_ELT 
+#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL)      \
+  if (TARGET_ARM)                                               \
+    fprintf (STREAM, "\tb\t.L%d\n", VALUE);                      \
+  else                                                          \
+    fprintf (STREAM, "\t.word\t.L%d-.L%d\n", VALUE, REL)        \
 
 #define ARM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) 	\
   do							\
Index: gcc/config/arm/arm.md
===================================================================
RCS file: /home/acter/Software/cvsroot/TOOLS/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- gcc/config/arm/arm.md	2001/12/06 14:08:05	1.1.1.1
+++ gcc/config/arm/arm.md	2002/01/08 15:29:37	1.2
@@ -991,6 +991,17 @@
   [(set_attr "length" "2")]
 )
 
+(define_insn "*thumb_subsi3imm_insn"
+  [(set (match_operand:SI           0 "register_operand" "=l,l")
+	(minus:SI (match_operand:SI 1 "register_operand" "l,0")
+		  (match_operand:SI 2 "const_int_operand" "L,I")))]
+  "TARGET_THUMB && ((unsigned int)INTVAL(operands[2]) < 256)"
+  "@
+  sub\\t%0, %1, %2
+  sub\\t%0, %2"
+  [(set_attr "length" "2")]
+)
+
 (define_insn_and_split "*arm_subsi3_insn"
   [(set (match_operand:SI           0 "s_register_operand" "=r,r")
 	(minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,?n")
@@ -6833,10 +6844,17 @@
    (match_operand:SI 2 "const_int_operand" "")	; total range
    (match_operand:SI 3 "" "")			; table label
    (match_operand:SI 4 "" "")]			; Out of range label
-  "TARGET_ARM"
+  "TARGET_ARM || (TARGET_THUMB && flag_pic)"
   "
   {
     rtx reg;
+
+    if (TARGET_THUMB && flag_pic) {
+      emit_insn (gen_thumbpic_casesi (operands[0], operands[1],
+              operands[2], operands[3], operands[4]));
+      DONE;
+    }
+    
     if (operands[1] != const0_rtx)
       {
 	reg = gen_reg_rtx (SImode);
@@ -6849,15 +6867,15 @@
     if (!const_ok_for_arm (INTVAL (operands[2])))
       operands[2] = force_reg (SImode, operands[2]);
 
-    emit_jump_insn (gen_casesi_internal (operands[0], operands[2], operands[3],
-					 operands[4]));
+    emit_jump_insn (gen_arm_casesi_internal (operands[0], operands[2],
+                operands[3], operands[4]));
     DONE;
   }"
 )
 
 ;; The USE in this pattern is needed to tell flow analysis that this is
 ;; a CASESI insn.  It has no other purpose.
-(define_insn "casesi_internal"
+(define_insn "arm_casesi_internal"
   [(parallel [(set (pc)
 	       (if_then_else
 		(leu (match_operand:SI 0 "s_register_operand" "r")
@@ -6877,6 +6895,53 @@
    (set_attr "length" "12")]
 )
 
+;; -fpic -mthumb is wrong with just tablejump.
+(define_expand "thumbpic_casesi"
+  [(set (match_dup 5)
+        (minus:SI (match_operand:SI 0 "" "")
+                  (match_operand:SI 1 "" "")))
+   (set (pc)
+        (if_then_else (gtu (match_dup 5)
+                           (match_operand 2 "" ""))
+                      (label_ref (match_operand 4 "" ""))
+                      (pc)))
+   (set (match_dup 7)
+        (label_ref (match_operand 3 "" "")))
+   (set (match_dup 6)
+        (ashift:SI (match_dup 5)
+                 (const_int 2)))
+   (set (match_dup 8)
+        (mem:SI (plus:SI (match_dup 6)
+                         (match_dup 7))))
+   (set (match_dup 9)
+        (plus:SI (match_dup 7)
+                 (match_dup 8)))
+   (parallel [
+     (set (pc)
+          (match_dup 9))
+     (use (label_ref (match_dup 3)))])]
+  "TARGET_THUMB && flag_pic"
+  "{
+    operands[5] = gen_reg_rtx (SImode);
+    operands[6] = gen_reg_rtx (SImode);
+    operands[7] = gen_reg_rtx (SImode);
+    operands[8] = gen_reg_rtx (SImode);
+    operands[9] = gen_reg_rtx (SImode);
+
+    operands[1] = force_reg(SImode, operands[1]);
+  }"
+)
+
+; this works only if the label_ref is close enough (10 bit word aligned)
+; but it should only be called from thumbpic_casesi anyway.
+(define_insn "*thumb_adr"
+  [(set (match_operand:SI 0 "s_register_operand" "=l")
+        (label_ref (match_operand 1 "" "")))]
+  "TARGET_THUMB"
+  "adr\\t%0, %a1"
+  [(set_attr "length" "2")]
+)
+
 (define_expand "indirect_jump"
   [(set (pc)
 	(match_operand:SI 0 "s_register_operand" ""))]
@@ -9136,12 +9201,11 @@
 )
 
 ;; Miscellaneous Thumb patterns
-
 (define_insn "tablejump"
   [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))
    (use (label_ref (match_operand 1 "" "")))]
   "TARGET_THUMB"
-  "mov	pc, %0"
+  "mov\\tpc, %0"
   [(set_attr "length" "2")]
 )
 

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