summaryrefslogtreecommitdiff
path: root/recipes/gcc/gcc-4.2.2/arm-crunch-cirrus-bugfixes.patch
blob: cb0af8546d5df6c5a2e02663997d2f47d0e21307 (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
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
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.c gcc-4.1.2/gcc/config/arm/arm.c
--- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.c	2007-05-09 16:32:29.000000000 +1000
+++ gcc-4.1.2/gcc/config/arm/arm.c	2007-05-15 09:39:41.000000000 +1000
@@ -4,6 +4,7 @@
    Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
    and Martin Simmons (@harleqn.co.uk).
    More major hacks by Richard Earnshaw (rearnsha@arm.com).
+   Cirrus Crunch bugfixes by Vladimir Ivanov (vladit@nucleusys.com)
 
    This file is part of GCC.
 
@@ -131,9 +132,17 @@
 static bool arm_xscale_rtx_costs (rtx, int, int, int *);
 static bool arm_9e_rtx_costs (rtx, int, int, int *);
 static int arm_address_cost (rtx);
-static bool arm_memory_load_p (rtx);
+// static bool arm_memory_load_p (rtx);
 static bool arm_cirrus_insn_p (rtx);
-static void cirrus_reorg (rtx);
+// static void cirrus_reorg (rtx);
+static bool arm_mem_access_p (rtx);
+static bool cirrus_dest_regn_p (rtx, int);
+static rtx cirrus_prev_next_mach_insn (rtx, int *, int);
+static rtx cirrus_prev_mach_insn (rtx, int *);
+static rtx cirrus_next_mach_insn (rtx, int *);
+static void cirrus_reorg_branch (rtx);
+static void cirrus_reorg_bug1 (rtx);
+static void cirrus_reorg_bug10_12 (rtx);
 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);
@@ -5399,41 +5412,6 @@
               || TREE_CODE (valtype) == COMPLEX_TYPE));
 }
 
-/* Returns TRUE if INSN is an "LDR REG, ADDR" instruction.
-   Use by the Cirrus Maverick code which has to workaround
-   a hardware bug triggered by such instructions.  */
-static bool
-arm_memory_load_p (rtx insn)
-{
-  rtx body, lhs, rhs;;
-
-  if (insn == NULL_RTX || GET_CODE (insn) != INSN)
-    return false;
-
-  body = PATTERN (insn);
-
-  if (GET_CODE (body) != SET)
-    return false;
-
-  lhs = XEXP (body, 0);
-  rhs = XEXP (body, 1);
-
-  lhs = REG_OR_SUBREG_RTX (lhs);
-
-  /* If the destination is not a general purpose
-     register we do not have to worry.  */
-  if (GET_CODE (lhs) != REG
-      || REGNO_REG_CLASS (REGNO (lhs)) != GENERAL_REGS)
-    return false;
-
-  /* As well as loads from memory we also have to react
-     to loads of invalid constants which will be turned
-     into loads from the minipool.  */
-  return (GET_CODE (rhs) == MEM
-	  || GET_CODE (rhs) == SYMBOL_REF
-	  || note_invalid_constants (insn, -1, false));
-}
-
 /* Return TRUE if INSN is a Cirrus instruction.  */
 static bool
 arm_cirrus_insn_p (rtx insn)
@@ -5452,124 +5433,218 @@
   return attr != CIRRUS_NOT;
 }
 
