1 // RUN: %clang_cc1 -fms-extensions -w -triple i386-pc-win32 -emit-llvm -o - %s | FileCheck %s
4 // MSVC passes overaligned types indirectly since MSVC 2015. Make sure that
5 // works with inalloca.
9 NonTrivial(const NonTrivial
&o
);
13 struct __declspec(align(64)) OverAligned
{
18 struct __declspec(align(8)) Both
{
26 int receive_inalloca_overaligned(NonTrivial nt
, OverAligned o
) {
27 return nt
.x
+ o
.buf
[0];
30 // CHECK-LABEL: define dso_local noundef i32 @"?receive_inalloca_overaligned@@Y{{.*}}"
31 // CHECK-SAME: (ptr inalloca(<{ %struct.NonTrivial, ptr }>) %0)
33 int pass_inalloca_overaligned() {
34 gvi32
= receive_inalloca_overaligned(NonTrivial(), OverAligned());
38 // CHECK-LABEL: define dso_local noundef i32 @"?pass_inalloca_overaligned@@Y{{.*}}"
39 // CHECK: [[TMP:%[^ ]*]] = alloca %struct.OverAligned, align 64
40 // CHECK: call ptr @llvm.stacksave.p0()
41 // CHECK: alloca inalloca <{ %struct.NonTrivial, ptr }>
43 // Construct OverAligned into TMP.
44 // CHECK: call x86_thiscallcc noundef ptr @"??0OverAligned@@QAE@XZ"(ptr {{[^,]*}} [[TMP]])
46 // Construct NonTrivial into the GEP.
47 // CHECK: [[GEP:%[^ ]*]] = getelementptr inbounds <{ %struct.NonTrivial, ptr }>, ptr %{{.*}}, i32 0, i32 0
48 // CHECK: call x86_thiscallcc noundef ptr @"??0NonTrivial@@QAE@XZ"(ptr {{[^,]*}} [[GEP]])
50 // Store the address of an OverAligned temporary into the struct.
51 // CHECK: getelementptr inbounds <{ %struct.NonTrivial, ptr }>, ptr %{{.*}}, i32 0, i32 1
52 // CHECK: store ptr [[TMP]], ptr %{{.*}}, align 4
53 // CHECK: call noundef i32 @"?receive_inalloca_overaligned@@Y{{.*}}"(ptr inalloca(<{ %struct.NonTrivial, ptr }>) %argmem)
55 int receive_both(Both o
) {
59 // CHECK-LABEL: define dso_local noundef i32 @"?receive_both@@Y{{.*}}"
60 // CHECK-SAME: (ptr noundef %o)
63 gvi32
= receive_both(Both());
67 // CHECK-LABEL: define dso_local noundef i32 @"?pass_both@@Y{{.*}}"
68 // CHECK: [[TMP:%[^ ]*]] = alloca %struct.Both, align 8
69 // CHECK: call x86_thiscallcc noundef ptr @"??0Both@@QAE@XZ"(ptr {{[^,]*}} [[TMP]])
70 // CHECK: call noundef i32 @"?receive_both@@Y{{.*}}"(ptr noundef [[TMP]])
72 int receive_inalloca_both(NonTrivial nt
, Both o
) {
73 return nt
.x
+ o
.x
+ o
.y
;
76 // CHECK-LABEL: define dso_local noundef i32 @"?receive_inalloca_both@@Y{{.*}}"
77 // CHECK-SAME: (ptr inalloca(<{ %struct.NonTrivial, ptr }>) %0)
79 int pass_inalloca_both() {
80 gvi32
= receive_inalloca_both(NonTrivial(), Both());
84 // CHECK-LABEL: define dso_local noundef i32 @"?pass_inalloca_both@@Y{{.*}}"
85 // CHECK: [[TMP:%[^ ]*]] = alloca %struct.Both, align 8
86 // CHECK: call x86_thiscallcc noundef ptr @"??0Both@@QAE@XZ"(ptr {{[^,]*}} [[TMP]])
87 // CHECK: call noundef i32 @"?receive_inalloca_both@@Y{{.*}}"(ptr inalloca(<{ %struct.NonTrivial, ptr }>) %argmem)
89 // Here we have a type that is:
91 // - not trivially copyable
92 // - can be "passed in registers" due to [[trivial_abi]]
93 // Clang should pass it directly.
94 struct [[trivial_abi
]] alignas(8) MyPtr
{
96 MyPtr(const MyPtr
&o
);
101 int receiveMyPtr(MyPtr o
) { return *o
.ptr
; }
103 // CHECK-LABEL: define dso_local noundef i32 @"?receiveMyPtr@@Y{{.*}}"
104 // CHECK-SAME: (ptr noundef %o)
106 int passMyPtr() { return receiveMyPtr(MyPtr()); }
108 // CHECK-LABEL: define dso_local noundef i32 @"?passMyPtr@@Y{{.*}}"
109 // CHECK: [[TMP:%[^ ]*]] = alloca %struct.MyPtr, align 8
110 // CHECK: call x86_thiscallcc noundef ptr @"??0MyPtr@@QAE@XZ"(ptr {{[^,]*}} [[TMP]])
111 // CHECK: call noundef i32 @"?receiveMyPtr@@Y{{.*}}"(ptr noundef [[TMP]])