Skip to content

Commit ef4c177

Browse files
mmuetzeltstellar
authored andcommitted
[flang] Complex numbers in function arguments on Windows
Function arguments or return values that are complex floating point values aren't correctly lowered for Windows x86 32-bit and 64-bit targets. See: #61976 Add targets that are specific for these platforms and OS. With thanks to @mstorsjo for pointing out the fix. Reviewed By: vzakhari Differential Revision: https://reviews.llvm.org/D147768 (cherry picked from commit 774703e)
1 parent 840ac8c commit ef4c177

File tree

2 files changed

+362
-4
lines changed

2 files changed

+362
-4
lines changed

flang/lib/Optimizer/CodeGen/Target.cpp

Lines changed: 141 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,65 @@ struct TargetI386 : public GenericTarget<TargetI386> {
117117
};
118118
} // namespace
119119

120+
//===----------------------------------------------------------------------===//
121+
// i386 (x86 32 bit) Windows target specifics.
122+
//===----------------------------------------------------------------------===//
123+
124+
namespace {
125+
struct TargetI386Win : public GenericTarget<TargetI386Win> {
126+
using GenericTarget::GenericTarget;
127+
128+
static constexpr int defaultWidth = 32;
129+
130+
CodeGenSpecifics::Marshalling
131+
complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override {
132+
CodeGenSpecifics::Marshalling marshal;
133+
// Use a type that will be translated into LLVM as:
134+
// { t, t } struct of 2 eleTy, byval, align 4
135+
auto structTy =
136+
mlir::TupleType::get(eleTy.getContext(), mlir::TypeRange{eleTy, eleTy});
137+
marshal.emplace_back(fir::ReferenceType::get(structTy),
138+
AT{/*align=*/4, /*byval=*/true});
139+
return marshal;
140+
}
141+
142+
CodeGenSpecifics::Marshalling
143+
complexReturnType(mlir::Location loc, mlir::Type eleTy) const override {
144+
CodeGenSpecifics::Marshalling marshal;
145+
const auto *sem = &floatToSemantics(kindMap, eleTy);
146+
if (sem == &llvm::APFloat::IEEEsingle()) {
147+
// i64 pack both floats in a 64-bit GPR
148+
marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64),
149+
AT{});
150+
} else if (sem == &llvm::APFloat::IEEEdouble()) {
151+
// Use a type that will be translated into LLVM as:
152+
// { double, double } struct of 2 double, sret, align 8
153+
marshal.emplace_back(
154+
fir::ReferenceType::get(mlir::TupleType::get(
155+
eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})),
156+
AT{/*align=*/8, /*byval=*/false, /*sret=*/true});
157+
} else if (sem == &llvm::APFloat::IEEEquad()) {
158+
// Use a type that will be translated into LLVM as:
159+
// { fp128, fp128 } struct of 2 fp128, sret, align 16
160+
marshal.emplace_back(
161+
fir::ReferenceType::get(mlir::TupleType::get(
162+
eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})),
163+
AT{/*align=*/16, /*byval=*/false, /*sret=*/true});
164+
} else if (sem == &llvm::APFloat::x87DoubleExtended()) {
165+
// Use a type that will be translated into LLVM as:
166+
// { x86_fp80, x86_fp80 } struct of 2 x86_fp80, sret, align 4
167+
marshal.emplace_back(
168+
fir::ReferenceType::get(mlir::TupleType::get(
169+
eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})),
170+
AT{/*align=*/4, /*byval=*/false, /*sret=*/true});
171+
} else {
172+
TODO(loc, "complex for this precision");
173+
}
174+
return marshal;
175+
}
176+
};
177+
} // namespace
178+
120179
//===----------------------------------------------------------------------===//
121180
// x86_64 (x86 64 bit) linux target specifics.
122181
//===----------------------------------------------------------------------===//
@@ -179,6 +238,76 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
179238
};
180239
} // namespace
181240

