aboutsummaryrefslogtreecommitdiffstats
path: root/packages/gcc/gcc-3.3.4/arm-ldm.dpatch
blob: 561624f39c61f4c5676b02eedba2c55734ec4e7f (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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#! /bin/sh -e

src=gcc
if [ $# -eq 3 -a "$2" = '-d' ]; then
    pdir="-d $3"
    src=$3/gcc
elif [ $# -ne 1 ]; then
    echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
    exit 1
fi
case "$1" in
    -patch)
        patch $pdir -f --no-backup-if-mismatch -p0 --fuzz 10 < $0
        ;;
    -unpatch)
        patch $pdir -f --no-backup-if-mismatch -R -p0 --fuzz 10 < $0
        ;;
    *)
        echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
        exit 1
esac
exit 0

# DP: try harder to avoid ldm in function epilogues

--- gcc/config/arm/arm.c	Fri Mar  5 18:49:42 2004
+++ gcc/config/arm/arm.c	Fri Mar  5 16:00:21 2004
@@ -7598,6 +7629,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 (really_return)
      int really_return;
@@ -7788,27 +7839,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)
@@ -9610,26 +9677,6 @@
     }
 }
 
-/* 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;
-}
-
 /* 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.  */