1
2/*
3This is a regression test for the following problem, noticed by
4Greg Parker:
5
6vex ppc64 generates bad code for instruction sequences like this:
7
8    li    r0, 2
9    stdx  r3, r1, r0
10
11gcc emits code like this when manipulating packed structures
12with 8-byte fields on 2-byte boundaries.
13
14First, 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
23Then 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
30Finally, the assembler silently strips the index&3 part,
31because `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
43typedef
44struct __attribute__ ((__packed__)) {
45  char before[2];
46  unsigned long long int w64;
47  char after[6];
48}
49T;
50
51void 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
59int 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