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 
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 
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