1 | // RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=PPC |
2 | // RUN: %clang_cc1 -mfloat-abi hard -triple armv7-unknown-linux-gnueabi -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM32 |
3 | // RUN: %clang_cc1 -mfloat-abi hard -triple aarch64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM64 |
4 | // RUN: %clang_cc1 -mfloat-abi hard -triple x86_64-unknown-windows-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=X64 |
5 | |
6 | #if defined(__x86_64__) |
7 | #define CC __attribute__((vectorcall)) |
8 | #else |
9 | #define CC |
10 | #endif |
11 | |
12 | // Test that C++ classes are correctly classified as homogeneous aggregates. |
13 | |
14 | struct Base1 { |
15 | int x; |
16 | }; |
17 | struct Base2 { |
18 | double x; |
19 | }; |
20 | struct Base3 { |
21 | double x; |
22 | }; |
23 | struct D1 : Base1 { // non-homogeneous aggregate |
24 | double y, z; |
25 | }; |
26 | struct D2 : Base2 { // homogeneous aggregate |
27 | double y, z; |
28 | }; |
29 | struct D3 : Base1, Base2 { // non-homogeneous aggregate |
30 | double y, z; |
31 | }; |
32 | struct D4 : Base2, Base3 { // homogeneous aggregate |
33 | double y, z; |
34 | }; |
35 | |
36 | struct I1 : Base2 {}; |
37 | struct I2 : Base2 {}; |
38 | struct I3 : Base2 {}; |
39 | struct D5 : I1, I2, I3 {}; // homogeneous aggregate |
40 | |
41 | // PPC: define void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, [3 x i64] %x.coerce) |
42 | // ARM32: define arm_aapcs_vfpcc void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, [3 x i64] %x.coerce) |
43 | // ARM64: define void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, %struct.D1* %x) |
44 | // X64: define dso_local x86_vectorcallcc void @"\01_Z7func_D12D1@@24"(%struct.D1* noalias sret %agg.result, %struct.D1* %x) |
45 | D1 CC func_D1(D1 x) { return x; } |
46 | |
47 | // PPC: define [3 x double] @_Z7func_D22D2([3 x double] %x.coerce) |
48 | // ARM32: define arm_aapcs_vfpcc %struct.D2 @_Z7func_D22D2(%struct.D2 %x.coerce) |
49 | // ARM64: define %struct.D2 @_Z7func_D22D2([3 x double] %x.coerce) |
50 | // X64: define dso_local x86_vectorcallcc %struct.D2 @"\01_Z7func_D22D2@@24"(%struct.D2 inreg %x.coerce) |
51 | D2 CC func_D2(D2 x) { return x; } |
52 | |
53 | // PPC: define void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, [4 x i64] %x.coerce) |
54 | // ARM32: define arm_aapcs_vfpcc void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, [4 x i64] %x.coerce) |
55 | // ARM64: define void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, %struct.D3* %x) |
56 | D3 CC func_D3(D3 x) { return x; } |
57 | |
58 | // PPC: define [4 x double] @_Z7func_D42D4([4 x double] %x.coerce) |
59 | // ARM32: define arm_aapcs_vfpcc %struct.D4 @_Z7func_D42D4(%struct.D4 %x.coerce) |
60 | // ARM64: define %struct.D4 @_Z7func_D42D4([4 x double] %x.coerce) |
61 | D4 CC func_D4(D4 x) { return x; } |
62 | |
63 | D5 CC func_D5(D5 x) { return x; } |
64 | // PPC: define [3 x double] @_Z7func_D52D5([3 x double] %x.coerce) |
65 | // ARM32: define arm_aapcs_vfpcc %struct.D5 @_Z7func_D52D5(%struct.D5 %x.coerce) |
66 | |
67 | // The C++ multiple inheritance expansion case is a little more complicated, so |
68 | // do some extra checking. |
69 | // |
70 | // ARM64-LABEL: define %struct.D5 @_Z7func_D52D5([3 x double] %x.coerce) |
71 | // ARM64: bitcast %struct.D5* %{{.*}} to [3 x double]* |
72 | // ARM64: store [3 x double] %x.coerce, [3 x double]* |
73 | |
74 | void call_D5(D5 *p) { |
75 | func_D5(*p); |
76 | } |
77 | |
78 | // Check the call site. |
79 | // |
80 | // ARM64-LABEL: define void @_Z7call_D5P2D5(%struct.D5* %p) |
81 | // ARM64: load [3 x double], [3 x double]* |
82 | // ARM64: call %struct.D5 @_Z7func_D52D5([3 x double] %{{.*}}) |
83 | |
84 | struct Empty { }; |
85 | struct Float1 { float x; }; |
86 | struct Float2 { float y; }; |
87 | struct HVAWithEmptyBase : Float1, Empty, Float2 { float z; }; |
88 | |
89 | // PPC: define void @_Z15with_empty_base16HVAWithEmptyBase([3 x float] %a.coerce) |
90 | // ARM64: define void @_Z15with_empty_base16HVAWithEmptyBase([3 x float] %a.coerce) |
91 | // ARM32: define arm_aapcs_vfpcc void @_Z15with_empty_base16HVAWithEmptyBase(%struct.HVAWithEmptyBase %a.coerce) |
92 | void CC with_empty_base(HVAWithEmptyBase a) {} |
93 | |
94 | // FIXME: MSVC doesn't consider this an HVA because of the empty base. |
95 | // X64: define dso_local x86_vectorcallcc void @"\01_Z15with_empty_base16HVAWithEmptyBase@@16"(%struct.HVAWithEmptyBase inreg %a.coerce) |
96 | |
97 | struct HVAWithEmptyBitField : Float1, Float2 { |
98 | int : 0; // Takes no space. |
99 | float z; |
100 | }; |
101 | |
102 | // PPC: define void @_Z19with_empty_bitfield20HVAWithEmptyBitField([3 x float] %a.coerce) |
103 | // ARM64: define void @_Z19with_empty_bitfield20HVAWithEmptyBitField([3 x float] %a.coerce) |
104 | // ARM32: define arm_aapcs_vfpcc void @_Z19with_empty_bitfield20HVAWithEmptyBitField(%struct.HVAWithEmptyBitField %a.coerce) |
105 | // X64: define dso_local x86_vectorcallcc void @"\01_Z19with_empty_bitfield20HVAWithEmptyBitField@@16"(%struct.HVAWithEmptyBitField inreg %a.coerce) |
106 | void CC with_empty_bitfield(HVAWithEmptyBitField a) {} |
107 | |