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