| |
| /* |
| This is a regression test for the following problem, noticed by |
| Greg Parker: |
| |
| vex ppc64 generates bad code for instruction sequences like this: |
| |
| li r0, 2 |
| stdx r3, r1, r0 |
| |
| gcc emits code like this when manipulating packed structures |
| with 8-byte fields on 2-byte boundaries. |
| |
| First, vex's optimizer substitutes a constant 0x2 for r0: |
| |
| ------ IMark(0x100000F34, 4) ------ |
| PUT(1024) = 0x100000F34:I64 |
| t3 = GET:I64(24) |
| t14 = GET:I64(8) |
| t13 = Add64(t14,0x2:I64) |
| STbe(t13) = t3 |
| |
| Then instruction selection chooses `std` with an index not divisible by 4: |
| |
| -- STbe(Add64(GET:I64(8),0x2:I64)) = GET:I64(24) |
| ldz %vR22,8(%r31) |
| ldz %vR23,24(%r31) |
| std %vR23,2(%vR22) |
| |
| Finally, the assembler silently strips the index&3 part, |
| because `std` can't encode that: |
| |
| std %r6,2(%r5) |
| F8 C5 00 00 |
| |
| ...but 0xF8C50000 is `std r6, 0(r5)`, which writes to the wrong address. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <assert.h> |
| |
| typedef |
| struct __attribute__ ((__packed__)) { |
| char before[2]; |
| unsigned long long int w64; |
| char after[6]; |
| } |
| T; |
| |
| void foo (T* t, unsigned long long int w) |
| { |
| __asm__ __volatile__( |
| "stdx %0,%1,%2" |
| : : "b"(w), "b"(t), "b"(2) : "memory" |
| ); |
| } |
| |
| int main ( void ) |
| { |
| T* t; |
| unsigned char* p; |
| int i; |
| assert(sizeof(T) == 16); |
| t = calloc(sizeof(T),1); |
| assert(t); |
| /* check t is 8-aligned. This causes the write done by 'foo' to be |
| misaligned by 2 as desired, triggering the bug. */ |
| assert(0 == (((unsigned long)t) & 7)); |
| foo(t, 0x1122334455667788); |
| p = (unsigned char*)t; |
| for (i = 0; i < 16; i++) |
| if (p[i] == 0) |
| printf(".."); |
| else |
| printf("%02x", (int)p[i]); |
| printf("\n"); |
| return 0; |
| } |