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