Skip to content

Commit 1d57b9a

Browse files
authored
[flang] Pass one element struct by register on X86-64 (#75802)
Implement the C struct passing ABI on X86-64 for the trivial case where the structs have one element. This is required to cover some cases of BIND(C) derived type pass with the VALUE attribute.
1 parent b0ac829 commit 1d57b9a

File tree

2 files changed

+199
-1
lines changed

2 files changed

+199
-1
lines changed

flang/lib/Optimizer/CodeGen/Target.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,21 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
589589
Hi = SSE;
590590
}
591591

592+
/// When \p recTy is a one field record type that can be passed
593+
/// like the field on its own, returns the field type. Returns
594+
/// a null type otherwise.
595+
mlir::Type passAsFieldIfOneFieldStruct(fir::RecordType recTy) const {
596+
auto typeList = recTy.getTypeList();
597+
if (typeList.size() != 1)
598+
return {};
599+
mlir::Type fieldType = typeList[0].second;
600+
if (mlir::isa<mlir::FloatType, mlir::IntegerType, fir::RealType,
601+
fir::CharacterType, fir::LogicalType>(fieldType))
602+
return fieldType;
603+
// Complex field that needs to be split, or array.
604+
return {};
605+
}
606+
592607
/// Marshal a derived type passed by value like a C struct.
593608
CodeGenSpecifics::Marshalling
594609
structArgumentType(mlir::Location loc, fir::RecordType recTy,
@@ -617,7 +632,14 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
617632
if (!hasEnoughRegisters(loc, neededIntRegisters, neededSSERegisters,
618633
previousArguments))
619634
return passOnTheStack(loc, recTy);
620-
// TODO, marshal the struct into registers.
635+
636+
if (auto fieldType = passAsFieldIfOneFieldStruct(recTy)) {
637+
CodeGenSpecifics::Marshalling marshal;
638+
marshal.emplace_back(fieldType, AT{});
639+
return marshal;
640+
}
641+
// TODO, marshal the struct with several components, or with a single
642+
// complex, array, or derived type component into registers.
621643
TODO(loc, "passing BIND(C), VALUE derived type in registers on X86-64");
622644
}
623645

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
// Test X86-64 passing ABI of struct in registers for the simple case
2+
// where the struct has a single intrinsic component that is not a complex.
3+
// REQUIRES: x86-registered-target
4+
// RUN: fir-opt -target-rewrite="target=x86_64-unknown-linux-gnu" %s -o - | FileCheck %s
5+
6+
module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.target_triple = "x86_64-unknown-linux-gnu"} {
7+
8+
func.func @test_call_i16(%0 : !fir.ref<!fir.type<ti16{i:i16}>>) {
9+
%7 = fir.load %0 : !fir.ref<!fir.type<ti16{i:i16}>>
10+
fir.call @test_func_i16(%7) : (!fir.type<ti16{i:i16}>) -> ()
11+
return
12+
}
13+
// CHECK-LABEL: func.func @test_call_i16(
14+
// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<ti16{i:i16}>>) {
15+
// CHECK: %[[VAL_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.type<ti16{i:i16}>>
16+
// CHECK: %[[VAL_2:.*]] = fir.call @llvm.stacksave.p0() : () -> !fir.ref<i8>
17+
// CHECK: %[[VAL_3:.*]] = fir.alloca i16
18+
// CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i16>) -> !fir.ref<!fir.type<ti16{i:i16}>>
19+
// CHECK: fir.store %[[VAL_1]] to %[[VAL_4]] : !fir.ref<!fir.type<ti16{i:i16}>>
20+
// CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_3]] : !fir.ref<i16>
21+
// CHECK: fir.call @test_func_i16(%[[VAL_5]]) : (i16) -> ()
22+
// CHECK: fir.call @llvm.stackrestore.p0(%[[VAL_2]]) : (!fir.ref<i8>) -> ()
23+
24+
func.func private @test_func_i16(%0 : !fir.type<ti16{i:i16}>) -> () {
25+
return
26+
}
27+
// CHECK-LABEL: func.func private @test_func_i16(
28+
// CHECK-SAME: %[[VAL_0:.*]]: i16) {
29+
// CHECK: %[[VAL_1:.*]] = fir.alloca i16
30+
// CHECK: fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref<i16>
31+
// CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<i16>) -> !fir.ref<!fir.type<ti16{i:i16}>>
32+
// CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.type<ti16{i:i16}>>
33+
34+
func.func @test_call_i32(%0 : !fir.ref<!fir.type<ti32{i:i32}>>) {
35+
%7 = fir.load %0 : !fir.ref<!fir.type<ti32{i:i32}>>
36+
fir.call @test_func_i32(%7) : (!fir.type<ti32{i:i32}>) -> ()
37+
return
38+
}
39+
func.func private @test_func_i32(%0 : !fir.type<ti32{i:i32}>) -> () {
40+
return
41+
}
42+
43+
func.func @test_call_i64(%0 : !fir.ref<!fir.type<ti64{i:i64}>>) {
44+
%7 = fir.load %0 : !fir.ref<!fir.type<ti64{i:i64}>>
45+
fir.call @test_func_i64(%7) : (!fir.type<ti64{i:i64}>) -> ()
46+
return
47+
}
48+
func.func private @test_func_i64(%0 : !fir.type<ti64{i:i64}>) -> () {
49+
return
50+
}
51+
52+
func.func @test_call_i128(%0 : !fir.ref<!fir.type<ti128{i:i128}>>) {
53+
%7 = fir.load %0 : !fir.ref<!fir.type<ti128{i:i128}>>
54+
fir.call @test_func_i128(%7) : (!fir.type<ti128{i:i128}>) -> ()
55+
return
56+
}
57+
func.func private @test_func_i128(%0 : !fir.type<ti128{i:i128}>) -> () {
58+
return
59+
}
60+
func.func @test_call_f16(%0 : !fir.ref<!fir.type<tf16{i:f16}>>) {
61+
%7 = fir.load %0 : !fir.ref<!fir.type<tf16{i:f16}>>
62+
fir.call @test_func_f16(%7) : (!fir.type<tf16{i:f16}>) -> ()
63+
return
64+
}
65+
func.func private @test_func_f16(%0 : !fir.type<tf16{i:f16}>) -> () {
66+
return
67+
}
68+
69+
func.func @test_call_f32(%0 : !fir.ref<!fir.type<tf32{i:f32}>>) {
70+
%7 = fir.load %0 : !fir.ref<!fir.type<tf32{i:f32}>>
71+
fir.call @test_func_f32(%7) : (!fir.type<tf32{i:f32}>) -> ()
72+
return
73+
}
74+
func.func private @test_func_f32(%0 : !fir.type<tf32{i:f32}>) -> () {
75+
return
76+
}
77+
78+
func.func @test_call_f64(%0 : !fir.ref<!fir.type<tf64{i:f64}>>) {
79+
%7 = fir.load %0 : !fir.ref<!fir.type<tf64{i:f64}>>
80+
fir.call @test_func_f64(%7) : (!fir.type<tf64{i:f64}>) -> ()
81+
return
82+
}
83+
func.func private @test_func_f64(%0 : !fir.type<tf64{i:f64}>) -> () {
84+
return
85+
}
86+
87+
func.func @test_call_f128(%0 : !fir.ref<!fir.type<tf128{i:f128}>>) {
88+
%7 = fir.load %0 : !fir.ref<!fir.type<tf128{i:f128}>>
89+
fir.call @test_func_f128(%7) : (!fir.type<tf128{i:f128}>) -> ()
90+
return
91+
}
92+
func.func private @test_func_f128(%0 : !fir.type<tf128{i:f128}>) -> () {
93+
return
94+
}
95+
96+
func.func @test_call_char1(%0 : !fir.ref<!fir.type<tchar1{i:!fir.char<1>}>>) {
97+
%7 = fir.load %0 : !fir.ref<!fir.type<tchar1{i:!fir.char<1>}>>
98+
fir.call @test_func_char1(%7) : (!fir.type<tchar1{i:!fir.char<1>}>) -> ()
99+
return
100+
}
101+
func.func private @test_func_char1(%0 : !fir.type<tchar1{i:!fir.char<1>}>) -> () {
102+
return
103+
}
104+
105+
func.func @test_call_log1(%0 : !fir.ref<!fir.type<tlog1{i:!fir.logical<1>}>>) {
106+
%7 = fir.load %0 : !fir.ref<!fir.type<tlog1{i:!fir.logical<1>}>>
107+
fir.call @test_func_log1(%7) : (!fir.type<tlog1{i:!fir.logical<1>}>) -> ()
108+
return
109+
}
110+
func.func private @test_func_log1(%0 : !fir.type<tlog1{i:!fir.logical<1>}>) -> () {
111+
return
112+
}
113+
114+
func.func @test_call_log2(%0 : !fir.ref<!fir.type<tlog2{i:!fir.logical<2>}>>) {
115+
%7 = fir.load %0 : !fir.ref<!fir.type<tlog2{i:!fir.logical<2>}>>
116+
fir.call @test_func_log2(%7) : (!fir.type<tlog2{i:!fir.logical<2>}>) -> ()
117+
return
118+
}
119+
func.func private @test_func_log2(%0 : !fir.type<tlog2{i:!fir.logical<2>}>) -> () {
120+
return
121+
}
122+
123+
func.func @test_call_log4(%0 : !fir.ref<!fir.type<tlog4{i:!fir.logical<4>}>>) {
124+
%7 = fir.load %0 : !fir.ref<!fir.type<tlog4{i:!fir.logical<4>}>>
125+
fir.call @test_func_log4(%7) : (!fir.type<tlog4{i:!fir.logical<4>}>) -> ()
126+
return
127+
}
128+
func.func private @test_func_log4(%0 : !fir.type<tlog4{i:!fir.logical<4>}>) -> () {
129+
return
130+
}
131+
132+
func.func @test_call_log8(%0 : !fir.ref<!fir.type<tlog8{i:!fir.logical<8>}>>) {
133+
%7 = fir.load %0 : !fir.ref<!fir.type<tlog8{i:!fir.logical<8>}>>
134+
fir.call @test_func_log8(%7) : (!fir.type<tlog8{i:!fir.logical<8>}>) -> ()
135+
return
136+
}
137+
func.func private @test_func_log8(%0 : !fir.type<tlog8{i:!fir.logical<8>}>) -> () {
138+
return
139+
}
140+
141+
func.func @test_call_log16(%0 : !fir.ref<!fir.type<tlog16{i:!fir.logical<16>}>>) {
142+
%7 = fir.load %0 : !fir.ref<!fir.type<tlog16{i:!fir.logical<16>}>>
143+
fir.call @test_func_log16(%7) : (!fir.type<tlog16{i:!fir.logical<16>}>) -> ()
144+
return
145+
}
146+
func.func private @test_func_log16(%0 : !fir.type<tlog16{i:!fir.logical<16>}>) -> () {
147+
return
148+
}
149+
}
150+
151+
// CHECK-LABEL: func.func private @test_func_i32(
152+
// CHECK-SAME: %[[VAL_0:.*]]: i32) {
153+
// CHECK-LABEL: func.func private @test_func_i64(
154+
// CHECK-SAME: %[[VAL_0:.*]]: i64) {
155+
// CHECK-LABEL: func.func private @test_func_i128(
156+
// CHECK-SAME: %[[VAL_0:.*]]: i128) {
157+
// CHECK-LABEL: func.func private @test_func_f16(
158+
// CHECK-SAME: %[[VAL_0:.*]]: f16) {
159+
// CHECK-LABEL: func.func private @test_func_f32(
160+
// CHECK-SAME: %[[VAL_0:.*]]: f32) {
161+
// CHECK-LABEL: func.func private @test_func_f64(
162+
// CHECK-SAME: %[[VAL_0:.*]]: f64) {
163+
// CHECK-LABEL: func.func private @test_func_f128(
164+
// CHECK-SAME: %[[VAL_0:.*]]: f128) {
165+
// CHECK-LABEL: func.func private @test_func_char1(
166+
// CHECK-SAME: %[[VAL_0:.*]]: !fir.char<1>) {
167+
// CHECK-LABEL: func.func private @test_func_log1(
168+
// CHECK-SAME: %[[VAL_0:.*]]: !fir.logical<1>) {
169+
// CHECK-LABEL: func.func private @test_func_log2(
170+
// CHECK-SAME: %[[VAL_0:.*]]: !fir.logical<2>) {
171+
// CHECK-LABEL: func.func private @test_func_log4(
172+
// CHECK-SAME: %[[VAL_0:.*]]: !fir.logical<4>) {
173+
// CHECK-LABEL: func.func private @test_func_log8(
174+
// CHECK-SAME: %[[VAL_0:.*]]: !fir.logical<8>) {
175+
// CHECK-LABEL: func.func private @test_func_log16(
176+
// CHECK-SAME: %[[VAL_0:.*]]: !fir.logical<16>) {

0 commit comments

Comments
 (0)