Reid Kleckner | 2c6a389 | 2020-02-11 16:03:26 -0800 | [diff] [blame] | 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 | |
Reid Kleckner | 2c6a389 | 2020-02-11 16:03:26 -0800 | [diff] [blame] | 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 | |
Reid Kleckner | 3b3a165 | 2020-09-18 11:22:15 -0700 | [diff] [blame] | 18 | struct __declspec(align(8)) Both { |
| 19 | Both(); |
| 20 | Both(const Both &o); |
| 21 | int x, y; |
| 22 | }; |
| 23 | |
Reid Kleckner | 2c6a389 | 2020-02-11 16:03:26 -0800 | [diff] [blame] | 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 i32 @"?receive_inalloca_overaligned@@Y{{.*}}" |
| 31 | // CHECK-SAME: (<{ %struct.NonTrivial, %struct.OverAligned* }>* inalloca %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 i32 @"?pass_inalloca_overaligned@@Y{{.*}}" |
| 39 | // CHECK: [[TMP:%[^ ]*]] = alloca %struct.OverAligned, align 64 |
| 40 | // CHECK: call i8* @llvm.stacksave() |
| 41 | // CHECK: alloca inalloca <{ %struct.NonTrivial, %struct.OverAligned* }> |
| 42 | |
| 43 | // Construct OverAligned into TMP. |
CJ Johnson | 69cd776 | 2020-11-16 15:04:55 -0800 | [diff] [blame] | 44 | // CHECK: call x86_thiscallcc %struct.OverAligned* @"??0OverAligned@@QAE@XZ"(%struct.OverAligned* {{[^,]*}} [[TMP]]) |
Reid Kleckner | 2c6a389 | 2020-02-11 16:03:26 -0800 | [diff] [blame] | 45 | |
| 46 | // Construct NonTrivial into the GEP. |
| 47 | // CHECK: [[GEP:%[^ ]*]] = getelementptr inbounds <{ %struct.NonTrivial, %struct.OverAligned* }>, <{ %struct.NonTrivial, %struct.OverAligned* }>* %{{.*}}, i32 0, i32 0 |
CJ Johnson | 69cd776 | 2020-11-16 15:04:55 -0800 | [diff] [blame] | 48 | // CHECK: call x86_thiscallcc %struct.NonTrivial* @"??0NonTrivial@@QAE@XZ"(%struct.NonTrivial* {{[^,]*}} [[GEP]]) |
Reid Kleckner | 2c6a389 | 2020-02-11 16:03:26 -0800 | [diff] [blame] | 49 | |
| 50 | // Store the address of an OverAligned temporary into the struct. |
| 51 | // CHECK: getelementptr inbounds <{ %struct.NonTrivial, %struct.OverAligned* }>, <{ %struct.NonTrivial, %struct.OverAligned* }>* %{{.*}}, i32 0, i32 1 |
| 52 | // CHECK: store %struct.OverAligned* [[TMP]], %struct.OverAligned** %{{.*}}, align 4 |
| 53 | // CHECK: call i32 @"?receive_inalloca_overaligned@@Y{{.*}}"(<{ %struct.NonTrivial, %struct.OverAligned* }>* inalloca %argmem) |
Reid Kleckner | 3b3a165 | 2020-09-18 11:22:15 -0700 | [diff] [blame] | 54 | |
| 55 | int receive_both(Both o) { |
| 56 | return o.x + o.y; |
| 57 | } |
| 58 | |
| 59 | // CHECK-LABEL: define dso_local i32 @"?receive_both@@Y{{.*}}" |
| 60 | // CHECK-SAME: (%struct.Both* %o) |
| 61 | |
| 62 | int pass_both() { |
| 63 | gvi32 = receive_both(Both()); |
| 64 | return gvi32; |
| 65 | } |
| 66 | |
| 67 | // CHECK-LABEL: define dso_local i32 @"?pass_both@@Y{{.*}}" |
| 68 | // CHECK: [[TMP:%[^ ]*]] = alloca %struct.Both, align 8 |
CJ Johnson | 69cd776 | 2020-11-16 15:04:55 -0800 | [diff] [blame] | 69 | // CHECK: call x86_thiscallcc %struct.Both* @"??0Both@@QAE@XZ"(%struct.Both* {{[^,]*}} [[TMP]]) |
Reid Kleckner | 3b3a165 | 2020-09-18 11:22:15 -0700 | [diff] [blame] | 70 | // CHECK: call i32 @"?receive_both@@Y{{.*}}"(%struct.Both* [[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 i32 @"?receive_inalloca_both@@Y{{.*}}" |
| 77 | // CHECK-SAME: (<{ %struct.NonTrivial, %struct.Both* }>* inalloca %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 i32 @"?pass_inalloca_both@@Y{{.*}}" |
| 85 | // CHECK: [[TMP:%[^ ]*]] = alloca %struct.Both, align 8 |
CJ Johnson | 69cd776 | 2020-11-16 15:04:55 -0800 | [diff] [blame] | 86 | // CHECK: call x86_thiscallcc %struct.Both* @"??0Both@@QAE@XZ"(%struct.Both* {{[^,]*}} [[TMP]]) |
Reid Kleckner | 3b3a165 | 2020-09-18 11:22:15 -0700 | [diff] [blame] | 87 | // CHECK: call i32 @"?receive_inalloca_both@@Y{{.*}}"(<{ %struct.NonTrivial, %struct.Both* }>* inalloca %argmem) |
Reid Kleckner | b8a50e9 | 2020-09-24 13:42:41 -0700 | [diff] [blame] | 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 i32 @"?receiveMyPtr@@Y{{.*}}" |
| 104 | // CHECK-SAME: (%struct.MyPtr* %o) |
| 105 | |
| 106 | int passMyPtr() { return receiveMyPtr(MyPtr()); } |
| 107 | |
| 108 | // CHECK-LABEL: define dso_local i32 @"?passMyPtr@@Y{{.*}}" |
| 109 | // CHECK: [[TMP:%[^ ]*]] = alloca %struct.MyPtr, align 8 |
CJ Johnson | 69cd776 | 2020-11-16 15:04:55 -0800 | [diff] [blame] | 110 | // CHECK: call x86_thiscallcc %struct.MyPtr* @"??0MyPtr@@QAE@XZ"(%struct.MyPtr* {{[^,]*}} [[TMP]]) |
Reid Kleckner | b8a50e9 | 2020-09-24 13:42:41 -0700 | [diff] [blame] | 111 | // CHECK: call i32 @"?receiveMyPtr@@Y{{.*}}"(%struct.MyPtr* [[TMP]]) |