Index: flang/include/flang/Optimizer/OptPasses.h =================================================================== --- /dev/null +++ flang/include/flang/Optimizer/OptPasses.h @@ -0,0 +1,21 @@ +//===-- Optimizer/Transforms/Passes.h ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef OPTIMIZER_OPTPASSES_H +#define OPTIMIZER_OPTPASSES_H + +#include "flang/Optimizer/CodeGen/CodeGen.h" +#include "flang/Optimizer/Transforms/Passes.h" + +namespace fir { +inline void registerOptPasses() { + registerOptCodeGenPasses(); +} +} // namespace fir + +#endif // OPTIMIZER_OPTPASSES_H Index: flang/include/flang/Optimizer/Support/FIRContext.h =================================================================== --- /dev/null +++ flang/include/flang/Optimizer/Support/FIRContext.h @@ -0,0 +1,64 @@ +//===-- Optimizer/Support/FIRContext.h --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// +/// Setters and getters for associating context with an instance of a ModuleOp. +/// The context is typically set by the tool and needed in later stages to +/// determine how to correctly generate code. +//===----------------------------------------------------------------------===// + +#ifndef OPTIMIZER_SUPPORT_FIRCONTEXT_H +#define OPTIMIZER_SUPPORT_FIRCONTEXT_H + +#include "llvm/ADT/Triple.h" + +namespace mlir { +class ModuleOp; +} + +namespace fir { +class KindMapping; +struct NameUniquer; + +/// Set the target triple for the module. `triple` must not be deallocated while +/// module `mod` is still live. +void setTargetTriple(mlir::ModuleOp mod, llvm::Triple &triple); + +/// Get a pointer to the Triple instance from the Module. If none was set, +/// returns a nullptr. +llvm::Triple *getTargetTriple(mlir::ModuleOp mod); + +/// Set the name uniquer for the module. `uniquer` must not be deallocated while +/// module `mod` is still live. +void setNameUniquer(mlir::ModuleOp mod, NameUniquer &uniquer); + +/// Get a pointer to the NameUniquer instance from the Module. If none was set, +/// returns a nullptr. +NameUniquer *getNameUniquer(mlir::ModuleOp mod); + +/// Set the kind mapping for the module. `kindMap` must not be deallocated while +/// module `mod` is still live. +void setKindMapping(mlir::ModuleOp mod, KindMapping &kindMap); + +/// Get a pointer to the KindMapping instance from the Module. If none was set, +/// returns a nullptr. +KindMapping *getKindMapping(mlir::ModuleOp mod); + +/// Helper for determining the target from the host, etc. Tools may use this +/// function to provide a consistent interpretation of the `--target=` +/// command-line option. +/// An empty string ("") or "default" will specify that the default triple +/// should be used. "native" will specify that the host machine be used to +/// construct the triple. +std::string determineTargetTriple(llvm::StringRef triple); + +} // namespace fir + +#endif // OPTIMIZER_SUPPORT_FIRCONTEXT_H Index: flang/include/flang/Optimizer/Support/FatalError.h =================================================================== --- /dev/null +++ flang/include/flang/Optimizer/Support/FatalError.h @@ -0,0 +1,37 @@ +//===-- Optimizer/Support/FatalError.h --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#ifndef OPTIMIZER_SUPPORT_FATALERROR_H +#define OPTIMIZER_SUPPORT_FATALERROR_H + +#include "mlir/IR/Diagnostics.h" +#include "llvm/Support/ErrorHandling.h" + +namespace fir { + +/// Fatal error reporting helper. Report a fatal error with a source location +/// and immediately abort flang. +LLVM_ATTRIBUTE_NORETURN inline void emitFatalError(mlir::Location loc, + const llvm::Twine &message) { + mlir::emitError(loc, message); + llvm::report_fatal_error("aborting"); +} + +/// Fatal error reporting helper. Report a fatal error without a source location +/// and immediately abort flang. +LLVM_ATTRIBUTE_NORETURN inline void emitFatalError(const llvm::Twine &message) { + llvm::report_fatal_error(message); +} + +} // namespace fir + +#endif // OPTIMIZER_SUPPORT_FATALERROR_H Index: flang/include/flang/Optimizer/Support/InternalNames.h =================================================================== --- flang/include/flang/Optimizer/Support/InternalNames.h +++ flang/include/flang/Optimizer/Support/InternalNames.h @@ -32,6 +32,7 @@ /// The sort of the unique name enum class NameKind { NOT_UNIQUED, + BLOCK_DATA_NAME, COMMON, CONSTANT, DERIVED_TYPE, @@ -63,6 +64,9 @@ /// Unique a common block name std::string doCommonBlock(llvm::StringRef name); + /// Unique a block data unit name + std::string doBlockData(llvm::StringRef name); + /// Unique a (global) constant name std::string doConstant(llvm::ArrayRef modules, llvm::Optional host, Index: flang/include/flang/Optimizer/Support/KindMapping.h =================================================================== --- flang/include/flang/Optimizer/Support/KindMapping.h +++ flang/include/flang/Optimizer/Support/KindMapping.h @@ -5,6 +5,10 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// #ifndef OPTIMIZER_SUPPORT_KINDMAPPING_H #define OPTIMIZER_SUPPORT_KINDMAPPING_H @@ -36,7 +40,8 @@ /// 'c' : COMPLEX (encoding value) /// /// kind-value is either an unsigned integer (for 'i', 'l', and 'a') or one of -/// 'Half', 'Float', 'Double', 'X86_FP80', or 'FP128' (for 'r' and 'c'). +/// 'Half', 'BFloat', 'Float', 'Double', 'X86_FP80', or 'FP128' (for 'r' and +/// 'c'). /// /// If LLVM adds support for new floating-point types, the final list should be /// extended. @@ -47,8 +52,10 @@ using LLVMTypeID = llvm::Type::TypeID; using MatchResult = mlir::ParseResult; - explicit KindMapping(mlir::MLIRContext *context); - explicit KindMapping(mlir::MLIRContext *context, llvm::StringRef map); + explicit KindMapping(mlir::MLIRContext *context, + llvm::ArrayRef defs = llvm::None); + explicit KindMapping(mlir::MLIRContext *context, llvm::StringRef map, + llvm::ArrayRef defs = llvm::None); /// Get the size in bits of !fir.char Bitsize getCharacterBitsize(KindTy kind) const; @@ -73,13 +80,26 @@ /// Get the float semantics of !fir.real const llvm::fltSemantics &getFloatSemantics(KindTy kind) const; + //===--------------------------------------------------------------------===// + // Default kinds of intrinsic types + //===--------------------------------------------------------------------===// + + KindTy defaultCharacterKind() const; + KindTy defaultComplexKind() const; + KindTy defaultDoubleKind() const; + KindTy defaultIntegerKind() const; + KindTy defaultLogicalKind() const; + KindTy defaultRealKind() const; + private: MatchResult badMapString(const llvm::Twine &ptr); MatchResult parse(llvm::StringRef kindMap); + mlir::LogicalResult setDefaultKinds(llvm::ArrayRef defs); mlir::MLIRContext *context; llvm::DenseMap, Bitsize> intMap; llvm::DenseMap, LLVMTypeID> floatMap; + llvm::DenseMap defaultMap; }; } // namespace fir Index: flang/include/flang/Optimizer/Support/Matcher.h =================================================================== --- /dev/null +++ flang/include/flang/Optimizer/Support/Matcher.h @@ -0,0 +1,35 @@ +//===-- Optimizer/Support/Matcher.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#ifndef OPTIMIZER_SUPPORT_MATCHER_H +#define OPTIMIZER_SUPPORT_MATCHER_H + +#include + +// Boilerplate CRTP class for a simplified type-casing syntactic sugar. This +// lets one write pattern matchers using a more compact syntax. +namespace fir::details { +// clang-format off +template struct matches : Ts... { using Ts::operator()...; }; +template matches(Ts...) -> matches; +template struct matcher { + template auto match(Ts... ts) { + return std::visit(matches{ts...}, static_cast(this)->matchee()); + } + template auto match(Ts... ts) const { + return std::visit(matches{ts...}, static_cast(this)->matchee()); + } +}; +// clang-format on +} // namespace fir::details + +#endif // OPTIMIZER_SUPPORT_MATCHER_H Index: flang/include/flang/Optimizer/Support/TypeCode.h =================================================================== --- /dev/null +++ flang/include/flang/Optimizer/Support/TypeCode.h @@ -0,0 +1,94 @@ +//===-- Optimizer/Support/TypeCode.h ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#ifndef OPTIMIZER_SUPPORT_TYPECODE_H +#define OPTIMIZER_SUPPORT_TYPECODE_H + +#include "flang/ISO_Fortran_binding.h" +#include "llvm/Support/ErrorHandling.h" + +namespace fir { + +//===----------------------------------------------------------------------===// +// Translations of category and bitwidths to the type codes defined in flang's +// ISO_Fortran_binding.h. +//===----------------------------------------------------------------------===// + +inline int characterBitsToTypeCode(unsigned bits) { + // clang-format off + switch (bits) { + case 8: return CFI_type_char; + case 16: return CFI_type_char16_t; + case 32: return CFI_type_char32_t; + default: llvm_unreachable("unsupported character size"); + } + // clang-format on +} + +inline int complexBitsToTypeCode(unsigned bits) { + // clang-format off + switch (bits) { + case 32: return CFI_type_float_Complex; + case 64: return CFI_type_double_Complex; + case 80: + case 128: return CFI_type_long_double_Complex; + default: llvm_unreachable("unsupported complex size"); + } + // clang-format on +} + +inline int integerBitsToTypeCode(unsigned bits) { + // clang-format off + switch (bits) { + case 8: return CFI_type_int8_t; + case 16: return CFI_type_int16_t; + case 32: return CFI_type_int32_t; + case 64: return CFI_type_int64_t; + case 128: return CFI_type_int128_t; + default: llvm_unreachable("unsupported integer size"); + } + // clang-format on +} + +// Always use CFI_type_Bool and let the rest get sorted out by the elem_size. +// NB: do *not* use the CFI_type_intN_t codes. The flang runtime will choke. +inline int logicalBitsToTypeCode(unsigned bits) { + // clang-format off + switch (bits) { + case 8: + case 16: + case 32: + case 64: return CFI_type_Bool; + default: llvm_unreachable("unsupported logical size"); + } + // clang-format on +} + +inline int realBitsToTypeCode(unsigned bits) { + // clang-format off + switch (bits) { + case 32: return CFI_type_float; + case 64: return CFI_type_double; + case 80: + case 128: return CFI_type_long_double; + default: llvm_unreachable("unsupported real size"); + } + // clang-format on +} + +static constexpr int derivedToTypeCode() { + return CFI_type_struct; +} + +} // namespace fir + +#endif // OPTIMIZER_SUPPORT_TYPECODE_H Index: flang/lib/Optimizer/Support/FIRContext.cpp =================================================================== --- /dev/null +++ flang/lib/Optimizer/Support/FIRContext.cpp @@ -0,0 +1,65 @@ +//===-- KindMapping.cpp ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Support/FIRContext.h" +#include "flang/Optimizer/Dialect/FIRAttr.h" +#include "flang/Optimizer/Support/InternalNames.h" +#include "flang/Optimizer/Support/KindMapping.h" +#include "mlir/IR/BuiltinOps.h" +#include "llvm/Support/Host.h" + +static constexpr const char *tripleName = "fir.triple"; + +void fir::setTargetTriple(mlir::ModuleOp mod, llvm::Triple &triple) { + mod->setAttr(tripleName, fir::OpaqueAttr::get(mod.getContext(), &triple)); +} + +llvm::Triple *fir::getTargetTriple(mlir::ModuleOp mod) { + if (auto triple = mod->getAttrOfType(tripleName)) + return static_cast(triple.getPointer()); + return nullptr; +} + +static constexpr const char *uniquerName = "fir.uniquer"; + +void fir::setNameUniquer(mlir::ModuleOp mod, fir::NameUniquer &uniquer) { + mod->setAttr(uniquerName, fir::OpaqueAttr::get(mod.getContext(), &uniquer)); +} + +fir::NameUniquer *fir::getNameUniquer(mlir::ModuleOp mod) { + if (auto triple = mod->getAttrOfType(uniquerName)) + return static_cast(triple.getPointer()); + return nullptr; +} + +static constexpr const char *kindMapName = "fir.kindmap"; + +void fir::setKindMapping(mlir::ModuleOp mod, fir::KindMapping &kindMap) { + mod->setAttr(kindMapName, fir::OpaqueAttr::get(mod.getContext(), &kindMap)); +} + +fir::KindMapping *fir::getKindMapping(mlir::ModuleOp mod) { + if (auto triple = mod->getAttrOfType(kindMapName)) + return static_cast(triple.getPointer()); + return nullptr; +} + +std::string fir::determineTargetTriple(llvm::StringRef triple) { + // Treat "" or "default" as stand-ins for the default machine. + if (triple.empty() || triple == "default") + return llvm::sys::getDefaultTargetTriple(); + // Treat "native" as stand-in for the host machine. + if (triple == "native") + return llvm::sys::getProcessTriple(); + // TODO: normalize the triple? + return triple.str(); +} Index: flang/lib/Optimizer/Support/InternalNames.cpp =================================================================== --- flang/lib/Optimizer/Support/InternalNames.cpp +++ flang/lib/Optimizer/Support/InternalNames.cpp @@ -7,7 +7,9 @@ //===----------------------------------------------------------------------===// #include "flang/Optimizer/Support/InternalNames.h" +#include "flang/Optimizer/Dialect/FIRType.h" #include "mlir/IR/Diagnostics.h" +#include "mlir/IR/BuiltinTypes.h" #include "llvm/Support/CommandLine.h" static llvm::cl::opt mainEntryName( @@ -97,6 +99,11 @@ return result.append("B").append(toLower(name)); } +std::string fir::NameUniquer::doBlockData(llvm::StringRef name) { + std::string result = prefix(); + return result.append("L").append(toLower(name)); +} + std::string fir::NameUniquer::doConstant(llvm::ArrayRef modules, llvm::Optional host, @@ -237,6 +244,10 @@ name = readName(uniq, i, i + 1, end); } break; + case 'L': + nk = NameKind::BLOCK_DATA_NAME; + name = readName(uniq, i, i + 1, end); + break; case 'P': nk = NameKind::PROCEDURE; name = readName(uniq, i, i + 1, end); Index: flang/lib/Optimizer/Support/KindMapping.cpp =================================================================== --- flang/lib/Optimizer/Support/KindMapping.cpp +++ flang/lib/Optimizer/Support/KindMapping.cpp @@ -5,6 +5,10 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// #include "flang/Optimizer/Support/KindMapping.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" @@ -32,12 +36,14 @@ } /// Floating-point types default to the kind value being the size of the value -/// in bytes. The default is to translate kinds of 2, 4, 8, 10, and 16 to a +/// in bytes. The default is to translate kinds of 2, 3, 4, 8, 10, and 16 to a /// valid llvm::Type::TypeID value. Otherwise, the default is FloatTyID. static LLVMTypeID defaultRealKind(KindTy kind) { switch (kind) { case 2: return LLVMTypeID::HalfTyID; + case 3: + return LLVMTypeID::BFloatTyID; case 4: return LLVMTypeID::FloatTyID; case 8: @@ -81,6 +87,8 @@ switch (doLookup(defaultRealKind, map, kind)) { case LLVMTypeID::HalfTyID: return llvm::APFloat::IEEEhalf(); + case LLVMTypeID::BFloatTyID: + return llvm::APFloat::BFloat(); case LLVMTypeID::FloatTyID: return llvm::APFloat::IEEEsingle(); case LLVMTypeID::DoubleTyID: @@ -148,6 +156,10 @@ result = LLVMTypeID::HalfTyID; return mlir::success(); } + if (mlir::succeeded(matchString(ptr, "BFloat"))) { + result = LLVMTypeID::BFloatTyID; + return mlir::success(); + } if (mlir::succeeded(matchString(ptr, "Float"))) { result = LLVMTypeID::FloatTyID; return mlir::success(); @@ -171,16 +183,23 @@ return mlir::failure(); } -fir::KindMapping::KindMapping(mlir::MLIRContext *context, llvm::StringRef map) +fir::KindMapping::KindMapping(mlir::MLIRContext *context, llvm::StringRef map, + llvm::ArrayRef defs) : context{context} { + if (mlir::failed(setDefaultKinds(defs))) { + mlir::emitError(mlir::UnknownLoc::get(context), "bad default kinds"); + return; + } if (mlir::failed(parse(map))) { + mlir::emitError(mlir::UnknownLoc::get(context), "could not parse kind map"); intMap.clear(); floatMap.clear(); } } -fir::KindMapping::KindMapping(mlir::MLIRContext *context) - : KindMapping{context, clKindMapping} {} +fir::KindMapping::KindMapping(mlir::MLIRContext *context, + llvm::ArrayRef defs) + : KindMapping{context, clKindMapping, defs} {} MatchResult fir::KindMapping::badMapString(const llvm::Twine &ptr) { auto unknown = mlir::UnknownLoc::get(context); @@ -248,3 +267,65 @@ fir::KindMapping::getFloatSemantics(KindTy kind) const { return getFloatSemanticsOfKind<'r'>(kind, floatMap); } + +mlir::LogicalResult +fir::KindMapping::setDefaultKinds(llvm::ArrayRef defs) { + if (defs.size() == 0) { + // generic front-end defaults + const KindTy genericKind = 4; + defaultMap.insert({'a', 1}); + defaultMap.insert({'c', genericKind}); + defaultMap.insert({'d', 2 * genericKind}); + defaultMap.insert({'i', genericKind}); + defaultMap.insert({'l', genericKind}); + defaultMap.insert({'r', genericKind}); + return mlir::success(); + } + if (defs.size() != 6) + return mlir::failure(); + + // defaults determined after command-line processing + defaultMap.insert({'a', defs[0]}); + defaultMap.insert({'c', defs[1]}); + defaultMap.insert({'d', defs[2]}); + defaultMap.insert({'i', defs[3]}); + defaultMap.insert({'l', defs[4]}); + defaultMap.insert({'r', defs[5]}); + return mlir::success(); +} + +KindTy fir::KindMapping::defaultCharacterKind() const { + auto iter = defaultMap.find('a'); + assert(iter != defaultMap.end()); + return iter->second; +} + +KindTy fir::KindMapping::defaultComplexKind() const { + auto iter = defaultMap.find('c'); + assert(iter != defaultMap.end()); + return iter->second; +} + +KindTy fir::KindMapping::defaultDoubleKind() const { + auto iter = defaultMap.find('d'); + assert(iter != defaultMap.end()); + return iter->second; +} + +KindTy fir::KindMapping::defaultIntegerKind() const { + auto iter = defaultMap.find('i'); + assert(iter != defaultMap.end()); + return iter->second; +} + +KindTy fir::KindMapping::defaultLogicalKind() const { + auto iter = defaultMap.find('l'); + assert(iter != defaultMap.end()); + return iter->second; +} + +KindTy fir::KindMapping::defaultRealKind() const { + auto iter = defaultMap.find('r'); + assert(iter != defaultMap.end()); + return iter->second; +}