summaryrefslogtreecommitdiff
blob: 38b183288ba9f8ade2e37fdc4eb2779950ae68d4 (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
--- gcc-3.4.2/gcc/config/mips/mips.h	Thu Jul 15 02:42:47 2004
+++ gcc-3.4.2/gcc/config/mips/mips.h	Sat Sep 18 00:41:48 2004
@@ -122,6 +122,7 @@
 extern const char *mips_isa_string;	/* for -mips{1,2,3,4} */
 extern const char *mips_abi_string;	/* for -mabi={32,n32,64} */
 extern const char *mips_cache_flush_func;/* for -mflush-func= and -mno-flush-func */
+extern const char *mips_ip28_cache_barrier;/* for -mip28-cache-barrier */
 extern int mips_string_length;		/* length of strings for mips16 */
 extern const struct mips_cpu_info mips_cpu_info_table[];
 extern const struct mips_cpu_info *mips_arch_info;
@@ -333,6 +334,7 @@
 #define TARGET_MIPS9000             (mips_arch == PROCESSOR_R9000)
 #define TARGET_SB1                  (mips_arch == PROCESSOR_SB1)
 #define TARGET_SR71K                (mips_arch == PROCESSOR_SR71000)
+#define TARGET_IP28                 (mips_ip28_cache_barrier != 0)
 
 /* Scheduling target defines.  */
 #define TUNE_MIPS3000               (mips_tune == PROCESSOR_R3000)
@@ -752,6 +754,8 @@
       N_("Don't call any cache flush functions"), 0},			\
   { "flush-func=", &mips_cache_flush_func,				\
       N_("Specify cache flush function"), 0},				\
+  { "ip28-cache-barrier", &mips_ip28_cache_barrier,			\
+      N_("Generate special cache barriers for SGI Indigo2 R10k"), 0},	\
 }
 
 /* This is meant to be redefined in the host dependent files.  */
@@ -3448,3 +3452,11 @@
 	" TEXT_SECTION_ASM_OP);
 #endif
 #endif
+
+#define ASM_OUTPUT_R10K_CACHE_BARRIER(STREAM)		\
+  fprintf (STREAM, "\tcache 0x14,0($sp)\t%s Cache Barrier\n", ASM_COMMENT_START)
+
+/*
+ * mips.h	Thu Jul 15 02:42:47 2004
+ * mips.h	Fri Sep 17 23:18:19 2004	ip28
+ */
--- gcc-3.4.2/gcc/config/mips/mips.c	Wed Jul  7 21:21:10 2004
+++ gcc-3.4.2/gcc/config/mips/mips.c	Fri Sep 17 23:33:44 2004
@@ -502,6 +502,11 @@
 
 const char *mips_cache_flush_func = CACHE_FLUSH_FUNC;
 
+/* Nonzero means generate special cache barriers to inhibit speculative
+   stores which might endanger cache coherency or reference invalid
+   addresses (especially on SGI's Indigo2 R10k (IP28)).  */
+const char *mips_ip28_cache_barrier;
+
 /* If TRUE, we split addresses into their high and low parts in the RTL.  */
 int mips_split_addresses;
 
@@ -9676,3 +9681,7 @@
 #endif /* TARGET_IRIX */
 
 #include "gt-mips.h"
+/*
+ * mips.c	Wed Jul  7 21:21:10 2004
+ * mips.c	Fri Sep 17 23:25:53 2004	ip28
+ */
--- gcc-3.4.2/gcc/final.c	Sun Jan 18 23:39:57 2004
+++ gcc-3.4.2/gcc/final.c	Fri Nov 19 00:40:50 2004
@@ -146,6 +146,13 @@
 
 static rtx last_ignored_compare = 0;
 
+/* Flag indicating this insn is the start of a new basic block.  */
+
+#define NEW_BLOCK_LABEL  1
+#define NEW_BLOCK_BRANCH 2
+
+static int new_block = NEW_BLOCK_LABEL;
+
 /* Assign a unique number to each insn that is output.
    This can be used to generate unique local labels.  */
 
@@ -235,6 +242,7 @@
 #ifdef HAVE_ATTR_length
 static int align_fuzz (rtx, rtx, int, unsigned);
 #endif
+static int output_store_cache_barrier (FILE *, rtx);
 
 /* Initialize data in final at the beginning of a compilation.  */
 
@@ -1505,6 +1513,7 @@
   int seen = 0;
 
   last_ignored_compare = 0;
