summaryrefslogtreecommitdiff
path: root/openwrt/toolchain/gcc/3.4.5/601-gcc34-arm-ldm.patch
blob: 142052fdf078f5ae01e82c6e761d2e41a59e5fe9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
--- gcc-3.4.0/gcc/config/arm/arm.c.arm-ldm	2004-02-27 09:51:05.000000000 -0500
+++ gcc-3.4.0/gcc/config/arm/arm.c	2004-04-24 18:16:25.000000000 -0400
@@ -8520,6 +8520,26 @@
   return_used_this_function = 0;  
 }
 
+/* Return the number (counting from 0) of
+   the least significant set bit in MASK.  */
+
+#ifdef __GNUC__
+inline
+#endif
+static int
+number_of_first_bit_set (mask)
+     int mask;
+{
+  int bit;
+
+  for (bit = 0;
+       (mask & (1 << bit)) == 0;
+       ++bit)
+    continue;
+
+  return bit;
+}
+
 const char *
 arm_output_epilogue (rtx sibling)
 {
@@ -8753,27 +8773,47 @@
 	  saved_regs_mask |=   (1 << PC_REGNUM);
 	}
 
-      /* Load the registers off the stack.  If we only have one register
-	 to load use the LDR instruction - it is faster.  */
-      if (saved_regs_mask == (1 << LR_REGNUM))
-	{
-	  /* The exception handler ignores the LR, so we do
-	     not really need to load it off the stack.  */
-	  if (eh_ofs)
-	    asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
-	  else
-	    asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
-	}
-      else if (saved_regs_mask)
+      if (saved_regs_mask)
 	{
-	  if (saved_regs_mask & (1 << SP_REGNUM))
-	    /* Note - write back to the stack register is not enabled
-	       (ie "ldmfd sp!...").  We know that the stack pointer is
-	       in the list of registers and if we add writeback the
-	       instruction becomes UNPREDICTABLE.  */
-	    print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
+	  /* Load the registers off the stack.  If we only have one register
+	     to load use the LDR instruction - it is faster.  */
+	  if (bit_count (saved_regs_mask) == 1)
+	    {
+	      int reg = number_of_first_bit_set (saved_regs_mask);
+
+	      switch (reg)
+		{
+		case SP_REGNUM:
+		  /* Mustn't use base writeback when loading SP.  */
+		  asm_fprintf (f, "\tldr\t%r, [%r]\n", SP_REGNUM, SP_REGNUM);
+		  break;
+		  
+		case LR_REGNUM:
+		  if (eh_ofs)
+		    {
+		      /* The exception handler ignores the LR, so we do
+			 not really need to load it off the stack.  */
+		      asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
+		      break;
+		    }
+		  /* else fall through */
+		  
+		default:
+		  asm_fprintf (f, "\tldr\t%r, [%r], #4\n", reg, SP_REGNUM);
+		  break;
+		}
+	    }
 	  else
-	    print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
+	    {
+	      if (saved_regs_mask & (1 << SP_REGNUM))
+		/* Note - write back to the stack register is not enabled
+		   (ie "ldmfd sp!...").  We know that the stack pointer is
+		   in the list of registers and if we add writeback the
+		   instruction becomes UNPREDICTABLE.  */
+		print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
+	      else
+		print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
+	    }
 	}
 
       if (current_function_pretend_args_size)
@@ -11401,22 +11441,6 @@
     }
 }
 
-/* Return the number (counting from 0) of
-   the least significant set bit in MASK.  */
-
-inline static int
-number_of_first_bit_set (int mask)
-{
-  int bit;
-
-  for (bit = 0;
-       (mask & (1 << bit)) == 0;
-       ++bit)
-    continue;
-
-  return bit;
-}
-
 /* Generate code to return from a thumb function.
    If 'reg_containing_return_addr' is -1, then the return address is
    actually on the stack, at the stack pointer.  */