-/* Cirrus reorg for invalid instruction combinations.  */
-static void
-cirrus_reorg (rtx first)
+/* Return TRUE if ISN does memory access.  */
+static bool
+arm_mem_access_p (rtx insn)
 {
-  enum attr_cirrus attr;
-  rtx body = PATTERN (first);
-  rtx t;
-  int nops;
+  enum attr_type attr;
 
-  /* 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);
+  /* get_attr aborts on USE and CLOBBER.  */
+  if (!insn
+      || GET_CODE (insn) != INSN
+      || GET_CODE (PATTERN (insn)) == USE
+      || GET_CODE (PATTERN (insn)) == CLOBBER)
+    return 0;
 
-      if (arm_cirrus_insn_p (t))
-	++ nops;
+    attr = get_attr_type (insn);
 
-      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
-	++ nops;
+  return attr == TYPE_LOAD_BYTE
+   || attr == TYPE_LOAD1   || attr == TYPE_LOAD2    || attr == TYPE_LOAD3 || attr == TYPE_LOAD4
+   || attr == TYPE_F_CVT
+   || attr == TYPE_F_MEM_R || attr == TYPE_R_MEM_F  || attr == TYPE_F_2_R || attr == TYPE_R_2_F
+   || attr == TYPE_F_LOAD	|| attr == TYPE_F_LOADS  || attr == TYPE_F_LOADD
+   || attr == TYPE_F_STORE || attr == TYPE_F_STORES || attr == TYPE_F_STORED
+   || attr == TYPE_STORE1  || attr == TYPE_STORE2   || attr == TYPE_STORE3  || attr == TYPE_STORE4;
+
+}
 
-      while (nops --)
-	emit_insn_after (gen_nop (), first);
+/* Return TRUE if destination is certain Cirrus register.  */
+static bool
+cirrus_dest_regn_p (rtx body, int regn)
+{
+  rtx lhs;
+  int reg;
+  lhs = XEXP (body, 0);
+  if (GET_CODE (lhs) != REG)
+    return 0;
 
-      return;
-    }
+  reg = REGNO (lhs);
+  if (REGNO_REG_CLASS (reg) != CIRRUS_REGS)
+    return 0;
 
-  /* (float (blah)) is in parallel with a clobber.  */
-  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
-    body = XVECEXP (body, 0, 0);
+  return reg == regn;
+}
+
+/* Get previous/next machine instruction during Cirrus workaround scans.
+   Assume worst case (for the purpose of Cirrus workarounds)
+   for JUMP / CALL instructions.  */
+static rtx
+cirrus_prev_next_mach_insn (rtx insn, int *len, int next)
+{
+  rtx t;
+  int l = 0;
 
-  if (GET_CODE (body) == SET)
+  /* It seems that we can count only on INSN length.  */
+  for ( ; ; )
     {
-      rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1);
+      if (next)
+    	insn = NEXT_INSN (insn);
+      else
+    	insn = PREV_INSN (insn);
+      if (!insn)
+    	break;
 
-      /* 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);
+    if (GET_CODE (insn) == INSN)
+      {
+	    l = get_attr_length (insn) / 4;
+        if (l)
+	      break;
+      }
+    else if (GET_CODE (insn) == JUMP_INSN)
+      {
+        l = 1;
+        t = is_jump_table (insn);
+        if (t)
+          l += get_jump_table_size (t) / 4;
+        break;
+      }
+        else if (GET_CODE (insn) == CALL_INSN)
+      {
+        l = 1;
+        break;
+      }
+    }
 
-	  return;
-	}
-      else if (arm_memory_load_p (first))
-	{
-	  unsigned int arm_regno;
+  if (len)
+    *len = l;
 
-	  /* 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:
-
-	     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);
-	    }
+  return insn;
+}
 
-	  /* Next insn.  */
-	  first = next_nonnote_insn (first);
+static rtx
+cirrus_prev_mach_insn (rtx insn, int *len)
+{
+  return cirrus_prev_next_mach_insn (insn, len, 0);
+}
 
-	  if (! arm_cirrus_insn_p (first))
-	    return;
+static rtx
+cirrus_next_mach_insn (rtx insn, int *len)
+{
+  return cirrus_prev_next_mach_insn (insn, len, 1);
+}
 
-	  body = PATTERN (first);
+/* Cirrus reorg for branch slots.  */
+static void
+cirrus_reorg_branch (rtx insn)
+{
+  rtx t;
+  int nops, l;
 
-          /* (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);
+  /* TODO: handle jump-tables.  */
+  t = is_jump_table (insn);
+  if (t)
+    return;
+
+  /* Any branch must be followed by 2 non Cirrus instructions.  */
+  t = insn;
+  for (nops = 2; nops > 0; )
+    {
+      if (!cirrus_next_mach_insn (t, 0))
+        {
+          insn = t;
+          break;
+        }
+      t = cirrus_next_mach_insn (t, &l);
+      if (arm_cirrus_insn_p (t))
+        break;
+      nops -= l;
 
-	  return;
-	}
     }
 
-  /* get_attr cannot accept USE or CLOBBER.  */
-  if (!first
-      || GET_CODE (first) != INSN
-      || GET_CODE (PATTERN (first)) == USE
-      || GET_CODE (PATTERN (first)) == CLOBBER)
-    return;
+  while (nops-- > 0)
+    emit_insn_after (gen_nop (), insn); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */
+}
 
