diff options
author | Reid Kleckner <reid@kleckner.net> | 2014-02-01 00:04:45 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2014-02-01 00:04:45 +0000 |
commit | 314ef7bafda9f507540f3294359f20ba7bcf7a8d (patch) | |
tree | 12c1045bd69401d2014764c56bb55a6a717913f3 /clang/test | |
parent | f5b76518c9c1afd2e08a59c11f3de8fb25540b58 (diff) | |
download | bcm5719-llvm-314ef7bafda9f507540f3294359f20ba7bcf7a8d.tar.gz bcm5719-llvm-314ef7bafda9f507540f3294359f20ba7bcf7a8d.zip |
[ms-cxxabi] Use inalloca on win32 when passing non-trivial C++ objects
When a non-trivial parameter is present, clang now gathers up all the
parameters that lack inreg and puts them into a packed struct. MSVC
always aligns each parameter to 4 bytes and no more, so this is a pretty
simple struct to lay out.
On win64, non-trivial records are passed indirectly. Prior to this
change, clang was incorrectly using byval on win64.
I'm able to self-host a working clang with this change and additional
LLVM patches.
Reviewers: rsmith
Differential Revision: http://llvm-reviews.chandlerc.com/D2636
llvm-svn: 200597
Diffstat (limited to 'clang/test')
7 files changed, 163 insertions, 46 deletions
diff --git a/clang/test/CodeGenCXX/copy-constructor-elim.cpp b/clang/test/CodeGenCXX/copy-constructor-elim.cpp index ad3a87b9d5f..8e9bee97377 100644 --- a/clang/test/CodeGenCXX/copy-constructor-elim.cpp +++ b/clang/test/CodeGenCXX/copy-constructor-elim.cpp @@ -1,6 +1,9 @@ -// RUN: %clang_cc1 -emit-llvm -o %t %s -// RUN: not grep "_ZN1CC1ERK1C" %t -// RUN: not grep "_ZN1SC1ERK1S" %t +// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK +// RUN: %clang_cc1 -triple %ms_abi_triple -emit-llvm -o - %s | FileCheck %s -check-prefix MS +// CHECK-NOT: _ZN1CC1ERK1C +// CHECK-NOT: _ZN1SC1ERK1S +// MS-NOT: ?0C@@QAE@ABV0 +// MS-NOT: ?0S@@QAE@ABV0 extern "C" int printf(...); diff --git a/clang/test/CodeGenCXX/microsoft-abi-arg-order.cpp b/clang/test/CodeGenCXX/microsoft-abi-arg-order.cpp index 4415c2e84a7..dff52ae9038 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-arg-order.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-arg-order.cpp @@ -12,7 +12,10 @@ void foo(A a, A b, A c) { // Order of destruction should be left to right. // // CHECK-LABEL: define void @"\01?foo@@YAXUA@@00@Z" -// CHECK: ({{.*}} %[[a:.*]], {{.*}} %[[b:.*]], {{.*}} %[[c:.*]]) +// CHECK: ([[argmem_ty:<{ %struct.A, %struct.A, %struct.A }>]]* inalloca) +// CHECK: %[[a:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %0, i32 0, i32 0 +// CHECK: %[[b:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %0, i32 0, i32 1 +// CHECK: %[[c:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %0, i32 0, i32 2 // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[a]]) // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[b]]) // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[c]]) @@ -27,10 +30,16 @@ void call_foo() { // things as we unwind. // // CHECK-LABEL: define void @"\01?call_foo@@YAXXZ"() -// CHECK: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@H@Z"(%struct.A* %[[arg3:.*]], i32 3) -// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@H@Z"(%struct.A* %[[arg2:.*]], i32 2) -// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@H@Z"(%struct.A* %[[arg1:.*]], i32 1) -// CHECK: call void @"\01?foo@@YAXUA@@00@Z"({{.*}} %[[arg1]], {{.*}} %[[arg2]], {{.*}} %[[arg3]]) +// CHECK: call i8* @llvm.stacksave() +// CHECK: %[[argmem:[^ ]*]] = alloca [[argmem_ty]], inalloca +// CHECK: %[[arg3:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 2 +// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@H@Z"(%struct.A* %[[arg3]], i32 3) +// CHECK: %[[arg2:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 1 +// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@H@Z"(%struct.A* %[[arg2]], i32 2) +// CHECK: %[[arg1:[^ ]*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 0 +// CHECK: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@H@Z"(%struct.A* %[[arg1]], i32 1) +// CHECK: invoke void @"\01?foo@@YAXUA@@00@Z"([[argmem_ty]]* inalloca %[[argmem]]) +// CHECK: call void @llvm.stackrestore // CHECK: ret void // // lpad2: diff --git a/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp b/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp new file mode 100644 index 00000000000..00d36b7d492 --- /dev/null +++ b/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i686-pc-win32 -mconstructor-aliases -fno-rtti | FileCheck %s + +struct A { + A() : a(42) {} + A(const A &o) : a(o.a) {} + ~A() {} + int a; + A foo(A o); +}; + +A A::foo(A x) { + A y(*this); + y.a += x.a; + return y; +} + +// CHECK: define x86_thiscallcc void @"\01?foo@A@@QAE?AU1@U1@@Z" +// CHECK: (%struct.A* %this, <{ %struct.A*, %struct.A }>* inalloca) + +int main() { + A x; + A y = x.foo(x); +} + +// CHECK: call x86_thiscallcc void @"\01?foo@A@@QAE?AU1@U1@@Z" +// CHECK: (%struct.A* %{{[^,]*}}, <{ %struct.A*, %struct.A }>* inalloca %{{[^,]*}}) diff --git a/clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp b/clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp new file mode 100644 index 00000000000..33619216e88 --- /dev/null +++ b/clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i686-pc-win32 -mconstructor-aliases -fno-rtti | FileCheck %s + +#include <stdarg.h> + +struct A { + A(int a) : a(a) {} + A(const A &o) : a(o.a) {} + ~A() {} + int a; +}; + +int foo(A a, ...) { + va_list ap; + va_start(ap, a); + int sum = 0; + for (int i = 0; i < a.a; ++i) + sum += va_arg(ap, int); + va_end(ap); + return sum; +} + +int main() { + return foo(A(3), 1, 2, 3); +} +// CHECK-LABEL: define i32 @main() +// CHECK: %[[argmem_cast:[^ ]*]] = bitcast <{ %struct.A, i32, i32, i32 }>* %argmem to <{ %struct.A }>* +// CHECK: call i32 (<{ %struct.A }>*, ...)* @"\01?foo@@YAHUA@@ZZ"(<{ %struct.A }>* inalloca %[[argmem_cast]]) diff --git a/clang/test/CodeGenCXX/microsoft-abi-exceptions.cpp b/clang/test/CodeGenCXX/microsoft-abi-exceptions.cpp index 6731c0effb0..ecce71d6c5c 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-exceptions.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-exceptions.cpp @@ -14,17 +14,21 @@ void HasEHCleanup() { } // With exceptions, we need to clean up at least one of these temporaries. -// WIN32: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} { -// First one doesn't have any cleanups, no need for invoke. -// WIN32: call void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) +// WIN32-LABEL: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} { +// WIN32: %[[base:.*]] = call i8* @llvm.stacksave() +// If this call throws, we have to restore the stack. +// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) // If this call throws, we have to cleanup the first temporary. // WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) -// If this call throws, we already popped our cleanups -// WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0@Z" +// If this call throws, we have to cleanup the stacksave. +// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" +// WIN32: call void @llvm.stackrestore(i8* %[[base]]) // WIN32: ret void // // There should be one dtor call for unwinding from the second getA. // WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32-NOT: @"\01??1A@@QAE@XZ" +// WIN32: call void @llvm.stackrestore // WIN32: } void TakeRef(const A &a); @@ -32,20 +36,28 @@ int HasDeactivatedCleanups() { return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())); } -// WIN32: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} { +// WIN32-LABEL: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} { // WIN32: %[[isactive:.*]] = alloca i1 -// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32: call i8* @llvm.stacksave() +// WIN32: %[[argmem:.*]] = alloca [[argmem_ty:<{ %struct.A, %struct.A }>]], inalloca +// WIN32: %[[arg1:.*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 1 +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" // WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1:.*]]) +// +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1]]) // WIN32: store i1 true, i1* %[[isactive]] +// +// WIN32: %[[arg0:.*]] = getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 0 // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" // WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" // WIN32: store i1 false, i1* %[[isactive]] -// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" +// +// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"([[argmem_ty]]* inalloca %[[argmem]]) +// WIN32: call void @llvm.stackrestore // Destroy the two const ref temporaries. // WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" -// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" // WIN32: ret i32 // // Conditionally destroy arg1. @@ -60,20 +72,22 @@ int HasConditionalCleanup(bool cond) { return (cond ? TakesTwo(A(), A()) : CouldThrow()); } -// WIN32: define i32 @"\01?HasConditionalCleanup@@YAH_N@Z"(i1 zeroext %{{.*}}) {{.*}} { +// WIN32-LABEL: define i32 @"\01?HasConditionalCleanup@@YAH_N@Z"(i1 zeroext %{{.*}}) {{.*}} { // WIN32: store i1 false // WIN32: br i1 -// No cleanups, so we call and then activate a cleanup if it succeeds. -// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1:.*]]) +// WIN32: call i8* @llvm.stacksave() +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}}) // WIN32: store i1 true -// Now we have a cleanup for the first aggregate, so we invoke. // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}}) -// Now we have no cleanups because TakeTwo will destruct both args. -// WIN32: call i32 @"\01?TakesTwo@@YAHUA@@0@Z" -// Still no cleanups, so call. +// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" +// WIN32: call void @llvm.stackrestore +// // WIN32: call i32 @"\01?CouldThrow@@YAHXZ"() -// Somewhere in the landing pad for our single invoke, call the dtor. -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]]) +// +// Only one dtor in the invoke for arg1 +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) +// WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32: call void @llvm.stackrestore // WIN32: } // Now test both. @@ -81,8 +95,7 @@ int HasConditionalDeactivatedCleanups(bool cond) { return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow()); } -// WIN32: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { -// WIN32: %[[arg1:.*]] = alloca %struct.A, align 4 +// WIN32-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { // WIN32: alloca i1 // WIN32: %[[arg1_cond:.*]] = alloca i1 // Start all four cleanups as deactivated. @@ -92,10 +105,10 @@ int HasConditionalDeactivatedCleanups(bool cond) { // WIN32: store i1 false // WIN32: br i1 // True condition. -// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" // WIN32: store i1 true // WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1]]) +// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" // WIN32: store i1 true, i1* %[[arg1_cond]] // WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" // WIN32: store i1 true @@ -108,13 +121,13 @@ int HasConditionalDeactivatedCleanups(bool cond) { // WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"() // Two normal cleanups for TakeRef args. // WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" -// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" // WIN32: ret i32 // // Somewhere in the landing pad soup, we conditionally destroy arg1. // WIN32: %[[isactive:.*]] = load i1* %[[arg1_cond]] // WIN32: br i1 %[[isactive]] -// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]]) +// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" // WIN32: } namespace crash_on_partial_destroy { diff --git a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp index bff5647fdd5..98001370d1f 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp @@ -47,6 +47,14 @@ struct Big { int a, b, c, d, e, f; }; +// WIN32: declare void @"{{.*take_bools_and_chars.*}}" +// WIN32: (<{ i8, [3 x i8], i8, [3 x i8], %struct.SmallWithDtor, +// WIN32: i8, [3 x i8], i8, [3 x i8], i32, i8 }>* inalloca) +void take_bools_and_chars(char a, char b, SmallWithDtor c, char d, bool e, int f, bool g); +void call_bools_and_chars() { + take_bools_and_chars('A', 'B', SmallWithDtor(), 'D', true, 13, false); +} + // Returning structs that fit into a register. Small small_return() { return Small(); } // LINUX-LABEL: define void @_Z12small_returnv(%struct.Small* noalias sret %agg.result) @@ -103,11 +111,11 @@ void small_arg_with_ctor(SmallWithCtor s) {} // Test that dtors are invoked in the callee. void small_arg_with_dtor(SmallWithDtor s) {} -// WIN32: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval align 4 %s) {{.*}} { -// WIN32: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ"(%struct.SmallWithDtor* %s) +// WIN32: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(<{ %struct.SmallWithDtor }>* inalloca) {{.*}} { +// WIN32: call x86_thiscallcc void @"\01??1SmallWithDtor@@QAE@XZ" // WIN32: } -// WIN64: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* byval %s) {{.*}} { -// WIN64: call void @"\01??1SmallWithDtor@@QEAA@XZ"(%struct.SmallWithDtor* %s) +// WIN64: define void @"\01?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(%struct.SmallWithDtor* %s) {{.*}} { +// WIN64: call void @"\01??1SmallWithDtor@@QEAA@XZ" // WIN64: } // Test that references aren't destroyed in the callee. @@ -141,13 +149,13 @@ void eh_cleanup_arg_with_dtor() { void small_arg_with_vftable(SmallWithVftable s) {} // LINUX-LABEL: define void @_Z22small_arg_with_vftable16SmallWithVftable(%struct.SmallWithVftable* %s) -// WIN32: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval align 4 %s) -// WIN64: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval %s) +// WIN32: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(<{ %struct.SmallWithVftable }>* inalloca) +// WIN64: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* %s) void medium_arg_with_copy_ctor(MediumWithCopyCtor s) {} // LINUX-LABEL: define void @_Z25medium_arg_with_copy_ctor18MediumWithCopyCtor(%struct.MediumWithCopyCtor* %s) -// WIN32: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval align 4 %s) -// WIN64: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval %s) +// WIN32: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(<{ %struct.MediumWithCopyCtor }>* inalloca) +// WIN64: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* %s) void big_arg(Big s) {} // LINUX-LABEL: define void @_Z7big_arg3Big(%struct.Big* byval align 4 %s) @@ -215,8 +223,8 @@ struct X { }; void g(X) { } -// WIN32: define void @"\01?g@@YAXUX@@@Z"(%struct.X* byval align 4) {{.*}} { -// WIN32: call x86_thiscallcc void @"\01??1X@@QAE@XZ"(%struct.X* %0) +// WIN32: define void @"\01?g@@YAXUX@@@Z"(<{ %struct.X }>* inalloca) {{.*}} { +// WIN32: call x86_thiscallcc void @"\01??1X@@QAE@XZ"(%struct.X* {{.*}}) // WIN32: } void f() { g(X()); @@ -224,3 +232,34 @@ void f() { // WIN32: define void @"\01?f@@YAXXZ"() {{.*}} { // WIN32-NOT: call {{.*}} @"\01??1X@@QAE@XZ" // WIN32: } + + +namespace test2 { +// We used to crash on this due to the mixture of POD byval and non-trivial +// byval. + +struct NonTrivial { + NonTrivial(); + NonTrivial(const NonTrivial &o); + ~NonTrivial(); + int a; +}; +struct POD { int b; }; + +int foo(NonTrivial a, POD b); +void bar() { + POD b; + b.b = 13; + int c = foo(NonTrivial(), b); +} +// WIN32-LABEL: define void @"\01?bar@test2@@YAXXZ"() {{.*}} { +// WIN32: %[[argmem:[^ ]*]] = alloca [[argmem_ty:<{ %"struct.test2::NonTrivial", %"struct.test2::POD" }>]], inalloca +// WIN32: getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 1 +// WIN32: call void @llvm.memcpy +// WIN32: getelementptr inbounds [[argmem_ty]]* %[[argmem]], i32 0, i32 0 +// WIN32: call x86_thiscallcc %"struct.test2::NonTrivial"* @"\01??0NonTrivial@test2@@QAE@XZ" +// WIN32: call i32 @"\01?foo@test2@@YAHUNonTrivial@1@UPOD@1@@Z"([[argmem_ty]]* inalloca %argmem) +// WIN32: ret void +// WIN32: } + +} diff --git a/clang/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm b/clang/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm index 3e01f03e26d..0b01b27fa79 100644 --- a/clang/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm +++ b/clang/test/CodeGenObjCXX/microsoft-abi-arc-param-order.mm @@ -10,11 +10,11 @@ struct A { // Verify that we destruct things from left to right in the MS C++ ABI: a, b, c, d. // // CHECK-LABEL: define void @"\01?test_arc_order@@YAXUA@@PAAAPAUobjc_object@@01@Z" -// CHECK: ({{.*}} %[[a:.*]], {{.*}}, {{.*}} %[[c:.*]], {{.*}}) +// CHECK: (<{ %struct.A, i8*, %struct.A, i8* }>* inalloca) void test_arc_order(A a, id __attribute__((ns_consumed)) b , A c, id __attribute__((ns_consumed)) d) { - // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[a]]) + // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %{{.*}}) // CHECK: call void @objc_storeStrong(i8** %{{.*}}, i8* null) - // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[c]]) + // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %{{.*}}) // CHECK: call void @objc_storeStrong(i8** %{{.*}}, i8* null) // CHECK: ret void } |