aboutsummaryrefslogtreecommitdiff
blob: fba697db4762f7b40e9e756d8326f03c2bd74e25 (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
#! /bin/sh -e

# DP: ARM patch for large constant generation

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 -p1 --fuzz 10 < $0
        cd $src && autoconf
        ;;
    -unpatch)
        patch $pdir -f --no-backup-if-mismatch -R -p1 --fuzz 10 < $0
        cd $src && autoconf
        ;;
    *)
        echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
        exit 1
esac
exit 0

--- src/gcc/config/arm/arm.c	2001/01/25 14:03:24	1.43.4.8
+++ src/gcc/config/arm/arm.c	2001/06/23 12:07:08
@@ -722,6 +722,33 @@ arm_split_constant (code, mode, val, tar
   return arm_gen_constant (code, mode, val, target, source, subtargets, 1);
 }
 
+static int
+count_insns_for_constant (HOST_WIDE_INT remainder, int i)
+{
+  HOST_WIDE_INT temp1;
+  int num_insns = 0;
+  do
+    {
+      int end;
+	  
+      if (i <= 0)
+	i += 32;
+      if (remainder & (3 << (i - 2)))
+	{
+	  end = i - 8;
+	  if (end < 0)
+	    end += 32;
+	  temp1 = remainder & ((0x0ff << end)
+				    | ((i < end) ? (0xff >> (32 - end)) : 0));
+	  remainder &= ~temp1;
+	  num_insns++;
+	  i -= 6;
+	}
+      i -= 2;
+    } while (remainder);
+  return num_insns;
+}
+
 /* As above, but extra parameter GENERATE which, if clear, suppresses
    RTL generation.  */
 int
@@ -1178,7 +1205,7 @@ arm_gen_constant (code, mode, val, targe
      We start by looking for the largest block of zeros that are aligned on
      a 2-bit boundary, we then fill up the temps, wrapping around to the
      top of the word when we drop off the bottom.
-     In the worst case this code should produce no more than four insns. */
+     In the worst case this code should produce no more than four insns.  */
   {
     int best_start = 0;
     int best_consecutive_zeros = 0;
@@ -1187,9 +1214,9 @@ arm_gen_constant (code, mode, val, targe
       {
 	int consecutive_zeros = 0;
 
-	if (! (remainder & (3 << i)))
+	if (!(remainder & (3 << i)))
 	  {
-	    while ((i < 32) && ! (remainder & (3 << i)))
+	    while ((i < 32) && !(remainder & (3 << i)))
 	      {
 		consecutive_zeros += 2;
 		i += 2;
@@ -1202,10 +1229,37 @@ arm_gen_constant (code, mode, val, targe
 	    i -= 2;
 	  }
       }
+
+    /* So long as it won't require any more insns to do so, it's
+       desirable to emit a small constant (in bits 0...9) in the last
+       insn.  This way there is more chance that it can be combined with
+       a later addressing insn to form a pre-indexed load or store
+       operation.  Consider:
+
+	       *((volatile int *)0xe0000100) = 1;
+	       *((volatile int *)0xe0000110) = 2;
+
+       We want this to wind up as:
+
+		mov rA, #0xe0000000
+		mov rB, #1
+		str rB, [rA, #0x100]
+		mov rB, #2
+		str rB, [rA, #0x110]
+
+       rather than having to synthesize both large constants from scratch.
+
+       Therefore, we calculate how many insns would be required to emit
+       the constant starting from `best_start', and also starting from 
+       zero (ie with bit 31 first to be output).  If `best_start' doesn't 
+       yield a shorter sequence, we may as well use zero.  */
+    if (best_start != 0
+	&& ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
+	&& (count_insns_for_constant (remainder, 0) <= 
+	    count_insns_for_constant (remainder, best_start)))
+      best_start = 0;
 
-    /* Now start emitting the insns, starting with the one with the highest
-       bit set: we do this so that the smallest number will be emitted last;
-       this is more likely to be combinable with addressing insns. */
+    /* Now start emitting the insns.  */
     i = best_start;
     do
       {