+  new_block = NEW_BLOCK_LABEL;
 
 #ifdef SDB_DEBUGGING_INFO
   /* When producing SDB debugging info, delete troublesome line number
@@ -1571,6 +1580,7 @@
 
       insn = final_scan_insn (insn, file, optimize, prescan, 0, &seen);
     }
+  new_block = 0;
 }
 
 const char *
@@ -1851,6 +1861,7 @@
 #endif
       if (prescan > 0)
 	break;
+      new_block = NEW_BLOCK_LABEL;
 
       if (LABEL_NAME (insn))
 	(*debug_hooks->label) (insn);
@@ -2009,6 +2020,26 @@
 
 	    break;
 	  }
+
+#ifdef TARGET_IP28
+	if (new_block)
+	  {
+	    /* .reorder: not really in the branch-delay-slot. */
+	    if (! set_noreorder)
+	      new_block = NEW_BLOCK_LABEL;
+
+	    if (new_block == NEW_BLOCK_BRANCH)
+	      /* Not yet, only *after* the branch-delay-slot ! */
+	      new_block = NEW_BLOCK_LABEL;
+	    else
+	      {
+	        if (TARGET_IP28)
+	          output_store_cache_barrier (file, insn);
+	        new_block = 0;
+	      }
+	  }
+#endif
+
 	/* Output this line note if it is the first or the last line
 	   note in a row.  */
 	if (notice_source_line (insn))
@@ -2132,8 +2163,29 @@
 	       clobbered by the function.  */
 	    if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
 	      {
+#ifdef TARGET_IP28
+	        if (TARGET_IP28)
+	          new_block = NEW_BLOCK_LABEL;
+#endif
 		CC_STATUS_INIT;
 	      }
+#ifdef TARGET_IP28
+	    /* Following a conditional branch sequence, we have a new basic
+	       block.  */
+	    if (TARGET_IP28)
+	      {
+		rtx insn = XVECEXP (body, 0, 0);
+		rtx body = PATTERN (insn);
+
+		if ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
+		     && GET_CODE (SET_SRC (body)) != LABEL_REF)
+		    || (GET_CODE (insn) == JUMP_INSN
+			&& GET_CODE (body) == PARALLEL
+			&& GET_CODE (XVECEXP (body, 0, 0)) == SET
+			&& GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF))
+		  new_block = NEW_BLOCK_LABEL;
+	      }
+#endif
 	    break;
 	  }
 
@@ -2188,6 +2240,20 @@
 	  }
 #endif
 
