Author: jeanPerier Date: 2024-10-10T17:24:23+02:00 New Revision: 7931f2ba5d2412af22b63318a941c9e3c4dbd8c5
URL: https://github.com/llvm/llvm-project/commit/7931f2ba5d2412af22b63318a941c9e3c4dbd8c5 DIFF: https://github.com/llvm/llvm-project/commit/7931f2ba5d2412af22b63318a941c9e3c4dbd8c5.diff LOG: Revert "[flang] correctly deal with bind(c) derived type result ABI (#111678)" This reverts commit 480e7f0667794822f7f3a065bed73d9a2ecc2d58. Added: Modified: flang/include/flang/Optimizer/CodeGen/Target.h flang/include/flang/Optimizer/Dialect/FIROpsSupport.h flang/lib/Optimizer/CodeGen/Target.cpp flang/lib/Optimizer/CodeGen/TargetRewrite.cpp flang/lib/Optimizer/Transforms/AbstractResult.cpp Removed: flang/test/Fir/abstract-results-bindc.fir flang/test/Fir/struct-return-x86-64.fir ################################################################################ diff --git a/flang/include/flang/Optimizer/CodeGen/Target.h b/flang/include/flang/Optimizer/CodeGen/Target.h index 3b38583511927a..a7161152a5c323 100644 --- a/flang/include/flang/Optimizer/CodeGen/Target.h +++ b/flang/include/flang/Optimizer/CodeGen/Target.h @@ -126,11 +126,6 @@ class CodeGenSpecifics { structArgumentType(mlir::Location loc, fir::RecordType recTy, const Marshalling &previousArguments) const = 0; - /// Type representation of a `fir.type<T>` type argument when returned by - /// value. Such value may need to be converted to a hidden reference argument. - virtual Marshalling structReturnType(mlir::Location loc, - fir::RecordType 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. /// diff --git a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h index fb7b1d16f62f3a..cdbefdb2341485 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h +++ b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h @@ -177,27 +177,6 @@ inline mlir::NamedAttribute getAdaptToByRefAttr(Builder &builder) { } bool isDummyArgument(mlir::Value v); - -template <fir::FortranProcedureFlagsEnum Flag> -inline bool hasProcedureAttr(fir::FortranProcedureFlagsEnumAttr flags) { - return flags && bitEnumContainsAny(flags.getValue(), Flag); -} - -template <fir::FortranProcedureFlagsEnum Flag> -inline bool hasProcedureAttr(mlir::Operation *op) { - if (auto firCallOp = mlir::dyn_cast<fir::CallOp>(op)) - return hasProcedureAttr<Flag>(firCallOp.getProcedureAttrsAttr()); - if (auto firCallOp = mlir::dyn_cast<fir::DispatchOp>(op)) - return hasProcedureAttr<Flag>(firCallOp.getProcedureAttrsAttr()); - return hasProcedureAttr<Flag>( - op->getAttrOfType<fir::FortranProcedureFlagsEnumAttr>( - getFortranProcedureFlagsAttrName())); -} - -inline bool hasBindcAttr(mlir::Operation *op) { - return hasProcedureAttr<fir::FortranProcedureFlagsEnum::bind_c>(op); -} - } // namespace fir #endif // FORTRAN_OPTIMIZER_DIALECT_FIROPSSUPPORT_H diff --git a/flang/lib/Optimizer/CodeGen/Target.cpp b/flang/lib/Optimizer/CodeGen/Target.cpp index 6c148dffb0e55a..a12b59413f4456 100644 --- a/flang/lib/Optimizer/CodeGen/Target.cpp +++ b/flang/lib/Optimizer/CodeGen/Target.cpp @@ -100,11 +100,6 @@ struct GenericTarget : public CodeGenSpecifics { TODO(loc, "passing VALUE BIND(C) derived type for this target"); } - CodeGenSpecifics::Marshalling - structReturnType(mlir::Location loc, fir::RecordType ty) const override { - TODO(loc, "returning BIND(C) derived type for this target"); - } - CodeGenSpecifics::Marshalling integerArgumentType(mlir::Location loc, mlir::IntegerType argTy) const override { @@ -538,8 +533,7 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> { /// When \p recTy is a one field record type that can be passed /// like the field on its own, returns the field type. Returns /// a null type otherwise. - mlir::Type passAsFieldIfOneFieldStruct(fir::RecordType recTy, - bool allowComplex = false) const { + mlir::Type passAsFieldIfOneFieldStruct(fir::RecordType recTy) const { auto typeList = recTy.getTypeList(); if (typeList.size() != 1) return {}; @@ -547,8 +541,6 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> { if (mlir::isa<mlir::FloatType, mlir::IntegerType, fir::LogicalType>( fieldType)) return fieldType; - if (allowComplex && mlir::isa<mlir::ComplexType>(fieldType)) - return fieldType; if (mlir::isa<fir::CharacterType>(fieldType)) { // Only CHARACTER(1) are expected in BIND(C) contexts, which is the only // contexts where derived type may be passed in registers. @@ -601,7 +593,7 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> { postMerge(byteOffset, Lo, Hi); if (Lo == ArgClass::Memory || Lo == ArgClass::X87 || Lo == ArgClass::ComplexX87) - return passOnTheStack(loc, recTy, /*isResult=*/false); + return passOnTheStack(loc, recTy); int neededIntRegisters = 0; int neededSSERegisters = 0; if (Lo == ArgClass::SSE) @@ -617,7 +609,7 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> { // all in registers or all on the stack). if (!hasEnoughRegisters(loc, neededIntRegisters, neededSSERegisters, previousArguments)) - return passOnTheStack(loc, recTy, /*isResult=*/false); + return passOnTheStack(loc, recTy); if (auto fieldType = passAsFieldIfOneFieldStruct(recTy)) { CodeGenSpecifics::Marshalling marshal; @@ -649,57 +641,9 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> { return marshal; } - CodeGenSpecifics::Marshalling - structReturnType(mlir::Location loc, fir::RecordType recTy) const override { - std::uint64_t byteOffset = 0; - ArgClass Lo, Hi; - Lo = Hi = ArgClass::NoClass; - byteOffset = classifyStruct(loc, recTy, byteOffset, Lo, Hi); - mlir::MLIRContext *context = recTy.getContext(); - postMerge(byteOffset, Lo, Hi); - if (Lo == ArgClass::Memory) - return passOnTheStack(loc, recTy, /*isResult=*/true); - - // Note that X87/ComplexX87 are passed in memory, but returned via %st0 - // %st1 registers. Here, they are returned as fp80 or {fp80, fp80} by - // passAsFieldIfOneFieldStruct, and LLVM will use the expected registers. - - // Note that {_Complex long double} is not 100% clear from an ABI - // perspective because the aggregate post merger rules say it should be - // passed in memory because it is bigger than 2 eight bytes. This has the - // funny effect of - // {_Complex long double} return to be dealt with diff erently than - // _Complex long double. - - if (auto fieldType = - passAsFieldIfOneFieldStruct(recTy, /*allowComplex=*/true)) { - if (auto complexType = mlir::dyn_cast<mlir::ComplexType>(fieldType)) - return complexReturnType(loc, complexType.getElementType()); - CodeGenSpecifics::Marshalling marshal; - marshal.emplace_back(fieldType, AT{}); - return marshal; - } - - if (Hi == ArgClass::NoClass || Hi == ArgClass::SSEUp) { - // Return a single integer or floating point argument. - mlir::Type lowType = pickLLVMArgType(loc, context, Lo, byteOffset); - CodeGenSpecifics::Marshalling marshal; - marshal.emplace_back(lowType, AT{}); - return marshal; - } - // Will be returned in two diff erent registers. Generate {lowTy, HiTy} for - // the LLVM IR result type. - CodeGenSpecifics::Marshalling marshal; - mlir::Type lowType = pickLLVMArgType(loc, context, Lo, 8u); - mlir::Type hiType = pickLLVMArgType(loc, context, Hi, byteOffset - 8u); - marshal.emplace_back(mlir::TupleType::get(context, {lowType, hiType}), - AT{}); - return marshal; - } - /// Marshal an argument that must be passed on the stack. - CodeGenSpecifics::Marshalling - passOnTheStack(mlir::Location loc, mlir::Type ty, bool isResult) const { + CodeGenSpecifics::Marshalling passOnTheStack(mlir::Location loc, + mlir::Type ty) const { CodeGenSpecifics::Marshalling marshal; auto sizeAndAlign = fir::getTypeSizeAndAlignmentOrCrash(loc, ty, getDataLayout(), kindMap); @@ -707,7 +651,7 @@ struct TargetX86_64 : public GenericTarget<TargetX86_64> { unsigned short align = std::max(sizeAndAlign.second, static_cast<unsigned short>(8)); marshal.emplace_back(fir::ReferenceType::get(ty), - AT{align, /*byval=*/!isResult, /*sret=*/isResult}); + AT{align, /*byval=*/true, /*sret=*/false}); return marshal; } }; diff --git a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp index 04a3ea684642c8..fd56fd6bf50f44 100644 --- a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp +++ b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp @@ -142,16 +142,20 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> { mlir::ModuleOp getModule() { return getOperation(); } - template <typename Ty, typename Callback> + template <typename A, typename B, typename C> std::optional<std::function<mlir::Value(mlir::Operation *)>> - rewriteCallResultType(mlir::Location loc, mlir::Type originalResTy, - Ty &newResTys, - fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs, - Callback &newOpers, mlir::Value &savedStackPtr, - fir::CodeGenSpecifics::Marshalling &m) { - // Currently, targets mandate COMPLEX or STRUCT is a single aggregate or - // packed scalar, including the sret case. - assert(m.size() == 1 && "return type not supported on this target"); + rewriteCallComplexResultType( + mlir::Location loc, A ty, B &newResTys, + fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs, C &newOpers, + mlir::Value &savedStackPtr) { + if (noComplexConversion) { + newResTys.push_back(ty); + return std::nullopt; + } + auto m = specifics->complexReturnType(loc, ty.getElementType()); + // Currently targets mandate COMPLEX is a single aggregate or packed + // scalar, including the sret case. + assert(m.size() == 1 && "target of complex return not supported"); auto resTy = std::get<mlir::Type>(m[0]); auto attr = std::get<fir::CodeGenSpecifics::Attributes>(m[0]); if (attr.isSRet()) { @@ -166,7 +170,7 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> { newInTyAndAttrs.push_back(m[0]); newOpers.push_back(stack); return [=](mlir::Operation *) -> mlir::Value { - auto memTy = fir::ReferenceType::get(originalResTy); + auto memTy = fir::ReferenceType::get(ty); auto cast = rewriter->create<fir::ConvertOp>(loc, memTy, stack); return rewriter->create<fir::LoadOp>(loc, cast); }; @@ -176,41 +180,11 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> { // We are going to generate an alloca, so save the stack pointer. if (!savedStackPtr) savedStackPtr = genStackSave(loc); - return this->convertValueInMemory(loc, call->getResult(0), originalResTy, + return this->convertValueInMemory(loc, call->getResult(0), ty, /*inputMayBeBigger=*/true); }; } - template <typename Ty, typename Callback> - std::optional<std::function<mlir::Value(mlir::Operation *)>> - rewriteCallComplexResultType( - mlir::Location loc, mlir::ComplexType ty, Ty &newResTys, - fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs, Callback &newOpers, - mlir::Value &savedStackPtr) { - if (noComplexConversion) { - newResTys.push_back(ty); - return std::nullopt; - } - auto m = specifics->complexReturnType(loc, ty.getElementType()); - return rewriteCallResultType(loc, ty, newResTys, newInTyAndAttrs, newOpers, - savedStackPtr, m); - } - - template <typename Ty, typename Callback> - std::optional<std::function<mlir::Value(mlir::Operation *)>> - rewriteCallStructResultType( - mlir::Location loc, fir::RecordType recTy, Ty &newResTys, - fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs, Callback &newOpers, - mlir::Value &savedStackPtr) { - if (noStructConversion) { - newResTys.push_back(recTy); - return std::nullopt; - } - auto m = specifics->structReturnType(loc, recTy); - return rewriteCallResultType(loc, recTy, newResTys, newInTyAndAttrs, - newOpers, savedStackPtr, m); - } - void passArgumentOnStackOrWithNewType( mlir::Location loc, fir::CodeGenSpecifics::TypeAndAttr newTypeAndAttr, mlir::Type oldType, mlir::Value oper, @@ -382,11 +356,6 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> { newInTyAndAttrs, newOpers, savedStackPtr); }) - .template Case<fir::RecordType>([&](fir::RecordType recTy) { - wrap = rewriteCallStructResultType(loc, recTy, newResTys, - newInTyAndAttrs, newOpers, - savedStackPtr); - }) .Default([&](mlir::Type ty) { newResTys.push_back(ty); }); } else if (fnTy.getResults().size() > 1) { TODO(loc, "multiple results not supported yet"); @@ -593,24 +562,6 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> { } } - template <typename Ty> - void - lowerStructSignatureRes(mlir::Location loc, fir::RecordType recTy, - Ty &newResTys, - fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs) { - if (noComplexConversion) { - newResTys.push_back(recTy); - return; - } else { - for (auto &tup : specifics->structReturnType(loc, recTy)) { - if (std::get<fir::CodeGenSpecifics::Attributes>(tup).isSRet()) - newInTyAndAttrs.push_back(tup); - else - newResTys.push_back(std::get<mlir::Type>(tup)); - } - } - } - void lowerStructSignatureArg(mlir::Location loc, fir::RecordType recTy, fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs) { @@ -644,9 +595,6 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> { .Case<mlir::ComplexType>([&](mlir::ComplexType ty) { lowerComplexSignatureRes(loc, ty, newResTys, newInTyAndAttrs); }) - .Case<fir::RecordType>([&](fir::RecordType ty) { - lowerStructSignatureRes(loc, ty, newResTys, newInTyAndAttrs); - }) .Default([&](mlir::Type ty) { newResTys.push_back(ty); }); } llvm::SmallVector<mlir::Type> trailingInTys; @@ -748,8 +696,7 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> { for (auto ty : func.getResults()) if ((mlir::isa<fir::BoxCharType>(ty) && !noCharacterConversion) || (fir::isa_complex(ty) && !noComplexConversion) || - (mlir::isa<mlir::IntegerType>(ty) && hasCCallingConv) || - (mlir::isa<fir::RecordType>(ty) && !noStructConversion)) { + (mlir::isa<mlir::IntegerType>(ty) && hasCCallingConv)) { LLVM_DEBUG(llvm::dbgs() << "rewrite " << signature << " for target\n"); return false; } @@ -823,9 +770,6 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> { rewriter->getUnitAttr())); newResTys.push_back(retTy); }) - .Case<fir::RecordType>([&](fir::RecordType recTy) { - doStructReturn(func, recTy, newResTys, newInTyAndAttrs, fixups); - }) .Default([&](mlir::Type ty) { newResTys.push_back(ty); }); // Saved potential shift in argument. Handling of result can add arguments @@ -1118,12 +1062,21 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> { 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 Ty, typename FIXUPS> - void doReturn(mlir::func::FuncOp func, Ty &newResTys, - fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs, - FIXUPS &fixups, fir::CodeGenSpecifics::Marshalling &m) { - assert(m.size() == 1 && - "expect result to be turned into single argument or result so far"); + void doComplexReturn(mlir::func::FuncOp func, mlir::ComplexType cmplx, + Ty &newResTys, + fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs, + FIXUPS &fixups) { + if (noComplexConversion) { + newResTys.push_back(cmplx); + return; + } + auto m = + specifics->complexReturnType(func.getLoc(), cmplx.getElementType()); + assert(m.size() == 1); auto &tup = m[0]; auto attr = std::get<fir::CodeGenSpecifics::Attributes>(tup); auto argTy = std::get<mlir::Type>(tup); @@ -1164,36 +1117,6 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> { newResTys.push_back(argTy); } - /// 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 Ty, typename FIXUPS> - void doComplexReturn(mlir::func::FuncOp func, mlir::ComplexType cmplx, - Ty &newResTys, - fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs, - FIXUPS &fixups) { - if (noComplexConversion) { - newResTys.push_back(cmplx); - return; - } - auto m = - specifics->complexReturnType(func.getLoc(), cmplx.getElementType()); - doReturn(func, newResTys, newInTyAndAttrs, fixups, m); - } - - template <typename Ty, typename FIXUPS> - void doStructReturn(mlir::func::FuncOp func, fir::RecordType recTy, - Ty &newResTys, - fir::CodeGenSpecifics::Marshalling &newInTyAndAttrs, - FIXUPS &fixups) { - if (noStructConversion) { - newResTys.push_back(recTy); - return; - } - auto m = specifics->structReturnType(func.getLoc(), recTy); - doReturn(func, newResTys, newInTyAndAttrs, fixups, m); - } - template <typename FIXUPS> void createFuncOpArgFixups(mlir::func::FuncOp func, diff --git a/flang/lib/Optimizer/Transforms/AbstractResult.cpp b/flang/lib/Optimizer/Transforms/AbstractResult.cpp index c0ec820d87ed44..7299ff80121e13 100644 --- a/flang/lib/Optimizer/Transforms/AbstractResult.cpp +++ b/flang/lib/Optimizer/Transforms/AbstractResult.cpp @@ -32,33 +32,6 @@ using namespace mlir; namespace fir { namespace { -// Helper to only build the symbol table if needed because its build time is -// linear on the number of symbols in the module. -struct LazySymbolTable { - LazySymbolTable(mlir::Operation *op) - : module{op->getParentOfType<mlir::ModuleOp>()} {} - void build() { - if (table) - return; - table = std::make_unique<mlir::SymbolTable>(module); - } - - template <typename T> - T lookup(llvm::StringRef name) { - build(); - return table->lookup<T>(name); - } - -private: - std::unique_ptr<mlir::SymbolTable> table; - mlir::ModuleOp module; -}; - -bool hasScalarDerivedResult(mlir::FunctionType funTy) { - return funTy.getNumResults() == 1 && - mlir::isa<fir::RecordType>(funTy.getResult(0)); -} - static mlir::Type getResultArgumentType(mlir::Type resultType, bool shouldBoxResult) { return llvm::TypeSwitch<mlir::Type, mlir::Type>(resultType) @@ -217,14 +190,7 @@ class SaveResultOpConversion llvm::LogicalResult matchAndRewrite(fir::SaveResultOp op, mlir::PatternRewriter &rewriter) const override { - mlir::Operation *call = op.getValue().getDefiningOp(); - if (mlir::isa<fir::RecordType>(op.getValue().getType()) && call && - fir::hasBindcAttr(call)) { - rewriter.replaceOpWithNewOp<fir::StoreOp>(op, op.getValue(), - op.getMemref()); - } else { - rewriter.eraseOp(op); - } + rewriter.eraseOp(op); return mlir::success(); } }; @@ -334,12 +300,6 @@ class AbstractResultOpt auto *context = &getContext(); // Convert function type itself if it has an abstract result. auto funcTy = mlir::cast<mlir::FunctionType>(func.getFunctionType()); - // Scalar derived result of BIND(C) function must be returned according - // to the C struct return ABI which is target dependent and implemented in - // the target-rewrite pass. - if (hasScalarDerivedResult(funcTy) && - fir::hasBindcAttr(func.getOperation())) - return; if (hasAbstractResult(funcTy)) { if (fir::isa_builtin_cptr_type(funcTy.getResult(0))) { func.setType(getCPtrFunctionType(funcTy)); @@ -435,8 +395,6 @@ class AbstractResultOpt return; } - LazySymbolTable symbolTable(op); - mlir::RewritePatternSet patterns(context); mlir::ConversionTarget target = *context; const bool shouldBoxResult = this->passResultAsBox.getValue(); @@ -451,29 +409,14 @@ class AbstractResultOpt mlir::func::FuncDialect>(); target.addIllegalOp<fir::SaveResultOp>(); target.addDynamicallyLegalOp<fir::CallOp>([](fir::CallOp call) { - mlir::FunctionType funTy = call.getFunctionType(); - if (hasScalarDerivedResult(funTy) && - fir::hasBindcAttr(call.getOperation())) - return true; - return !hasAbstractResult(funTy); + return !hasAbstractResult(call.getFunctionType()); }); - target.addDynamicallyLegalOp<fir::AddrOfOp>([&symbolTable]( - fir::AddrOfOp addrOf) { - if (auto funTy = mlir::dyn_cast<mlir::FunctionType>(addrOf.getType())) { - if (hasScalarDerivedResult(funTy)) { - auto func = symbolTable.lookup<mlir::func::FuncOp>( - addrOf.getSymbol().getRootReference().getValue()); - return func && fir::hasBindcAttr(func.getOperation()); - } + target.addDynamicallyLegalOp<fir::AddrOfOp>([](fir::AddrOfOp addrOf) { + if (auto funTy = mlir::dyn_cast<mlir::FunctionType>(addrOf.getType())) return !hasAbstractResult(funTy); - } return true; }); target.addDynamicallyLegalOp<fir::DispatchOp>([](fir::DispatchOp dispatch) { - mlir::FunctionType funTy = dispatch.getFunctionType(); - if (hasScalarDerivedResult(funTy) && - fir::hasBindcAttr(dispatch.getOperation())) - return true; return !hasAbstractResult(dispatch.getFunctionType()); }); diff --git a/flang/test/Fir/abstract-results-bindc.fir b/flang/test/Fir/abstract-results-bindc.fir deleted file mode 100644 index 9b26730f7d2923..00000000000000 --- a/flang/test/Fir/abstract-results-bindc.fir +++ /dev/null @@ -1,43 +0,0 @@ -// Test that bind_c derived type results are not moved to a hidden argument -// by the abstract-result pass. They will be dealt with according to the C -// struct returning ABI for the target in the target-rewrite pass. -// RUN: fir-opt %s --abstract-result | FileCheck %s - -!t = !fir.type<t{i:f32, j: i32, k: f32}> - -func.func private @foo() -> !t attributes {fir.proc_attrs = #fir.proc_attrs<bind_c>} - -func.func @test_call(%x: !fir.ref<!t>) { - %0 = fir.call @foo() proc_attrs<bind_c> : () -> !t - fir.save_result %0 to %x : !t, !fir.ref<!t> - return -} - -func.func @test_addr_of() -> (() -> !t) { - %0 = fir.address_of(@foo) : () -> !t - return %0 : () -> !t -} - -func.func @test_dispatch(%x: !fir.ref<!t>, %y : !fir.class<!fir.type<somet>>) { - %0 = fir.dispatch "bar"(%y : !fir.class<!fir.type<somet>>) (%y : !fir.class<!fir.type<somet>>) -> !t proc_attrs<bind_c> {pass_arg_pos = 0 : i32} - fir.save_result %0 to %x : !t, !fir.ref<!t> - return -} - -// CHECK-LABEL: func.func @test_call( -// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t{i:f32,j:i32,k:f32}>>) { -// CHECK: %[[VAL_1:.*]] = fir.call @foo() proc_attrs<bind_c> : () -> !fir.type<t{i:f32,j:i32,k:f32}> -// CHECK: fir.store %[[VAL_1]] to %[[VAL_0]] : !fir.ref<!fir.type<t{i:f32,j:i32,k:f32}>> -// CHECK: return -// CHECK: } -// CHECK-LABEL: func.func @test_addr_of() -> (() -> !fir.type<t{i:f32,j:i32,k:f32}>) { -// CHECK: %[[VAL_0:.*]] = fir.address_of(@foo) : () -> !fir.type<t{i:f32,j:i32,k:f32}> -// CHECK: return %[[VAL_0]] : () -> !fir.type<t{i:f32,j:i32,k:f32}> -// CHECK: } -// CHECK-LABEL: func.func @test_dispatch( -// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t{i:f32,j:i32,k:f32}>>, -// CHECK-SAME: %[[VAL_1:.*]]: !fir.class<!fir.type<somet>>) { -// CHECK: %[[VAL_2:.*]] = fir.dispatch "bar"(%[[VAL_1]] : !fir.class<!fir.type<somet>>) (%[[VAL_1]] : !fir.class<!fir.type<somet>>) -> !fir.type<t{i:f32,j:i32,k:f32}> proc_attrs <bind_c> {pass_arg_pos = 0 : i32} -// CHECK: fir.store %[[VAL_2]] to %[[VAL_0]] : !fir.ref<!fir.type<t{i:f32,j:i32,k:f32}>> -// CHECK: return -// CHECK: } diff --git a/flang/test/Fir/struct-return-x86-64.fir b/flang/test/Fir/struct-return-x86-64.fir deleted file mode 100644 index f4c2add69ff7e9..00000000000000 --- a/flang/test/Fir/struct-return-x86-64.fir +++ /dev/null @@ -1,120 +0,0 @@ -// Test X86-64 ABI rewrite of struct returned by value (BIND(C), VALUE derived types). -// REQUIRES: x86-registered-target -// RUN: fir-opt --target-rewrite %s | FileCheck %s - -!fits_in_reg = !fir.type<t1{i:f32,j:i32,k:f32}> -!too_big = !fir.type<t2{i:!fir.array<5xf32>}> - -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"} { - - func.func private @test_inreg() -> !fits_in_reg - func.func @test_call_inreg(%arg0: !fir.ref<!fits_in_reg>) { - %0 = fir.call @test_inreg() : () -> !fits_in_reg - fir.store %0 to %arg0 : !fir.ref<!fits_in_reg> - return - } - func.func @test_addr_of_inreg() -> (() -> ()) { - %0 = fir.address_of(@test_inreg) : () -> !fits_in_reg - %1 = fir.convert %0 : (() -> !fits_in_reg) -> (() -> ()) - return %1 : () -> () - } - func.func @test_dispatch_inreg(%arg0: !fir.ref<!fits_in_reg>, %arg1: !fir.class<!fir.type<somet>>) { - %0 = fir.dispatch "bar"(%arg1 : !fir.class<!fir.type<somet>>) (%arg1 : !fir.class<!fir.type<somet>>) -> !fits_in_reg {pass_arg_pos = 0 : i32} - fir.store %0 to %arg0 : !fir.ref<!fits_in_reg> - return - } - - func.func private @test_sret() -> !too_big - func.func @test_call_sret(%arg0: !fir.ref<!too_big>) { - %0 = fir.call @test_sret() : () -> !too_big - fir.store %0 to %arg0 : !fir.ref<!too_big> - return - } - func.func @test_addr_of_sret() -> (() -> ()) { - %0 = fir.address_of(@test_sret) : () -> !too_big - %1 = fir.convert %0 : (() -> !too_big) -> (() -> ()) - return %1 : () -> () - } - func.func @test_dispatch_sret(%arg0: !fir.ref<!too_big>, %arg1: !fir.class<!fir.type<somet>>) { - %0 = fir.dispatch "bar"(%arg1 : !fir.class<!fir.type<somet>>) (%arg1 : !fir.class<!fir.type<somet>>) -> !too_big {pass_arg_pos = 0 : i32} - fir.store %0 to %arg0 : !fir.ref<!too_big> - return - } - func.func private @test_fp_80() -> !fir.type<t3{i:f80}> - func.func private @test_complex_80() -> !fir.type<t4{i:complex<f80>}> - func.func private @test_two_fp_80() -> !fir.type<t5{i:f80,j:f80}> - func.func private @test_fp128() -> !fir.type<t6{i:f128}> -} - -// CHECK-LABEL: func.func private @test_inreg() -> tuple<i64, f32> - -// CHECK-LABEL: func.func @test_call_inreg( -// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>) { -// CHECK: %[[VAL_1:.*]] = fir.call @test_inreg() : () -> tuple<i64, f32> -// CHECK: %[[VAL_2:.*]] = llvm.intr.stacksave : !llvm.ptr -// CHECK: %[[VAL_3:.*]] = fir.alloca tuple<i64, f32> -// CHECK: fir.store %[[VAL_1]] to %[[VAL_3]] : !fir.ref<tuple<i64, f32>> -// CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<tuple<i64, f32>>) -> !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>> -// CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>> -// CHECK: llvm.intr.stackrestore %[[VAL_2]] : !llvm.ptr -// CHECK: fir.store %[[VAL_5]] to %[[VAL_0]] : !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>> -// CHECK: return -// CHECK: } - -// CHECK-LABEL: func.func @test_addr_of_inreg() -> (() -> ()) { -// CHECK: %[[VAL_0:.*]] = fir.address_of(@test_inreg) : () -> tuple<i64, f32> -// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (() -> tuple<i64, f32>) -> (() -> ()) -// CHECK: return %[[VAL_1]] : () -> () -// CHECK: } - -// CHECK-LABEL: func.func @test_dispatch_inreg( -// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>>, -// CHECK-SAME: %[[VAL_1:.*]]: !fir.class<!fir.type<somet>>) { -// CHECK: %[[VAL_2:.*]] = fir.dispatch "bar"(%[[VAL_1]] : !fir.class<!fir.type<somet>>) (%[[VAL_1]] : !fir.class<!fir.type<somet>>) -> tuple<i64, f32> {pass_arg_pos = 0 : i32} -// CHECK: %[[VAL_3:.*]] = llvm.intr.stacksave : !llvm.ptr -// CHECK: %[[VAL_4:.*]] = fir.alloca tuple<i64, f32> -// CHECK: fir.store %[[VAL_2]] to %[[VAL_4]] : !fir.ref<tuple<i64, f32>> -// CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<tuple<i64, f32>>) -> !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>> -// CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]] : !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>> -// CHECK: llvm.intr.stackrestore %[[VAL_3]] : !llvm.ptr -// CHECK: fir.store %[[VAL_6]] to %[[VAL_0]] : !fir.ref<!fir.type<t1{i:f32,j:i32,k:f32}>> -// CHECK: return -// CHECK: } -// CHECK: func.func private @test_sret(!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>> {llvm.align = 8 : i32, llvm.sret = !fir.type<t2{i:!fir.array<5xf32>}>}) - -// CHECK-LABEL: func.func @test_call_sret( -// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) { -// CHECK: %[[VAL_1:.*]] = llvm.intr.stacksave : !llvm.ptr -// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.type<t2{i:!fir.array<5xf32>}> -// CHECK: fir.call @test_sret(%[[VAL_2]]) : (!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> () -// CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>> -// CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]] : !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>> -// CHECK: llvm.intr.stackrestore %[[VAL_1]] : !llvm.ptr -// CHECK: fir.store %[[VAL_4]] to %[[VAL_0]] : !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>> -// CHECK: return -// CHECK: } - -// CHECK-LABEL: func.func @test_addr_of_sret() -> (() -> ()) { -// CHECK: %[[VAL_0:.*]] = fir.address_of(@test_sret) : (!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> () -// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : ((!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> ()) -> (() -> ()) -// CHECK: return %[[VAL_1]] : () -> () -// CHECK: } - -// CHECK-LABEL: func.func @test_dispatch_sret( -// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>, -// CHECK-SAME: %[[VAL_1:.*]]: !fir.class<!fir.type<somet>>) { -// CHECK: %[[VAL_2:.*]] = llvm.intr.stacksave : !llvm.ptr -// CHECK: %[[VAL_3:.*]] = fir.alloca !fir.type<t2{i:!fir.array<5xf32>}> -// CHECK: fir.dispatch "bar"(%[[VAL_1]] : !fir.class<!fir.type<somet>>) (%[[VAL_3]], %[[VAL_1]] : !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>, !fir.class<!fir.type<somet>>) {pass_arg_pos = 1 : i32} -// CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>> -// CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>> -// CHECK: llvm.intr.stackrestore %[[VAL_2]] : !llvm.ptr -// CHECK: fir.store %[[VAL_5]] to %[[VAL_0]] : !fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>> -// CHECK: return -// CHECK: } - - -// CHECK: func.func private @test_fp_80() -> f80 -// CHECK: func.func private @test_complex_80(!fir.ref<!fir.type<t4{i:complex<f80>}>> {llvm.align = 16 : i32, llvm.sret = !fir.type<t4{i:complex<f80>}>}) -// CHECK: func.func private @test_two_fp_80(!fir.ref<!fir.type<t5{i:f80,j:f80}>> {llvm.align = 16 : i32, llvm.sret = !fir.type<t5{i:f80,j:f80}>}) -// CHECK: func.func private @test_fp128() -> f128 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits