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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
|
This patch:
- maps branch-cirrus_insn to branch-nop-nop-cirrus_insn
- maps branch-noncirrus-cirrus to branch-noncirrus-nop-cirrus
- inserts a nop in load rN - load/store64 mvX,[rN] sequences to avoid an
undocumented hardware bug.
- always fixes up invalid code sequences when compiling hard Maverick insns
and removes the -mcirrus-fix-invalid-insns flag because chip development
has stopped and all existing silicon has these bugs, while the extra code
that claimed to do other things for the extra bugs in the old revision D0
silicon was complete junk.
- Takes the cirrus checking out of the main arm_reorg loop, to remove the
speed penalty it caused when not compiling for Maverick.
Martin Guy <martinwguy@yahoo.it> 3 March 2009
--- gcc-4.3.2/gcc/config/arm/arm.c.orig 2009-02-18 14:59:22.000000000 +0000
+++ gcc-4.3.2/gcc/config/arm/arm.c 2009-03-10 09:32:31.000000000 +0000
@@ -134,7 +134,7 @@
static int arm_address_cost (rtx);
static bool arm_memory_load_p (rtx);
static bool arm_cirrus_insn_p (rtx);
-static void cirrus_reorg (rtx);
+static void cirrus_reorg (void);
static void arm_init_builtins (void);
static rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
static void arm_init_iwmmxt_builtins (void);
@@ -6580,122 +6580,122 @@
/* Cirrus reorg for invalid instruction combinations. */
static void
-cirrus_reorg (rtx first)
+cirrus_reorg (void)
{
- enum attr_cirrus attr;
- rtx body = PATTERN (first);
- rtx t;
- int nops;
-
- /* Any branch must be followed by 2 non Cirrus instructions. */
- if (GET_CODE (first) == JUMP_INSN && GET_CODE (body) != RETURN)
- {
- nops = 0;
- t = next_nonnote_insn (first);
-
- if (arm_cirrus_insn_p (t))
- ++ nops;
-
- if (arm_cirrus_insn_p (next_nonnote_insn (t)))
- ++ nops;
-
- while (nops --)
- emit_insn_after (gen_nop (), first);
-
- return;
- }
-
- /* (float (blah)) is in parallel with a clobber. */
- if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
- body = XVECEXP (body, 0, 0);
-
- if (GET_CODE (body) == SET)
- {
- rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1);
-
- /* cfldrd, cfldr64, cfstrd, cfstr64 must
- be followed by a non Cirrus insn. */
- if (get_attr_cirrus (first) == CIRRUS_DOUBLE)
- {
- if (arm_cirrus_insn_p (next_nonnote_insn (first)))
- emit_insn_after (gen_nop (), first);
+ rtx insn, body;
- return;
- }
- else if (arm_memory_load_p (first))
- {
- unsigned int arm_regno;
+ /* Examine every instruction and see if it needs adjusting */
+ for (insn = get_insns (); insn; insn = next_insn (insn))
+ switch (GET_CODE (insn))
+ {
+ case JUMP_INSN:
+ /* Any branch must be followed by 2 non Cirrus instructions. */
+ body = PATTERN (insn);
+ if (GET_CODE (body) != RETURN)
+ {
+ rtx next = next_real_insn (insn);
- /* Any ldr/cfmvdlr, ldr/cfmvdhr, ldr/cfmvsr, ldr/cfmv64lr,
- ldr/cfmv64hr combination where the Rd field is the same
- in both instructions must be split with a non Cirrus
- insn. Example:
+ if (arm_cirrus_insn_p (next))
+ {
+ emit_insn_after (gen_nop (), insn);
+ emit_insn_after (gen_nop (), insn);
+ }
+ else
+ if (arm_cirrus_insn_p (next_real_insn (next)))
+ emit_insn_after (gen_nop (), next);
+ }
+ break;
+ case INSN:
+ /* Any ldr/cfstrd combination where the Rd field is the same
+ in both instructions must be split with a non Cirrus insn.
+ Example:
ldr r0, blah
nop
- cfmvsr mvf0, r0. */
-
- /* Get Arm register number for ldr insn. */
- if (GET_CODE (lhs) == REG)
- arm_regno = REGNO (lhs);
- else
- {
- gcc_assert (GET_CODE (rhs) == REG);
- arm_regno = REGNO (rhs);
- }
+ cfstrd mvd0, [r0]
+ otherwise the FPU stores to random memory locations.
+ */
+ body = PATTERN (insn);
- /* Next insn. */
- first = next_nonnote_insn (first);
-
- if (! arm_cirrus_insn_p (first))
- return;
+ /* If first insn is ldr rN, <mem>... */
+ if (GET_CODE (body) == SET && arm_memory_load_p (insn))
+ {
+ rtx next = next_real_insn (insn);
- body = PATTERN (first);
+ /* ...and second is cirrus double word load or store... */
+ if (arm_cirrus_insn_p (next)
+ && get_attr_cirrus (next) == CIRRUS_DOUBLE)
+ {
+ rtx nextbody = PATTERN (next);
+ rtx ldr_target; /* destination of ldr insn: rN */
+ rtx arm_part; /* src or dest espression involving [rN] */
+ unsigned int arm_regno; /* the arm reg in the [rN] part */
- /* (float (blah)) is in parallel with a clobber. */
- if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0))
- body = XVECEXP (body, 0, 0);
-
- if (GET_CODE (body) == FLOAT)
- body = XEXP (body, 0);
-
- if (get_attr_cirrus (first) == CIRRUS_MOVE
- && GET_CODE (XEXP (body, 1)) == REG
- && arm_regno == REGNO (XEXP (body, 1)))
- emit_insn_after (gen_nop (), first);
+ ldr_target = XEXP (body, 0);
+ gcc_assert (GET_CODE (ldr_target) == REG);
- return;
- }
- }
+ gcc_assert (GET_CODE (nextbody) == SET);
- /* get_attr cannot accept USE or CLOBBER. */
- if (!first
- || GET_CODE (first) != INSN
- || GET_CODE (PATTERN (first)) == USE
- || GET_CODE (PATTERN (first)) == CLOBBER)
- return;
+ /* Find the load or store address of the insn */
+ switch (GET_CODE (XEXP (nextbody, 0)))
+ {
+ case MEM: /* it's cfstrd/64 */
+ gcc_assert (GET_CODE (XEXP (nextbody, 1)) == REG);
+ arm_part = XEXP (XEXP (nextbody, 0), 0);
+ break;
- attr = get_attr_cirrus (first);
+ case REG: /* it's cfldrd/64 */
+ if (GET_CODE (XEXP (nextbody, 1)) == MEM)
+ arm_part = XEXP (XEXP (nextbody, 1), 0);
+ else
+ /* It can also be const_double or const_int, which will
+ * turn into harmless [pc, #offset] in arm_reorg() */
+ continue;
+ break;
- /* Any coprocessor compare instruction (cfcmps, cfcmpd, ...)
- must be followed by a non-coprocessor instruction. */
- if (attr == CIRRUS_COMPARE)
- {
- nops = 0;
+ default:
+ gcc_unreachable ();
+ }
- t = next_nonnote_insn (first);
+ /* Find the arm register number in the [rN] expression */
+ arm_regno = 0; /* none */
+ switch (GET_CODE (arm_part))
+ {
+ case REG: /* it's [rN] */
+ arm_regno = REGNO (arm_part);
+ break;
- if (arm_cirrus_insn_p (t))
- ++ nops;
+ case PLUS: /* it's [rN, #XXX] or [rN, -#YYY]. */
+ if (GET_CODE (XEXP (arm_part, 0)) == REG)
+ arm_regno = REGNO (XEXP (arm_part, 0)); /* usual case */
+ else if (GET_CODE (XEXP (arm_part, 1)) == REG)
+ arm_regno = REGNO (XEXP (arm_part, 1)); /* inverted */
+ else
+ gcc_unreachable();
+ break;
- if (arm_cirrus_insn_p (next_nonnote_insn (t)))
- ++ nops;
+ case PRE_INC:
+ case POST_INC:
+ case PRE_DEC:
+ case POST_DEC:
+ gcc_assert (GET_CODE (XEXP (arm_part, 0)) == REG);
+ arm_regno = REGNO (XEXP (arm_part, 0));
+ break;
- while (nops --)
- emit_insn_after (gen_nop (), first);
+ default:
+ /* Do nothing */
+ continue;
+ }
- return;
- }
+ if (arm_regno == REGNO (ldr_target))
+ emit_insn_after (gen_nop (), insn);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
}
/* Return TRUE if X references a SYMBOL_REF. */
@@ -9293,6 +9296,10 @@
minipool_fix_head = minipool_fix_tail = NULL;
+ /* Do cirrus_reorg() first as it may insert extra instructions */
+ if (TARGET_MAVERICK && TARGET_HARD_FLOAT)
+ cirrus_reorg ();
+
/* The first insn must always be a note, or the code below won't
scan it properly. */
insn = get_insns ();
@@ -9302,12 +9309,6 @@
/* Scan all the insns and record the operands that will need fixing. */
for (insn = next_nonnote_insn (insn); insn; insn = next_nonnote_insn (insn))
{
- if (TARGET_CIRRUS_FIX_INVALID_INSNS
- && (arm_cirrus_insn_p (insn)
- || GET_CODE (insn) == JUMP_INSN
- || arm_memory_load_p (insn)))
- cirrus_reorg (insn);
-
if (GET_CODE (insn) == BARRIER)
push_minipool_barrier (insn, address);
else if (INSN_P (insn))
--- gcc-4.3.2/gcc/config/arm/arm.opt.orig 2009-03-02 10:17:08.000000000 +0000
+++ gcc-4.3.2/gcc/config/arm/arm.opt 2009-03-02 10:27:30.000000000 +0000
@@ -63,10 +63,6 @@
Target Report Mask(CALLER_INTERWORKING)
Thumb: Assume function pointers may go to non-Thumb aware code
-mcirrus-fix-invalid-insns
-Target Report Mask(CIRRUS_FIX_INVALID_INSNS)
-Cirrus: Place NOPs to avoid invalid instruction combinations
-
mcpu=
Target RejectNegative Joined
Specify the name of the target CPU
--- gcc-4.3.2/gcc/doc/invoke.texi.old 2008-12-04 11:48:54.000000000 +0000
+++ gcc-4.3.2/gcc/doc/invoke.texi 2009-03-02 10:26:45.000000000 +0000
@@ -429,7 +429,6 @@
-msingle-pic-base -mno-single-pic-base @gol
-mpic-register=@var{reg} @gol
-mnop-fun-dllimport @gol
--mcirrus-fix-invalid-insns -mno-cirrus-fix-invalid-insns @gol
-mieee @gol
-mpoke-function-name @gol
-mthumb -marm @gol
@@ -8671,18 +8671,6 @@
Specify the register to be used for PIC addressing. The default is R10
unless stack-checking is enabled, when R9 is used.
-@item -mcirrus-fix-invalid-insns
-@opindex mcirrus-fix-invalid-insns
-@opindex mno-cirrus-fix-invalid-insns
-Insert NOPs into the instruction stream to in order to work around
-problems with invalid Maverick instruction combinations. This option
-is only valid if the @option{-mcpu=ep9312} option has been used to
-enable generation of instructions for the Cirrus Maverick floating
-point co-processor. This option is not enabled by default, since the
-problem is only present in older Maverick implementations. The default
-can be re-enabled by use of the @option{-mno-cirrus-fix-invalid-insns}
-switch.
-
@item -mieee
When compiling for the Maverick FPU, disable the instructions that fail
to honor denormalized values. As these include floating point add, sub,
|