diff --git a/flang/include/flang/Lower/CallInterface.h b/flang/include/flang/Lower/CallInterface.h --- a/flang/include/flang/Lower/CallInterface.h +++ b/flang/include/flang/Lower/CallInterface.h @@ -102,9 +102,31 @@ using FortranEntity = typename PassedEntityTypes::FortranEntity; using FirValue = typename PassedEntityTypes::FirValue; + /// FirPlaceHolder are place holders for the mlir inputs and outputs that are + /// created during the first pass before the mlir::FuncOp is created. + struct FirPlaceHolder { + FirPlaceHolder(mlir::Type t, int passedPosition, Property p) + : type{t}, passedEntityPosition{passedPosition}, property{p} {} + /// Type for this input/output + mlir::Type type; + /// Position of related passedEntity in passedArguments. + /// (passedEntity is the passedResult this value is resultEntityPosition). + int passedEntityPosition; + static constexpr int resultEntityPosition = -1; + /// Indicate property of the entity passedEntityPosition that must be passed + /// through this argument. + Property property; + }; + /// Returns the mlir function type mlir::FunctionType genFunctionType(); + /// determineInterface is the entry point of the first pass that defines the + /// interface and is required to get the mlir::FuncOp. + void + determineInterface(bool isImplicit, + const Fortran::evaluate::characteristics::Procedure &); + protected: CallInterface(Fortran::lower::AbstractConverter &c) : converter{c} {} /// CRTP handle. @@ -113,9 +135,14 @@ /// create/find the mlir::FuncOp. Child needs to be initialized first. void declare(); + llvm::SmallVector outputs; mlir::FuncOp func; Fortran::lower::AbstractConverter &converter; + /// Store characteristic once created, it is required for further information + /// (e.g. getting the length of character result) + std::optional characteristic = + std::nullopt; }; //===----------------------------------------------------------------------===// @@ -132,9 +159,11 @@ declare(); } + bool hasAlternateReturns() const; std::string getMangledName() const; mlir::Location getCalleeLocation() const; Fortran::evaluate::characteristics::Procedure characterize() const; + bool isMainProgram() const; /// On the callee side it does not matter whether the procedure is /// called through pointers or not. diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -99,9 +99,8 @@ TODO_NOLOC("Not implemented genType SomeExpr. Needed for more complex " "expression lowering"); } - mlir::Type genType(Fortran::lower::SymbolRef) override final { - TODO_NOLOC("Not implemented genType SymbolRef. Needed for more complex " - "expression lowering"); + mlir::Type genType(Fortran::lower::SymbolRef sym) override final { + return Fortran::lower::translateSymbolToFIRType(*this, sym); } mlir::Type genType(Fortran::common::TypeCategory tc) override final { TODO_NOLOC("Not implemented genType TypeCategory. Needed for more complex " @@ -247,8 +246,11 @@ for (const Fortran::lower::pft::Variable &var : funit.getOrderedSymbolTable()) { const Fortran::semantics::Symbol &sym = var.getSymbol(); - if (!sym.IsFuncResult() || !funit.primaryResult) + if (!sym.IsFuncResult() || !funit.primaryResult) { + instantiateVar(var); + } else if (&sym == funit.primaryResult) { instantiateVar(var); + } } // Create most function blocks in advance. @@ -335,6 +337,36 @@ } void genFIR(const Fortran::parser::EndProgramStmt &) { genExitRoutine(); } + /// END of procedure-like constructs + /// + /// Generate the cleanup block before the procedure exits + void genReturnSymbol(const Fortran::semantics::Symbol &functionSymbol) { + const Fortran::semantics::Symbol &resultSym = + functionSymbol.get().result(); + Fortran::lower::SymbolBox resultSymBox = lookupSymbol(resultSym); + mlir::Location loc = toLocation(); + if (!resultSymBox) { + mlir::emitError(loc, "failed lowering function return"); + return; + } + mlir::Value resultVal = resultSymBox.match( + [&](const fir::CharBoxValue &x) -> mlir::Value { + TODO(loc, "Function return CharBoxValue"); + }, + [&](const auto &) -> mlir::Value { + mlir::Value resultRef = resultSymBox.getAddr(); + mlir::Type resultType = genType(resultSym); + mlir::Type resultRefType = builder->getRefType(resultType); + // A function with multiple entry points returning different types + // tags all result variables with one of the largest types to allow + // them to share the same storage. Convert this to the actual type. + if (resultRef.getType() != resultRefType) + TODO(loc, "Convert to actual type"); + return builder->create(loc, resultRef); + }); + builder->create(loc, resultVal); + } + void genFIRProcedureExit(Fortran::lower::pft::FunctionLikeUnit &funit, const Fortran::semantics::Symbol &symbol) { if (mlir::Block *finalBlock = funit.finalBlock) { @@ -345,7 +377,7 @@ builder->setInsertionPoint(finalBlock, finalBlock->end()); } if (Fortran::semantics::IsFunction(symbol)) { - TODO(toLocation(), "Function lowering"); + genReturnSymbol(symbol); } else { genExitRoutine(); } @@ -719,10 +751,6 @@ TODO(toLocation(), "EndDoStmt lowering"); } - void genFIR(const Fortran::parser::EndFunctionStmt &) { - TODO(toLocation(), "EndFunctionStmt lowering"); - } - void genFIR(const Fortran::parser::EndIfStmt &) { TODO(toLocation(), "EndIfStmt lowering"); } @@ -736,6 +764,7 @@ } // Nop statements - No code, or code is generated at the construct level. + void genFIR(const Fortran::parser::EndFunctionStmt &) {} // nop void genFIR(const Fortran::parser::EndSubroutineStmt &) {} // nop void genFIR(const Fortran::parser::EntryStmt &) { diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp --- a/flang/lib/Lower/CallInterface.cpp +++ b/flang/lib/Lower/CallInterface.cpp @@ -12,6 +12,7 @@ #include "flang/Lower/Mangler.h" #include "flang/Lower/PFTBuilder.h" #include "flang/Lower/Support/Utils.h" +#include "flang/Lower/Todo.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Dialect/FIRDialect.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" @@ -33,6 +34,11 @@ // Callee side interface implementation //===----------------------------------------------------------------------===// +bool Fortran::lower::CalleeInterface::hasAlternateReturns() const { + return !funit.isMainProgram() && + Fortran::semantics::HasAlternateReturns(funit.getSubprogramSymbol()); +} + std::string Fortran::lower::CalleeInterface::getMangledName() const { if (funit.isMainProgram()) return fir::NameUniquer::doProgramEntry().str(); @@ -52,6 +58,21 @@ return converter.genLocation(funit.getStartingSourceLoc()); } +Fortran::evaluate::characteristics::Procedure +Fortran::lower::CalleeInterface::characterize() const { + Fortran::evaluate::FoldingContext &foldingContext = + converter.getFoldingContext(); + std::optional characteristic = + Fortran::evaluate::characteristics::Procedure::Characterize( + funit.getSubprogramSymbol(), foldingContext); + assert(characteristic && "Fail to get characteristic from symbol"); + return *characteristic; +} + +bool Fortran::lower::CalleeInterface::isMainProgram() const { + return funit.isMainProgram(); +} + mlir::FuncOp Fortran::lower::CalleeInterface::addEntryBlockAndMapArguments() { // On the callee side, directly map the mlir::value argument of // the function block to the Fortran symbols. @@ -81,6 +102,13 @@ /// signature and building/finding the mlir::FuncOp. template void Fortran::lower::CallInterface::declare() { + if (!side().isMainProgram()) { + characteristic.emplace(side().characterize()); + bool isImplicit = characteristic->CanBeCalledViaImplicitInterface(); + determineInterface(isImplicit, *characteristic); + } + // No input/output for main program + // Create / get funcOp for direct calls. For indirect calls (only meaningful // on the caller side), no funcOp has to be created here. The mlir::Value // holding the indirection is used when creating the fir::CallOp. @@ -98,9 +126,90 @@ } } +//===----------------------------------------------------------------------===// +// CallInterface implementation: this part is common to both caller and caller +// sides. +//===----------------------------------------------------------------------===// + +/// This is the actual part that defines the FIR interface based on the +/// characteristic. It directly mutates the CallInterface members. +template +class Fortran::lower::CallInterfaceImpl { + using CallInterface = Fortran::lower::CallInterface; + using FirPlaceHolder = typename CallInterface::FirPlaceHolder; + using Property = typename CallInterface::Property; + using TypeAndShape = Fortran::evaluate::characteristics::TypeAndShape; + +public: + CallInterfaceImpl(CallInterface &i) + : interface(i), mlirContext{i.converter.getMLIRContext()} {} + + void buildImplicitInterface( + const Fortran::evaluate::characteristics::Procedure &procedure) { + // Handle result + if (const std::optional + &result = procedure.functionResult) + handleImplicitResult(*result); + else if (interface.side().hasAlternateReturns()) + addFirResult(mlir::IndexType::get(&mlirContext), + FirPlaceHolder::resultEntityPosition, Property::Value); + } + +private: + void handleImplicitResult( + const Fortran::evaluate::characteristics::FunctionResult &result) { + if (result.IsProcedurePointer()) + TODO(interface.converter.getCurrentLocation(), + "procedure pointer result not yet handled"); + const Fortran::evaluate::characteristics::TypeAndShape *typeAndShape = + result.GetTypeAndShape(); + assert(typeAndShape && "expect type for non proc pointer result"); + Fortran::evaluate::DynamicType dynamicType = typeAndShape->type(); + if (dynamicType.category() == Fortran::common::TypeCategory::Character) { + TODO(interface.converter.getCurrentLocation(), + "implicit result character type"); + } else if (dynamicType.category() == + Fortran::common::TypeCategory::Derived) { + TODO(interface.converter.getCurrentLocation(), + "implicit result derived type"); + } else { + // All result other than characters/derived are simply returned by value + // in implicit interfaces + mlir::Type mlirType = + getConverter().genType(dynamicType.category(), dynamicType.kind()); + addFirResult(mlirType, FirPlaceHolder::resultEntityPosition, + Property::Value); + } + } + + void addFirResult(mlir::Type type, int entityPosition, Property p) { + interface.outputs.emplace_back(FirPlaceHolder{type, entityPosition, p}); + } + + Fortran::lower::AbstractConverter &getConverter() { + return interface.converter; + } + CallInterface &interface; + mlir::MLIRContext &mlirContext; +}; + +template +void Fortran::lower::CallInterface::determineInterface( + bool isImplicit, + const Fortran::evaluate::characteristics::Procedure &procedure) { + CallInterfaceImpl impl(*this); + if (isImplicit) + impl.buildImplicitInterface(procedure); + else + TODO_NOLOC("determineImplicitInterface"); +} + template mlir::FunctionType Fortran::lower::CallInterface::genFunctionType() { - return mlir::FunctionType::get(&converter.getMLIRContext(), {}, {}); + llvm::SmallVector returnTys; + for (const FirPlaceHolder &placeHolder : outputs) + returnTys.emplace_back(placeHolder.type); + return mlir::FunctionType::get(&converter.getMLIRContext(), {}, returnTys); } template class Fortran::lower::CallInterface; diff --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp --- a/flang/lib/Lower/ConvertType.cpp +++ b/flang/lib/Lower/ConvertType.cpp @@ -9,6 +9,7 @@ #include "flang/Lower/ConvertType.h" #include "flang/Lower/AbstractConverter.h" #include "flang/Lower/PFTBuilder.h" +#include "flang/Lower/Todo.h" #include "flang/Lower/Utils.h" #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Semantics/tools.h" @@ -16,15 +17,61 @@ #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinTypes.h" -#undef QUOTE -#undef TODO -#define QUOTE(X) #X -#define TODO(S) \ - { \ - emitError(__FILE__ ":" QUOTE(__LINE__) ": type lowering of " S \ - " not implemented"); \ - exit(1); \ +#define DEBUG_TYPE "flang-lower-type" + +//===--------------------------------------------------------------------===// +// Intrinsic type translation helpers +//===--------------------------------------------------------------------===// + +template +int getIntegerBits() { + return Fortran::evaluate::Type::Scalar::bits; +} +static mlir::Type genIntegerType(mlir::MLIRContext *context, int kind) { + if (Fortran::evaluate::IsValidKindOfIntrinsicType( + Fortran::common::TypeCategory::Integer, kind)) { + switch (kind) { + case 1: + return mlir::IntegerType::get(context, getIntegerBits<1>()); + case 2: + return mlir::IntegerType::get(context, getIntegerBits<2>()); + case 4: + return mlir::IntegerType::get(context, getIntegerBits<4>()); + case 8: + return mlir::IntegerType::get(context, getIntegerBits<8>()); + case 16: + return mlir::IntegerType::get(context, getIntegerBits<16>()); + } + } + llvm_unreachable("INTEGER kind not translated"); +} + +static mlir::Type genLogicalType(mlir::MLIRContext *context, int KIND) { + if (Fortran::evaluate::IsValidKindOfIntrinsicType( + Fortran::common::TypeCategory::Logical, KIND)) + return fir::LogicalType::get(context, KIND); + return {}; +} + +static mlir::Type genFIRType(mlir::MLIRContext *context, + Fortran::common::TypeCategory tc, int kind) { + switch (tc) { + case Fortran::common::TypeCategory::Real: + TODO_NOLOC("genFIRType Real"); + case Fortran::common::TypeCategory::Integer: + return genIntegerType(context, kind); + case Fortran::common::TypeCategory::Complex: + TODO_NOLOC("genFIRType Complex"); + case Fortran::common::TypeCategory::Logical: + return genLogicalType(context, kind); + case Fortran::common::TypeCategory::Character: + TODO_NOLOC("genFIRType Character"); + default: + break; } + llvm_unreachable("unhandled type category"); +} template bool isConstant(const Fortran::evaluate::Expr &e) { @@ -120,38 +167,6 @@ llvm_unreachable("REAL type translation not implemented"); } -template <> -mlir::Type -genFIRType(mlir::MLIRContext *context, - int kind) { - if (Fortran::evaluate::IsValidKindOfIntrinsicType( - Fortran::common::TypeCategory::Integer, kind)) { - switch (kind) { - case 1: - return genFIRType(context); - case 2: - return genFIRType(context); - case 4: - return genFIRType(context); - case 8: - return genFIRType(context); - case 16: - return genFIRType(context); - } - } - llvm_unreachable("INTEGER type translation not implemented"); -} - -template <> -mlir::Type -genFIRType(mlir::MLIRContext *context, - int KIND) { - if (Fortran::evaluate::IsValidKindOfIntrinsicType( - Fortran::common::TypeCategory::Logical, KIND)) - return fir::LogicalType::get(context, KIND); - return {}; -} - template <> mlir::Type genFIRType(mlir::MLIRContext *context, @@ -179,7 +194,54 @@ class TypeBuilder { public: TypeBuilder(Fortran::lower::AbstractConverter &converter) - : context{&converter.getMLIRContext()} {} + : converter{converter}, context{&converter.getMLIRContext()} {} + + template + std::optional toInt64(A &&expr) { + return Fortran::evaluate::ToInt64(Fortran::evaluate::Fold( + converter.getFoldingContext(), std::move(expr))); + } + + mlir::Type genSymbolType(const Fortran::semantics::Symbol &symbol, + bool isAlloc = false, bool isPtr = false) { + mlir::Location loc = converter.genLocation(symbol.name()); + mlir::Type ty; + // If the symbol is not the same as the ultimate one (i.e, it is host or use + // associated), all the symbol properties are the ones of the ultimate + // symbol but the volatile and asynchronous attributes that may differ. To + // avoid issues with helper functions that would not follow association + // links, the fir type is built based on the ultimate symbol. This relies + // on the fact volatile and asynchronous are not reflected in fir types. + const Fortran::semantics::Symbol &ultimate = symbol.GetUltimate(); + if (const Fortran::semantics::DeclTypeSpec *type = ultimate.GetType()) { + if (const Fortran::semantics::IntrinsicTypeSpec *tySpec = + type->AsIntrinsic()) { + int kind = toInt64(Fortran::common::Clone(tySpec->kind())).value(); + ty = genFIRType(context, tySpec->category(), kind); + } else if (type->IsPolymorphic()) { + TODO(loc, "genSymbolType polymorphic types"); + } else if (type->AsDerived()) { + TODO(loc, "genSymbolType derived type"); + } else { + fir::emitFatalError(loc, "symbol's type must have a type spec"); + } + } else { + fir::emitFatalError(loc, "symbol must have a type"); + } + + if (Fortran::semantics::IsPointer(symbol)) + return fir::BoxType::get(fir::PointerType::get(ty)); + if (Fortran::semantics::IsAllocatable(symbol)) + return fir::BoxType::get(fir::HeapType::get(ty)); + // isPtr and isAlloc are variable that were promoted to be on the + // heap or to be pointers, but they do not have Fortran allocatable + // or pointer semantics, so do not use box for them. + if (isPtr) + return fir::PointerType::get(ty); + if (isAlloc) + return fir::HeapType::get(ty); + return ty; + } //===--------------------------------------------------------------------===// // Generate type entry points @@ -207,26 +269,18 @@ template mlir::Type gen(const Fortran::evaluate::Expr> &expr) { - return genVariant(expr); + return {}; } template mlir::Type gen(const Fortran::evaluate::Expr &expr) { - return genVariant(expr); + return {}; } - mlir::Type gen(const Fortran::evaluate::DataRef &dref) { - return genVariant(dref); - } + mlir::Type gen(const Fortran::evaluate::DataRef &dref) { return {}; } mlir::Type genVariableType(const Fortran::lower::pft::Variable &var) { - return genSymbolHelper(var.getSymbol(), var.isHeapAlloc(), var.isPointer()); - } - - /// Type consing from a symbol. A symbol's type must be created from the type - /// discovered by the front-end at runtime. - mlir::Type gen(Fortran::semantics::SymbolRef symbol) { - return genSymbolHelper(symbol); + return genSymbolType(var.getSymbol(), var.isHeapAlloc(), var.isPointer()); } // non-template, category is runtime values, kind is defaulted @@ -280,9 +334,7 @@ return fir::SequenceType::get(trivialShape(ptr->itemBytes()), byteTy); } - mlir::Type gen(const Fortran::evaluate::Substring &ss) { - return genVariant(ss.GetBaseObject()); - } + mlir::Type gen(const Fortran::evaluate::Substring &ss) { return {}; } mlir::Type gen(const Fortran::evaluate::NullPointer &) { return genTypelessPtr(); @@ -296,17 +348,23 @@ mlir::Type gen(const Fortran::evaluate::BOZLiteralConstant &) { return genTypelessPtr(); } - mlir::Type gen(const Fortran::evaluate::ArrayRef &) { TODO("array ref"); } - mlir::Type gen(const Fortran::evaluate::CoarrayRef &) { TODO("coarray ref"); } - mlir::Type gen(const Fortran::evaluate::Component &) { TODO("component"); } + mlir::Type gen(const Fortran::evaluate::ArrayRef &) { + TODO_NOLOC("array ref"); + } + mlir::Type gen(const Fortran::evaluate::CoarrayRef &) { + TODO_NOLOC("coarray ref"); + } + mlir::Type gen(const Fortran::evaluate::Component &) { + TODO_NOLOC("component"); + } mlir::Type gen(const Fortran::evaluate::ComplexPart &) { - TODO("complex part"); + TODO_NOLOC("complex part"); } mlir::Type gen(const Fortran::evaluate::DescriptorInquiry &) { - TODO("descriptor inquiry"); + TODO_NOLOC("descriptor inquiry"); } mlir::Type gen(const Fortran::evaluate::StructureConstructor &) { - TODO("structure constructor"); + TODO_NOLOC("structure constructor"); } fir::SequenceType::Shape genSeqShape(Fortran::semantics::SymbolRef symbol) { @@ -323,84 +381,6 @@ return seqShapeHelper(symbol, bounds); } - mlir::Type genSymbolHelper(const Fortran::semantics::Symbol &symbol, - bool isAlloc = false, bool isPtr = false) { - mlir::Type ty; - if (auto *type{symbol.GetType()}) { - if (auto *tySpec{type->AsIntrinsic()}) { - int kind = toConstant(tySpec->kind()); - switch (tySpec->category()) { - case Fortran::common::TypeCategory::Integer: - ty = - genFIRType(context, kind); - break; - case Fortran::common::TypeCategory::Real: - ty = genFIRType(context, kind); - break; - case Fortran::common::TypeCategory::Complex: - ty = - genFIRType(context, kind); - break; - case Fortran::common::TypeCategory::Character: - ty = genFIRType(context, - kind); - break; - case Fortran::common::TypeCategory::Logical: - ty = - genFIRType(context, kind); - break; - default: - emitError("symbol has unknown intrinsic type"); - return {}; - } - } else if (auto *tySpec = type->AsDerived()) { - std::vector> ps; - std::vector> cs; - auto &symbol = tySpec->typeSymbol(); - // FIXME: don't want to recurse forever here, but this won't happen - // since we don't know the components at this time - auto rec = fir::RecordType::get(context, toStringRef(symbol.name())); - auto &details = symbol.get(); - for (auto ¶m : details.paramDecls()) { - auto &p{*param}; - ps.push_back(std::pair{p.name().ToString(), gen(p)}); - } - emitError("the front-end returns symbols of derived type that have " - "components that are simple names and not symbols, so cannot " - "construct the type '" + - toStringRef(symbol.name()) + "'"); - rec.finalize(ps, cs); - ty = rec; - } else { - emitError("symbol's type must have a type spec"); - return {}; - } - } else { - emitError("symbol must have a type"); - return {}; - } - if (symbol.IsObjectArray()) { - if (symbol.GetType()->category() == - Fortran::semantics::DeclTypeSpec::Character) { - auto charLen = fir::SequenceType::getUnknownExtent(); - const auto &lenParam = symbol.GetType()->characterTypeSpec().length(); - if (auto expr = lenParam.GetExplicit()) { - auto len = Fortran::evaluate::AsGenericExpr(std::move(*expr)); - auto asInt = Fortran::evaluate::ToInt64(len); - if (asInt) - charLen = *asInt; - } - return fir::SequenceType::get(genSeqShape(symbol, charLen), ty); - } - return fir::SequenceType::get(genSeqShape(symbol), ty); - } - if (isPtr || Fortran::semantics::IsPointer(symbol)) - ty = fir::PointerType::get(ty); - else if (isAlloc || Fortran::semantics::IsAllocatable(symbol)) - ty = fir::HeapType::get(ty); - return ty; - } - //===--------------------------------------------------------------------===// // Other helper functions //===--------------------------------------------------------------------===// @@ -414,11 +394,6 @@ mlir::Type mkVoid() { return mlir::TupleType::get(context); } mlir::Type genTypelessPtr() { return fir::ReferenceType::get(mkVoid()); } - template - mlir::Type genVariant(const A &variant) { - return std::visit([&](const auto &x) { return gen(x); }, variant.u); - } - template int defaultKind() { return defaultKind(TC); @@ -465,50 +440,12 @@ //===--------------------------------------------------------------------===// + Fortran::lower::AbstractConverter &converter; mlir::MLIRContext *context; }; } // namespace -template -int getIntegerBits() { - return Fortran::evaluate::Type::Scalar::bits; -} -static mlir::Type genIntegerType(mlir::MLIRContext *context, int kind) { - if (Fortran::evaluate::IsValidKindOfIntrinsicType( - Fortran::common::TypeCategory::Integer, kind)) { - switch (kind) { - case 1: - return mlir::IntegerType::get(context, getIntegerBits<1>()); - case 2: - return mlir::IntegerType::get(context, getIntegerBits<2>()); - case 4: - return mlir::IntegerType::get(context, getIntegerBits<4>()); - case 8: - return mlir::IntegerType::get(context, getIntegerBits<8>()); - case 16: - return mlir::IntegerType::get(context, getIntegerBits<16>()); - } - } - llvm_unreachable("INTEGER kind not translated"); -} - -static mlir::Type genFIRType(mlir::MLIRContext *context, - Fortran::common::TypeCategory tc, int kind) { - switch (tc) { - case Fortran::common::TypeCategory::Integer: - return genIntegerType(context, kind); - case Fortran::common::TypeCategory::Real: - case Fortran::common::TypeCategory::Complex: - case Fortran::common::TypeCategory::Logical: - case Fortran::common::TypeCategory::Character: - default: - break; - } - llvm_unreachable("unhandled type category"); -} - mlir::Type Fortran::lower::getFIRType(mlir::MLIRContext *context, Fortran::common::TypeCategory tc, int kind) { @@ -534,7 +471,7 @@ mlir::Type Fortran::lower::translateSymbolToFIRType( Fortran::lower::AbstractConverter &converter, const SymbolRef symbol) { - return TypeBuilder{converter}.gen(symbol); + return TypeBuilder{converter}.genSymbolType(symbol); } mlir::Type Fortran::lower::translateVariableToFIRType( diff --git a/flang/test/Lower/basic-function.f90 b/flang/test/Lower/basic-function.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/basic-function.f90 @@ -0,0 +1,69 @@ +! RUN: bbc %s -o "-" -emit-fir | FileCheck %s + +integer(1) function fct1() +end +! CHECK-LABEL: func @_QPfct1() -> i8 +! CHECK: return %{{.*}} : i8 + +integer(2) function fct2() +end +! CHECK-LABEL: func @_QPfct2() -> i16 +! CHECK: return %{{.*}} : i16 + +integer(4) function fct3() +end +! CHECK-LABEL: func @_QPfct3() -> i32 +! CHECK: return %{{.*}} : i32 + +integer(8) function fct4() +end +! CHECK-LABEL: func @_QPfct4() -> i64 +! CHECK: return %{{.*}} : i64 + +integer(16) function fct5() +end +! CHECK-LABEL: func @_QPfct5() -> i128 +! CHECK: return %{{.*}} : i128 + +function fct() + integer :: fct +end +! CHECK-LABEL: func @_QPfct() -> i32 +! CHECK: return %{{.*}} : i32 + +function fct_res() result(res) + integer :: res +end +! CHECK-LABEL: func @_QPfct_res() -> i32 +! CHECK: return %{{.*}} : i32 + +integer function fct_body() + goto 1 + 1 stop +end + +! CHECK-LABEL: func @_QPfct_body() -> i32 +! CHECK: cf.br ^bb1 +! CHECK: ^bb1 +! CHECK: %{{.*}} = fir.call @_FortranAStopStatement +! CHECK: fir.unreachable + +logical(1) function lfct1() +end +! CHECK-LABEL: func @_QPlfct1() -> !fir.logical<1> +! CHECK: return %{{.*}} : !fir.logical<1> + +logical(2) function lfct2() +end +! CHECK-LABEL: func @_QPlfct2() -> !fir.logical<2> +! CHECK: return %{{.*}} : !fir.logical<2> + +logical(4) function lfct3() +end +! CHECK-LABEL: func @_QPlfct3() -> !fir.logical<4> +! CHECK: return %{{.*}} : !fir.logical<4> + +logical(8) function lfct4() +end +! CHECK-LABEL: func @_QPlfct4() -> !fir.logical<8> +! CHECK: return %{{.*}} : !fir.logical<8>