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
27typedef  unsigned int  UInt;
28
29typedef  unsigned char  Bool;
30#define False ((Bool)0)
31#define True  ((Bool)1)
32
33static void make_undef ( void* addr, size_t len )
34{
35  (void) VALGRIND_MAKE_MEM_UNDEFINED(addr, len);
36}
37
38static 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))
45UInt 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))
72UInt 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*/
122typedef  enum { Cond_D1=10, Cond_D0, Cond_U1, Cond_U0 }  Inp_Cond;
123typedef  enum { Addr_DV=20, Addr_DI, Addr_UV, Addr_UI }  Inp_Addr;
124typedef  enum { Alt_Da=30,  Alt_Ub }                     Inp_Alt;
125typedef  enum { Data_Dc=40, Data_Ud }                    Inp_Data;
126
127typedef
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
133const 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
232static Bool c_Cond_D1, c_Cond_D0, c_Cond_U1, c_Cond_U0;
233static UInt *c_Addr_DV, *c_Addr_DI, *c_Addr_UV, *c_Addr_UI;
234static UInt c_Alt_Da, c_Alt_Ub;
235
236static 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
269static 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
353void 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
516const 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
614void usage ( char* pname )
615{
616  fprintf(stderr, "usage: %s [loads|stores]\n", pname);
617  exit(1);
618}
619
620int 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