1
2 /*
3 This is a regression test for the following problem, noticed by
4 Greg Parker:
5
6 vex ppc64 generates bad code for instruction sequences like this:
7
8 li r0, 2
9 stdx r3, r1, r0
10
11 gcc emits code like this when manipulating packed structures
12 with 8-byte fields on 2-byte boundaries.
13
14 First, vex's optimizer substitutes a constant 0x2 for r0:
15
16 ------ IMark(0x100000F34, 4) ------
17 PUT(1024) = 0x100000F34:I64
18 t3 = GET:I64(24)
19 t14 = GET:I64(8)
20 t13 = Add64(t14,0x2:I64)
21 STbe(t13) = t3
22
23 Then instruction selection chooses `std` with an index not divisible by 4:
24
25 -- STbe(Add64(GET:I64(8),0x2:I64)) = GET:I64(24)
26 ldz %vR22,8(%r31)
27 ldz %vR23,24(%r31)
28 std %vR23,2(%vR22)
29
30 Finally, the assembler silently strips the index&3 part,
31 because `std` can't encode that:
32
33 std %r6,2(%r5)
34 F8 C5 00 00
35
36 ...but 0xF8C50000 is `std r6, 0(r5)`, which writes to the wrong address.
37 */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <assert.h>
42
43 typedef
44 struct __attribute__ ((__packed__)) {
45 char before[2];
46 unsigned long long int w64;
47 char after[6];
48 }
49 T;
50
foo(T * t,unsigned long long int w)51 void foo (T* t, unsigned long long int w)
52 {
53 __asm__ __volatile__(
54 "stdx %0,%1,%2"
55 : : "b"(w), "b"(t), "b"(2) : "memory"
56 );
57 }
58
main(void)59 int main ( void )
60 {
61 T* t;
62 unsigned char* p;
63 int i;
64 assert(sizeof(T) == 16);
65 t = calloc(sizeof(T),1);
66 assert(t);
67 /* check t is 8-aligned. This causes the write done by 'foo' to be
68 misaligned by 2 as desired, triggering the bug. */
69 assert(0 == (((unsigned long)t) & 7));
70 foo(t, 0x1122334455667788);
71 p = (unsigned char*)t;
72 for (i = 0; i < 16; i++)
73 if (p[i] == 0)
74 printf("..");
75 else
76 printf("%02x", (int)p[i]);
77 printf("\n");
78 return 0;
79 }
80