-  attr = get_attr_cirrus (first);
+/* Cirrus reorg for bug #1 (cirrus + cfcmpxx).  */
+static void
+cirrus_reorg_bug1 (rtx insn)
+{
+  rtx body = PATTERN (insn), body2;
+  rtx t;
+  int i, nops, l;
+  enum attr_cirrus attr;
 
-  /* Any coprocessor compare instruction (cfcmps, cfcmpd, ...)
-     must be followed by a non-coprocessor instruction.  */
-  if (attr == CIRRUS_COMPARE)
+  /* Check if destination or clobber is Cirrus register.  */
+  if (GET_CODE (body) == PARALLEL)
     {
-      nops = 0;
-
-      t = next_nonnote_insn (first);
+      for (i = 0; i < XVECLEN (body, 0); i++)
+	  {
+	  body2 = XVECEXP (body, 0, i);
+      if (GET_CODE (body2) == SET)
+        {
+          if (cirrus_dest_regn_p (body2, LAST_CIRRUS_FP_REGNUM))
+            {
+		       nops = 5;
+               goto fix;
+            }
+        }
+      else if (GET_CODE (body2) == CLOBBER)
+        {
+          if (cirrus_dest_regn_p (body2, LAST_CIRRUS_FP_REGNUM))
+		    {
+		      nops = 4;
+		      goto fix;
+            }
+        }
+      }
+    }
+  else if (GET_CODE (body) == SET)
+    {
+      if (cirrus_dest_regn_p (body, LAST_CIRRUS_FP_REGNUM))
+	  {
+	    nops = 5;
+        goto fix;
+	  }
+    }
+  return;
 
-      if (arm_cirrus_insn_p (t))
-	++ nops;
+fix:
+  t = insn;
+  for ( ; nops > 0; )
+    {
+      t = cirrus_next_mach_insn (t, &l);
+      if (!t)
+	break;
+      if (GET_CODE (t) == JUMP_INSN
+	  || GET_CODE (t) == CALL_INSN)
+	{
+	  nops -= l;
+	  break;
+	}
+      else if (arm_cirrus_insn_p (t))
+	{
+	  attr = get_attr_cirrus (t);
+	  if (attr == CIRRUS_COMPARE)
+	    break;
+	}
+      nops -= l;
+    }
 
-      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
-	++ nops;
+  while (nops-- > 0)
+    emit_insn_after (gen_nop (), insn); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */
+}
 
-      while (nops --)
-	emit_insn_after (gen_nop (), first);
+/* Cirrus reorg for bugs #10 and #12 (data aborts).  */
+static void
+cirrus_reorg_bug10_12 (rtx insn)
+{
+  rtx t;
 
-      return;
-    }
+  t = cirrus_next_mach_insn (insn, 0);
+  if (arm_cirrus_insn_p (t))
+    if (TARGET_CIRRUS_D0 ||
+	get_attr_cirrus (t) == CIRRUS_DOUBLE)
+      emit_insn_after (gen_nop (), insn); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */
 }
 
 /* Return TRUE if X references a SYMBOL_REF.  */
