2 /* A Memcheck test program for conditional loads and stores,
3 as shown in do_conditional_{load,store}32.
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
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. */
25 #include "../memcheck.h"
27 typedef unsigned int UInt
;
29 typedef unsigned char Bool
;
30 #define False ((Bool)0)
31 #define True ((Bool)1)
33 static void make_undef ( void* addr
, size_t len
)
35 (void) VALGRIND_MAKE_MEM_UNDEFINED(addr
, len
);
38 static void make_def ( void* addr
, size_t len
)
40 (void) VALGRIND_MAKE_MEM_DEFINED(addr
, len
);
43 // Returns either |*src| or |alt|.
44 __attribute__((noinline
))
45 UInt
do_conditional_load32 ( UInt
* src
, UInt alt
, Bool b
)
48 # if defined(__linux__) && defined(__arm__)
50 "mov r5, %2" "\n\t" // alt
51 "tst %3, #0xFF" "\n\t" // b
53 "ldrne r5, [%1]" "\n\t" // src
54 "mov %0, r5" "\n\t" // res
56 : /*IN*/"r"(src
), "r"(alt
), "r"(b
)
57 : /*TRASH*/ "r5","cc","memory"
60 __asm__
__volatile__("" ::: "cc","memory");
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
));
69 // Possibly writes |alt| to |*dst|, and returns the resulting
71 __attribute__((noinline
))
72 UInt
do_conditional_store32 ( UInt
* dst
, UInt alt
, Bool b
)
74 # if defined(__linux__) && defined(__arm__)
76 "mov r5, %1" "\n\t" // alt
77 "tst %2, #0xFF" "\n\t" // b
79 "strne r5, [%0]" "\n\t" // dst
81 : /*IN*/"r"(dst
), "r"(alt
), "r"(b
)
82 : /*TRASH*/ "r5","cc","memory"
85 __asm__
__volatile__("" ::: "cc","memory");
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
92 VALGRIND_DISABLE_ERROR_REPORTING
;
94 VALGRIND_ENABLE_ERROR_REPORTING
;
95 make_def(&res
, sizeof(res
));
100 /* --- LOAD ----------------------------------------- LOAD --- */
101 /* --- LOAD ----------------------------------------- LOAD --- */
102 /* --- LOAD ----------------------------------------- LOAD --- */
104 /* For conditional loads, there are 64 combinations to test.
106 cond: { defined-true, defined-false,
107 undefined-true, undefined-false } D1 D0 U1 U0
109 addr: { defined-valid, defined-invalid,
110 undefined-valid, undefined-invalid } DV DI UV UI
112 alt: { defined, undefined } Da Ub
114 data: { defined, undefined } Dc Ud
116 // a, b, c, d refer to actual values
118 The general form of the test is:
119 1. Place data at *addr
120 2. return "cond ? *addr : alt"
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
;
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
; }
133 const TestCase loadCases
[64] = {
135 // ADDR ALT COND DATA Res
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' },
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' },
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' },
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' },
180 // ADDR ALT COND DATA Res
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' },
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' },
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' },
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
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
;
236 static void setup_test_data ( Inp_Data inp_Data
)
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
));
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
251 make_undef(c_Addr_DV
, 4);
252 make_undef(c_Addr_DI
, 4);
255 // make the invalid address invalid. This unfortunately loses
256 // the definedness state of the data that is stored there.
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
));
264 c_Alt_Da
= 0xAAAAAAAA;
265 c_Alt_Ub
= 0xBBBBBBBB;
266 make_undef(&c_Alt_Ub
, sizeof(c_Alt_Ub
));
269 static void do_test_case ( int caseNo
, Bool isLoad
, const TestCase
* lc
)
272 "\n-----------------------------------------------------------\n");
273 fprintf(stderr
, "%s CASE %d\n", isLoad
? "LOAD" : "STORE", caseNo
);
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
);
286 // and select constants for the test, depending on |lc|
287 // Except, skip i_Data since setup_test_data takes care of it.
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;
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;
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;
311 // How many errors do we expect from this?
313 = (lc
->defErr_Cond
== 'Y' ? 1 : 0) + (lc
->defErr_Addr
== 'Y' ? 1 : 0)
314 + (lc
->addrErr
== 'Y' ? 1 : 0);
316 UInt n_errs_act
= VALGRIND_COUNT_ERRORS
;
319 res_act
= do_conditional_load32(i_Addr
, i_Alt
, i_Cond
);
321 res_act
= do_conditional_store32(i_Addr
, i_Alt
, i_Cond
);
323 n_errs_act
= VALGRIND_COUNT_ERRORS
- n_errs_act
;
325 if (n_errs_act
== n_errs_exp
) {
326 fprintf(stderr
, "PASS: %u errors\n", n_errs_act
);
328 fprintf(stderr
, "FAIL: %u errors expected, %u actual\n",
329 n_errs_exp
, n_errs_act
);
332 // What's the expected result value (actual loaded data?)
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;
342 if (res_act
== res_exp
) {
343 fprintf(stderr
, "PASS: correct result\n");
345 fprintf(stderr
, "FAIL: result: %08x expected, %08x actual\n",
353 void do_test_case_steer ( void (*fn
)(int,Bool
,const TestCase
*),
354 int i
, Bool isLd
, const TestCase
* tc
)
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; };
488 /* --- STORE --------------------------------------- STORE --- */
489 /* --- STORE --------------------------------------- STORE --- */
490 /* --- STORE --------------------------------------- STORE --- */
492 /* For conditional stores, there are 64 combinations to test.
494 cond: { defined-true, defined-false,
495 undefined-true, undefined-false } D1 D0 U1 U0
497 addr: { defined-valid, defined-invalid,
498 undefined-valid, undefined-invalid } DV DI UV UI
500 alt: { defined, undefined } Da Ub
502 data: { defined, undefined } Dc Ud
504 // a, b, c, d refer to actual values
506 The general form of the test is:
507 1. Place data at *addr
508 2. do "if (cond) *addr = alt"
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.
516 const TestCase storeCases
[64] = {
518 // ADDR ALT COND DATA Res
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' },
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' },
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' },
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' },
563 // ADDR ALT COND DATA Res
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' },
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' },
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' },
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
614 void usage ( char* pname
)
616 fprintf(stderr
, "usage: %s [loads|stores]\n", pname
);
620 int main ( int argc
, char** argv
)
624 if (argc
!= 2) usage(argv
[0]);
627 if (0 == strcmp(argv
[1], "loads")) {
630 else if (0 == strcmp(argv
[1], "stores")) {
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
] );
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
] );