Skip to content

Commit 717429e

Browse files
committed
[flang] AArch64 support for BIND(C) derived return types
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 8239ea3 commit 717429e

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed

flang/lib/Optimizer/CodeGen/Target.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,48 @@ struct TargetAArch64 : public GenericTarget<TargetAArch64> {
825825
}
826826
return marshal;
827827
}
828+
829+
static bool isHFA(fir::RecordType ty) {
830+
auto types = ty.getTypeList();
831+
if (types.empty() || types.size() > 4) {
832+
return false;
833+
}
834+
835+
if (!isa_real(types.front().second)) {
836+
types.front().second.dump();
837+
return false;
838+
}
839+
840+
return llvm::all_equal(llvm::make_second_range(types));
841+
}
842+
843+
CodeGenSpecifics::Marshalling
844+
structReturnType(mlir::Location loc, fir::RecordType ty) const override {
845+
CodeGenSpecifics::Marshalling marshal;
846+
847+
if (isHFA(ty)) {
848+
auto newTy = fir::SequenceType::get({ty.getNumFields()}, ty.getType(0));
849+
marshal.emplace_back(newTy, AT{});
850+
return marshal;
851+
}
852+
853+
auto [size, align] =
854+
fir::getTypeSizeAndAlignmentOrCrash(loc, ty, getDataLayout(), kindMap);
855+
856+
// return in registers if size <= 16 bytes
857+
if (size <= 16) {
858+
auto dwordSize = (size + 7) / 8;
859+
auto newTy = fir::SequenceType::get(
860+
dwordSize, mlir::IntegerType::get(ty.getContext(), 64));
861+
marshal.emplace_back(newTy, AT{});
862+
return marshal;
863+
}
864+
865+
unsigned short stackAlign = std::max<unsigned short>(align, 8u);
866+
marshal.emplace_back(fir::ReferenceType::get(ty),
867+
AT{stackAlign, false, true});
868+
return marshal;
869+
}
828870
};
829871
} // namespace
830872

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
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.array<2xf16>
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.array<2xf16>
31+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
32+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.array<2xf16>
33+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.array<2xf16>>
34+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.array<2xf16>>) -> !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.array<4xf32>
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.array<4xf32>
50+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
51+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.array<4xf32>
52+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.array<4xf32>>
53+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.array<4xf32>>) -> !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.array<3xf64>
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.array<3xf64>
69+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
70+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.array<3xf64>
71+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.array<3xf64>>
72+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.array<3xf64>>) -> !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.array<4xf128>
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.array<4xf128>
88+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
89+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.array<4xf128>
90+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.array<4xf128>>
91+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.array<4xf128>>) -> !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.array<4xbf16>
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.array<4xbf16>
107+
// CHECK: %[[STACK:.*]] = llvm.intr.stacksave : !llvm.ptr
108+
// CHECK: %[[ARR:.*]] = fir.alloca !fir.array<4xbf16>
109+
// CHECK: fir.store %[[OUT]] to %[[ARR]] : !fir.ref<!fir.array<4xbf16>>
110+
// CHECK: %[[CVT:.*]] = fir.convert %[[ARR]] : (!fir.ref<!fir.array<4xbf16>>) -> !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+
}

0 commit comments

Comments
 (0)