@@ -7727,7 +7796,7 @@
 {
   Mnode * mp;
   Mnode * nmp;
-  int align64 = 0;
+  int align64 = 0, stuffnop = 0;
 
   if (ARM_DOUBLEWORD_ALIGN)
     for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
@@ -7742,8 +7811,27 @@
 	     ";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n",
 	     INSN_UID (scan), (unsigned long) minipool_barrier->address, align64 ? 8 : 4);
 
+  /* Check if branch before minipool is already stuffed with nops.  */
+  if (TARGET_CIRRUS_D0 || TARGET_CIRRUS_D1)
+    {
+      rtx t;
+
+      t = prev_active_insn (scan);
+      if (GET_CODE (t) != INSN
+	  || PATTERN (t) != const0_rtx)
+	  stuffnop = 1;
+    }
   scan = emit_label_after (gen_label_rtx (), scan);
   scan = emit_insn_after (align64 ? gen_align_8 () : gen_align_4 (), scan);
+  /* Last instruction was branch, so put two non-Cirrus opcodes.  */
+  if (stuffnop)
+    {
+#if TARGET_CIRRUS /* This is doubling up on nops, so I don't think this is a good idea */
+      emit_insn_before (gen_nop (), scan); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */
+      emit_insn_before (gen_nop (), scan); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */
+#endif
+    }
+
   scan = emit_label_after (minipool_vector_label, scan);
 
   for (mp = minipool_vector_head; mp != NULL; mp = nmp)
@@ -8151,15 +8239,38 @@
   gcc_assert (GET_CODE (insn) == NOTE);
   minipool_pad = 0;
 
+#if TARGET_CIRRUS /* I think this is a double-up */
+  /* Scan all the insn and fix Cirrus issues.  */
+  if (TARGET_CIRRUS_D0 || TARGET_CIRRUS_D1)
+    {
+      rtx t, s;
+
+      for (t = cirrus_next_mach_insn (insn, 0); t; t = cirrus_next_mach_insn (t, 0))
+    if (arm_mem_access_p (t))
+      cirrus_reorg_bug10_12 (t);
+
+      if (TARGET_CIRRUS_D0)
+        for (t = cirrus_next_mach_insn (insn, 0); t; t = cirrus_next_mach_insn (t, 0))
+      if (arm_cirrus_insn_p (t))
+        cirrus_reorg_bug1 (t);
+
+      /* Find last insn.  */
+      for (t = insn; ; t = s)
+        {
+          s = cirrus_next_mach_insn (t, 0);
+          if (!s)
+            break;
+	    }
+      /* Scan backward and fix branches. - WARNING: appears to cause "bad immediate value for offset" problems! */
+      for ( ; t; t = cirrus_prev_mach_insn (t, 0))
+        if (GET_CODE (t) == JUMP_INSN
+        || GET_CODE (t) == CALL_INSN)
+          cirrus_reorg_branch (t);
+    }
+#endif
   /* 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))
@@ -11755,16 +11910,10 @@
 		  || get_attr_conds (this_insn) != CONDS_NOCOND)
 		fail = TRUE;
 
-	      /* A conditional cirrus instruction must be followed by
-		 a non Cirrus instruction.  However, since we
-		 conditionalize instructions in this function and by
-		 the time we get here we can't add instructions
-		 (nops), because shorten_branches() has already been
-		 called, we will disable conditionalizing Cirrus
-		 instructions to be safe.  */
-	      if (GET_CODE (scanbody) != USE
-		  && GET_CODE (scanbody) != CLOBBER
-		  && get_attr_cirrus (this_insn) != CIRRUS_NOT)
+	      /* To avoid erratic behaviour, we avoid conditional Cirrus
+		 instructions when doing workarounds.  */
+	      if (arm_cirrus_insn_p(this_insn)
+    	  && (TARGET_CIRRUS_D0 || TARGET_CIRRUS_D1))
 		fail = TRUE;
 	      break;
 
diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.h gcc-4.1.2/gcc/config/arm/arm.h
--- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.h	2005-11-05 01:02:51.000000000 +1000
+++ gcc-4.1.2/gcc/config/arm/arm.h	2007-05-15 10:15:05.000000000 +1000
@@ -5,6 +5,7 @@
    and Martin Simmons (@harleqn.co.uk).
    More major hacks by Richard Earnshaw (rearnsha@arm.com)
    Minor hacks by Nick Clifton (nickc@cygnus.com)
+   Cirrus Crunch fixes by Vladimir Ivanov (vladitx@nucleusys.com)
 
    This file is part of GCC.
 
@@ -140,7 +141,9 @@
 %{msoft-float:%{mhard-float:						\
 	%e-msoft-float and -mhard_float may not be used together}}	\
 %{mbig-endian:%{mlittle-endian:						\
-	%e-mbig-endian and -mlittle-endian may not be used together}}"
+	%e-mbig-endian and -mlittle-endian may not be used together}}  \
+%{mfix-crunch-d0:%{mfix-crunch-d1:					\
+	%e-mfix-crunch-d0 and -mfix-crunch-d1 may not be used together}}"
 
 #ifndef CC1_SPEC
 #define CC1_SPEC ""
@@ -179,6 +182,9 @@
 #define TARGET_HARD_FLOAT_ABI		(arm_float_abi == ARM_FLOAT_ABI_HARD)
 #define TARGET_FPA			(arm_fp_model == ARM_FP_MODEL_FPA)
 #define TARGET_MAVERICK			(arm_fp_model == ARM_FP_MODEL_MAVERICK)
+#define TARGET_CIRRUS			(arm_arch_cirrus)
+#define TARGET_CIRRUS_D0		0 /* (target_flags & ARM_FLAG_CIRRUS_D0) */
+#define TARGET_CIRRUS_D1		1 /* (target_flags & ARM_FLAG_CIRRUS_D1) */
 #define TARGET_VFP			(arm_fp_model == ARM_FP_MODEL_VFP)
 #define TARGET_IWMMXT			(arm_arch_iwmmxt)
 #define TARGET_REALLY_IWMMXT		(TARGET_IWMMXT && TARGET_ARM)
diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.opt gcc-4.1.2/gcc/config/arm/arm.opt
--- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.opt	2005-11-05 01:02:51.000000000 +1000
+++ gcc-4.1.2/gcc/config/arm/arm.opt	2007-05-15 10:09:31.000000000 +1000
@@ -68,6 +68,14 @@
 Target Report Mask(CIRRUS_FIX_INVALID_INSNS)
 Cirrus: Place NOPs to avoid invalid instruction combinations
 
+fix-crunch-d0
+Target Report Mask(ARM_FLAG_CIRRUS_D0)
+Cirrus: workarounds for Crunch coprocessor revision D0
+
+fix-crunch-d1
+Target Report Mask(ARM_FLAG_CIRRUS_D1)
+Cirrus: workarounds for Crunch coprocessor revision D1
+
 mcpu=
 Target RejectNegative Joined
 Specify the name of the target CPU
diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/doc/invoke.texi gcc-4.1.2/gcc/doc/invoke.texi
--- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/doc/invoke.texi	2006-09-26 07:21:58.000000000 +1000
+++ gcc-4.1.2/gcc/doc/invoke.texi	2007-05-15 10:07:04.000000000 +1000
@@ -408,7 +408,7 @@
 -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
+-mfix-crunch-d0 -mfix-crunch-d1 @gol
 -mpoke-function-name @gol
 -mthumb  -marm @gol
 -mtpcs-frame  -mtpcs-leaf-frame @gol
@@ -7435,17 +7435,12 @@
 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 -mfix-crunch-d0
+@itemx -mfix-crunch-d1
+@opindex mfix-crunch-d0
+@opindex mfix-crunch-d1
+Enable workarounds for the Cirrus MaverickCrunch coprocessor revisions
+D0 and D1 respectively.
 
 @item -mpoke-function-name
 @opindex mpoke-function-name