241+
//===----------------------------------------------------------------------===//
242+
// x86_64 (x86 64 bit) Windows target specifics.
243+
//===----------------------------------------------------------------------===//
244+
245+
namespace {
246+
struct TargetX86_64Win : public GenericTarget<TargetX86_64Win> {
247+
using GenericTarget::GenericTarget;
248+
249+
static constexpr int defaultWidth = 64;
250+
251+
CodeGenSpecifics::Marshalling
252+
complexArgumentType(mlir::Location loc, mlir::Type eleTy) const override {
253+
CodeGenSpecifics::Marshalling marshal;
254+
const auto *sem = &floatToSemantics(kindMap, eleTy);
255+
if (sem == &llvm::APFloat::IEEEsingle()) {
256+
// i64 pack both floats in a 64-bit GPR
257+
marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64),
258+
AT{});
259+
} else if (sem == &llvm::APFloat::IEEEdouble()) {
260+
// Use a type that will be translated into LLVM as:
261+
// { double, double } struct of 2 double, byval, align 8
262+
marshal.emplace_back(
263+
fir::ReferenceType::get(mlir::TupleType::get(
264+
eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})),
265+
AT{/*align=*/8, /*byval=*/true});
266+
} else if (sem == &llvm::APFloat::IEEEquad() ||
267+
sem == &llvm::APFloat::x87DoubleExtended()) {
268+
// Use a type that will be translated into LLVM as:
269+
// { t, t } struct of 2 eleTy, byval, align 16
270+
marshal.emplace_back(
271+
fir::ReferenceType::get(mlir::TupleType::get(
272+
eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})),
273+
AT{/*align=*/16, /*byval=*/true});
274+
} else {
275+
TODO(loc, "complex for this precision");
276+
}
277+
return marshal;
278+
}
279+
280+
CodeGenSpecifics::Marshalling
281+
complexReturnType(mlir::Location loc, mlir::Type eleTy) const override {
282+
CodeGenSpecifics::Marshalling marshal;
283+
const auto *sem = &floatToSemantics(kindMap, eleTy);
284+
if (sem == &llvm::APFloat::IEEEsingle()) {
285+
// i64 pack both floats in a 64-bit GPR
286+
marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64),
287+
AT{});
288+
} else if (sem == &llvm::APFloat::IEEEdouble()) {
289+
// Use a type that will be translated into LLVM as:
290+
// { double, double } struct of 2 double, sret, align 8
291+
marshal.emplace_back(
292+
fir::ReferenceType::get(mlir::TupleType::get(
293+
eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})),
294+
AT{/*align=*/8, /*byval=*/false, /*sret=*/true});
295+
} else if (sem == &llvm::APFloat::IEEEquad() ||
296+
sem == &llvm::APFloat::x87DoubleExtended()) {
297+
// Use a type that will be translated into LLVM as:
298+
// { t, t } struct of 2 eleTy, sret, align 16
299+
marshal.emplace_back(
300+
fir::ReferenceType::get(mlir::TupleType::get(
301+
eleTy.getContext(), mlir::TypeRange{eleTy, eleTy})),
302+
AT{/*align=*/16, /*byval=*/false, /*sret=*/true});
303+
} else {
304+
TODO(loc, "complex for this precision");
305+
}
306+
return marshal;
307+
}
308+
};
309+
} // namespace
310+
182311
//===----------------------------------------------------------------------===//
183312
// AArch64 linux target specifics.
184313
//===----------------------------------------------------------------------===//
@@ -418,11 +547,19 @@ fir::CodeGenSpecifics::get(mlir::MLIRContext *ctx, llvm::Triple &&trp,
418547
default:
419548
break;
420549
case llvm::Triple::ArchType::x86:
421-
return std::make_unique<TargetI386>(ctx, std::move(trp),
422-
std::move(kindMap));
423-
case llvm::Triple::ArchType::x86_64:
424-
return std::make_unique<TargetX86_64>(ctx, std::move(trp),
550+
if (trp.isOSWindows())
551+
return std::make_unique<TargetI386Win>(ctx, std::move(trp),
552+
std::move(kindMap));
553+
else
554+
return std::make_unique<TargetI386>(ctx, std::move(trp),
425555
std::move(kindMap));
556+
case llvm::Triple::ArchType::x86_64:
557+
if (trp.isOSWindows())
558+
return std::make_unique<TargetX86_64Win>(ctx, std::move(trp),
559+
std::move(kindMap));
560+
else
561+
return std::make_unique<TargetX86_64>(ctx, std::move(trp),
562+
std::move(kindMap));
426563
case llvm::Triple::ArchType::aarch64:
427564
return std::make_unique<TargetAArch64>(ctx, std::move(trp),
428565
std::move(kindMap));

0 commit comments

Comments
 (0)