<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - [AArch64] 16-byte aligned parameter of empty struct type does not follow round NGNR to next even number"
   href="https://bugs.llvm.org/show_bug.cgi?id=47155">47155</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>[AArch64] 16-byte aligned parameter of empty struct type does not follow round NGNR to next even number
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Backend: AArch64
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>tbaeder@redhat.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>arnaud.degrandmaison@arm.com, llvm-bugs@lists.llvm.org, smithp352@googlemail.com, Ties.Stuij@arm.com
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Take the following C++ code:

struct __attribute__((aligned(16))) A {};

static void foo(struct A a, int f) {}

int main(int argc, char **argv) {
  struct A a;

  foo(a, 10);

  return 0;
}

If compiled into AArch64 code, the generated LLVM IR looks like this:

%struct.A = type { [16 x i8] }

; Function Attrs: noinline norecurse optnone
define dso_local i32 @main(i32 %argc, i8** %argv) #0 {
entry:
  %retval = alloca i32, align 4
  %argc.addr = alloca i32, align 4
  %argv.addr = alloca i8**, align 8
  %a = alloca %struct.A, align 16
  %agg.tmp = alloca %struct.A, align 16
  store i32 0, i32* %retval, align 4
  store i32 %argc, i32* %argc.addr, align 4
  store i8** %argv, i8*** %argv.addr, align 8
  %coerce.dive = getelementptr inbounds %struct.A, %struct.A* %agg.tmp, i32 0,
i32 0
  %0 = bitcast [16 x i8]* %coerce.dive to i8*
  %1 = load i8, i8* %0, align 16
  call void @_ZL3foo1Ai(i8 %1, i32 10)
  ret i32 0
}

; Function Attrs: noinline nounwind optnone
define internal void @_ZL3foo1Ai(i8 %a.coerce, i32 %f) #1 {
entry:
  %a = alloca %struct.A, align 16
  %f.addr = alloca i32, align 4
  %coerce.dive = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 0
  %0 = bitcast [16 x i8]* %coerce.dive to i8*
  store i8 %a.coerce, i8* %0, align 16
  store i32 %f, i32* %f.addr, align 4
  ret void
}



and the disassembly of the compiled executable looks like this:

0000000000000000 <main>:
   0:   d10143ff        sub     sp, sp, #0x50
   4:   a9047bfd        stp     x29, x30, [sp, #64]
   8:   910103fd        add     x29, sp, #0x40
   c:   2a1f03e8        mov     w8, wzr
  10:   b81fc3bf        stur    wzr, [x29, #-4]
  14:   b81f83a0        stur    w0, [x29, #-8]
  18:   f81f03a1        stur    x1, [x29, #-16]
  1c:   394043e0        ldrb    w0, [sp, #16]
  20:   52800141        mov     w1, #0xa                        // #10
  24:   b9000fe8        str     w8, [sp, #12]
  28:   94000005        bl      3c <_ZL3foo1Ai>
  2c:   b9400fe0        ldr     w0, [sp, #12]
  30:   a9447bfd        ldp     x29, x30, [sp, #64]
  34:   910143ff        add     sp, sp, #0x50
  38:   d65f03c0        ret

000000000000003c <_ZL3foo1Ai>:
  3c:   d10083ff        sub     sp, sp, #0x20
  40:   390043e0        strb    w0, [sp, #16]
  44:   b9000fe1        str     w1, [sp, #12]
  48:   910083ff        add     sp, sp, #0x20
  4c:   d65f03c0        ret


Note that the literal 10 (the second parameter to function call foo()) is being
passed in the w1 register.

The first parameter is a 16-byte aligned empty struct, which according to the
AAPCS clause C.8 ("If the argument has an alignment of 16 then the NGRN is
rounded up to the next even number.") means that the next parameter should be
passed in register 2.

g++ passes the second parameter in w2, was I would expect.

This problem does *not* happen if...
  1) The struct has an alignment other than 16
  2) The struct has a member
  3) The code is compiled as C and not as C++</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>