1
2 /* A Memcheck test program for conditional loads and stores,
3 as shown in do_conditional_{load,store}32.
4
5 Program is run twice, once for loads and once for stores, only
6 because each run generates 80 errors, and we want to see them all.
7 Doing both loads and stores in each run runs into the problem that
8 errors are more aggressively commoned up after the 100th, and so
9 some that we want to see aren't shown. Splitting the run into two
10 pieces avoids this.
11
12 On ARM we hardwire genuine conditional loads and stores to be
13 tested -- which is the real point of this test, since we are sure
14 they will turn into IRLoadG/IRStoreG. On other platforms we make
15 do with whatever gcc gives us for the equivalent C fragment. In
16 both cases Memcheck's results should be identical -- at least in
17 error counts; line numbers unfortunately will differ. Hence there
18 are -arm and -non-arm expected output files. */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <assert.h>
23 #include <string.h>
24
25 #include "../memcheck.h"
26
27 typedef unsigned int UInt;
28
29 typedef unsigned char Bool;
30 #define False ((Bool)0)
31 #define True ((Bool)1)
32
make_undef(void * addr,size_t len)33 static void make_undef ( void* addr, size_t len )
34 {
35 (void) VALGRIND_MAKE_MEM_UNDEFINED(addr, len);
36 }
37
make_def(void * addr,size_t len)38 static void make_def ( void* addr, size_t len )
39 {
40 (void) VALGRIND_MAKE_MEM_DEFINED(addr, len);
41 }
42
43 // Returns either |*src| or |alt|.
44 __attribute__((noinline))
do_conditional_load32(UInt * src,UInt alt,Bool b)45 UInt do_conditional_load32 ( UInt* src, UInt alt, Bool b )
46 {
47 UInt res;
48 # if defined(__linux__) && defined(__arm__)
49 __asm__ __volatile__(
50 "mov r5, %2" "\n\t" // alt
51 "tst %3, #0xFF" "\n\t" // b
52 "it ne" "\n\t"
53 "ldrne r5, [%1]" "\n\t" // src
54 "mov %0, r5" "\n\t" // res
55 : /*OUT*/"=r"(res)
56 : /*IN*/"r"(src), "r"(alt), "r"(b)
57 : /*TRASH*/ "r5","cc","memory"
58 );
59 # else
60 __asm__ __volatile__("" ::: "cc","memory");
61 res = b ? *src : alt;
62 # endif
63 // res might be undefined. Paint it as defined so the
64 // caller can look at it without invoking further errors.
65 make_def(&res, sizeof(res));
66 return res;
67 }
68
69 // Possibly writes |alt| to |*dst|, and returns the resulting
70 // value of |*dst|.
71 __attribute__((noinline))
do_conditional_store32(UInt * dst,UInt alt,Bool b)72 UInt do_conditional_store32 ( UInt* dst, UInt alt, Bool b )
73 {
74 # if defined(__linux__) && defined(__arm__)
75 __asm__ __volatile__(
76 "mov r5, %1" "\n\t" // alt
77 "tst %2, #0xFF" "\n\t" // b
78 "it ne" "\n\t"
79 "strne r5, [%0]" "\n\t" // dst
80 : /*OUT*/
81 : /*IN*/"r"(dst), "r"(alt), "r"(b)
82 : /*TRASH*/ "r5","cc","memory"
83 );
84 # else
85 __asm__ __volatile__("" ::: "cc","memory");
86 if (b) *dst = alt;
87 # endif
88 /* Now we need to get hold of the value at *dst. But it might be
89 unaddressible and/or undefined. Hence turn off error reporting
90 when getting it. */
91 UInt res;
92 VALGRIND_DISABLE_ERROR_REPORTING;
93 res = *dst;
94 VALGRIND_ENABLE_ERROR_REPORTING;
95 make_def(&res, sizeof(res));
96 return res;
97 }
98
99
100 /* --- LOAD ----------------------------------------- LOAD --- */
101 /* --- LOAD ----------------------------------------- LOAD --- */
102 /* --- LOAD ----------------------------------------- LOAD --- */
103
104 /* For conditional loads, there are 64 combinations to test.
105
106 cond: { defined-true, defined-false,
107 undefined-true, undefined-false } D1 D0 U1 U0
108 x
109 addr: { defined-valid, defined-invalid,
110 undefined-valid, undefined-invalid } DV DI UV UI
111 x
112 alt: { defined, undefined } Da Ub
113 x
114 data: { defined, undefined } Dc Ud
115
116 // a, b, c, d refer to actual values
117
118 The general form of the test is:
119 1. Place data at *addr
120 2. return "cond ? *addr : alt"
121 */
122 typedef enum { Cond_D1=10, Cond_D0, Cond_U1, Cond_U0 } Inp_Cond;
123 typedef enum { Addr_DV=20, Addr_DI, Addr_UV, Addr_UI } Inp_Addr;
124 typedef enum { Alt_Da=30, Alt_Ub } Inp_Alt;
125 typedef enum { Data_Dc=40, Data_Ud } Inp_Data;
126
127 typedef
128 struct { Inp_Cond inp_Cond; Inp_Addr inp_Addr;
129 Inp_Alt inp_Alt; Inp_Data inp_Data;
130 char res; char defErr_Cond; char defErr_Addr; char addrErr; }
131 TestCase;
132
133 const TestCase loadCases[64] = {
134
135 // ADDR ALT COND DATA Res
136 // defErr-COND
137 // defErr-ADDR
138 // addrErr
139
140 // In all of the next 16 cases, the load definitely happens
141 // and |alt| is therefore irrelevant
142 { Cond_D1, Addr_DV, Alt_Da, Data_Dc, 'C', 'N', 'N', 'N' }, // 0
143 { Cond_D1, Addr_DV, Alt_Da, Data_Ud, 'D', 'N', 'N', 'N' },
144 { Cond_D1, Addr_DV, Alt_Ub, Data_Dc, 'C', 'N', 'N', 'N' },
145 { Cond_D1, Addr_DV, Alt_Ub, Data_Ud, 'D', 'N', 'N', 'N' },
146 { Cond_D1, Addr_DI, Alt_Da, Data_Dc, 'C', 'N', 'N', 'Y' },
147 { Cond_D1, Addr_DI, Alt_Da, Data_Ud, 'D', 'N', 'N', 'Y' },
148 { Cond_D1, Addr_DI, Alt_Ub, Data_Dc, 'C', 'N', 'N', 'Y' },
149 { Cond_D1, Addr_DI, Alt_Ub, Data_Ud, 'D', 'N', 'N', 'Y' },
150
151 { Cond_D1, Addr_UV, Alt_Da, Data_Dc, 'C', 'N', 'Y', 'N' }, // 8
152 { Cond_D1, Addr_UV, Alt_Da, Data_Ud, 'D', 'N', 'Y', 'N' },
153 { Cond_D1, Addr_UV, Alt_Ub, Data_Dc, 'C', 'N', 'Y', 'N' },
154 { Cond_D1, Addr_UV, Alt_Ub, Data_Ud, 'D', 'N', 'Y', 'N' },
155 { Cond_D1, Addr_UI, Alt_Da, Data_Dc, 'C', 'N', 'Y', 'Y' },
156 { Cond_D1, Addr_UI, Alt_Da, Data_Ud, 'D', 'N', 'Y', 'Y' },
157 { Cond_D1, Addr_UI, Alt_Ub, Data_Dc, 'C', 'N', 'Y', 'Y' },
158 { Cond_D1, Addr_UI, Alt_Ub, Data_Ud, 'D', 'N', 'Y', 'Y' },
159
160 // In the next 16 cases, the load definitely does not happen,
161 // so we just return |alt|.
162 { Cond_D0, Addr_DV, Alt_Da, Data_Dc, 'A', 'N', 'N', 'N' }, // 16
163 { Cond_D0, Addr_DV, Alt_Da, Data_Ud, 'A', 'N', 'N', 'N' },
164 { Cond_D0, Addr_DV, Alt_Ub, Data_Dc, 'B', 'N', 'N', 'N' },
165 { Cond_D0, Addr_DV, Alt_Ub, Data_Ud, 'B', 'N', 'N', 'N' },
166 { Cond_D0, Addr_DI, Alt_Da, Data_Dc, 'A', 'N', 'N', 'N' },
167 { Cond_D0, Addr_DI, Alt_Da, Data_Ud, 'A', 'N', 'N', 'N' },
168 { Cond_D0, Addr_DI, Alt_Ub, Data_Dc, 'B', 'N', 'N', 'N' },
169 { Cond_D0, Addr_DI, Alt_Ub, Data_Ud, 'B', 'N', 'N', 'N' },
170
171 { Cond_D0, Addr_UV, Alt_Da, Data_Dc, 'A', 'N', 'N', 'N' }, // 24
172 { Cond_D0, Addr_UV, Alt_Da, Data_Ud, 'A', 'N', 'N', 'N' },
173 { Cond_D0, Addr_UV, Alt_Ub, Data_Dc, 'B', 'N', 'N', 'N' },
174 { Cond_D0, Addr_UV, Alt_Ub, Data_Ud, 'B', 'N', 'N', 'N' },
175 { Cond_D0, Addr_UI, Alt_Da, Data_Dc, 'A', 'N', 'N', 'N' },
176 { Cond_D0, Addr_UI, Alt_Da, Data_Ud, 'A', 'N', 'N', 'N' },
177 { Cond_D0, Addr_UI, Alt_Ub, Data_Dc, 'B', 'N', 'N', 'N' },
178 { Cond_D0, Addr_UI, Alt_Ub, Data_Ud, 'B', 'N', 'N', 'N' },
179
180 // ADDR ALT COND DATA Res
181 // defErr-COND
182 // defErr-ADDR
183 // addrErr
184
185 // In the next 16 cases, the load happens, but the condition
186 // is undefined. This means that it should behave like the
187 // first group of 16 cases, except that we should also get a
188 // complaint about the definedness of the condition.
189 { Cond_U1, Addr_DV, Alt_Da, Data_Dc, 'C', 'Y', 'N', 'N' }, // 32
190 { Cond_U1, Addr_DV, Alt_Da, Data_Ud, 'D', 'Y', 'N', 'N' },
191 { Cond_U1, Addr_DV, Alt_Ub, Data_Dc, 'C', 'Y', 'N', 'N' },
192 { Cond_U1, Addr_DV, Alt_Ub, Data_Ud, 'D', 'Y', 'N', 'N' },
193 { Cond_U1, Addr_DI, Alt_Da, Data_Dc, 'C', 'Y', 'N', 'Y' },
194 { Cond_U1, Addr_DI, Alt_Da, Data_Ud, 'D', 'Y', 'N', 'Y' },
195 { Cond_U1, Addr_DI, Alt_Ub, Data_Dc, 'C', 'Y', 'N', 'Y' },
196 { Cond_U1, Addr_DI, Alt_Ub, Data_Ud, 'D', 'Y', 'N', 'Y' },
197
198 { Cond_U1, Addr_UV, Alt_Da, Data_Dc, 'C', 'Y', 'Y', 'N' }, // 40
199 { Cond_U1, Addr_UV, Alt_Da, Data_Ud, 'D', 'Y', 'Y', 'N' },
200 { Cond_U1, Addr_UV, Alt_Ub, Data_Dc, 'C', 'Y', 'Y', 'N' },
201 { Cond_U1, Addr_UV, Alt_Ub, Data_Ud, 'D', 'Y', 'Y', 'N' },
202 { Cond_U1, Addr_UI, Alt_Da, Data_Dc, 'C', 'Y', 'Y', 'Y' },
203 { Cond_U1, Addr_UI, Alt_Da, Data_Ud, 'D', 'Y', 'Y', 'Y' },
204 { Cond_U1, Addr_UI, Alt_Ub, Data_Dc, 'C', 'Y', 'Y', 'Y' },
205 { Cond_U1, Addr_UI, Alt_Ub, Data_Ud, 'D', 'Y', 'Y', 'Y' },
206
207 // In this last group of 16 cases, the load does not happen,
208 // but the condition is undefined. So we just return |alt|,
209 // and also complain about the condition. Hence it's like the
210 // second group of 16 cases except that we also get a complaint
211 // about the condition.
212 { Cond_U0, Addr_DV, Alt_Da, Data_Dc, 'A', 'Y', 'N', 'N' }, // 48
213 { Cond_U0, Addr_DV, Alt_Da, Data_Ud, 'A', 'Y', 'N', 'N' },
214 { Cond_U0, Addr_DV, Alt_Ub, Data_Dc, 'B', 'Y', 'N', 'N' },
215 { Cond_U0, Addr_DV, Alt_Ub, Data_Ud, 'B', 'Y', 'N', 'N' },
216 { Cond_U0, Addr_DI, Alt_Da, Data_Dc, 'A', 'Y', 'N', 'N' },
217 { Cond_U0, Addr_DI, Alt_Da, Data_Ud, 'A', 'Y', 'N', 'N' },
218 { Cond_U0, Addr_DI, Alt_Ub, Data_Dc, 'B', 'Y', 'N', 'N' },
219 { Cond_U0, Addr_DI, Alt_Ub, Data_Ud, 'B', 'Y', 'N', 'N' },
220
221 { Cond_U0, Addr_UV, Alt_Da, Data_Dc, 'A', 'Y', 'N', 'N' }, // 56
222 { Cond_U0, Addr_UV, Alt_Da, Data_Ud, 'A', 'Y', 'N', 'N' },
223 { Cond_U0, Addr_UV, Alt_Ub, Data_Dc, 'B', 'Y', 'N', 'N' },
224 { Cond_U0, Addr_UV, Alt_Ub, Data_Ud, 'B', 'Y', 'N', 'N' },
225 { Cond_U0, Addr_UI, Alt_Da, Data_Dc, 'A', 'Y', 'N', 'N' },
226 { Cond_U0, Addr_UI, Alt_Da, Data_Ud, 'A', 'Y', 'N', 'N' },
227 { Cond_U0, Addr_UI, Alt_Ub, Data_Dc, 'B', 'Y', 'N', 'N' },
228 { Cond_U0, Addr_UI, Alt_Ub, Data_Ud, 'B', 'Y', 'N', 'N' } // 63
229 };
230
231 // Constant, corresponding to the test enums
232 static Bool c_Cond_D1, c_Cond_D0, c_Cond_U1, c_Cond_U0;
233 static UInt *c_Addr_DV, *c_Addr_DI, *c_Addr_UV, *c_Addr_UI;
234 static UInt c_Alt_Da, c_Alt_Ub;
235
setup_test_data(Inp_Data inp_Data)236 static void setup_test_data ( Inp_Data inp_Data )
237 {
238 c_Cond_D1 = c_Cond_U1 = True;
239 c_Cond_D0 = c_Cond_U0 = False;
240 make_undef(&c_Cond_U1, sizeof(c_Cond_U1));
241 make_undef(&c_Cond_U0, sizeof(c_Cond_U0));
242
243 c_Addr_DV = c_Addr_UV = malloc(4);
244 c_Addr_DI = c_Addr_UI = malloc(4);
245 // install test data at the given address
246 UInt testd = inp_Data == Data_Dc ? 0xCCCCCCCC : 0xDDDDDDDD;
247 *c_Addr_DV = *c_Addr_DI = testd;
248 if (inp_Data == Data_Dc) {
249 // it's already defined
250 } else {
251 make_undef(c_Addr_DV, 4);
252 make_undef(c_Addr_DI, 4);
253 }
254
255 // make the invalid address invalid. This unfortunately loses
256 // the definedness state of the data that is stored there.
257 free(c_Addr_DI);
258
259 // and set the definedness of the pointers themselves.
260 make_undef(&c_Addr_UV, sizeof(c_Addr_UV));
261 make_undef(&c_Addr_UI, sizeof(c_Addr_UI));
262
263 // and set up alt
264 c_Alt_Da = 0xAAAAAAAA;
265 c_Alt_Ub = 0xBBBBBBBB;
266 make_undef(&c_Alt_Ub, sizeof(c_Alt_Ub));
267 }
268
do_test_case(int caseNo,Bool isLoad,const TestCase * lc)269 static void do_test_case ( int caseNo, Bool isLoad, const TestCase* lc )
270 {
271 fprintf(stderr,
272 "\n-----------------------------------------------------------\n");
273 fprintf(stderr, "%s CASE %d\n", isLoad ? "LOAD" : "STORE", caseNo);
274 // validate ..
275 assert(Cond_D1 <= lc->inp_Cond && lc->inp_Cond <= Cond_U0);
276 assert(Addr_DV <= lc->inp_Addr && lc->inp_Addr <= Addr_UI);
277 assert(lc->inp_Alt == Alt_Da || lc->inp_Alt == Alt_Ub);
278 assert(lc->inp_Data == Data_Dc || lc->inp_Data == Data_Ud);
279 assert('A' <= lc->res && lc->res <= 'D');
280 assert(lc->defErr_Cond == 'Y' || lc->defErr_Cond == 'N');
281 assert(lc->defErr_Addr == 'Y' || lc->defErr_Addr == 'N');
282 assert(lc->addrErr == 'Y' || lc->addrErr == 'N');
283 // set up test data constants
284 setup_test_data(lc->inp_Data);
285
286 // and select constants for the test, depending on |lc|
287 // Except, skip i_Data since setup_test_data takes care of it.
288 Bool i_Cond;
289 UInt* i_Addr;
290 UInt i_Alt;
291 switch (lc->inp_Cond) {
292 case Cond_D1: i_Cond = c_Cond_D1; break;
293 case Cond_D0: i_Cond = c_Cond_D0; break;
294 case Cond_U1: i_Cond = c_Cond_U1; break;
295 case Cond_U0: i_Cond = c_Cond_U0; break;
296 default: assert(0);
297 }
298 switch (lc->inp_Addr) {
299 case Addr_DV: i_Addr = c_Addr_DV; break;
300 case Addr_DI: i_Addr = c_Addr_DI; break;
301 case Addr_UV: i_Addr = c_Addr_UV; break;
302 case Addr_UI: i_Addr = c_Addr_UI; break;
303 default: assert(0);
304 }
305 switch (lc->inp_Alt) {
306 case Alt_Da: i_Alt = c_Alt_Da; break;
307 case Alt_Ub: i_Alt = c_Alt_Ub; break;
308 default: assert(0);
309 }
310
311 // How many errors do we expect from this?
312 UInt n_errs_exp
313 = (lc->defErr_Cond == 'Y' ? 1 : 0) + (lc->defErr_Addr == 'Y' ? 1 : 0)
314 + (lc->addrErr == 'Y' ? 1 : 0);
315
316 UInt n_errs_act = VALGRIND_COUNT_ERRORS;
317 UInt res_act;
318 if (isLoad) {
319 res_act = do_conditional_load32(i_Addr, i_Alt, i_Cond);
320 } else {
321 res_act = do_conditional_store32(i_Addr, i_Alt, i_Cond);
322 }
323 n_errs_act = VALGRIND_COUNT_ERRORS - n_errs_act;
324
325 if (n_errs_act == n_errs_exp) {
326 fprintf(stderr, "PASS: %u errors\n", n_errs_act);
327 } else {
328 fprintf(stderr, "FAIL: %u errors expected, %u actual\n",
329 n_errs_exp, n_errs_act);
330 }
331
332 // What's the expected result value (actual loaded data?)
333 UInt res_exp = 0;
334 switch (lc->res) {
335 case 'A': res_exp = 0xAAAAAAAA; break;
336 case 'B': res_exp = 0xBBBBBBBB; break;
337 case 'C': res_exp = 0xCCCCCCCC; break;
338 case 'D': res_exp = 0xDDDDDDDD; break;
339 default: assert(0);
340 }
341
342 if (res_act == res_exp) {
343 fprintf(stderr, "PASS: correct result\n");
344 } else {
345 fprintf(stderr, "FAIL: result: %08x expected, %08x actual\n",
346 res_exp, res_act);
347 }
348
349 free(c_Addr_DV);
350 }
351
352
do_test_case_steer(void (* fn)(int,Bool,const TestCase *),int i,Bool isLd,const TestCase * tc)353 void do_test_case_steer ( void (*fn)(int,Bool,const TestCase*),
354 int i, Bool isLd, const TestCase* tc )
355 {
356 __asm__ __volatile__("");
357 if (i == 0) { fn(i,isLd,tc); return; };
358 __asm__ __volatile__("");
359 if (i == 1) { fn(i,isLd,tc); return; };
360 __asm__ __volatile__("");
361 if (i == 2) { fn(i,isLd,tc); return; };
362 __asm__ __volatile__("");
363 if (i == 3) { fn(i,isLd,tc); return; };
364 __asm__ __volatile__("");
365 if (i == 4) { fn(i,isLd,tc); return; };
366 __asm__ __volatile__("");
367 if (i == 5) { fn(i,isLd,tc); return; };
368 __asm__ __volatile__("");
369 if (i == 6) { fn(i,isLd,tc); return; };
370 __asm__ __volatile__("");
371 if (i == 7) { fn(i,isLd,tc); return; };
372 __asm__ __volatile__("");
373 if (i == 8) { fn(i,isLd,tc); return; };
374 __asm__ __volatile__("");
375 if (i == 9) { fn(i,isLd,tc); return; };
376 __asm__ __volatile__("");
377 if (i == 10) { fn(i,isLd,tc); return; };
378 __asm__ __volatile__("");
379 if (i == 11) { fn(i,isLd,tc); return; };
380 __asm__ __volatile__("");
381 if (i == 12) { fn(i,isLd,tc); return; };
382 __asm__ __volatile__("");
383 if (i == 13) { fn(i,isLd,tc); return; };
384 __asm__ __volatile__("");
385 if (i == 14) { fn(i,isLd,tc); return; };
386 __asm__ __volatile__("");
387 if (i == 15) { fn(i,isLd,tc); return; };
388 __asm__ __volatile__("");
389 if (i == 16) { fn(i,isLd,tc); return; };
390 __asm__ __volatile__("");
391 if (i == 17) { fn(i,isLd,tc); return; };
392 __asm__ __volatile__("");
393 if (i == 18) { fn(i,isLd,tc); return; };
394 __asm__ __volatile__("");
395 if (i == 19) { fn(i,isLd,tc); return; };
396 __asm__ __volatile__("");
397 if (i == 20) { fn(i,isLd,tc); return; };
398 __asm__ __volatile__("");
399 if (i == 21) { fn(i,isLd,tc); return; };
400 __asm__ __volatile__("");
401 if (i == 22) { fn(i,isLd,tc); return; };
402 __asm__ __volatile__("");
403 if (i == 23) { fn(i,isLd,tc); return; };
404 __asm__ __volatile__("");
405 if (i == 24) { fn(i,isLd,tc); return; };
406 __asm__ __volatile__("");
407 if (i == 25) { fn(i,isLd,tc); return; };
408 __asm__ __volatile__("");
409 if (i == 26) { fn(i,isLd,tc); return; };
410 __asm__ __volatile__("");
411 if (i == 27) { fn(i,isLd,tc); return; };
412 __asm__ __volatile__("");
413 if (i == 28) { fn(i,isLd,tc); return; };
414 __asm__ __volatile__("");
415 if (i == 29) { fn(i,isLd,tc); return; };
416 __asm__ __volatile__("");
417 if (i == 30) { fn(i,isLd,tc); return; };
418 __asm__ __volatile__("");
419 if (i == 31) { fn(i,isLd,tc); return; };
420 __asm__ __volatile__("");
421 if (i == 32) { fn(i,isLd,tc); return; };
422 __asm__ __volatile__("");
423 if (i == 33) { fn(i,isLd,tc); return; };
424 __asm__ __volatile__("");
425 if (i == 34) { fn(i,isLd,tc); return; };
426 __asm__ __volatile__("");
427 if (i == 35) { fn(i,isLd,tc); return; };
428 __asm__ __volatile__("");
429 if (i == 36) { fn(i,isLd,tc); return; };
430 __asm__ __volatile__("");
431 if (i == 37) { fn(i,isLd,tc); return; };
432 __asm__ __volatile__("");
433 if (i == 38) { fn(i,isLd,tc); return; };
434 __asm__ __volatile__("");
435 if (i == 39) { fn(i,isLd,tc); return; };
436 __asm__ __volatile__("");
437 if (i == 40) { fn(i,isLd,tc); return; };
438 __asm__ __volatile__("");
439 if (i == 41) { fn(i,isLd,tc); return; };
440 __asm__ __volatile__("");
441 if (i == 42) { fn(i,isLd,tc); return; };
442 __asm__ __volatile__("");
443 if (i == 43) { fn(i,isLd,tc); return; };
444 __asm__ __volatile__("");
445 if (i == 44) { fn(i,isLd,tc); return; };
446 __asm__ __volatile__("");
447 if (i == 45) { fn(i,isLd,tc); return; };
448 __asm__ __volatile__("");
449 if (i == 46) { fn(i,isLd,tc); return; };
450 __asm__ __volatile__("");
451 if (i == 47) { fn(i,isLd,tc); return; };
452 __asm__ __volatile__("");
453 if (i == 48) { fn(i,isLd,tc); return; };
454 __asm__ __volatile__("");
455 if (i == 49) { fn(i,isLd,tc); return; };
456 __asm__ __volatile__("");
457 if (i == 50) { fn(i,isLd,tc); return; };
458 __asm__ __volatile__("");
459 if (i == 51) { fn(i,isLd,tc); return; };
460 __asm__ __volatile__("");
461 if (i == 52) { fn(i,isLd,tc); return; };
462 __asm__ __volatile__("");
463 if (i == 53) { fn(i,isLd,tc); return; };
464 __asm__ __volatile__("");
465 if (i == 54) { fn(i,isLd,tc); return; };
466 __asm__ __volatile__("");
467 if (i == 55) { fn(i,isLd,tc); return; };
468 __asm__ __volatile__("");
469 if (i == 56) { fn(i,isLd,tc); return; };
470 __asm__ __volatile__("");
471 if (i == 57) { fn(i,isLd,tc); return; };
472 __asm__ __volatile__("");
473 if (i == 58) { fn(i,isLd,tc); return; };
474 __asm__ __volatile__("");
475 if (i == 59) { fn(i,isLd,tc); return; };
476 __asm__ __volatile__("");
477 if (i == 60) { fn(i,isLd,tc); return; };
478 __asm__ __volatile__("");
479 if (i == 61) { fn(i,isLd,tc); return; };
480 __asm__ __volatile__("");
481 if (i == 62) { fn(i,isLd,tc); return; };
482 __asm__ __volatile__("");
483 if (i == 63) { fn(i,isLd,tc); return; };
484 assert(0);
485 }
486
487
488 /* --- STORE --------------------------------------- STORE --- */
489 /* --- STORE --------------------------------------- STORE --- */
490 /* --- STORE --------------------------------------- STORE --- */
491
492 /* For conditional stores, there are 64 combinations to test.
493
494 cond: { defined-true, defined-false,
495 undefined-true, undefined-false } D1 D0 U1 U0
496 x
497 addr: { defined-valid, defined-invalid,
498 undefined-valid, undefined-invalid } DV DI UV UI
499 x
500 alt: { defined, undefined } Da Ub
501 x
502 data: { defined, undefined } Dc Ud
503
504 // a, b, c, d refer to actual values
505
506 The general form of the test is:
507 1. Place data at *addr
508 2. do "if (cond) *addr = alt"
509 3 return *addr
510
511 Hence identical setup to the load cases, although the roles of
512 data and alt are somewhat confusingly swapped. |data| here is
513 the "didn't happen" result, and |alt| is the "did happen" result.
514 */
515
516 const TestCase storeCases[64] = {
517
518 // ADDR ALT COND DATA Res
519 // defErr-COND
520 // defErr-ADDR
521 // addrErr
522
523 // In all of the next 16 cases, the store definitely happens
524 // and |data| is therefore irrelevant
525 { Cond_D1, Addr_DV, Alt_Da, Data_Dc, 'A', 'N', 'N', 'N' }, // 0
526 { Cond_D1, Addr_DV, Alt_Da, Data_Ud, 'A', 'N', 'N', 'N' },
527 { Cond_D1, Addr_DV, Alt_Ub, Data_Dc, 'B', 'N', 'N', 'N' },
528 { Cond_D1, Addr_DV, Alt_Ub, Data_Ud, 'B', 'N', 'N', 'N' },
529 { Cond_D1, Addr_DI, Alt_Da, Data_Dc, 'A', 'N', 'N', 'Y' },
530 { Cond_D1, Addr_DI, Alt_Da, Data_Ud, 'A', 'N', 'N', 'Y' },
531 { Cond_D1, Addr_DI, Alt_Ub, Data_Dc, 'B', 'N', 'N', 'Y' },
532 { Cond_D1, Addr_DI, Alt_Ub, Data_Ud, 'B', 'N', 'N', 'Y' },
533
534 { Cond_D1, Addr_UV, Alt_Da, Data_Dc, 'A', 'N', 'Y', 'N' }, // 8
535 { Cond_D1, Addr_UV, Alt_Da, Data_Ud, 'A', 'N', 'Y', 'N' },
536 { Cond_D1, Addr_UV, Alt_Ub, Data_Dc, 'B', 'N', 'Y', 'N' },
537 { Cond_D1, Addr_UV, Alt_Ub, Data_Ud, 'B', 'N', 'Y', 'N' },
538 { Cond_D1, Addr_UI, Alt_Da, Data_Dc, 'A', 'N', 'Y', 'Y' },
539 { Cond_D1, Addr_UI, Alt_Da, Data_Ud, 'A', 'N', 'Y', 'Y' },
540 { Cond_D1, Addr_UI, Alt_Ub, Data_Dc, 'B', 'N', 'Y', 'Y' },
541 { Cond_D1, Addr_UI, Alt_Ub, Data_Ud, 'B', 'N', 'Y', 'Y' },
542
543 // In the next 16 cases, the store definitely does not happen,
544 // so we just return |data|.
545 { Cond_D0, Addr_DV, Alt_Da, Data_Dc, 'C', 'N', 'N', 'N' }, // 16
546 { Cond_D0, Addr_DV, Alt_Da, Data_Ud, 'D', 'N', 'N', 'N' },
547 { Cond_D0, Addr_DV, Alt_Ub, Data_Dc, 'C', 'N', 'N', 'N' },
548 { Cond_D0, Addr_DV, Alt_Ub, Data_Ud, 'D', 'N', 'N', 'N' },
549 { Cond_D0, Addr_DI, Alt_Da, Data_Dc, 'C', 'N', 'N', 'N' },
550 { Cond_D0, Addr_DI, Alt_Da, Data_Ud, 'D', 'N', 'N', 'N' },
551 { Cond_D0, Addr_DI, Alt_Ub, Data_Dc, 'C', 'N', 'N', 'N' },
552 { Cond_D0, Addr_DI, Alt_Ub, Data_Ud, 'D', 'N', 'N', 'N' },
553
554 { Cond_D0, Addr_UV, Alt_Da, Data_Dc, 'C', 'N', 'N', 'N' }, // 24
555 { Cond_D0, Addr_UV, Alt_Da, Data_Ud, 'D', 'N', 'N', 'N' },
556 { Cond_D0, Addr_UV, Alt_Ub, Data_Dc, 'C', 'N', 'N', 'N' },
557 { Cond_D0, Addr_UV, Alt_Ub, Data_Ud, 'D', 'N', 'N', 'N' },
558 { Cond_D0, Addr_UI, Alt_Da, Data_Dc, 'C', 'N', 'N', 'N' },
559 { Cond_D0, Addr_UI, Alt_Da, Data_Ud, 'D', 'N', 'N', 'N' },
560 { Cond_D0, Addr_UI, Alt_Ub, Data_Dc, 'C', 'N', 'N', 'N' },
561 { Cond_D0, Addr_UI, Alt_Ub, Data_Ud, 'D', 'N', 'N', 'N' },
562
563 // ADDR ALT COND DATA Res
564 // defErr-COND
565 // defErr-ADDR
566 // addrErr
567
568 // In the next 16 cases, the store happens, but the condition
569 // is undefined. This means that it should behave like the
570 // first group of 16 cases, except that we should also get a
571 // complaint about the definedness of the condition.
572 { Cond_U1, Addr_DV, Alt_Da, Data_Dc, 'A', 'Y', 'N', 'N' }, // 32
573 { Cond_U1, Addr_DV, Alt_Da, Data_Ud, 'A', 'Y', 'N', 'N' },
574 { Cond_U1, Addr_DV, Alt_Ub, Data_Dc, 'B', 'Y', 'N', 'N' },
575 { Cond_U1, Addr_DV, Alt_Ub, Data_Ud, 'B', 'Y', 'N', 'N' },
576 { Cond_U1, Addr_DI, Alt_Da, Data_Dc, 'A', 'Y', 'N', 'Y' },
577 { Cond_U1, Addr_DI, Alt_Da, Data_Ud, 'A', 'Y', 'N', 'Y' },
578 { Cond_U1, Addr_DI, Alt_Ub, Data_Dc, 'B', 'Y', 'N', 'Y' },
579 { Cond_U1, Addr_DI, Alt_Ub, Data_Ud, 'B', 'Y', 'N', 'Y' },
580
581 { Cond_U1, Addr_UV, Alt_Da, Data_Dc, 'A', 'Y', 'Y', 'N' }, // 40
582 { Cond_U1, Addr_UV, Alt_Da, Data_Ud, 'A', 'Y', 'Y', 'N' },
583 { Cond_U1, Addr_UV, Alt_Ub, Data_Dc, 'B', 'Y', 'Y', 'N' },
584 { Cond_U1, Addr_UV, Alt_Ub, Data_Ud, 'B', 'Y', 'Y', 'N' },
585 { Cond_U1, Addr_UI, Alt_Da, Data_Dc, 'A', 'Y', 'Y', 'Y' },
586 { Cond_U1, Addr_UI, Alt_Da, Data_Ud, 'A', 'Y', 'Y', 'Y' },
587 { Cond_U1, Addr_UI, Alt_Ub, Data_Dc, 'B', 'Y', 'Y', 'Y' },
588 { Cond_U1, Addr_UI, Alt_Ub, Data_Ud, 'B', 'Y', 'Y', 'Y' },
589
590 // In this last group of 16 cases, the store does not happen,
591 // but the condition is undefined. So we just return |data|,
592 // and also complain about the condition. Hence it's like the
593 // second group of 16 cases except that we also get a complaint
594 // about the condition.
595 { Cond_U0, Addr_DV, Alt_Da, Data_Dc, 'C', 'Y', 'N', 'N' }, // 48
596 { Cond_U0, Addr_DV, Alt_Da, Data_Ud, 'D', 'Y', 'N', 'N' },
597 { Cond_U0, Addr_DV, Alt_Ub, Data_Dc, 'C', 'Y', 'N', 'N' },
598 { Cond_U0, Addr_DV, Alt_Ub, Data_Ud, 'D', 'Y', 'N', 'N' },
599 { Cond_U0, Addr_DI, Alt_Da, Data_Dc, 'C', 'Y', 'N', 'N' },
600 { Cond_U0, Addr_DI, Alt_Da, Data_Ud, 'D', 'Y', 'N', 'N' },
601 { Cond_U0, Addr_DI, Alt_Ub, Data_Dc, 'C', 'Y', 'N', 'N' },
602 { Cond_U0, Addr_DI, Alt_Ub, Data_Ud, 'D', 'Y', 'N', 'N' },
603
604 { Cond_U0, Addr_UV, Alt_Da, Data_Dc, 'C', 'Y', 'N', 'N' }, // 56
605 { Cond_U0, Addr_UV, Alt_Da, Data_Ud, 'D', 'Y', 'N', 'N' },
606 { Cond_U0, Addr_UV, Alt_Ub, Data_Dc, 'C', 'Y', 'N', 'N' },
607 { Cond_U0, Addr_UV, Alt_Ub, Data_Ud, 'D', 'Y', 'N', 'N' },
608 { Cond_U0, Addr_UI, Alt_Da, Data_Dc, 'C', 'Y', 'N', 'N' },
609 { Cond_U0, Addr_UI, Alt_Da, Data_Ud, 'D', 'Y', 'N', 'N' },
610 { Cond_U0, Addr_UI, Alt_Ub, Data_Dc, 'C', 'Y', 'N', 'N' },
611 { Cond_U0, Addr_UI, Alt_Ub, Data_Ud, 'D', 'Y', 'N', 'N' } // 63
612 };
613
usage(char * pname)614 void usage ( char* pname )
615 {
616 fprintf(stderr, "usage: %s [loads|stores]\n", pname);
617 exit(1);
618 }
619
main(int argc,char ** argv)620 int main ( int argc, char** argv )
621 {
622 UInt i, nCases;
623
624 if (argc != 2) usage(argv[0]);
625
626 Bool doLoad = False;
627 if (0 == strcmp(argv[1], "loads")) {
628 doLoad = True;
629 }
630 else if (0 == strcmp(argv[1], "stores")) {
631 doLoad = False;
632 }
633 else usage(argv[0]);
634
635 if (doLoad) {
636 nCases = sizeof(loadCases) / sizeof(loadCases[0]);
637 assert(nCases == 64);
638 for (i = 0; i < nCases; i++)
639 do_test_case_steer( do_test_case, i, True/*isLoad*/, &loadCases[i] );
640 } else {
641 nCases = sizeof(storeCases) / sizeof(storeCases[0]);
642 assert(nCases == 64);
643 for (i = 0; i < nCases; i++)
644 do_test_case_steer( do_test_case, i, False/*!isLoad*/, &storeCases[i] );
645 }
646
647 return 0;
648 }
649