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