1 // RUN: %clang_cc1 -fms-extensions -w -triple i386-pc-win32 -emit-llvm -o - %s | FileCheck %s 2 3 // PR44395 4 // MSVC passes overaligned types indirectly since MSVC 2015. Make sure that 5 // works with inalloca. 6 7 struct NonTrivial { 8 NonTrivial(); 9 NonTrivial(const NonTrivial &o); 10 int x; 11 }; 12 13 struct __declspec(align(64)) OverAligned { 14 OverAligned(); 15 int buf[16]; 16 }; 17 18 struct __declspec(align(8)) Both { 19 Both(); 20 Both(const Both &o); 21 int x, y; 22 }; 23 24 extern int gvi32; 25 26 int receive_inalloca_overaligned(NonTrivial nt, OverAligned o) { 27 return nt.x + o.buf[0]; 28 } 29 30 // CHECK-LABEL: define dso_local noundef i32 @"?receive_inalloca_overaligned@@Y{{.*}}" 31 // CHECK-SAME: (ptr inalloca(<{ %struct.NonTrivial, ptr }>) %0) 32 33 int pass_inalloca_overaligned() { 34 gvi32 = receive_inalloca_overaligned(NonTrivial(), OverAligned()); 35 return gvi32; 36 } 37 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 }> 42 43 // Construct OverAligned into TMP. 44 // CHECK: call x86_thiscallcc noundef ptr @"??0OverAligned@@QAE@XZ"(ptr {{[^,]*}} [[TMP]]) 45 46 // Construct NonTrivial into the GEP. 47 // CHECK: [[GEP:%[^ ]*]] = getelementptr inbounds nuw <{ %struct.NonTrivial, ptr }>, ptr %{{.*}}, i32 0, i32 0 48 // CHECK: call x86_thiscallcc noundef ptr @"??0NonTrivial@@QAE@XZ"(ptr {{[^,]*}} [[GEP]]) 49 50 // Store the address of an OverAligned temporary into the struct. 51 // CHECK: getelementptr inbounds nuw <{ %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) 54 55 int receive_both(Both o) { 56 return o.x + o.y; 57 } 58 59 // CHECK-LABEL: define dso_local noundef i32 @"?receive_both@@Y{{.*}}" 60 // CHECK-SAME: (ptr noundef %o) 61 62 int pass_both() { 63 gvi32 = receive_both(Both()); 64 return gvi32; 65 } 66 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]]) 71 72 int receive_inalloca_both(NonTrivial nt, Both o) { 73 return nt.x + o.x + o.y; 74 } 75 76 // CHECK-LABEL: define dso_local noundef i32 @"?receive_inalloca_both@@Y{{.*}}" 77 // CHECK-SAME: (ptr inalloca(<{ %struct.NonTrivial, ptr }>) %0) 78 79 int pass_inalloca_both() { 80 gvi32 = receive_inalloca_both(NonTrivial(), Both()); 81 return gvi32; 82 } 83 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) 88 89 // Here we have a type that is: 90 // - overaligned 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 { 95 MyPtr(); 96 MyPtr(const MyPtr &o); 97 ~MyPtr(); 98 int *ptr; 99 }; 100 101 int receiveMyPtr(MyPtr o) { return *o.ptr; } 102 103 // CHECK-LABEL: define dso_local noundef i32 @"?receiveMyPtr@@Y{{.*}}" 104 // CHECK-SAME: (ptr noundef %o) 105 106 int passMyPtr() { return receiveMyPtr(MyPtr()); } 107 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]]) 112