forked from OSchip/llvm-project
[fir] TargetRewrite: Rewrite COMPLEX values
Rewrite function signatures and calls to functions that accept or return COMPLEX values. Also teach insert_value and extract_value about the MLIR ComplexType, by adding AnyComplex to AnyCompositeLike. This patch is part of the effort for upstreaming the fir-dev branch. Differential Revision: https://reviews.llvm.org/D113273 Co-authored-by: Eric Schweitz <eschweitz@nvidia.com> Co-authored-by: Kiran Chandramohan <kiran.chandramohan@arm.com> Co-authored-by: Tim Keith <tkeith@nvidia.com> Co-authored-by: Jean Perier <jperier@nvidia.com>
This commit is contained in:
parent
5c3c7adf3a
commit
65431d3aeb
|
@ -54,7 +54,10 @@ def TargetRewrite : Pass<"target-rewrite", "mlir::ModuleOp"> {
|
|||
"Override module's target triple.">,
|
||||
Option<"noCharacterConversion", "no-character-conversion",
|
||||
"bool", /*default=*/"false",
|
||||
"Disable target-specific conversion of CHARACTER.">
|
||||
"Disable target-specific conversion of CHARACTER.">,
|
||||
Option<"noComplexConversion", "no-complex-conversion",
|
||||
"bool", /*default=*/"false",
|
||||
"Disable target-specific conversion of COMPLEX.">
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ std::unique_ptr<mlir::Pass> createFirCodeGenRewritePass();
|
|||
// FirTargetRewritePass options.
|
||||
struct TargetRewriteOptions {
|
||||
bool noCharacterConversion{};
|
||||
bool noComplexConversion{};
|
||||
};
|
||||
|
||||
/// Prerequiste pass for code gen. Perform intermediate rewrites to tailor the
|
||||
|
|
|
@ -506,8 +506,11 @@ def AnyRealLike : TypeConstraint<Or<[FloatLike.predicate,
|
|||
def AnyIntegerType : Type<AnyIntegerLike.predicate, "any integer">;
|
||||
|
||||
// Composable types
|
||||
// Note that we include both fir_ComplexType and AnyComplex, so we can use both
|
||||
// the FIR ComplexType and the MLIR ComplexType (the former is used to represent
|
||||
// Fortran complex and the latter for C++ std::complex).
|
||||
def AnyCompositeLike : TypeConstraint<Or<[fir_RecordType.predicate,
|
||||
fir_SequenceType.predicate, fir_ComplexType.predicate,
|
||||
fir_SequenceType.predicate, fir_ComplexType.predicate, AnyComplex.predicate,
|
||||
fir_VectorType.predicate, IsTupleTypePred, fir_CharacterType.predicate]>,
|
||||
"any composite">;
|
||||
|
||||
|
|
|
@ -20,6 +20,15 @@
|
|||
|
||||
using namespace fir;
|
||||
|
||||
// Reduce a REAL/float type to the floating point semantics.
|
||||
static const llvm::fltSemantics &floatToSemantics(const KindMapping &kindMap,
|
||||
mlir::Type type) {
|
||||
assert(isa_real(type));
|
||||
if (auto ty = type.dyn_cast<fir::RealType>())
|
||||
return kindMap.getFloatSemantics(ty.getFKind());
|
||||
return type.cast<mlir::FloatType>().getFloatSemantics();
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename S>
|
||||
struct GenericTarget : public CodeGenSpecifics {
|
||||
|
@ -35,7 +44,8 @@ struct GenericTarget : public CodeGenSpecifics {
|
|||
// split format with all pointers first (in the declared position) and all
|
||||
// LEN arguments appended after all of the dummy arguments.
|
||||
// NB: Other conventions/ABIs can/should be supported via options.
|
||||
marshal.emplace_back(idxTy, AT{/*append=*/!sret});
|
||||
marshal.emplace_back(idxTy, AT{/*alignment=*/0, /*byval=*/false,
|
||||
/*sret=*/sret, /*append=*/!sret});
|
||||
return marshal;
|
||||
}
|
||||
};
|
||||
|
@ -50,6 +60,39 @@ struct TargetI386 : public GenericTarget<TargetI386> {
|
|||
using GenericTarget::GenericTarget;
|
||||
|
||||
static constexpr int defaultWidth = 32;
|
||||
|
||||
CodeGenSpecifics::Marshalling
|
||||
complexArgumentType(mlir::Type eleTy) const override {
|
||||
assert(fir::isa_real(eleTy));
|
||||
CodeGenSpecifics::Marshalling marshal;
|
||||
// { t, t } struct of 2 eleTy, byval, align 4
|
||||
mlir::TypeRange range = {eleTy, eleTy};
|
||||
auto structTy = mlir::TupleType::get(eleTy.getContext(), range);
|
||||
marshal.emplace_back(fir::ReferenceType::get(structTy),
|
||||
AT{/*alignment=*/4, /*byval=*/true});
|
||||
return marshal;
|
||||
}
|
||||
|
||||
CodeGenSpecifics::Marshalling
|
||||
complexReturnType(mlir::Type eleTy) const override {
|
||||
assert(fir::isa_real(eleTy));
|
||||
CodeGenSpecifics::Marshalling marshal;
|
||||
const auto *sem = &floatToSemantics(kindMap, eleTy);
|
||||
if (sem == &llvm::APFloat::IEEEsingle()) {
|
||||
// i64 pack both floats in a 64-bit GPR
|
||||
marshal.emplace_back(mlir::IntegerType::get(eleTy.getContext(), 64),
|
||||
AT{});
|
||||
} else if (sem == &llvm::APFloat::IEEEdouble()) {
|
||||
// { t, t } struct of 2 eleTy, sret, align 4
|
||||
mlir::TypeRange range = {eleTy, eleTy};
|
||||
auto structTy = mlir::TupleType::get(eleTy.getContext(), range);
|
||||
marshal.emplace_back(fir::ReferenceType::get(structTy),
|
||||
AT{/*alignment=*/4, /*byval=*/false, /*sret=*/true});
|
||||
} else {
|
||||
llvm::report_fatal_error("complex for this precision not implemented");
|
||||
}
|
||||
return marshal;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@ -62,6 +105,41 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> {
|
|||
using GenericTarget::GenericTarget;
|
||||
|
||||
static constexpr int defaultWidth = 64;
|
||||
|
||||
CodeGenSpecifics::Marshalling
|
||||
complexArgumentType(mlir::Type eleTy) const override {
|
||||
CodeGenSpecifics::Marshalling marshal;
|
||||
const auto *sem = &floatToSemantics(kindMap, eleTy);
|
||||
if (sem == &llvm::APFloat::IEEEsingle()) {
|
||||
// <2 x t> vector of 2 eleTy
|
||||
marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{});
|
||||
} else if (sem == &llvm::APFloat::IEEEdouble()) {
|
||||
// two distinct double arguments
|
||||
marshal.emplace_back(eleTy, AT{});
|
||||
marshal.emplace_back(eleTy, AT{});
|
||||
} else {
|
||||
llvm::report_fatal_error("complex for this precision not implemented");
|
||||
}
|
||||
return marshal;
|
||||
}
|
||||
|
||||
CodeGenSpecifics::Marshalling
|
||||
complexReturnType(mlir::Type eleTy) const override {
|
||||
CodeGenSpecifics::Marshalling marshal;
|
||||
const auto *sem = &floatToSemantics(kindMap, eleTy);
|
||||
if (sem == &llvm::APFloat::IEEEsingle()) {
|
||||
// <2 x t> vector of 2 eleTy
|
||||
marshal.emplace_back(fir::VectorType::get(2, eleTy), AT{});
|
||||
} else if (sem == &llvm::APFloat::IEEEdouble()) {
|
||||
// ( t, t ) tuple of 2 eleTy
|
||||
mlir::TypeRange range = {eleTy, eleTy};
|
||||
marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range),
|
||||
AT{});
|
||||
} else {
|
||||
llvm::report_fatal_error("complex for this precision not implemented");
|
||||
}
|
||||
return marshal;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@ -74,6 +152,36 @@ struct TargetAArch64 : public GenericTarget<TargetAArch64> {
|
|||
using GenericTarget::GenericTarget;
|
||||
|
||||
static constexpr int defaultWidth = 64;
|
||||
|
||||
CodeGenSpecifics::Marshalling
|
||||
complexArgumentType(mlir::Type eleTy) const override {
|
||||
CodeGenSpecifics::Marshalling marshal;
|
||||
const auto *sem = &floatToSemantics(kindMap, eleTy);
|
||||
if (sem == &llvm::APFloat::IEEEsingle() ||
|
||||
sem == &llvm::APFloat::IEEEdouble()) {
|
||||
// [2 x t] array of 2 eleTy
|
||||
marshal.emplace_back(fir::SequenceType::get({2}, eleTy), AT{});
|
||||
} else {
|
||||
llvm::report_fatal_error("complex for this precision not implemented");
|
||||
}
|
||||
return marshal;
|
||||
}
|
||||
|
||||
CodeGenSpecifics::Marshalling
|
||||
complexReturnType(mlir::Type eleTy) const override {
|
||||
CodeGenSpecifics::Marshalling marshal;
|
||||
const auto *sem = &floatToSemantics(kindMap, eleTy);
|
||||
if (sem == &llvm::APFloat::IEEEsingle() ||
|
||||
sem == &llvm::APFloat::IEEEdouble()) {
|
||||
// ( t, t ) tuple of 2 eleTy
|
||||
mlir::TypeRange range = {eleTy, eleTy};
|
||||
marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range),
|
||||
AT{});
|
||||
} else {
|
||||
llvm::report_fatal_error("complex for this precision not implemented");
|
||||
}
|
||||
return marshal;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@ -86,6 +194,24 @@ struct TargetPPC64le : public GenericTarget<TargetPPC64le> {
|
|||
using GenericTarget::GenericTarget;
|
||||
|
||||
static constexpr int defaultWidth = 64;
|
||||
|
||||
CodeGenSpecifics::Marshalling
|
||||
complexArgumentType(mlir::Type eleTy) const override {
|
||||
CodeGenSpecifics::Marshalling marshal;
|
||||
// two distinct element type arguments (re, im)
|
||||
marshal.emplace_back(eleTy, AT{});
|
||||
marshal.emplace_back(eleTy, AT{});
|
||||
return marshal;
|
||||
}
|
||||
|
||||
CodeGenSpecifics::Marshalling
|
||||
complexReturnType(mlir::Type eleTy) const override {
|
||||
CodeGenSpecifics::Marshalling marshal;
|
||||
// ( t, t ) tuple of 2 element type
|
||||
mlir::TypeRange range = {eleTy, eleTy};
|
||||
marshal.emplace_back(mlir::TupleType::get(eleTy.getContext(), range), AT{});
|
||||
return marshal;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -29,11 +29,20 @@ namespace details {
|
|||
/// LLVMContext.
|
||||
class Attributes {
|
||||
public:
|
||||
Attributes(bool append = false) : append{append} {}
|
||||
Attributes(unsigned short alignment = 0, bool byval = false,
|
||||
bool sret = false, bool append = false)
|
||||
: alignment{alignment}, byval{byval}, sret{sret}, append{append} {}
|
||||
|
||||
unsigned getAlignment() const { return alignment; }
|
||||
bool hasAlignment() const { return alignment != 0; }
|
||||
bool isByVal() const { return byval; }
|
||||
bool isSRet() const { return sret; }
|
||||
bool isAppend() const { return append; }
|
||||
|
||||
private:
|
||||
unsigned short alignment{};
|
||||
bool byval : 1;
|
||||
bool sret : 1;
|
||||
bool append : 1;
|
||||
};
|
||||
|
||||
|
@ -56,6 +65,15 @@ public:
|
|||
CodeGenSpecifics() = delete;
|
||||
virtual ~CodeGenSpecifics() {}
|
||||
|
||||
/// Type representation of a `complex<eleTy>` type argument when passed by
|
||||
/// value. An argument value may need to be passed as a (safe) reference
|
||||
/// argument.
|
||||
virtual Marshalling complexArgumentType(mlir::Type eleTy) const = 0;
|
||||
|
||||
/// Type representation of a `complex<eleTy>` type return value. Such a return
|
||||
/// value may need to be converted to a hidden reference argument.
|
||||
virtual Marshalling complexReturnType(mlir::Type eleTy) const = 0;
|
||||
|
||||
/// Type representation of a `boxchar<n>` type argument when passed by value.
|
||||
/// An argument value may need to be passed as a (safe) reference argument.
|
||||
///
|
||||
|
|
|
@ -35,7 +35,15 @@ namespace {
|
|||
|
||||
/// Fixups for updating a FuncOp's arguments and return values.
|
||||
struct FixupTy {
|
||||
enum class Codes { CharPair, Trailing };
|
||||
enum class Codes {
|
||||
ArgumentAsLoad,
|
||||
ArgumentType,
|
||||
CharPair,
|
||||
ReturnAsStore,
|
||||
ReturnType,
|
||||
Split,
|
||||
Trailing
|
||||
};
|
||||
|
||||
FixupTy(Codes code, std::size_t index, std::size_t second = 0)
|
||||
: code{code}, index{index}, second{second} {}
|
||||
|
@ -60,6 +68,7 @@ class TargetRewrite : public TargetRewriteBase<TargetRewrite> {
|
|||
public:
|
||||
TargetRewrite(const TargetRewriteOptions &options) {
|
||||
noCharacterConversion = options.noCharacterConversion;
|
||||
noComplexConversion = options.noComplexConversion;
|
||||
}
|
||||
|
||||
void runOnOperation() override final {
|
||||
|
@ -99,6 +108,76 @@ public:
|
|||
|
||||
mlir::ModuleOp getModule() { return getOperation(); }
|
||||
|
||||
template <typename A, typename B, typename C>
|
||||
std::function<mlir::Value(mlir::Operation *)>
|
||||
rewriteCallComplexResultType(A ty, B &newResTys, B &newInTys, C &newOpers) {
|
||||
auto m = specifics->complexReturnType(ty.getElementType());
|
||||
// Currently targets mandate COMPLEX is a single aggregate or packed
|
||||
// scalar, including the sret case.
|
||||
assert(m.size() == 1 && "target lowering of complex return not supported");
|
||||
auto resTy = std::get<mlir::Type>(m[0]);
|
||||
auto attr = std::get<CodeGenSpecifics::Attributes>(m[0]);
|
||||
auto loc = mlir::UnknownLoc::get(resTy.getContext());
|
||||
if (attr.isSRet()) {
|
||||
assert(isa_ref_type(resTy));
|
||||
mlir::Value stack =
|
||||
rewriter->create<fir::AllocaOp>(loc, dyn_cast_ptrEleTy(resTy));
|
||||
newInTys.push_back(resTy);
|
||||
newOpers.push_back(stack);
|
||||
return [=](mlir::Operation *) -> mlir::Value {
|
||||
auto memTy = ReferenceType::get(ty);
|
||||
auto cast = rewriter->create<ConvertOp>(loc, memTy, stack);
|
||||
return rewriter->create<fir::LoadOp>(loc, cast);
|
||||
};
|
||||
}
|
||||
newResTys.push_back(resTy);
|
||||
return [=](mlir::Operation *call) -> mlir::Value {
|
||||
auto mem = rewriter->create<fir::AllocaOp>(loc, resTy);
|
||||
rewriter->create<fir::StoreOp>(loc, call->getResult(0), mem);
|
||||
auto memTy = ReferenceType::get(ty);
|
||||
auto cast = rewriter->create<ConvertOp>(loc, memTy, mem);
|
||||
return rewriter->create<fir::LoadOp>(loc, cast);
|
||||
};
|
||||
}
|
||||
|
||||
template <typename A, typename B, typename C>
|
||||
void rewriteCallComplexInputType(A ty, mlir::Value oper, B &newInTys,
|
||||
C &newOpers) {
|
||||
auto m = specifics->complexArgumentType(ty.getElementType());
|
||||
auto *ctx = ty.getContext();
|
||||
auto loc = mlir::UnknownLoc::get(ctx);
|
||||
if (m.size() == 1) {
|
||||
// COMPLEX is a single aggregate
|
||||
auto resTy = std::get<mlir::Type>(m[0]);
|
||||
auto attr = std::get<CodeGenSpecifics::Attributes>(m[0]);
|
||||
auto oldRefTy = ReferenceType::get(ty);
|
||||
if (attr.isByVal()) {
|
||||
auto mem = rewriter->create<fir::AllocaOp>(loc, ty);
|
||||
rewriter->create<fir::StoreOp>(loc, oper, mem);
|
||||
newOpers.push_back(rewriter->create<ConvertOp>(loc, resTy, mem));
|
||||
} else {
|
||||
auto mem = rewriter->create<fir::AllocaOp>(loc, resTy);
|
||||
auto cast = rewriter->create<ConvertOp>(loc, oldRefTy, mem);
|
||||
rewriter->create<fir::StoreOp>(loc, oper, cast);
|
||||
newOpers.push_back(rewriter->create<fir::LoadOp>(loc, mem));
|
||||
}
|
||||
newInTys.push_back(resTy);
|
||||
} else {
|
||||
assert(m.size() == 2);
|
||||
// COMPLEX is split into 2 separate arguments
|
||||
for (auto e : llvm::enumerate(m)) {
|
||||
auto &tup = e.value();
|
||||
auto ty = std::get<mlir::Type>(tup);
|
||||
auto index = e.index();
|
||||
auto idx = rewriter->getIntegerAttr(rewriter->getIndexType(), index);
|
||||
auto val = rewriter->create<ExtractValueOp>(
|
||||
loc, ty, oper, rewriter->getArrayAttr(idx));
|
||||
newInTys.push_back(ty);
|
||||
newOpers.push_back(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert fir.call and fir.dispatch Ops.
|
||||
template <typename A>
|
||||
void convertCallOp(A callOp) {
|
||||
|
@ -124,7 +203,16 @@ public:
|
|||
llvm::Optional<std::function<mlir::Value(mlir::Operation *)>> wrap;
|
||||
if (fnTy.getResults().size() == 1) {
|
||||
mlir::Type ty = fnTy.getResult(0);
|
||||
newResTys.push_back(ty);
|
||||
llvm::TypeSwitch<mlir::Type>(ty)
|
||||
.template Case<fir::ComplexType>([&](fir::ComplexType cmplx) {
|
||||
wrap = rewriteCallComplexResultType(cmplx, newResTys, newInTys,
|
||||
newOpers);
|
||||
})
|
||||
.template Case<mlir::ComplexType>([&](mlir::ComplexType cmplx) {
|
||||
wrap = rewriteCallComplexResultType(cmplx, newResTys, newInTys,
|
||||
newOpers);
|
||||
})
|
||||
.Default([&](mlir::Type ty) { newResTys.push_back(ty); });
|
||||
} else if (fnTy.getResults().size() > 1) {
|
||||
TODO(loc, "multiple results not supported yet");
|
||||
}
|
||||
|
@ -169,6 +257,12 @@ public:
|
|||
}
|
||||
}
|
||||
})
|
||||
.template Case<fir::ComplexType>([&](fir::ComplexType cmplx) {
|
||||
rewriteCallComplexInputType(cmplx, oper, newInTys, newOpers);
|
||||
})
|
||||
.template Case<mlir::ComplexType>([&](mlir::ComplexType cmplx) {
|
||||
rewriteCallComplexInputType(cmplx, oper, newInTys, newOpers);
|
||||
})
|
||||
.Default([&](mlir::Type ty) {
|
||||
newInTys.push_back(ty);
|
||||
newOpers.push_back(oper);
|
||||
|
@ -198,6 +292,33 @@ public:
|
|||
TODO(loc, "dispatch not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
// Result type fixup for fir::ComplexType and mlir::ComplexType
|
||||
template <typename A, typename B>
|
||||
void lowerComplexSignatureRes(A cmplx, B &newResTys, B &newInTys) {
|
||||
if (noComplexConversion) {
|
||||
newResTys.push_back(cmplx);
|
||||
} else {
|
||||
for (auto &tup : specifics->complexReturnType(cmplx.getElementType())) {
|
||||
auto argTy = std::get<mlir::Type>(tup);
|
||||
if (std::get<CodeGenSpecifics::Attributes>(tup).isSRet())
|
||||
newInTys.push_back(argTy);
|
||||
else
|
||||
newResTys.push_back(argTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Argument type fixup for fir::ComplexType and mlir::ComplexType
|
||||
template <typename A, typename B>
|
||||
void lowerComplexSignatureArg(A cmplx, B &newInTys) {
|
||||
if (noComplexConversion)
|
||||
newInTys.push_back(cmplx);
|
||||
else
|
||||
for (auto &tup : specifics->complexArgumentType(cmplx.getElementType()))
|
||||
newInTys.push_back(std::get<mlir::Type>(tup));
|
||||
}
|
||||
|
||||
/// Convert the type signatures on all the functions present in the module.
|
||||
/// As the type signature is being changed, this must also update the
|
||||
/// function itself to use any new arguments, etc.
|
||||
|
@ -215,12 +336,14 @@ public:
|
|||
assert(signature.isa<mlir::FunctionType>());
|
||||
auto func = signature.dyn_cast<mlir::FunctionType>();
|
||||
for (auto ty : func.getResults())
|
||||
if ((ty.isa<BoxCharType>() && !noCharacterConversion)) {
|
||||
if ((ty.isa<BoxCharType>() && !noCharacterConversion) ||
|
||||
(isa_complex(ty) && !noComplexConversion)) {
|
||||
LLVM_DEBUG(llvm::dbgs() << "rewrite " << signature << " for target\n");
|
||||
return false;
|
||||
}
|
||||
for (auto ty : func.getInputs())
|
||||
if ((ty.isa<BoxCharType>() && !noCharacterConversion)) {
|
||||
if ((ty.isa<BoxCharType>() && !noCharacterConversion) ||
|
||||
(isa_complex(ty) && !noComplexConversion)) {
|
||||
LLVM_DEBUG(llvm::dbgs() << "rewrite " << signature << " for target\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -239,7 +362,20 @@ public:
|
|||
|
||||
// Convert return value(s)
|
||||
for (auto ty : funcTy.getResults())
|
||||
newResTys.push_back(ty);
|
||||
llvm::TypeSwitch<mlir::Type>(ty)
|
||||
.Case<fir::ComplexType>([&](fir::ComplexType cmplx) {
|
||||
if (noComplexConversion)
|
||||
newResTys.push_back(cmplx);
|
||||
else
|
||||
doComplexReturn(func, cmplx, newResTys, newInTys, fixups);
|
||||
})
|
||||
.Case<mlir::ComplexType>([&](mlir::ComplexType cmplx) {
|
||||
if (noComplexConversion)
|
||||
newResTys.push_back(cmplx);
|
||||
else
|
||||
doComplexReturn(func, cmplx, newResTys, newInTys, fixups);
|
||||
})
|
||||
.Default([&](mlir::Type ty) { newResTys.push_back(ty); });
|
||||
|
||||
// Convert arguments
|
||||
llvm::SmallVector<mlir::Type> trailingTys;
|
||||
|
@ -276,6 +412,18 @@ public:
|
|||
}
|
||||
}
|
||||
})
|
||||
.Case<fir::ComplexType>([&](fir::ComplexType cmplx) {
|
||||
if (noComplexConversion)
|
||||
newInTys.push_back(cmplx);
|
||||
else
|
||||
doComplexArg(func, cmplx, newInTys, fixups);
|
||||
})
|
||||
.Case<mlir::ComplexType>([&](mlir::ComplexType cmplx) {
|
||||
if (noComplexConversion)
|
||||
newInTys.push_back(cmplx);
|
||||
else
|
||||
doComplexArg(func, cmplx, newInTys, fixups);
|
||||
})
|
||||
.Default([&](mlir::Type ty) { newInTys.push_back(ty); });
|
||||
}
|
||||
|
||||
|
@ -289,6 +437,37 @@ public:
|
|||
for (std::remove_const_t<decltype(fixupSize)> i = 0; i < fixupSize; ++i) {
|
||||
const auto &fixup = fixups[i];
|
||||
switch (fixup.code) {
|
||||
case FixupTy::Codes::ArgumentAsLoad: {
|
||||
// Argument was pass-by-value, but is now pass-by-reference and
|
||||
// possibly with a different element type.
|
||||
auto newArg =
|
||||
func.front().insertArgument(fixup.index, newInTys[fixup.index]);
|
||||
rewriter->setInsertionPointToStart(&func.front());
|
||||
auto oldArgTy = ReferenceType::get(oldArgTys[fixup.index - offset]);
|
||||
auto cast = rewriter->create<ConvertOp>(loc, oldArgTy, newArg);
|
||||
auto load = rewriter->create<fir::LoadOp>(loc, cast);
|
||||
func.getArgument(fixup.index + 1).replaceAllUsesWith(load);
|
||||
func.front().eraseArgument(fixup.index + 1);
|
||||
} break;
|
||||
case FixupTy::Codes::ArgumentType: {
|
||||
// Argument is pass-by-value, but its type has likely been modified to
|
||||
// suit the target ABI convention.
|
||||
auto newArg =
|
||||
func.front().insertArgument(fixup.index, newInTys[fixup.index]);
|
||||
rewriter->setInsertionPointToStart(&func.front());
|
||||
auto mem =
|
||||
rewriter->create<fir::AllocaOp>(loc, newInTys[fixup.index]);
|
||||
rewriter->create<fir::StoreOp>(loc, newArg, mem);
|
||||
auto oldArgTy = ReferenceType::get(oldArgTys[fixup.index - offset]);
|
||||
auto cast = rewriter->create<ConvertOp>(loc, oldArgTy, mem);
|
||||
mlir::Value load = rewriter->create<fir::LoadOp>(loc, cast);
|
||||
func.getArgument(fixup.index + 1).replaceAllUsesWith(load);
|
||||
func.front().eraseArgument(fixup.index + 1);
|
||||
LLVM_DEBUG(llvm::dbgs()
|
||||
<< "old argument: " << oldArgTy.getEleTy()
|
||||
<< ", repl: " << load << ", new argument: "
|
||||
<< func.getArgument(fixup.index).getType() << '\n');
|
||||
} break;
|
||||
case FixupTy::Codes::CharPair: {
|
||||
// The FIR boxchar argument has been split into a pair of distinct
|
||||
// arguments that are in juxtaposition to each other.
|
||||
|
@ -304,6 +483,59 @@ public:
|
|||
offset++;
|
||||
}
|
||||
} break;
|
||||
case FixupTy::Codes::ReturnAsStore: {
|
||||
// The value being returned is now being returned in memory (callee
|
||||
// stack space) through a hidden reference argument.
|
||||
auto newArg =
|
||||
func.front().insertArgument(fixup.index, newInTys[fixup.index]);
|
||||
offset++;
|
||||
func.walk([&](mlir::ReturnOp ret) {
|
||||
rewriter->setInsertionPoint(ret);
|
||||
auto oldOper = ret.getOperand(0);
|
||||
auto oldOperTy = ReferenceType::get(oldOper.getType());
|
||||
auto cast = rewriter->create<ConvertOp>(loc, oldOperTy, newArg);
|
||||
rewriter->create<fir::StoreOp>(loc, oldOper, cast);
|
||||
rewriter->create<mlir::ReturnOp>(loc);
|
||||
ret.erase();
|
||||
});
|
||||
} break;
|
||||
case FixupTy::Codes::ReturnType: {
|
||||
// The function is still returning a value, but its type has likely
|
||||
// changed to suit the target ABI convention.
|
||||
func.walk([&](mlir::ReturnOp ret) {
|
||||
rewriter->setInsertionPoint(ret);
|
||||
auto oldOper = ret.getOperand(0);
|
||||
auto oldOperTy = ReferenceType::get(oldOper.getType());
|
||||
auto mem =
|
||||
rewriter->create<fir::AllocaOp>(loc, newResTys[fixup.index]);
|
||||
auto cast = rewriter->create<ConvertOp>(loc, oldOperTy, mem);
|
||||
rewriter->create<fir::StoreOp>(loc, oldOper, cast);
|
||||
mlir::Value load = rewriter->create<fir::LoadOp>(loc, mem);
|
||||
rewriter->create<mlir::ReturnOp>(loc, load);
|
||||
ret.erase();
|
||||
});
|
||||
} break;
|
||||
case FixupTy::Codes::Split: {
|
||||
// The FIR argument has been split into a pair of distinct arguments
|
||||
// that are in juxtaposition to each other. (For COMPLEX value.)
|
||||
auto newArg =
|
||||
func.front().insertArgument(fixup.index, newInTys[fixup.index]);
|
||||
if (fixup.second == 1) {
|
||||
rewriter->setInsertionPointToStart(&func.front());
|
||||
auto cplxTy = oldArgTys[fixup.index - offset - fixup.second];
|
||||
auto undef = rewriter->create<UndefOp>(loc, cplxTy);
|
||||
auto zero = rewriter->getIntegerAttr(rewriter->getIndexType(), 0);
|
||||
auto one = rewriter->getIntegerAttr(rewriter->getIndexType(), 1);
|
||||
auto cplx1 = rewriter->create<InsertValueOp>(
|
||||
loc, cplxTy, undef, func.front().getArgument(fixup.index - 1),
|
||||
rewriter->getArrayAttr(zero));
|
||||
auto cplx = rewriter->create<InsertValueOp>(
|
||||
loc, cplxTy, cplx1, newArg, rewriter->getArrayAttr(one));
|
||||
func.getArgument(fixup.index + 1).replaceAllUsesWith(cplx);
|
||||
func.front().eraseArgument(fixup.index + 1);
|
||||
offset++;
|
||||
}
|
||||
} break;
|
||||
case FixupTy::Codes::Trailing: {
|
||||
// The FIR argument has been split into a pair of distinct arguments.
|
||||
// The first part of the pair appears in the original argument
|
||||
|
@ -341,6 +573,81 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/// Convert a complex return value. This can involve converting the return
|
||||
/// value to a "hidden" first argument or packing the complex into a wide
|
||||
/// GPR.
|
||||
template <typename A, typename B, typename C>
|
||||
void doComplexReturn(mlir::FuncOp func, A cmplx, B &newResTys, B &newInTys,
|
||||
C &fixups) {
|
||||
if (noComplexConversion) {
|
||||
newResTys.push_back(cmplx);
|
||||
return;
|
||||
}
|
||||
auto m = specifics->complexReturnType(cmplx.getElementType());
|
||||
assert(m.size() == 1);
|
||||
auto &tup = m[0];
|
||||
auto attr = std::get<CodeGenSpecifics::Attributes>(tup);
|
||||
auto argTy = std::get<mlir::Type>(tup);
|
||||
if (attr.isSRet()) {
|
||||
unsigned argNo = newInTys.size();
|
||||
fixups.emplace_back(
|
||||
FixupTy::Codes::ReturnAsStore, argNo, [=](mlir::FuncOp func) {
|
||||
func.setArgAttr(argNo, "llvm.sret", rewriter->getUnitAttr());
|
||||
});
|
||||
newInTys.push_back(argTy);
|
||||
return;
|
||||
}
|
||||
fixups.emplace_back(FixupTy::Codes::ReturnType, newResTys.size());
|
||||
newResTys.push_back(argTy);
|
||||
}
|
||||
|
||||
/// Convert a complex argument value. This can involve storing the value to
|
||||
/// a temporary memory location or factoring the value into two distinct
|
||||
/// arguments.
|
||||
template <typename A, typename B, typename C>
|
||||
void doComplexArg(mlir::FuncOp func, A cmplx, B &newInTys, C &fixups) {
|
||||
if (noComplexConversion) {
|
||||
newInTys.push_back(cmplx);
|
||||
return;
|
||||
}
|
||||
auto m = specifics->complexArgumentType(cmplx.getElementType());
|
||||
const auto fixupCode =
|
||||
m.size() > 1 ? FixupTy::Codes::Split : FixupTy::Codes::ArgumentType;
|
||||
for (auto e : llvm::enumerate(m)) {
|
||||
auto &tup = e.value();
|
||||
auto index = e.index();
|
||||
auto attr = std::get<CodeGenSpecifics::Attributes>(tup);
|
||||
auto argTy = std::get<mlir::Type>(tup);
|
||||
auto argNo = newInTys.size();
|
||||
if (attr.isByVal()) {
|
||||
if (auto align = attr.getAlignment())
|
||||
fixups.emplace_back(
|
||||
FixupTy::Codes::ArgumentAsLoad, argNo, [=](mlir::FuncOp func) {
|
||||
func.setArgAttr(argNo, "llvm.byval", rewriter->getUnitAttr());
|
||||
func.setArgAttr(argNo, "llvm.align",
|
||||
rewriter->getIntegerAttr(
|
||||
rewriter->getIntegerType(32), align));
|
||||
});
|
||||
else
|
||||
fixups.emplace_back(FixupTy::Codes::ArgumentAsLoad, newInTys.size(),
|
||||
[=](mlir::FuncOp func) {
|
||||
func.setArgAttr(argNo, "llvm.byval",
|
||||
rewriter->getUnitAttr());
|
||||
});
|
||||
} else {
|
||||
if (auto align = attr.getAlignment())
|
||||
fixups.emplace_back(fixupCode, argNo, index, [=](mlir::FuncOp func) {
|
||||
func.setArgAttr(
|
||||
argNo, "llvm.align",
|
||||
rewriter->getIntegerAttr(rewriter->getIntegerType(32), align));
|
||||
});
|
||||
else
|
||||
fixups.emplace_back(fixupCode, argNo, index);
|
||||
}
|
||||
newInTys.push_back(argTy);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Replace `op` and remove it.
|
||||
void replaceOp(mlir::Operation *op, mlir::ValueRange newValues) {
|
||||
|
|
|
@ -0,0 +1,454 @@
|
|||
// RUN: fir-opt --target-rewrite="target=i386-unknown-linux-gnu" %s | FileCheck %s --check-prefix=I32
|
||||
// RUN: fir-opt --target-rewrite="target=x86_64-unknown-linux-gnu" %s | FileCheck %s --check-prefix=X64
|
||||
// RUN: fir-opt --target-rewrite="target=aarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefix=AARCH64
|
||||
// RUN: fir-opt --target-rewrite="target=powerpc64le-unknown-linux-gnu" %s | FileCheck %s --check-prefix=PPC
|
||||
|
||||
// Test that we rewrite the signature and body of a function that returns a
|
||||
// complex<4>.
|
||||
// I32-LABEL: func @returncomplex4() -> i64
|
||||
// X64-LABEL: func @returncomplex4() -> !fir.vector<2:!fir.real<4>>
|
||||
// AARCH64-LABEL: func @returncomplex4() -> tuple<!fir.real<4>, !fir.real<4>>
|
||||
// PPC-LABEL: func @returncomplex4() -> tuple<!fir.real<4>, !fir.real<4>>
|
||||
func @returncomplex4() -> !fir.complex<4> {
|
||||
// I32: fir.insert_value
|
||||
// I32: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value
|
||||
// X64: fir.insert_value
|
||||
// X64: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value
|
||||
// AARCH64: fir.insert_value
|
||||
// AARCH64: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value
|
||||
// PPC: fir.insert_value
|
||||
// PPC: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value
|
||||
%1 = fir.undefined !fir.complex<4>
|
||||
%2 = arith.constant 2.0 : f32
|
||||
%3 = fir.convert %2 : (f32) -> !fir.real<4>
|
||||
%c0 = arith.constant 0 : i32
|
||||
%4 = fir.insert_value %1, %3, [0 : index] : (!fir.complex<4>, !fir.real<4>) -> !fir.complex<4>
|
||||
%c1 = arith.constant 1 : i32
|
||||
%5 = arith.constant -42.0 : f32
|
||||
%6 = fir.insert_value %4, %5, [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
|
||||
|
||||
// I32: [[ADDRI64:%[0-9A-Za-z]+]] = fir.alloca i64
|
||||
// I32: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRI64]] : (!fir.ref<i64>) -> !fir.ref<!fir.complex<4>>
|
||||
// I32: fir.store [[VAL]] to [[ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// I32: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRI64]] : !fir.ref<i64>
|
||||
// I32: return [[RES]] : i64
|
||||
// X64: [[ADDRV:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:!fir.real<4>>
|
||||
// X64: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRV]] : (!fir.ref<!fir.vector<2:!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// X64: fir.store [[VAL]] to [[ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// X64: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRV]] : !fir.ref<!fir.vector<2:!fir.real<4>>>
|
||||
// X64: return [[RES]] : !fir.vector<2:!fir.real<4>>
|
||||
// AARCH64: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<!fir.real<4>, !fir.real<4>>
|
||||
// AARCH64: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<!fir.real<4>, !fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// AARCH64: fir.store [[VAL]] to [[ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// AARCH64: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRT]] : !fir.ref<tuple<!fir.real<4>, !fir.real<4>>>
|
||||
// AARCH64: return [[RES]] : tuple<!fir.real<4>, !fir.real<4>>
|
||||
// PPC: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<!fir.real<4>, !fir.real<4>>
|
||||
// PPC: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<!fir.real<4>, !fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// PPC: fir.store [[VAL]] to [[ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// PPC: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRT]] : !fir.ref<tuple<!fir.real<4>, !fir.real<4>>>
|
||||
// PPC: return [[RES]] : tuple<!fir.real<4>, !fir.real<4>>
|
||||
return %6 : !fir.complex<4>
|
||||
}
|
||||
|
||||
// Test that we rewrite the signature and body of a function that returns a
|
||||
// complex<8>.
|
||||
// I32-LABEL:func @returncomplex8
|
||||
// I32-SAME: ([[ARG0:%[0-9A-Za-z]+]]: !fir.ref<tuple<!fir.real<8>, !fir.real<8>>> {llvm.sret})
|
||||
// X64-LABEL: func @returncomplex8() -> tuple<!fir.real<8>, !fir.real<8>>
|
||||
// AARCH64-LABEL: func @returncomplex8() -> tuple<!fir.real<8>, !fir.real<8>>
|
||||
// PPC-LABEL: func @returncomplex8() -> tuple<!fir.real<8>, !fir.real<8>>
|
||||
func @returncomplex8() -> !fir.complex<8> {
|
||||
// I32: fir.insert_value
|
||||
// I32: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value {{.*}}
|
||||
// X64: fir.insert_value
|
||||
// X64: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value {{.*}}
|
||||
// AARCH64: fir.insert_value
|
||||
// AARCH64: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value {{.*}}
|
||||
// PPC: fir.insert_value
|
||||
// PPC: [[VAL:%[0-9A-Za-z]+]] = fir.insert_value {{.*}}
|
||||
%1 = fir.undefined !fir.complex<8>
|
||||
%2 = arith.constant 1.0 : f64
|
||||
%3 = arith.constant -4.0 : f64
|
||||
%c0 = arith.constant 0 : i32
|
||||
%4 = fir.insert_value %1, %3, [0 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
|
||||
%c1 = arith.constant 1 : i32
|
||||
%5 = fir.insert_value %4, %2, [1 : index] : (!fir.complex<8>, f64) -> !fir.complex<8>
|
||||
|
||||
// I32: [[ADDR:%[0-9A-Za-z]+]] = fir.convert [[ARG0]] : (!fir.ref<tuple<!fir.real<8>, !fir.real<8>>>) -> !fir.ref<!fir.complex<8>>
|
||||
// I32: fir.store [[VAL]] to [[ADDR]] : !fir.ref<!fir.complex<8>>
|
||||
// I32: return{{ *$}}
|
||||
// X64: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<!fir.real<8>, !fir.real<8>>
|
||||
// X64: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<!fir.real<8>, !fir.real<8>>>) -> !fir.ref<!fir.complex<8>>
|
||||
// X64: fir.store [[VAL]] to [[ADDRC]] : !fir.ref<!fir.complex<8>>
|
||||
// X64: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRT]] : !fir.ref<tuple<!fir.real<8>, !fir.real<8>>>
|
||||
// X64: return [[RES]] : tuple<!fir.real<8>, !fir.real<8>>
|
||||
// AARCH64: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<!fir.real<8>, !fir.real<8>>
|
||||
// AARCH64: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<!fir.real<8>, !fir.real<8>>>) -> !fir.ref<!fir.complex<8>>
|
||||
// AARCH64: fir.store [[VAL]] to [[ADDRC]] : !fir.ref<!fir.complex<8>>
|
||||
// AARCH64: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRT]] : !fir.ref<tuple<!fir.real<8>, !fir.real<8>>>
|
||||
// AARCH64: return [[RES]] : tuple<!fir.real<8>, !fir.real<8>>
|
||||
// PPC: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<!fir.real<8>, !fir.real<8>>
|
||||
// PPC: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<!fir.real<8>, !fir.real<8>>>) -> !fir.ref<!fir.complex<8>>
|
||||
// PPC: fir.store [[VAL]] to [[ADDRC]] : !fir.ref<!fir.complex<8>>
|
||||
// PPC: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRT]] : !fir.ref<tuple<!fir.real<8>, !fir.real<8>>>
|
||||
// PPC: return [[RES]] : tuple<!fir.real<8>, !fir.real<8>>
|
||||
return %5 : !fir.complex<8>
|
||||
}
|
||||
|
||||
// Test that we rewrite the signature of a function that accepts a complex<4>.
|
||||
// I32-LABEL: func private @paramcomplex4(!fir.ref<tuple<!fir.real<4>, !fir.real<4>>> {llvm.align = 4 : i32, llvm.byval})
|
||||
// X64-LABEL: func private @paramcomplex4(!fir.vector<2:!fir.real<4>>)
|
||||
// AARCH64-LABEL: func private @paramcomplex4(!fir.array<2x!fir.real<4>>)
|
||||
// PPC-LABEL: func private @paramcomplex4(!fir.real<4>, !fir.real<4>)
|
||||
func private @paramcomplex4(!fir.complex<4>) -> ()
|
||||
|
||||
// Test that we rewrite calls to functions that return or accept complex<4>.
|
||||
// I32-LABEL: func @callcomplex4()
|
||||
// X64-LABEL: func @callcomplex4()
|
||||
// AARCH64-LABEL: func @callcomplex4()
|
||||
func @callcomplex4() {
|
||||
|
||||
// I32: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex4() : () -> i64
|
||||
// X64: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex4() : () -> !fir.vector<2:!fir.real<4>>
|
||||
// AARCH64: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex4() : () -> tuple<!fir.real<4>, !fir.real<4>>
|
||||
// PPC: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex4() : () -> tuple<!fir.real<4>, !fir.real<4>>
|
||||
%1 = fir.call @returncomplex4() : () -> !fir.complex<4>
|
||||
|
||||
// I32: [[ADDRI64:%[0-9A-Za-z]+]] = fir.alloca i64
|
||||
// I32: fir.store [[RES]] to [[ADDRI64]] : !fir.ref<i64>
|
||||
// I32: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRI64]] : (!fir.ref<i64>) -> !fir.ref<!fir.complex<4>>
|
||||
// I32: [[C:%[0-9A-Za-z]+]] = fir.load [[ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// I32: [[ADDRC2:%[0-9A-Za-z]+]] = fir.alloca !fir.complex<4>
|
||||
// I32: fir.store [[C]] to [[ADDRC2]] : !fir.ref<!fir.complex<4>>
|
||||
// I32: [[T:%[0-9A-Za-z]+]] = fir.convert [[ADDRC2]] : (!fir.ref<!fir.complex<4>>) -> !fir.ref<tuple<!fir.real<4>, !fir.real<4>>>
|
||||
// I32: fir.call @paramcomplex4([[T]]) : (!fir.ref<tuple<!fir.real<4>, !fir.real<4>>>) -> ()
|
||||
|
||||
// X64: [[ADDRV:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:!fir.real<4>>
|
||||
// X64: fir.store [[RES]] to [[ADDRV]] : !fir.ref<!fir.vector<2:!fir.real<4>>>
|
||||
// X64: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRV]] : (!fir.ref<!fir.vector<2:!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// X64: [[V:%[0-9A-Za-z]+]] = fir.load [[ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// X64: [[ADDRV2:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:!fir.real<4>>
|
||||
// X64: [[ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[ADDRV2]] : (!fir.ref<!fir.vector<2:!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// X64: fir.store [[V]] to [[ADDRC2]] : !fir.ref<!fir.complex<4>>
|
||||
// X64: [[VRELOADED:%[0-9A-Za-z]+]] = fir.load [[ADDRV2]] : !fir.ref<!fir.vector<2:!fir.real<4>>>
|
||||
// X64: fir.call @paramcomplex4([[VRELOADED]]) : (!fir.vector<2:!fir.real<4>>) -> ()
|
||||
|
||||
// AARCH64: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<!fir.real<4>, !fir.real<4>>
|
||||
// AARCH64: fir.store [[RES]] to [[ADDRT]] : !fir.ref<tuple<!fir.real<4>, !fir.real<4>>>
|
||||
// AARCH64: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<!fir.real<4>, !fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// AARCH64: [[V:%[0-9A-Za-z]+]] = fir.load [[ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// AARCH64: [[ADDRARR:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2x!fir.real<4>>
|
||||
// AARCH64: [[ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[ADDRARR]] : (!fir.ref<!fir.array<2x!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// AARCH64: fir.store [[V]] to [[ADDRC2]] : !fir.ref<!fir.complex<4>>
|
||||
// AARCH64: [[ARR:%[0-9A-Za-z]+]] = fir.load [[ADDRARR]] : !fir.ref<!fir.array<2x!fir.real<4>>>
|
||||
// AARCH64: fir.call @paramcomplex4([[ARR]]) : (!fir.array<2x!fir.real<4>>) -> ()
|
||||
|
||||
// PPC: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<!fir.real<4>, !fir.real<4>>
|
||||
// PPC: fir.store [[RES]] to [[ADDRT]] : !fir.ref<tuple<!fir.real<4>, !fir.real<4>>>
|
||||
// PPC: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<!fir.real<4>, !fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// PPC: [[V:%[0-9A-Za-z]+]] = fir.load [[ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// PPC: [[A:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [0 : index] : (!fir.complex<4>) -> !fir.real<4>
|
||||
// PPC: [[B:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [1 : index] : (!fir.complex<4>) -> !fir.real<4>
|
||||
// PPC: fir.call @paramcomplex4([[A]], [[B]]) : (!fir.real<4>, !fir.real<4>) -> ()
|
||||
fir.call @paramcomplex4(%1) : (!fir.complex<4>) -> ()
|
||||
return
|
||||
}
|
||||
|
||||
// Test that we rewrite the signature of a function that accepts a complex<8>.
|
||||
// I32-LABEL: func private @paramcomplex8(!fir.ref<tuple<!fir.real<8>, !fir.real<8>>> {llvm.align = 4 : i32, llvm.byval})
|
||||
// X64-LABEL: func private @paramcomplex8(!fir.real<8>, !fir.real<8>)
|
||||
// AARCH64-LABEL: func private @paramcomplex8(!fir.array<2x!fir.real<8>>)
|
||||
// PPC-LABEL: func private @paramcomplex8(!fir.real<8>, !fir.real<8>)
|
||||
func private @paramcomplex8(!fir.complex<8>) -> ()
|
||||
|
||||
// Test that we rewrite calls to functions that return or accept complex<8>.
|
||||
// I32-LABEL: func @callcomplex8()
|
||||
// X64-LABEL: func @callcomplex8()
|
||||
// AARCH64-LABEL: func @callcomplex8()
|
||||
// PPC-LABEL: func @callcomplex8()
|
||||
func @callcomplex8() {
|
||||
// I32: [[RES:%[0-9A-Za-z]+]] = fir.alloca tuple<!fir.real<8>, !fir.real<8>>
|
||||
// I32: fir.call @returncomplex8([[RES]]) : (!fir.ref<tuple<!fir.real<8>, !fir.real<8>>>) -> ()
|
||||
// X64: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex8() : () -> tuple<!fir.real<8>, !fir.real<8>>
|
||||
// AARCH64: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex8() : () -> tuple<!fir.real<8>, !fir.real<8>>
|
||||
// PPC: [[RES:%[0-9A-Za-z]+]] = fir.call @returncomplex8() : () -> tuple<!fir.real<8>, !fir.real<8>>
|
||||
%1 = fir.call @returncomplex8() : () -> !fir.complex<8>
|
||||
|
||||
// I32: [[RESC:%[0-9A-Za-z]+]] = fir.convert [[RES]] : (!fir.ref<tuple<!fir.real<8>, !fir.real<8>>>) -> !fir.ref<!fir.complex<8>>
|
||||
// I32: [[V:%[0-9A-Za-z]+]] = fir.load [[RESC]] : !fir.ref<!fir.complex<8>>
|
||||
// I32: [[ADDRC:%[0-9A-Za-z]+]] = fir.alloca !fir.complex<8>
|
||||
// I32: fir.store [[V]] to [[ADDRC]] : !fir.ref<!fir.complex<8>>
|
||||
// I32: [[ADDRT:%[0-9A-Za-z]+]] = fir.convert [[ADDRC]] : (!fir.ref<!fir.complex<8>>) -> !fir.ref<tuple<!fir.real<8>, !fir.real<8>>>
|
||||
// I32: fir.call @paramcomplex8([[ADDRT]]) : (!fir.ref<tuple<!fir.real<8>, !fir.real<8>>>) -> ()
|
||||
|
||||
// X64: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<!fir.real<8>, !fir.real<8>>
|
||||
// X64: fir.store [[RES]] to [[ADDRT]] : !fir.ref<tuple<!fir.real<8>, !fir.real<8>>>
|
||||
// X64: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<!fir.real<8>, !fir.real<8>>>) -> !fir.ref<!fir.complex<8>>
|
||||
// X64: [[V:%[0-9A-Za-z]+]] = fir.load [[ADDRC]] : !fir.ref<!fir.complex<8>>
|
||||
// X64: [[A:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [0 : index] : (!fir.complex<8>) -> !fir.real<8>
|
||||
// X64: [[B:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [1 : index] : (!fir.complex<8>) -> !fir.real<8>
|
||||
// X64: fir.call @paramcomplex8([[A]], [[B]]) : (!fir.real<8>, !fir.real<8>) -> ()
|
||||
|
||||
// AARCH64: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<!fir.real<8>, !fir.real<8>>
|
||||
// AARCH64: fir.store [[RES]] to [[ADDRT]] : !fir.ref<tuple<!fir.real<8>, !fir.real<8>>>
|
||||
// AARCH64: [[ADDRV:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<!fir.real<8>, !fir.real<8>>>) -> !fir.ref<!fir.complex<8>>
|
||||
// AARCH64: [[V:%[0-9A-Za-z]+]] = fir.load [[ADDRV]] : !fir.ref<!fir.complex<8>>
|
||||
// AARCH64: [[ADDRARR:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2x!fir.real<8>>
|
||||
// AARCH64: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRARR]] : (!fir.ref<!fir.array<2x!fir.real<8>>>) -> !fir.ref<!fir.complex<8>>
|
||||
// AARCH64: fir.store [[V]] to [[ADDRC]] : !fir.ref<!fir.complex<8>>
|
||||
// AARCH64: [[ARR:%[0-9A-Za-z]+]] = fir.load [[ADDRARR]] : !fir.ref<!fir.array<2x!fir.real<8>>>
|
||||
// AARCH64: fir.call @paramcomplex8([[ARR]]) : (!fir.array<2x!fir.real<8>>) -> ()
|
||||
|
||||
// PPC: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<!fir.real<8>, !fir.real<8>>
|
||||
// PPC: fir.store [[RES]] to [[ADDRT]] : !fir.ref<tuple<!fir.real<8>, !fir.real<8>>>
|
||||
// PPC: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<!fir.real<8>, !fir.real<8>>>) -> !fir.ref<!fir.complex<8>>
|
||||
// PPC: [[V:%[0-9A-Za-z]+]] = fir.load [[ADDRC]] : !fir.ref<!fir.complex<8>>
|
||||
// PPC: [[A:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [0 : index] : (!fir.complex<8>) -> !fir.real<8>
|
||||
// PPC: [[B:%[0-9A-Za-z]+]] = fir.extract_value [[V]], [1 : index] : (!fir.complex<8>) -> !fir.real<8>
|
||||
// PPC: fir.call @paramcomplex8([[A]], [[B]]) : (!fir.real<8>, !fir.real<8>) -> ()
|
||||
fir.call @paramcomplex8(%1) : (!fir.complex<8>) -> ()
|
||||
return
|
||||
}
|
||||
|
||||
// Test multiple complex<4> parameters and arguments
|
||||
// I32-LABEL: func private @calleemultipleparamscomplex4(!fir.ref<tuple<!fir.real<4>, !fir.real<4>>> {llvm.align = 4 : i32, llvm.byval}, !fir.ref<tuple<!fir.real<4>, !fir.real<4>>> {llvm.align = 4 : i32, llvm.byval}, !fir.ref<tuple<!fir.real<4>, !fir.real<4>>> {llvm.align = 4 : i32, llvm.byval})
|
||||
// X64-LABEL: func private @calleemultipleparamscomplex4(!fir.vector<2:!fir.real<4>>, !fir.vector<2:!fir.real<4>>, !fir.vector<2:!fir.real<4>>)
|
||||
// AARCH64-LABEL: func private @calleemultipleparamscomplex4(!fir.array<2x!fir.real<4>>, !fir.array<2x!fir.real<4>>, !fir.array<2x!fir.real<4>>)
|
||||
// PPC-LABEL: func private @calleemultipleparamscomplex4(!fir.real<4>, !fir.real<4>, !fir.real<4>, !fir.real<4>, !fir.real<4>, !fir.real<4>)
|
||||
func private @calleemultipleparamscomplex4(!fir.complex<4>, !fir.complex<4>, !fir.complex<4>) -> ()
|
||||
|
||||
// I32-LABEL: func @multipleparamscomplex4
|
||||
// I32-SAME: ([[Z1:%[0-9A-Za-z]+]]: !fir.ref<tuple<!fir.real<4>, !fir.real<4>>> {llvm.align = 4 : i32, llvm.byval}, [[Z2:%[0-9A-Za-z]+]]: !fir.ref<tuple<!fir.real<4>, !fir.real<4>>> {llvm.align = 4 : i32, llvm.byval}, [[Z3:%[0-9A-Za-z]+]]: !fir.ref<tuple<!fir.real<4>, !fir.real<4>>> {llvm.align = 4 : i32, llvm.byval})
|
||||
// X64-LABEL: func @multipleparamscomplex4
|
||||
// X64-SAME: ([[Z1:%[0-9A-Za-z]+]]: !fir.vector<2:!fir.real<4>>, [[Z2:%[0-9A-Za-z]+]]: !fir.vector<2:!fir.real<4>>, [[Z3:%[0-9A-Za-z]+]]: !fir.vector<2:!fir.real<4>>)
|
||||
// AARCH64-LABEL: func @multipleparamscomplex4
|
||||
// AARCH64-SAME: ([[Z1:%[0-9A-Za-z]+]]: !fir.array<2x!fir.real<4>>, [[Z2:%[0-9A-Za-z]+]]: !fir.array<2x!fir.real<4>>, [[Z3:%[0-9A-Za-z]+]]: !fir.array<2x!fir.real<4>>)
|
||||
// PPC-LABEL: func @multipleparamscomplex4
|
||||
// PPC-SAME: ([[A1:%[0-9A-Za-z]+]]: !fir.real<4>, [[B1:%[0-9A-Za-z]+]]: !fir.real<4>, [[A2:%[0-9A-Za-z]+]]: !fir.real<4>, [[B2:%[0-9A-Za-z]+]]: !fir.real<4>, [[A3:%[0-9A-Za-z]+]]: !fir.real<4>, [[B3:%[0-9A-Za-z]+]]: !fir.real<4>)
|
||||
func @multipleparamscomplex4(%z1 : !fir.complex<4>, %z2 : !fir.complex<4>, %z3 : !fir.complex<4>) {
|
||||
// I32-DAG: [[Z1_ADDR:%[0-9A-Za-z]+]] = fir.convert [[Z1]] : (!fir.ref<tuple<!fir.real<4>, !fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// I32-DAG: [[Z1_VAL:%[0-9A-Za-z]+]] = fir.load [[Z1_ADDR]] : !fir.ref<!fir.complex<4>>
|
||||
// I32-DAG: [[Z2_ADDR:%[0-9A-Za-z]+]] = fir.convert [[Z2]] : (!fir.ref<tuple<!fir.real<4>, !fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// I32-DAG: [[Z2_VAL:%[0-9A-Za-z]+]] = fir.load [[Z2_ADDR]] : !fir.ref<!fir.complex<4>>
|
||||
// I32-DAG: [[Z3_ADDR:%[0-9A-Za-z]+]] = fir.convert [[Z3]] : (!fir.ref<tuple<!fir.real<4>, !fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// I32-DAG: [[Z3_VAL:%[0-9A-Za-z]+]] = fir.load [[Z3_ADDR]] : !fir.ref<!fir.complex<4>>
|
||||
|
||||
// I32-DAG: [[Z1_ADDRC:%[0-9A-Za-z]+]] = fir.alloca !fir.complex<4>
|
||||
// I32-DAG: fir.store [[Z1_VAL]] to [[Z1_ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// I32-DAG: [[Z1_ADDRT:%[0-9A-Za-z]+]] = fir.convert [[Z1_ADDRC]] : (!fir.ref<!fir.complex<4>>) -> !fir.ref<tuple<!fir.real<4>, !fir.real<4>>>
|
||||
// I32-DAG: [[Z2_ADDRC:%[0-9A-Za-z]+]] = fir.alloca !fir.complex<4>
|
||||
// I32-DAG: fir.store [[Z2_VAL]] to [[Z2_ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// I32-DAG: [[Z2_ADDRT:%[0-9A-Za-z]+]] = fir.convert [[Z2_ADDRC]] : (!fir.ref<!fir.complex<4>>) -> !fir.ref<tuple<!fir.real<4>, !fir.real<4>>>
|
||||
// I32-DAG: [[Z3_ADDRC:%[0-9A-Za-z]+]] = fir.alloca !fir.complex<4>
|
||||
// I32-DAG: fir.store [[Z3_VAL]] to [[Z3_ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// I32-DAG: [[Z3_ADDRT:%[0-9A-Za-z]+]] = fir.convert [[Z3_ADDRC]] : (!fir.ref<!fir.complex<4>>) -> !fir.ref<tuple<!fir.real<4>, !fir.real<4>>>
|
||||
|
||||
// I32: fir.call @calleemultipleparamscomplex4([[Z1_ADDRT]], [[Z2_ADDRT]], [[Z3_ADDRT]]) : (!fir.ref<tuple<!fir.real<4>, !fir.real<4>>>, !fir.ref<tuple<!fir.real<4>, !fir.real<4>>>, !fir.ref<tuple<!fir.real<4>, !fir.real<4>>>) -> ()
|
||||
|
||||
// X64-DAG: [[Z3_ADDR:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:!fir.real<4>>
|
||||
// X64-DAG: fir.store [[Z3]] to [[Z3_ADDR]] : !fir.ref<!fir.vector<2:!fir.real<4>>>
|
||||
// X64-DAG: [[Z3_ADDRC:%[0-9A-Za-z]+]] = fir.convert [[Z3_ADDR]] : (!fir.ref<!fir.vector<2:!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// X64-DAG: [[Z3_VAL:%[0-9A-Za-z]+]] = fir.load [[Z3_ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// X64-DAG: [[Z2_ADDR:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:!fir.real<4>>
|
||||
// X64-DAG: fir.store [[Z2]] to [[Z2_ADDR]] : !fir.ref<!fir.vector<2:!fir.real<4>>>
|
||||
// X64-DAG: [[Z2_ADDRC:%[0-9A-Za-z]+]] = fir.convert [[Z2_ADDR]] : (!fir.ref<!fir.vector<2:!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// X64-DAG: [[Z2_VAL:%[0-9A-Za-z]+]] = fir.load [[Z2_ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// X64-DAG: [[Z1_ADDR:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:!fir.real<4>>
|
||||
// X64-DAG: fir.store [[Z1]] to [[Z1_ADDR]] : !fir.ref<!fir.vector<2:!fir.real<4>>>
|
||||
// X64-DAG: [[Z1_ADDRC:%[0-9A-Za-z]+]] = fir.convert [[Z1_ADDR]] : (!fir.ref<!fir.vector<2:!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// X64-DAG: [[Z1_VAL:%[0-9A-Za-z]+]] = fir.load [[Z1_ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
|
||||
// X64-DAG: [[Z1_ADDRV:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:!fir.real<4>>
|
||||
// X64-DAG: [[Z1_ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[Z1_ADDRV]] : (!fir.ref<!fir.vector<2:!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// X64-DAG: fir.store [[Z1_VAL]] to [[Z1_ADDRC2]] : !fir.ref<!fir.complex<4>>
|
||||
// X64-DAG: [[Z1_RELOADED:%[0-9A-Za-z]+]] = fir.load [[Z1_ADDRV]] : !fir.ref<!fir.vector<2:!fir.real<4>>>
|
||||
// X64-DAG: [[Z2_ADDRV:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:!fir.real<4>>
|
||||
// X64-DAG: [[Z2_ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[Z2_ADDRV]] : (!fir.ref<!fir.vector<2:!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// X64-DAG: fir.store [[Z2_VAL]] to [[Z2_ADDRC2]] : !fir.ref<!fir.complex<4>>
|
||||
// X64-DAG: [[Z2_RELOADED:%[0-9A-Za-z]+]] = fir.load [[Z2_ADDRV]] : !fir.ref<!fir.vector<2:!fir.real<4>>>
|
||||
// X64-DAG: [[Z3_ADDRV:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:!fir.real<4>>
|
||||
// X64-DAG: [[Z3_ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[Z3_ADDRV]] : (!fir.ref<!fir.vector<2:!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// X64-DAG: fir.store [[Z3_VAL]] to [[Z3_ADDRC2]] : !fir.ref<!fir.complex<4>>
|
||||
// X64-DAG: [[Z3_RELOADED:%[0-9A-Za-z]+]] = fir.load [[Z3_ADDRV]] : !fir.ref<!fir.vector<2:!fir.real<4>>>
|
||||
|
||||
// X64: fir.call @calleemultipleparamscomplex4([[Z1_RELOADED]], [[Z2_RELOADED]], [[Z3_RELOADED]]) : (!fir.vector<2:!fir.real<4>>, !fir.vector<2:!fir.real<4>>, !fir.vector<2:!fir.real<4>>) -> ()
|
||||
|
||||
// AARCH64-DAG: [[Z3_ARR:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2x!fir.real<4>>
|
||||
// AARCH64-DAG: fir.store [[Z3]] to [[Z3_ARR]] : !fir.ref<!fir.array<2x!fir.real<4>>>
|
||||
// AARCH64-DAG: [[Z3_ADDRC:%[0-9A-Za-z]+]] = fir.convert [[Z3_ARR]] : (!fir.ref<!fir.array<2x!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// AARCH64-DAG: [[Z3_VAL:%[0-9A-Za-z]+]] = fir.load [[Z3_ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// AARCH64-DAG: [[Z2_ARR:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2x!fir.real<4>>
|
||||
// AARCH64-DAG: fir.store [[Z2]] to [[Z2_ARR]] : !fir.ref<!fir.array<2x!fir.real<4>>>
|
||||
// AARCH64-DAG: [[Z2_ADDRC:%[0-9A-Za-z]+]] = fir.convert [[Z2_ARR]] : (!fir.ref<!fir.array<2x!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// AARCH64-DAG: [[Z2_VAL:%[0-9A-Za-z]+]] = fir.load [[Z2_ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
// AARCH64-DAG: [[Z1_ARR:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2x!fir.real<4>>
|
||||
// AARCH64-DAG: fir.store [[Z1]] to [[Z1_ARR]] : !fir.ref<!fir.array<2x!fir.real<4>>>
|
||||
// AARCH64-DAG: [[Z1_ADDRC:%[0-9A-Za-z]+]] = fir.convert [[Z1_ARR]] : (!fir.ref<!fir.array<2x!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// AARCH64-DAG: [[Z1_VAL:%[0-9A-Za-z]+]] = fir.load [[Z1_ADDRC]] : !fir.ref<!fir.complex<4>>
|
||||
|
||||
// AARCH64-DAG: [[Z1_ARR2:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2x!fir.real<4>>
|
||||
// AARCH64-DAG: [[Z1_ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[Z1_ARR2]] : (!fir.ref<!fir.array<2x!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// AARCH64-DAG: fir.store [[Z1_VAL]] to [[Z1_ADDRC2]] : !fir.ref<!fir.complex<4>>
|
||||
// AARCH64-DAG: [[Z1_RELOADED:%[0-9A-Za-z]+]] = fir.load [[Z1_ARR2]] : !fir.ref<!fir.array<2x!fir.real<4>>>
|
||||
// AARCH64-DAG: [[Z2_ARR2:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2x!fir.real<4>>
|
||||
// AARCH64-DAG: [[Z2_ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[Z2_ARR2]] : (!fir.ref<!fir.array<2x!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// AARCH64-DAG: fir.store [[Z2_VAL]] to [[Z2_ADDRC2]] : !fir.ref<!fir.complex<4>>
|
||||
// AARCH64-DAG: [[Z2_RELOADED:%[0-9A-Za-z]+]] = fir.load [[Z2_ARR2]] : !fir.ref<!fir.array<2x!fir.real<4>>>
|
||||
// AARCH64-DAG: [[Z3_ARR2:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2x!fir.real<4>>
|
||||
// AARCH64-DAG: [[Z3_ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[Z3_ARR2]] : (!fir.ref<!fir.array<2x!fir.real<4>>>) -> !fir.ref<!fir.complex<4>>
|
||||
// AARCH64-DAG: fir.store [[Z3_VAL]] to [[Z3_ADDRC2]] : !fir.ref<!fir.complex<4>>
|
||||
// AARCH64-DAG: [[Z3_RELOADED:%[0-9A-Za-z]+]] = fir.load [[Z3_ARR2]] : !fir.ref<!fir.array<2x!fir.real<4>>>
|
||||
|
||||
// AARCH64: fir.call @calleemultipleparamscomplex4([[Z1_RELOADED]], [[Z2_RELOADED]], [[Z3_RELOADED]]) : (!fir.array<2x!fir.real<4>>, !fir.array<2x!fir.real<4>>, !fir.array<2x!fir.real<4>>) -> ()
|
||||
|
||||
// PPC-DAG: [[Z3_EMPTY:%[0-9A-Za-z]+]] = fir.undefined !fir.complex<4>
|
||||
// PPC-DAG: [[Z3_PARTIAL:%[0-9A-Za-z]+]] = fir.insert_value [[Z3_EMPTY]], [[A3]], [0 : index] : (!fir.complex<4>, !fir.real<4>) -> !fir.complex<4>
|
||||
// PPC-DAG: [[Z3:%[0-9A-Za-z]+]] = fir.insert_value [[Z3_PARTIAL]], [[B3]], [1 : index] : (!fir.complex<4>, !fir.real<4>) -> !fir.complex<4>
|
||||
// PPC-DAG: [[Z2_EMPTY:%[0-9A-Za-z]+]] = fir.undefined !fir.complex<4>
|
||||
// PPC-DAG: [[Z2_PARTIAL:%[0-9A-Za-z]+]] = fir.insert_value [[Z2_EMPTY]], [[A2]], [0 : index] : (!fir.complex<4>, !fir.real<4>) -> !fir.complex<4>
|
||||
// PPC-DAG: [[Z2:%[0-9A-Za-z]+]] = fir.insert_value [[Z2_PARTIAL]], [[B2]], [1 : index] : (!fir.complex<4>, !fir.real<4>) -> !fir.complex<4>
|
||||
// PPC-DAG: [[Z1_EMPTY:%[0-9A-Za-z]+]] = fir.undefined !fir.complex<4>
|
||||
// PPC-DAG: [[Z1_PARTIAL:%[0-9A-Za-z]+]] = fir.insert_value [[Z1_EMPTY]], [[A1]], [0 : index] : (!fir.complex<4>, !fir.real<4>) -> !fir.complex<4>
|
||||
// PPC-DAG: [[Z1:%[0-9A-Za-z]+]] = fir.insert_value [[Z1_PARTIAL]], [[B1]], [1 : index] : (!fir.complex<4>, !fir.real<4>) -> !fir.complex<4>
|
||||
|
||||
// PPC-DAG: [[A1_EXTR:%[0-9A-Za-z]+]] = fir.extract_value [[Z1]], [0 : index] : (!fir.complex<4>) -> !fir.real<4>
|
||||
// PPC-DAG: [[B1_EXTR:%[0-9A-Za-z]+]] = fir.extract_value [[Z1]], [1 : index] : (!fir.complex<4>) -> !fir.real<4>
|
||||
// PPC-DAG: [[A2_EXTR:%[0-9A-Za-z]+]] = fir.extract_value [[Z2]], [0 : index] : (!fir.complex<4>) -> !fir.real<4>
|
||||
// PPC-DAG: [[B2_EXTR:%[0-9A-Za-z]+]] = fir.extract_value [[Z2]], [1 : index] : (!fir.complex<4>) -> !fir.real<4>
|
||||
// PPC-DAG: [[A3_EXTR:%[0-9A-Za-z]+]] = fir.extract_value [[Z3]], [0 : index] : (!fir.complex<4>) -> !fir.real<4>
|
||||
// PPC-DAG: [[B3_EXTR:%[0-9A-Za-z]+]] = fir.extract_value [[Z3]], [1 : index] : (!fir.complex<4>) -> !fir.real<4>
|
||||
|
||||
// PPC: fir.call @calleemultipleparamscomplex4([[A1_EXTR]], [[B1_EXTR]], [[A2_EXTR]], [[B2_EXTR]], [[A3_EXTR]], [[B3_EXTR]]) : (!fir.real<4>, !fir.real<4>, !fir.real<4>, !fir.real<4>, !fir.real<4>, !fir.real<4>) -> ()
|
||||
|
||||
fir.call @calleemultipleparamscomplex4(%z1, %z2, %z3) : (!fir.complex<4>, !fir.complex<4>, !fir.complex<4>) -> ()
|
||||
return
|
||||
}
|
||||
|
||||
// Test that we rewrite the signature of and calls to a function that accepts
|
||||
// and returns MLIR complex<f32>.
|
||||
|
||||
// I32-LABEL: func private @mlircomplexf32
|
||||
// I32-SAME: ([[Z1:%[0-9A-Za-z]+]]: !fir.ref<tuple<f32, f32>> {llvm.align = 4 : i32, llvm.byval}, [[Z2:%[0-9A-Za-z]+]]: !fir.ref<tuple<f32, f32>> {llvm.align = 4 : i32, llvm.byval})
|
||||
// I32-SAME: -> i64
|
||||
// X64-LABEL: func private @mlircomplexf32
|
||||
// X64-SAME: ([[Z1:%[0-9A-Za-z]+]]: !fir.vector<2:f32>, [[Z2:%[0-9A-Za-z]+]]: !fir.vector<2:f32>)
|
||||
// X64-SAME: -> !fir.vector<2:f32>
|
||||
// AARCH64-LABEL: func private @mlircomplexf32
|
||||
// AARCH64-SAME: ([[Z1:%[0-9A-Za-z]+]]: !fir.array<2xf32>, [[Z2:%[0-9A-Za-z]+]]: !fir.array<2xf32>)
|
||||
// AARCH64-SAME: -> tuple<f32, f32>
|
||||
// PPC-LABEL: func private @mlircomplexf32
|
||||
// PPC-SAME: ([[A1:%[0-9A-Za-z]+]]: f32, [[B1:%[0-9A-Za-z]+]]: f32, [[A2:%[0-9A-Za-z]+]]: f32, [[B2:%[0-9A-Za-z]+]]: f32)
|
||||
// PPC-SAME: -> tuple<f32, f32>
|
||||
func private @mlircomplexf32(%z1: complex<f32>, %z2: complex<f32>) -> complex<f32> {
|
||||
|
||||
// I32-DAG: [[Z1_ADDR:%[0-9A-Za-z]+]] = fir.convert [[Z1]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
|
||||
// I32-DAG: [[Z1_VAL:%[0-9A-Za-z]+]] = fir.load [[Z1_ADDR]] : !fir.ref<complex<f32>>
|
||||
// I32-DAG: [[Z2_ADDR:%[0-9A-Za-z]+]] = fir.convert [[Z2]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
|
||||
// I32-DAG: [[Z2_VAL:%[0-9A-Za-z]+]] = fir.load [[Z2_ADDR]] : !fir.ref<complex<f32>>
|
||||
|
||||
// I32-DAG: [[Z1_ADDRC:%[0-9A-Za-z]+]] = fir.alloca complex<f32>
|
||||
// I32-DAG: fir.store [[Z1_VAL]] to [[Z1_ADDRC]] : !fir.ref<complex<f32>>
|
||||
// I32-DAG: [[Z1_ADDRT:%[0-9A-Za-z]+]] = fir.convert [[Z1_ADDRC]] : (!fir.ref<complex<f32>>) -> !fir.ref<tuple<f32, f32>>
|
||||
// I32-DAG: [[Z2_ADDRC:%[0-9A-Za-z]+]] = fir.alloca complex<f32>
|
||||
// I32-DAG: fir.store [[Z2_VAL]] to [[Z2_ADDRC]] : !fir.ref<complex<f32>>
|
||||
// I32-DAG: [[Z2_ADDRT:%[0-9A-Za-z]+]] = fir.convert [[Z2_ADDRC]] : (!fir.ref<complex<f32>>) -> !fir.ref<tuple<f32, f32>>
|
||||
|
||||
// I32: [[VAL:%[0-9A-Za-z]+]] = fir.call @mlircomplexf32([[Z1_ADDRT]], [[Z2_ADDRT]]) : (!fir.ref<tuple<f32, f32>>, !fir.ref<tuple<f32, f32>>) -> i64
|
||||
|
||||
// X64-DAG: [[Z2_ADDR:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:f32>
|
||||
// X64-DAG: fir.store [[Z2]] to [[Z2_ADDR]] : !fir.ref<!fir.vector<2:f32>>
|
||||
// X64-DAG: [[Z2_ADDRC:%[0-9A-Za-z]+]] = fir.convert [[Z2_ADDR]] : (!fir.ref<!fir.vector<2:f32>>) -> !fir.ref<complex<f32>>
|
||||
// X64-DAG: [[Z2_VAL:%[0-9A-Za-z]+]] = fir.load [[Z2_ADDRC]] : !fir.ref<complex<f32>>
|
||||
// X64-DAG: [[Z1_ADDR:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:f32>
|
||||
// X64-DAG: fir.store [[Z1]] to [[Z1_ADDR]] : !fir.ref<!fir.vector<2:f32>>
|
||||
// X64-DAG: [[Z1_ADDRC:%[0-9A-Za-z]+]] = fir.convert [[Z1_ADDR]] : (!fir.ref<!fir.vector<2:f32>>) -> !fir.ref<complex<f32>>
|
||||
// X64-DAG: [[Z1_VAL:%[0-9A-Za-z]+]] = fir.load [[Z1_ADDRC]] : !fir.ref<complex<f32>>
|
||||
|
||||
// X64-DAG: [[Z1_ADDRV:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:f32>
|
||||
// X64-DAG: [[Z1_ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[Z1_ADDRV]] : (!fir.ref<!fir.vector<2:f32>>) -> !fir.ref<complex<f32>>
|
||||
// X64-DAG: fir.store [[Z1_VAL]] to [[Z1_ADDRC2]] : !fir.ref<complex<f32>>
|
||||
// X64-DAG: [[Z1_RELOADED:%[0-9A-Za-z]+]] = fir.load [[Z1_ADDRV]] : !fir.ref<!fir.vector<2:f32>>
|
||||
// X64-DAG: [[Z2_ADDRV:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:f32>
|
||||
// X64-DAG: [[Z2_ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[Z2_ADDRV]] : (!fir.ref<!fir.vector<2:f32>>) -> !fir.ref<complex<f32>>
|
||||
// X64-DAG: fir.store [[Z2_VAL]] to [[Z2_ADDRC2]] : !fir.ref<complex<f32>>
|
||||
// X64-DAG: [[Z2_RELOADED:%[0-9A-Za-z]+]] = fir.load [[Z2_ADDRV]] : !fir.ref<!fir.vector<2:f32>>
|
||||
|
||||
// X64: [[VAL:%[0-9A-Za-z]+]] = fir.call @mlircomplexf32([[Z1_RELOADED]], [[Z2_RELOADED]]) : (!fir.vector<2:f32>, !fir.vector<2:f32>) -> !fir.vector<2:f32>
|
||||
|
||||
// AARCH64-DAG: [[Z2_ARR:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2xf32>
|
||||
// AARCH64-DAG: fir.store [[Z2]] to [[Z2_ARR]] : !fir.ref<!fir.array<2xf32>>
|
||||
// AARCH64-DAG: [[Z2_ADDRC:%[0-9A-Za-z]+]] = fir.convert [[Z2_ARR]] : (!fir.ref<!fir.array<2xf32>>) -> !fir.ref<complex<f32>>
|
||||
// AARCH64-DAG: [[Z2_VAL:%[0-9A-Za-z]+]] = fir.load [[Z2_ADDRC]] : !fir.ref<complex<f32>>
|
||||
// AARCH64-DAG: [[Z1_ARR:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2xf32>
|
||||
// AARCH64-DAG: fir.store [[Z1]] to [[Z1_ARR]] : !fir.ref<!fir.array<2xf32>>
|
||||
// AARCH64-DAG: [[Z1_ADDRC:%[0-9A-Za-z]+]] = fir.convert [[Z1_ARR]] : (!fir.ref<!fir.array<2xf32>>) -> !fir.ref<complex<f32>>
|
||||
// AARCH64-DAG: [[Z1_VAL:%[0-9A-Za-z]+]] = fir.load [[Z1_ADDRC]] : !fir.ref<complex<f32>>
|
||||
|
||||
// AARCH64-DAG: [[Z1_ARR2:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2xf32>
|
||||
// AARCH64-DAG: [[Z1_ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[Z1_ARR2]] : (!fir.ref<!fir.array<2xf32>>) -> !fir.ref<complex<f32>>
|
||||
// AARCH64-DAG: fir.store [[Z1_VAL]] to [[Z1_ADDRC2]] : !fir.ref<complex<f32>>
|
||||
// AARCH64-DAG: [[Z1_RELOADED:%[0-9A-Za-z]+]] = fir.load [[Z1_ARR2]] : !fir.ref<!fir.array<2xf32>>
|
||||
// AARCH64-DAG: [[Z2_ARR2:%[0-9A-Za-z]+]] = fir.alloca !fir.array<2xf32>
|
||||
// AARCH64-DAG: [[Z2_ADDRC2:%[0-9A-Za-z]+]] = fir.convert [[Z2_ARR2]] : (!fir.ref<!fir.array<2xf32>>) -> !fir.ref<complex<f32>>
|
||||
// AARCH64-DAG: fir.store [[Z2_VAL]] to [[Z2_ADDRC2]] : !fir.ref<complex<f32>>
|
||||
// AARCH64-DAG: [[Z2_RELOADED:%[0-9A-Za-z]+]] = fir.load [[Z2_ARR2]] : !fir.ref<!fir.array<2xf32>>
|
||||
|
||||
// AARCH64: [[VAL:%[0-9A-Za-z]+]] = fir.call @mlircomplexf32([[Z1_RELOADED]], [[Z2_RELOADED]]) : (!fir.array<2xf32>, !fir.array<2xf32>) -> tuple<f32, f32>
|
||||
|
||||
// PPC-DAG: [[Z2_EMPTY:%[0-9A-Za-z]+]] = fir.undefined complex<f32>
|
||||
// PPC-DAG: [[Z2_PARTIAL:%[0-9A-Za-z]+]] = fir.insert_value [[Z2_EMPTY]], [[A2]], [0 : index] : (complex<f32>, f32) -> complex<f32>
|
||||
// PPC-DAG: [[Z2:%[0-9A-Za-z]+]] = fir.insert_value [[Z2_PARTIAL]], [[B2]], [1 : index] : (complex<f32>, f32) -> complex<f32>
|
||||
// PPC-DAG: [[Z1_EMPTY:%[0-9A-Za-z]+]] = fir.undefined complex<f32>
|
||||
// PPC-DAG: [[Z1_PARTIAL:%[0-9A-Za-z]+]] = fir.insert_value [[Z1_EMPTY]], [[A1]], [0 : index] : (complex<f32>, f32) -> complex<f32>
|
||||
// PPC-DAG: [[Z1:%[0-9A-Za-z]+]] = fir.insert_value [[Z1_PARTIAL]], [[B1]], [1 : index] : (complex<f32>, f32) -> complex<f32>
|
||||
|
||||
// PPC-DAG: [[A1_EXTR:%[0-9A-Za-z]+]] = fir.extract_value [[Z1]], [0 : index] : (complex<f32>) -> f32
|
||||
// PPC-DAG: [[B1_EXTR:%[0-9A-Za-z]+]] = fir.extract_value [[Z1]], [1 : index] : (complex<f32>) -> f32
|
||||
// PPC-DAG: [[A2_EXTR:%[0-9A-Za-z]+]] = fir.extract_value [[Z2]], [0 : index] : (complex<f32>) -> f32
|
||||
// PPC-DAG: [[B2_EXTR:%[0-9A-Za-z]+]] = fir.extract_value [[Z2]], [1 : index] : (complex<f32>) -> f32
|
||||
|
||||
// PPC: [[VAL:%[0-9A-Za-z]+]] = fir.call @mlircomplexf32([[A1_EXTR]], [[B1_EXTR]], [[A2_EXTR]], [[B2_EXTR]]) : (f32, f32, f32, f32) -> tuple<f32, f32>
|
||||
%0 = fir.call @mlircomplexf32(%z1, %z2) : (complex<f32>, complex<f32>) -> complex<f32>
|
||||
|
||||
|
||||
// I32: [[ADDRI64:%[0-9A-Za-z]+]] = fir.alloca i64
|
||||
// I32: fir.store [[VAL]] to [[ADDRI64]] : !fir.ref<i64>
|
||||
// I32: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRI64]] : (!fir.ref<i64>) -> !fir.ref<complex<f32>>
|
||||
// I32: [[VAL_2:%[0-9A-Za-z]+]] = fir.load [[ADDRC]] : !fir.ref<complex<f32>>
|
||||
// I32: [[ADDRI64_2:%[0-9A-Za-z]+]] = fir.alloca i64
|
||||
// I32: [[ADDRC_2:%[0-9A-Za-z]+]] = fir.convert [[ADDRI64_2]] : (!fir.ref<i64>) -> !fir.ref<complex<f32>>
|
||||
// I32: fir.store [[VAL_2]] to [[ADDRC_2]] : !fir.ref<complex<f32>>
|
||||
// I32: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRI64_2]] : !fir.ref<i64>
|
||||
// I32: return [[RES]] : i64
|
||||
|
||||
// X64: [[ADDRV:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:f32>
|
||||
// X64: fir.store [[VAL]] to [[ADDRV]] : !fir.ref<!fir.vector<2:f32>>
|
||||
// X64: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRV]] : (!fir.ref<!fir.vector<2:f32>>) -> !fir.ref<complex<f32>>
|
||||
// X64: [[V:%[0-9A-Za-z]+]] = fir.load [[ADDRC]] : !fir.ref<complex<f32>>
|
||||
// X64: [[ADDRV_2:%[0-9A-Za-z]+]] = fir.alloca !fir.vector<2:f32>
|
||||
// X64: [[ADDRC_2:%[0-9A-Za-z]+]] = fir.convert [[ADDRV_2]] : (!fir.ref<!fir.vector<2:f32>>) -> !fir.ref<complex<f32>>
|
||||
// X64: fir.store [[V]] to [[ADDRC_2]] : !fir.ref<complex<f32>>
|
||||
// X64: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRV_2]] : !fir.ref<!fir.vector<2:f32>>
|
||||
// X64: return [[RES]] : !fir.vector<2:f32>
|
||||
|
||||
// AARCH64: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<f32, f32>
|
||||
// AARCH64: fir.store [[VAL]] to [[ADDRT]] : !fir.ref<tuple<f32, f32>>
|
||||
// AARCH64: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
|
||||
// AARCH64: [[V:%[0-9A-Za-z]+]] = fir.load [[ADDRC]] : !fir.ref<complex<f32>>
|
||||
// AARCH64: [[ADDRT_2:%[0-9A-Za-z]+]] = fir.alloca tuple<f32, f32>
|
||||
// AARCH64: [[ADDRC_2:%[0-9A-Za-z]+]] = fir.convert [[ADDRT_2]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
|
||||
// AARCH64: fir.store [[V]] to [[ADDRC_2]] : !fir.ref<complex<f32>>
|
||||
// AARCH64: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRT_2]] : !fir.ref<tuple<f32, f32>>
|
||||
// AARCH64: return [[RES]] : tuple<f32, f32>
|
||||
|
||||
// PPC: [[ADDRT:%[0-9A-Za-z]+]] = fir.alloca tuple<f32, f32>
|
||||
// PPC: fir.store [[VAL]] to [[ADDRT]] : !fir.ref<tuple<f32, f32>>
|
||||
// PPC: [[ADDRC:%[0-9A-Za-z]+]] = fir.convert [[ADDRT]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
|
||||
// PPC: [[V:%[0-9A-Za-z]+]] = fir.load [[ADDRC]] : !fir.ref<complex<f32>>
|
||||
// PPC: [[ADDRT_2:%[0-9A-Za-z]+]] = fir.alloca tuple<f32, f32>
|
||||
// PPC: [[ADDRC_2:%[0-9A-Za-z]+]] = fir.convert [[ADDRT_2]] : (!fir.ref<tuple<f32, f32>>) -> !fir.ref<complex<f32>>
|
||||
// PPC: fir.store [[V]] to [[ADDRC_2]] : !fir.ref<complex<f32>>
|
||||
// PPC: [[RES:%[0-9A-Za-z]+]] = fir.load [[ADDRT_2]] : !fir.ref<tuple<f32, f32>>
|
||||
// PPC: return [[RES]] : tuple<f32, f32>
|
||||
return %0 : complex<f32>
|
||||
}
|
Loading…
Reference in New Issue