| // RUN: %clang_cc1 -triple aarch64-windows -ffreestanding -emit-llvm -O0 \ |
| // RUN: -x c++ -o - %s | FileCheck %s |
| |
| // Pass and return for type size <= 8 bytes. |
| // CHECK: define {{.*}} i64 @{{.*}}f1{{.*}}() |
| // CHECK: call i64 {{.*}}func1{{.*}}(i64 %3) |
| struct S1 { |
| int a[2]; |
| }; |
| |
| S1 func1(S1 x); |
| S1 f1() { |
| S1 x; |
| return func1(x); |
| } |
| |
| // Pass and return type size <= 16 bytes. |
| // CHECK: define {{.*}} [2 x i64] @{{.*}}f2{{.*}}() |
| // CHECK: call [2 x i64] {{.*}}func2{{.*}}([2 x i64] %3) |
| struct S2 { |
| int a[4]; |
| }; |
| |
| S2 func2(S2 x); |
| S2 f2() { |
| S2 x; |
| return func2(x); |
| } |
| |
| // Pass and return for type size > 16 bytes. |
| // CHECK: define {{.*}} void @{{.*}}f3{{.*}}(%struct.S3* noalias sret %agg.result) |
| // CHECK: call void {{.*}}func3{{.*}}(%struct.S3* sret %agg.result, %struct.S3* %agg.tmp) |
| struct S3 { |
| int a[5]; |
| }; |
| |
| S3 func3(S3 x); |
| S3 f3() { |
| S3 x; |
| return func3(x); |
| } |
| |
| // Pass and return aggregate (of size < 16 bytes) with non-trivial destructor. |
| // Passed directly but returned indirectly. |
| // CHECK: define {{.*}} void {{.*}}f4{{.*}}(%struct.S4* inreg noalias sret %agg.result) |
| // CHECK: call void {{.*}}func4{{.*}}(%struct.S4* inreg sret %agg.result, [2 x i64] %5) |
| struct S4 { |
| int a[3]; |
| ~S4(); |
| }; |
| |
| S4 func4(S4 x); |
| S4 f4() { |
| S4 x; |
| return func4(x); |
| } |
| |
| // Pass and return from instance method called from instance method. |
| // CHECK: define {{.*}} void @{{.*}}bar@Q1{{.*}}(%class.Q1* %this, %class.P1* inreg noalias sret %agg.result) |
| // CHECK: call void {{.*}}foo@P1{{.*}}(%class.P1* %ref.tmp, %class.P1* inreg sret %agg.result, i8 %1) |
| |
| class P1 { |
| public: |
| P1 foo(P1 x); |
| }; |
| |
| class Q1 { |
| public: |
| P1 bar(); |
| }; |
| |
| P1 Q1::bar() { |
| P1 p1; |
| return P1().foo(p1); |
| } |
| |
| // Pass and return from instance method called from free function. |
| // CHECK: define {{.*}} void {{.*}}bar{{.*}}() |
| // CHECK: call void {{.*}}foo@P2{{.*}}(%class.P2* %ref.tmp, %class.P2* inreg sret %retval, i8 %0) |
| class P2 { |
| public: |
| P2 foo(P2 x); |
| }; |
| |
| P2 bar() { |
| P2 p2; |
| return P2().foo(p2); |
| } |
| |
| // Pass and return an object with a user-provided constructor (passed directly, |
| // returned indirectly) |
| // CHECK: define {{.*}} void @{{.*}}f5{{.*}}(%struct.S5* inreg noalias sret %agg.result) |
| // CHECK: call void {{.*}}func5{{.*}}(%struct.S5* inreg sret %agg.result, i64 {{.*}}) |
| struct S5 { |
| S5(); |
| int x; |
| }; |
| |
| S5 func5(S5 x); |
| S5 f5() { |
| S5 x; |
| return func5(x); |
| } |
| |
| // Pass and return an object with a non-trivial explicitly defaulted constructor |
| // (passed directly, returned directly) |
| // CHECK: define {{.*}} i64 @"?f6@@YA?AUS6@@XZ"() |
| // CHECK: call i64 {{.*}}func6{{.*}}(i64 {{.*}}) |
| struct S6a { |
| S6a(); |
| }; |
| |
| struct S6 { |
| S6() = default; |
| S6a x; |
| }; |
| |
| S6 func6(S6 x); |
| S6 f6() { |
| S6 x; |
| return func6(x); |
| } |
| |
| // Pass and return an object with a non-trivial implicitly defaulted constructor |
| // (passed directly, returned directly) |
| // CHECK: define {{.*}} i64 @"?f7@@YA?AUS7@@XZ"() |
| // CHECK: call i64 {{.*}}func7{{.*}}(i64 {{.*}}) |
| struct S7 { |
| S6a x; |
| }; |
| |
| S7 func7(S7 x); |
| S7 f7() { |
| S7 x; |
| return func7(x); |
| } |
| |
| struct S8a { |
| ~S8a(); |
| }; |
| |
| // Pass and return an object with a non-trivial default destructor (passed |
| // directly, returne indirectly) |
| struct S8 { |
| S8a x; |
| int y; |
| }; |
| |
| // CHECK: define {{.*}} void {{.*}}?f8{{.*}}(%struct.S8* inreg noalias sret {{.*}}) |
| // CHECK: call void {{.*}}func8{{.*}}(%struct.S8* inreg sret {{.*}}, i64 {{.*}}) |
| S8 func8(S8 x); |
| S8 f8() { |
| S8 x; |
| return func8(x); |
| } |
| |
| |
| // Pass and return an object with a non-trivial copy-assignment operator and |
| // a trivial copy constructor (passed directly, returned indirectly) |
| // CHECK: define {{.*}} void @"?f9@@YA?AUS9@@XZ"(%struct.S9* inreg noalias sret {{.*}}) |
| // CHECK: call void {{.*}}func9{{.*}}(%struct.S9* inreg sret {{.*}}, i64 {{.*}}) |
| struct S9 { |
| S9& operator=(const S9&); |
| int x; |
| }; |
| |
| S9 func9(S9 x); |
| S9 f9() { |
| S9 x; |
| S9 y = x; |
| x = y; |
| return func9(x); |
| } |
| |
| // Pass and return an object with a base class (passed directly, returned |
| // indirectly). |
| // CHECK: define dso_local void {{.*}}f10{{.*}}(%struct.S10* inreg noalias sret {{.*}}) |
| // CHECK: call void {{.*}}func10{{.*}}(%struct.S10* inreg sret {{.*}}, [2 x i64] {{.*}}) |
| struct S10 : public S1 { |
| int x; |
| }; |
| |
| S10 func10(S10 x); |
| S10 f10() { |
| S10 x; |
| return func10(x); |
| } |
| |
| |
| // Pass and return a non aggregate object exceeding > 128 bits (passed |
| // indirectly, returned indirectly) |
| // CHECK: define dso_local void {{.*}}f11{{.*}}(%struct.S11* inreg noalias sret {{.*}}) |
| // CHECK: call void {{.*}}func11{{.*}}(%struct.S11* inreg sret {{.*}}, %struct.S11* {{.*}}) |
| struct S11 { |
| virtual void f(); |
| int a[5]; |
| }; |
| |
| S11 func11(S11 x); |
| S11 f11() { |
| S11 x; |
| return func11(x); |
| } |