1 // This program is a thorough test of the LOADVn/STOREVn shadow memory
8 #include "memcheck/memcheck.h"
10 // All the sizes here are in *bytes*, not bits.
12 typedef unsigned char U1
;
13 typedef unsigned short U2
;
14 typedef unsigned int U4
;
15 typedef unsigned long long U8
;
22 // a[] is the array in which we do our loads and stores.
23 // b[] is another one in which we do some copying.
24 U8 a
[SZB_OF_a
/ 8]; // Type is U8 to ensure it's 8-aligned
25 U8 b
[SZB_OF_a
/ 8]; // same size as a[]
27 // XXX: should check the error cases for SET/GET_VBITS also
29 // For the byte 'x', build a value of 'size' bytes from that byte, eg:
33 // size 8 --> xxxxxxxx
34 // where the 0 bits are seen by Memcheck as defined, and the 1 bits are
35 // seen as undefined (ie. the value of each bit matches its V bit, ie. the
36 // resulting value is the same as its metavalue).
38 U8
build(int size
, U1 byte
)
43 U8 res
= 0xffffffffffffffffULL
, res2
;
44 (void)VALGRIND_MAKE_MEM_UNDEFINED(&res
, 8);
45 assert(1 == size
|| 2 == size
|| 4 == size
|| 8 == size
);
47 for (i
= 0; i
< size
; i
++) {
54 // res is now considered partially defined, but we know exactly what its
55 // value is (it happens to be the same as its metavalue).
57 (void)VALGRIND_GET_VBITS(&res
, &shres
, 8);
59 (void)VALGRIND_MAKE_MEM_DEFINED(&res2
, 8); // avoid the 'undefined' warning
60 assert(res2
== shres
);
64 // Check that all the bytes in a[x..y-1] have their V byte equal
65 // to either 'expected_byte' or 'expected_byte_alt'.
66 // 'str' and 'offset' are only used for printing an error message if
67 // something goes wrong.
68 void check_all(U4 x
, U4 y
, U1 expected_byte
, U1 expected_byte_alt
,
69 char* str
, int offset
)
71 U1 sh
[SZB_OF_a
]; // Used for getting a[]'s V bits
74 (void)VALGRIND_GET_VBITS(a
, sh
, sizeof(a
));
75 for (i
= x
; i
< y
; i
++) {
76 if ( expected_byte
!= sh
[i
] && expected_byte_alt
!= sh
[i
] ) {
77 fprintf(stderr
, "\n\nFAILURE: %s, offset %d, byte %d -- "
78 "is 0x%x, should be 0x%x or 0x%x\n\n",
79 str
, offset
, i
, sh
[i
], expected_byte
,
89 U1
*undefA
, expected_byte
, expected_byte_alt
;
91 if (0 == RUNNING_ON_VALGRIND
) {
93 "error: this program only works when run under Valgrind\n");
97 // Check a[] has the expected alignment, and that it's not too high in
98 // the address space (which would trigger the slow cases in
99 // LOADVn/STOREVn) on 64-bit platforms).
100 assert( 0 == (long)a
% 8);
101 if (sizeof(void*) == 8) {
102 assert( ((U1
*)(&a
[0])) < ((U1
*)(32ULL * 1024*1024*1024)/*32G*/) );
105 // Check basic types have the expected sizes.
106 assert(1 == sizeof(U1
));
107 assert(2 == sizeof(U2
));
108 assert(4 == sizeof(U4
));
109 assert(8 == sizeof(U8
));
111 // Create an array of values that has all the possible V bit metavalues.
112 // Because 0 represents a defined bit, and because undefA[] is initially
113 // zeroed, we have the nice property that:
115 // i == undefA[i] == V_bits_of(undefA[i])
117 // which is useful for testing below.
118 undefA
= calloc(1, 256); // one for each possible undefinedness value
119 (void)VALGRIND_MAKE_MEM_UNDEFINED(undefA
, 256);
120 for (i
= 0; i
< 256; i
++) {
124 // This code does a whole lot of reads and writes of a particular size
125 // (NNN = 1, 2, 4 or 8), with varying alignments, of values with
126 // different not/partially/fully defined metavalues, and checks that the
127 // V bits are set in a[] as expected using GET_VBITS.
129 // 'Ty' is the type of the thing we are copying. It can be an integer
130 // type or an FP type. 'ITy' is the same-sized integer type (and thus
131 // will be the same as 'Ty' if 'ITy' is an integer type). 'ITy' is used
132 // when doing shifting/masking and stuff like that.
134 #define DO(NNN, Ty, ITy, isF4) \
135 fprintf(stderr, "-- NNN: %d %s %s ------------------------\n", \
137 /* For all of the alignments from (0..NNN-1), eg. if NNN==4, we do */ \
138 /* alignments of 0, 1, 2, 3. */ \
139 for (h = 0; h < NNN; h++) { \
141 size_t n = sizeof(a); \
142 size_t nN = n / sizeof(Ty); \
145 Ty* aNb = (Ty*)(((U1*)aN) + h); /* set offset from a[] */ \
146 Ty* bNb = (Ty*)(((U1*)bN) + h); /* set offset from b[] */ \
148 fprintf(stderr, "h = %d (checking %d..%d) ", h, h, (int)(n-NNN+h)); \
150 /* For each of the 256 possible V byte values... */ \
151 for (j = 0; j < 256; j++) { \
152 /* build the value for i (one of: i, ii, iiii, iiiiiiii) */ \
153 U8 tmp = build(NNN, j); \
154 ITy undefN_ITy = (ITy)tmp; \
156 { /* This just checks that no overflow occurred when squeezing */ \
157 /* the output of build() into a variable of type 'Ty'. */ \
159 ITy undefN_ITyDef = undefN_ITy; \
160 (void)VALGRIND_MAKE_MEM_DEFINED(&tmpDef, 8 ); \
161 (void)VALGRIND_MAKE_MEM_DEFINED(&undefN_ITyDef, NNN); \
162 assert(tmpDef == (U8)undefN_ITyDef); \
165 /* We have to use an array for undefN_Ty -- because if we try to
166 * convert an integer type from build into an FP type with a
167 * straight cast -- eg "float f = (float)i" -- the value gets
168 * converted. With this pointer/array nonsense the exact bit
169 * pattern gets used as an FP value unchanged (that FP value is
170 * undoubtedly nonsense, but that's not a problem here). */ \
171 undefN_Ty = (Ty*)&undefN_ITy; \
172 if (0 == j % 32) fprintf(stderr, "%d...", j); /* progress meter */ \
174 /* A nasty exception: most machines so far (x86/PPC32/PPC64)
175 * don't have 32-bit floats. So 32-bit floats get cast to 64-bit
176 * floats. Memcheck does a PCast in this case, which means that if
177 * any V bits for the 32-bit float are undefined (ie. 0 != j), all
178 * the V bits in the 64-bit float are undefined. So account for
179 * this when checking. AMD64 typically does FP arithmetic on
180 * SSE, effectively giving it access to 32-bit FP registers. So
181 * in short, for floats, we have to allow either 'j' or 0xFF
182 * as an acceptable result. Sigh. */ \
185 expected_byte_alt = 0 != j ? 0xFF : j; \
188 expected_byte_alt = j; \
191 /* STOREVn. Note that we use the first element of the undefN_Ty
192 * array, as explained above. */ \
193 for (i = 0; i < nN-1; i++) { aNb[i] = undefN_Ty[0]; } \
194 check_all(h, n-NNN+h, expected_byte, expected_byte_alt, \
197 /* LOADVn -- by copying the values to one place and then back,
198 * we ensure that LOADVn gets exercised. */ \
199 for (i = 0; i < nN-1; i++) { bNb[i] = aNb[i]; } \
200 for (i = 0; i < nN-1; i++) { aNb[i] = bNb[i]; } \
201 check_all(h, n-NNN+h, expected_byte, expected_byte_alt, "LOADVn", h); \
203 fprintf(stderr, "\n"); \
206 // For sizes 4 and 8 we do both integer and floating-point types. The
207 // reason being that on 32-bit machines just using integer types never
208 // exercises LOADV8/STOREV8 -- for integer types these loads/stores get
209 // broken into two 32-bit loads/stores.
210 DO(1, U1
, U1
, /*isF4*/0);
211 DO(2, U2
, U2
, /*isF4*/0);
212 DO(4, U4
, U4
, /*isF4*/0);
213 DO(4, F4
, U4
, /*isF4*/1);
214 DO(8, U8
, U8
, /*isF4*/0);
215 DO(8, F8
, U8
, /*isF4*/0);