+#ifdef TARGET_IP28
+	/* Following a conditional branch, we have a new basic block.
+	   But if we are inside a sequence, the new block starts after the
+	   last insn of the sequence.  */
+	if (TARGET_IP28 && final_sequence == 0
+	    && (GET_CODE (insn) == CALL_INSN
+	        || (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
+	            && GET_CODE (SET_SRC (body)) != LABEL_REF)
+	        || (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == PARALLEL
+	            && GET_CODE (XVECEXP (body, 0, 0)) == SET
+	            && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF)))
+	      new_block = NEW_BLOCK_BRANCH;
+#endif
+
 #ifndef STACK_REGS
 	/* Don't bother outputting obvious no-ops, even without -O.
 	   This optimization is fast and doesn't interfere with debugging.
@@ -2402,6 +2468,7 @@
 
 	    if (prev_nonnote_insn (insn) != last_ignored_compare)
 	      abort ();
+	    new_block = 0;
 
 	    /* We have already processed the notes between the setter and
 	       the user.  Make sure we don't process them again, this is
@@ -2435,6 +2502,7 @@
 	    abort ();
 #endif
 
+	    new_block = 0;
 	    return new;
 	  }
 
@@ -3866,3 +3934,188 @@
       symbol_queue_size = 0;
     }
 }
+
+
+#ifdef TARGET_IP28
+
+/* Check, whether `insn' is a possibly harmful store instruction, i.e.
+   a store which might cause damage, if speculatively executed. */
+
+static int /*inline*/
+check_pattern_for_store (rtx body)
+{
+  /* Check for (set (mem:M (non_stackpointer_address) ...)).  Here we
+     assume, that addressing with the stackpointer accesses neither
+     uncached-aliased nor invalid memory.  (May be, this applies to the
+     global pointer and frame pointer also, but its saver not to assume
+     it. And probably it's not worthwile to regard these registers) */
+
+  if (body && GET_CODE (body) == SET)
+    {
+      rtx xexp = SET_DEST (body);
+      if (GET_CODE (xexp) == MEM)
+        {
+          /* Check for the most common stackpointer-addressing modes.
+             It's not worthwile to avoid a cache barrier also on the
+             remaining unfrequently used modes.  */
+          xexp = XEXP (xexp, 0);
+          switch (GET_CODE (xexp))
+            {
+            case REG:
+              if (REGNO (xexp) == STACK_POINTER_REGNUM)
+                return 0;
+              break;
+            case PLUS: case MINUS: /* always `SP + const' ? */
+              if (GET_CODE (XEXP (xexp, 0)) == REG
+                  && REGNO (XEXP (xexp, 0)) == STACK_POINTER_REGNUM)
+                return 0;
+              if (GET_CODE (XEXP (xexp, 1)) == REG
+                  && REGNO (XEXP (xexp, 1)) == STACK_POINTER_REGNUM)
+                return 0;
+            }
+          return 1;
+        }
+    }
+  return 0;
+}
+
+static int
+check_insn_for_store (int state, rtx insn)
+{
+  /* Check for (ins (set (mem:M (dangerous_address)) ...)) or end of the
+     current basic block.
+     Criteria to recognize end-of/next basic-block are reduplicated here
+     from final_scan_insn. */
+
+  rtx body;
+  int code;
+
+  if (INSN_DELETED_P (insn))
+    return 0;
+
+  switch (code = GET_CODE (insn))
+    {
+    case CODE_LABEL:
+      return -1;
+    case CALL_INSN:
+    case JUMP_INSN:
+    case INSN:
+      body = PATTERN (insn);
+      if (GET_CODE (body) == SEQUENCE)
+        {
+          /* A delayed-branch sequence */
+          rtx ins0 = XVECEXP (body, 0, 0);
+          rtx pat0 = PATTERN (ins0);
+          int i;
+          for (i = 0; i < XVECLEN (body, 0); i++)
+            {
+              rtx insq = XVECEXP (body, 0, i);
+              if (! INSN_DELETED_P (insq))
+                {
+                  int j = check_insn_for_store (state|1, insq);
+                  if (j)
+                    return j;
+                }
+            }
+          /* Following a conditional branch sequence, we have a new
+             basic block.  */
+          if (GET_CODE (ins0) == JUMP_INSN)
+            if ((GET_CODE (pat0) == SET
+                 && GET_CODE (SET_SRC (pat0)) != LABEL_REF)
+                || (GET_CODE (pat0) == PARALLEL
+                    && GET_CODE (XVECEXP (pat0, 0, 0)) == SET
+                    && GET_CODE (SET_SRC (XVECEXP (pat0, 0, 0))) != LABEL_REF))
+              return -1;
+          /* Handle a call sequence like a conditional branch sequence */
+          if (GET_CODE (ins0) == CALL_INSN)
+            return -1;
+          break;
+        }
+      if (GET_CODE (body) == PARALLEL)
+        {
+          int i;
+          for (i = 0; i < XVECLEN (body, 0); i++)
+            if (check_pattern_for_store (XVECEXP (body, 0, i)))
+              return 1;
+        }
+      /* Now, only a `simple' INSN or JUMP_INSN remains to be checked. */
+      if (code == INSN)
+        if (check_pattern_for_store (body))
+          return 1;
+      /* Handle a CALL_INSN instruction like a conditional branch */
+      if (code == JUMP_INSN || code == CALL_INSN)
+        {
+          /* Following a conditional branch, we have a new basic block. */
+          int ckds = 0;
+          if (code == CALL_INSN)
+            ckds = 1;
+          else
+            {
+              code = GET_CODE (body);
+              if ((code == SET
+                   && GET_CODE (SET_SRC (body)) != LABEL_REF)
+                  || (code == PARALLEL
+                      && GET_CODE (XVECEXP (body, 0, 0)) == SET
+                      && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF))
+                ckds = 1;
+            }
+          if (ckds)
+            {
+              /* But check insn(s) in delay-slot first.  If we could know in
+                 advance that this jump is in `.reorder' mode, where gas will
+                 insert a `nop' into the delay-slot, we could skip this test.
+                 Since we don't know, always assume `.noreorder', sometimes
+                 emitting a cache-barrier, that isn't needed.  */
+              /* But if we are here recursively, already checking a (pseudo-)
+                 delay-slot, we are done.  */
+              if ( !(state & 2) )
+                for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
+                  switch (GET_CODE (insn))
+                    {
+                    case INSN:
+                      if (check_insn_for_store (state|1|2, insn) > 0)
+                        return 1;
+                    case CODE_LABEL:
+                    case CALL_INSN:
+                    case JUMP_INSN:
+                      return -1;
+                    default:
+                      /* skip NOTE,... */;
+                    }
+              return -1;
+            }
+        }
+      /*break*/
+    }
+  return 0;
+}
+
+/* Scan a basic block, starting with `insn', for a possibly harmful store
+   instruction.  If found, output a cache barrier at the start of this
+   block.  */
+
+static int
+output_store_cache_barrier (FILE *file, rtx insn)
+{
+  for (; insn; insn = NEXT_INSN (insn))
+    {
+      int found = check_insn_for_store (0, insn);
+      if (found < 0)
+        break;
+      if (found > 0)
+        {
+          /* found critical store instruction */
+          ASM_OUTPUT_R10K_CACHE_BARRIER(file);
+          return 1;
+        }
+    }
+  fprintf(file, "\t%s Cache Barrier omitted.\n", ASM_COMMENT_START);
+  return 0;
+}
+
+#endif /* TARGET_IP28 */
+
+/*
+ * final.c	Sun Jan 18 23:39:57 2004
+ * final.c	Sat Sep 18 00:23:34 2004	ip28
+ */