Skip to content

Commit 2d62daa

Browse files
authored
[flang] AArch64 support for BIND(C) derived return types (#114051)
This patch adds support for BIND(C) derived types as return values matching the AArch64 Procedure Call Standard for C. Support for BIND(C) derived types as value parameters will be in a separate patch.
1 parent 6f16a8b commit 2d62daa

File tree

2 files changed

+320
-0
lines changed

2 files changed

+320
-0
lines changed

flang/lib/Optimizer/CodeGen/Target.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,97 @@ struct TargetAArch64 : public GenericTarget<TargetAArch64> {
825825
}
826826
return marshal;
827827
}
828+
829+
// Flatten a RecordType::TypeList containing more record types or array types
830+
static std::optional<std::vector<mlir::Type>>
831+
flattenTypeList(const RecordType::TypeList &types) {
832+
std::vector<mlir::Type> flatTypes;
833+
// The flat list will be at least the same size as the non-flat list.
834+
flatTypes.reserve(types.size());
835+
for (auto [c, type] : types) {
836+
// Flatten record type
837+
if (auto recTy = mlir::dyn_cast<RecordType>(type)) {
838+
auto subTypeList = flattenTypeList(recTy.getTypeList());
839+
if (!subTypeList)
840+
return std::nullopt;
841+
llvm::copy(*subTypeList, std::back_inserter(flatTypes));
842+
continue;
843+
}
844+
845+
// Flatten array type
846+
if (auto seqTy = mlir::dyn_cast<SequenceType>(type)) {
847+
if (seqTy.hasDynamicExtents())
848+
return std::nullopt;
849+
std::size_t n = seqTy.getConstantArraySize();
850+
auto eleTy = seqTy.getElementType();
851+
// Flatten array of record types
852+
if (auto recTy = mlir::dyn_cast<RecordType>(eleTy)) {
853+
auto subTypeList = flattenTypeList(recTy.getTypeList());
854+
if (!subTypeList)
855+
return std::nullopt;
856+
for (std::size_t i = 0; i < n; ++i)
857+
llvm::copy(*subTypeList, std::back_inserter(flatTypes));
858+
} else {
859+
std::fill_n(std::back_inserter(flatTypes),
860+
seqTy.getConstantArraySize(), eleTy);
861+
}
862+
continue;
863+
}
864+
865+
// Other types are already flat
866+
flatTypes.push_back(type);
867+
}
868+
return flatTypes;
869+
}
870+
871+
// Determine if the type is a Homogenous Floating-point Aggregate (HFA). An
872+
// HFA is a record type with up to 4 floating-point members of the same type.
873+
static bool isHFA(fir::RecordType ty) {
874+
RecordType::TypeList types = ty.getTypeList();
875+
if (types.empty() || types.size() > 4)
876+
return false;
877+
878+
std::optional<std::vector<mlir::Type>> flatTypes = flattenTypeList(types);
879+
if (!flatTypes || flatTypes->size() > 4) {
880+
return false;
881+
}
882+
883+
if (!isa_real(flatTypes->front())) {
884+
return false;
885+
}
886+
887+
return llvm::all_equal(*flatTypes);
888+
}
889+
890+
// AArch64 procedure call ABI:
891+
// https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#parameter-passing
892+
CodeGenSpecifics::Marshalling
893+
structReturnType(mlir::Location loc, fir::RecordType ty) const override {
894+
CodeGenSpecifics::Marshalling marshal;
895+
896+
if (isHFA(ty)) {
897+
// Just return the existing record type
898+
marshal.emplace_back(ty, AT{});
899+
return marshal;
900+
}
901+
902+
auto [size, align] =
903+
fir::getTypeSizeAndAlignmentOrCrash(loc, ty, getDataLayout(), kindMap);
904+
905+
// return in registers if size <= 16 bytes
906+
if (size <= 16) {
907+
std::size_t dwordSize = (size + 7) / 8;
908+
auto newTy = fir::SequenceType::get(
909+
dwordSize, mlir::IntegerType::get(ty.getContext(), 64));
910+
marshal.emplace_back(newTy, AT{});
911+
return marshal;
912+
}
913+
914+
unsigned short stackAlign = std::max<unsigned short>(align, 8u);
915+
marshal.emplace_back(fir::ReferenceType::get(ty),
916+
AT{stackAlign, false, true});
917+
return marshal;
918+
}
828919
};
829920
} // namespace
830921

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
// Test AArch64 ABI rewrite of struct returned by value (BIND(C), VALUE derived types).
2+
// RUN: fir-opt --target-rewrite="target=aarch64-unknown-linux-gnu" %s | FileCheck %s
3+
4+
!composite = !fir.type<t1{i:f32,j:i32,k:f32}>
5+
// CHECK-LABEL: func.func private @test_composite() -> !fir.array<2xi64>
6+
func.func private @test_composite() -> !composite
7+
// CHECK-LABEL: func.func @test_call_composite(
8+
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>)
9+
func.func @test_call_composite(%arg0 : !fir.ref<!composite>) {
10+
// CHECK: %[[OUT:.*]] = fir.call @test_composite() : () -> !fir.array<2xi64>
11+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
12+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.array<2xi64>
13+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.array<2xi64>>
14+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.array<2xi64>>) -> !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>
15+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>
16+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
17+
%out = fir.call @test_composite() : () -> !composite
18+
// CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>
19+
fir.store %out to %arg0 : !fir.ref<!composite>
20+
// CHECK: return
21+
return
22+
}
23+
24+
!hfa_f16 = !fir.type<t2{x:f16, y:f16}>
25+
// CHECK-LABEL: func.func private @test_hfa_f16() -> !fir.type<t2{x:f16,y:f16}>
26+
func.func private @test_hfa_f16() -> !hfa_f16
27+
// CHECK-LABEL: func.func @test_call_hfa_f16(
28+
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.type<t2{x:f16,y:f16}>>) {
29+
func.func @test_call_hfa_f16(%arg0 : !fir.ref<!hfa_f16>) {
30+
// CHECK: %[[OUT:.*]] = fir.call @test_hfa_f16() : () -> !fir.type<t2{x:f16,y:f16}>
31+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
32+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.type<t2{x:f16,y:f16}>
33+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.type<t2{x:f16,y:f16}>>
34+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.type<t2{x:f16,y:f16}>>) -> !fir.ref<!fir.type<t2{x:f16,y:f16}>>
35+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t2{x:f16,y:f16}>>
36+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
37+
%out = fir.call @test_hfa_f16() : () -> !hfa_f16
38+
// CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t2{x:f16,y:f16}>>
39+
fir.store %out to %arg0 : !fir.ref<!hfa_f16>
40+
return
41+
}
42+
43+
!hfa_f32 = !fir.type<t3{w:f32, x:f32, y:f32, z:f32}>
44+
// CHECK-LABEL: func.func private @test_hfa_f32() -> !fir.type<t3{w:f32,x:f32,y:f32,z:f32}>
45+
func.func private @test_hfa_f32() -> !hfa_f32
46+
// CHECK-LABEL: func.func @test_call_hfa_f32(
47+
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.type<t3{w:f32,x:f32,y:f32,z:f32}>>) {
48+
func.func @test_call_hfa_f32(%arg0 : !fir.ref<!hfa_f32>) {
49+
// CHECK: %[[OUT:.*]] = fir.call @test_hfa_f32() : () -> !fir.type<t3{w:f32,x:f32,y:f32,z:f32}>
50+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
51+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.type<t3{w:f32,x:f32,y:f32,z:f32}>
52+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.type<t3{w:f32,x:f32,y:f32,z:f32}>>
53+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.type<t3{w:f32,x:f32,y:f32,z:f32}>>) -> !fir.ref<!fir.type<t3{w:f32,x:f32,y:f32,z:f32}>>
54+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t3{w:f32,x:f32,y:f32,z:f32}>>
55+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
56+
%out = fir.call @test_hfa_f32() : () -> !hfa_f32
57+
// CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t3{w:f32,x:f32,y:f32,z:f32}>>
58+
fir.store %out to %arg0 : !fir.ref<!hfa_f32>
59+
return
60+
}
61+
62+
!hfa_f64 = !fir.type<t4{x:f64, y:f64, z:f64}>
63+
// CHECK-LABEL: func.func private @test_hfa_f64() -> !fir.type<t4{x:f64,y:f64,z:f64}>
64+
func.func private @test_hfa_f64() -> !hfa_f64
65+
// CHECK-LABEL: func.func @test_call_hfa_f64(
66+
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.type<t4{x:f64,y:f64,z:f64}>>)
67+
func.func @test_call_hfa_f64(%arg0 : !fir.ref<!hfa_f64>) {
68+
// CHECK: %[[OUT:.*]] = fir.call @test_hfa_f64() : () -> !fir.type<t4{x:f64,y:f64,z:f64}>
69+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
70+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.type<t4{x:f64,y:f64,z:f64}>
71+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.type<t4{x:f64,y:f64,z:f64}>>
72+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.type<t4{x:f64,y:f64,z:f64}>>) -> !fir.ref<!fir.type<t4{x:f64,y:f64,z:f64}>>
73+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t4{x:f64,y:f64,z:f64}>>
74+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
75+
%out = fir.call @test_hfa_f64() : () -> !hfa_f64
76+
// CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t4{x:f64,y:f64,z:f64}>>
77+
fir.store %out to %arg0 : !fir.ref<!hfa_f64>
78+
return
79+
}
80+
81+
!hfa_f128 = !fir.type<t5{w:f128, x:f128, y:f128, z:f128}>
82+
// CHECK-LABEL: func.func private @test_hfa_f128() -> !fir.type<t5{w:f128,x:f128,y:f128,z:f128}>
83+
func.func private @test_hfa_f128() -> !hfa_f128
84+
// CHECK-LABEL: func.func @test_call_hfa_f128(
85+
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.type<t5{w:f128,x:f128,y:f128,z:f128}>>) {
86+
func.func @test_call_hfa_f128(%arg0 : !fir.ref<!hfa_f128>) {
87+
// CHECK: %[[OUT:.*]] = fir.call @test_hfa_f128() : () -> !fir.type<t5{w:f128,x:f128,y:f128,z:f128}>
88+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
89+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.type<t5{w:f128,x:f128,y:f128,z:f128}>
90+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.type<t5{w:f128,x:f128,y:f128,z:f128}>>
91+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.type<t5{w:f128,x:f128,y:f128,z:f128}>>) -> !fir.ref<!fir.type<t5{w:f128,x:f128,y:f128,z:f128}>>
92+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t5{w:f128,x:f128,y:f128,z:f128}>>
93+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
94+
%out = fir.call @test_hfa_f128() : () -> !hfa_f128
95+
// CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t5{w:f128,x:f128,y:f128,z:f128}>>
96+
fir.store %out to %arg0 : !fir.ref<!hfa_f128>
97+
return
98+
}
99+
100+
!hfa_bf16 = !fir.type<t6{w:bf16, x:bf16, y:bf16, z:bf16}>
101+
// CHECK-LABEL: func.func private @test_hfa_bf16() -> !fir.type<t6{w:bf16,x:bf16,y:bf16,z:bf16}>
102+
func.func private @test_hfa_bf16() -> !hfa_bf16
103+
// CHECK-LABEL: func.func @test_call_hfa_bf16(
104+
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.type<t6{w:bf16,x:bf16,y:bf16,z:bf16}>>) {
105+
func.func @test_call_hfa_bf16(%arg0 : !fir.ref<!hfa_bf16>) {
106+
// CHECK: %[[OUT:.*]] = fir.call @test_hfa_bf16() : () -> !fir.type<t6{w:bf16,x:bf16,y:bf16,z:bf16}>
107+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
108+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.type<t6{w:bf16,x:bf16,y:bf16,z:bf16}>
109+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.type<t6{w:bf16,x:bf16,y:bf16,z:bf16}>>
110+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.type<t6{w:bf16,x:bf16,y:bf16,z:bf16}>>) -> !fir.ref<!fir.type<t6{w:bf16,x:bf16,y:bf16,z:bf16}>>
111+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t6{w:bf16,x:bf16,y:bf16,z:bf16}>>
112+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
113+
%out = fir.call @test_hfa_bf16() : () -> !hfa_bf16
114+
// CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t6{w:bf16,x:bf16,y:bf16,z:bf16}>>
115+
fir.store %out to %arg0 : !fir.ref<!hfa_bf16>
116+
return
117+
}
118+
119+
!too_big = !fir.type<t7{x:i64, y:i64, z:i64}>
120+
// CHECK-LABEL: func.func private @test_too_big(!fir.ref<!fir.type<t7{x:i64,y:i64,z:i64}>>
121+
// CHECK-SAME: {llvm.align = 8 : i32, llvm.sret = !fir.type<t7{x:i64,y:i64,z:i64}>})
122+
func.func private @test_too_big() -> !too_big
123+
// CHECK-LABEL: func.func @test_call_too_big(
124+
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.type<t7{x:i64,y:i64,z:i64}>>) {
125+
func.func @test_call_too_big(%arg0 : !fir.ref<!too_big>) {
126+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
127+
// CHECK: %[[ARG:.*]] = fir.alloca !fir.type<t7{x:i64,y:i64,z:i64}>
128+
// CHECK: fir.call @test_too_big(%[[ARG]]) : (!fir.ref<!fir.type<t7{x:i64,y:i64,z:i64}>>) -> ()
129+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref<!fir.type<t7{x:i64,y:i64,z:i64}>>) -> !fir.ref<!fir.type<t7{x:i64,y:i64,z:i64}>>
130+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t7{x:i64,y:i64,z:i64}>>
131+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
132+
%out = fir.call @test_too_big() : () -> !too_big
133+
// CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t7{x:i64,y:i64,z:i64}>>
134+
fir.store %out to %arg0 : !fir.ref<!too_big>
135+
return
136+
}
137+
138+
139+
!too_big_hfa = !fir.type<t8{i:!fir.array<5xf32>}>
140+
// CHECK-LABEL: func.func private @test_too_big_hfa(!fir.ref<!fir.type<t8{i:!fir.array<5xf32>}>>
141+
// CHECK-SAME: {llvm.align = 8 : i32, llvm.sret = !fir.type<t8{i:!fir.array<5xf32>}>})
142+
func.func private @test_too_big_hfa() -> !too_big_hfa
143+
// CHECK-LABEL: func.func @test_call_too_big_hfa(
144+
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.type<t8{i:!fir.array<5xf32>}>>) {
145+
func.func @test_call_too_big_hfa(%arg0 : !fir.ref<!too_big_hfa>) {
146+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
147+
// CHECK: %[[ARG:.*]] = fir.alloca !fir.type<t8{i:!fir.array<5xf32>}>
148+
// CHECK: fir.call @test_too_big_hfa(%[[ARG]]) : (!fir.ref<!fir.type<t8{i:!fir.array<5xf32>}>>) -> ()
149+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARG]] : (!fir.ref<!fir.type<t8{i:!fir.array<5xf32>}>>) -> !fir.ref<!fir.type<t8{i:!fir.array<5xf32>}>>
150+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t8{i:!fir.array<5xf32>}>>
151+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
152+
%out = fir.call @test_too_big_hfa() : () -> !too_big_hfa
153+
// CHECK: fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t8{i:!fir.array<5xf32>}>>
154+
fir.store %out to %arg0 : !fir.ref<!too_big_hfa>
155+
return
156+
}
157+
158+
!nested_hfa_first = !fir.type<t9{s:!hfa_f16,c:f16}>
159+
// CHECK-LABEL: func.func private @test_nested_hfa_first() -> !fir.type<t9{s:!fir.type<t2{x:f16,y:f16}>,c:f16}>
160+
func.func private @test_nested_hfa_first() -> !nested_hfa_first
161+
// CHECK-LABEL: func.func @test_call_nested_hfa_first(%arg0: !fir.ref<!fir.type<t9{s:!fir.type<t2{x:f16,y:f16}>,c:f16}>>) {
162+
func.func @test_call_nested_hfa_first(%arg0 : !fir.ref<!nested_hfa_first>) {
163+
%out = fir.call @test_nested_hfa_first() : () -> !nested_hfa_first
164+
// CHECK: %[[OUT:.*]] = fir.call @test_nested_hfa_first() : () -> !fir.type<t9{s:!fir.type<t2{x:f16,y:f16}>,c:f16}>
165+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
166+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.type<t9{s:!fir.type<t2{x:f16,y:f16}>,c:f16}>
167+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.type<t9{s:!fir.type<t2{x:f16,y:f16}>,c:f16}>>
168+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.type<t9{s:!fir.type<t2{x:f16,y:f16}>,c:f16}>>
169+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t9{s:!fir.type<t2{x:f16,y:f16}>,c:f16}>>
170+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
171+
fir.store %out to %arg0 : !fir.ref<!nested_hfa_first>
172+
// CHECK fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t9{s:!fir.type<t2{x:f16,y:f16}>,c:f16}>>
173+
return
174+
}
175+
176+
177+
!nested_hfa_middle = !fir.type<t10{a:f16,s:!hfa_f16,c:f16}>
178+
// CHECK-LABEL: func.func private @test_nested_hfa_middle() -> !fir.type<t10{a:f16,s:!fir.type<t2{x:f16,y:f16}>,c:f16}>
179+
func.func private @test_nested_hfa_middle() -> !nested_hfa_middle
180+
// CHECK-LABEL: func.func @test_call_nested_hfa_middle(%arg0: !fir.ref<!fir.type<t10{a:f16,s:!fir.type<t2{x:f16,y:f16}>,c:f16}>>) {
181+
func.func @test_call_nested_hfa_middle(%arg0 : !fir.ref<!nested_hfa_middle>) {
182+
%out = fir.call @test_nested_hfa_middle() : () -> !nested_hfa_middle
183+
// CHECK: %[[OUT:.*]] = fir.call @test_nested_hfa_middle() : () -> !fir.type<t10{a:f16,s:!fir.type<t2{x:f16,y:f16}>,c:f16}>
184+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
185+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.type<t10{a:f16,s:!fir.type<t2{x:f16,y:f16}>,c:f16}>
186+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.type<t10{a:f16,s:!fir.type<t2{x:f16,y:f16}>,c:f16}>>
187+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.type<t10{a:f16,s:!fir.type<t2{x:f16,y:f16}>,c:f16}>>
188+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t10{a:f16,s:!fir.type<t2{x:f16,y:f16}>,c:f16}>>
189+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
190+
fir.store %out to %arg0 : !fir.ref<!nested_hfa_middle>
191+
// CHECK fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t10{a:f16,s:!fir.type<t2{x:f16,y:f16}>,c:f16}>>
192+
return
193+
}
194+
195+
!nested_hfa_end = !fir.type<t11{a:f16,s:!hfa_f16}>
196+
// CHECK-LABEL: func.func private @test_nested_hfa_end() -> !fir.type<t11{a:f16,s:!fir.type<t2{x:f16,y:f16}>}>
197+
func.func private @test_nested_hfa_end() -> !nested_hfa_end
198+
// CHECK-LABEL: func.func @test_call_nested_hfa_end(%arg0: !fir.ref<!fir.type<t11{a:f16,s:!fir.type<t2{x:f16,y:f16}>}>>) {
199+
func.func @test_call_nested_hfa_end(%arg0 : !fir.ref<!nested_hfa_end>) {
200+
%out = fir.call @test_nested_hfa_end() : () -> !nested_hfa_end
201+
// CHECK: %[[OUT:.*]] = fir.call @test_nested_hfa_end() : () -> !fir.type<t11{a:f16,s:!fir.type<t2{x:f16,y:f16}>}>
202+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
203+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.type<t11{a:f16,s:!fir.type<t2{x:f16,y:f16}>}>
204+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.type<t11{a:f16,s:!fir.type<t2{x:f16,y:f16}>}>>
205+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.type<t11{a:f16,s:!fir.type<t2{x:f16,y:f16}>}>>
206+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t11{a:f16,s:!fir.type<t2{x:f16,y:f16}>}>>
207+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
208+
fir.store %out to %arg0 : !fir.ref<!nested_hfa_end>
209+
// CHECK fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t11{a:f16,s:!fir.type<t2{x:f16,y:f16}>}>>
210+
return
211+
}
212+
213+
!nested_hfa_array = !fir.type<t12{a:!fir.array<2xf32>,b:f32}>
214+
// CHECK-LABEL: func.func private @test_nested_hfa_array() -> !fir.type<t12{a:!fir.array<2xf32>,b:f32}>
215+
func.func private @test_nested_hfa_array() -> !nested_hfa_array
216+
// CHECK-LABEL: func.func @test_call_nested_hfa_array(%arg0: !fir.ref<!fir.type<t12{a:!fir.array<2xf32>,b:f32}>
217+
func.func @test_call_nested_hfa_array(%arg0 : !fir.ref<!nested_hfa_array>) {
218+
%out = fir.call @test_nested_hfa_array() : () -> !nested_hfa_array
219+
// CHECK: %[[OUT:.*]] = fir.call @test_nested_hfa_array() : () -> !fir.type<t12{a:!fir.array<2xf32>,b:f32}>
220+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
221+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.type<t12{a:!fir.array<2xf32>,b:f32}>
222+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.type<t12{a:!fir.array<2xf32>,b:f32}>
223+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.type<t12{a:!fir.array<2xf32>,b:f32}>
224+
// CHECK: %[[LD:.*]] = fir.load %[[CVT]] : !fir.ref<!fir.type<t12{a:!fir.array<2xf32>,b:f32}>
225+
// CHECK: llvm.intr.stackrestore %[[STACK]] : !llvm.ptr
226+
fir.store %out to %arg0 : !fir.ref<!nested_hfa_array>
227+
// CHECK fir.store %[[LD]] to %[[ARG0]] : !fir.ref<!fir.type<t12{a:!fir.array<2xf32>,b:f32}>
228+
return
229+
}

0 commit comments

Comments
 (0)