Index: flang/include/flang/Optimizer/Dialect/FIRDialect.h =================================================================== --- flang/include/flang/Optimizer/Dialect/FIRDialect.h +++ flang/include/flang/Optimizer/Dialect/FIRDialect.h @@ -14,8 +14,6 @@ #define OPTIMIZER_DIALECT_FIRDIALECT_H #include "mlir/IR/Dialect.h" -#include "mlir/InitAllDialects.h" -#include "mlir/InitAllPasses.h" namespace fir { @@ -36,47 +34,6 @@ mlir::DialectAsmPrinter &p) const override; }; -/// Register the dialect with the provided registry. -inline void registerFIRDialects(mlir::DialectRegistry ®istry) { - // clang-format off - registry.insert(); - // clang-format on -} - -/// Register the standard passes we use. This comes from registerAllPasses(), -/// but is a smaller set since we aren't using many of the passes found there. -inline void registerGeneralPasses() { - mlir::createCanonicalizerPass(); - mlir::createCSEPass(); - mlir::createSuperVectorizePass({}); - mlir::createLoopUnrollPass(); - mlir::createLoopUnrollAndJamPass(); - mlir::createSimplifyAffineStructuresPass(); - mlir::createLoopFusionPass(); - mlir::createLoopInvariantCodeMotionPass(); - mlir::createAffineLoopInvariantCodeMotionPass(); - mlir::createPipelineDataTransferPass(); - mlir::createLowerAffinePass(); - mlir::createLoopTilingPass(0); - mlir::createLoopCoalescingPass(); - mlir::createAffineDataCopyGenerationPass(0, 0); - mlir::createMemRefDataFlowOptPass(); - mlir::createStripDebugInfoPass(); - mlir::createPrintOpStatsPass(); - mlir::createInlinerPass(); - mlir::createSymbolDCEPass(); - mlir::createLocationSnapshotPass({}); -} - -inline void registerFIRPasses() { registerGeneralPasses(); } - } // namespace fir #endif // OPTIMIZER_DIALECT_FIRDIALECT_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/InitFIR.h =================================================================== --- /dev/null +++ flang/include/flang/Optimizer/Support/InitFIR.h @@ -0,0 +1,73 @@ +//===-- Optimizer/Support/InitFIR.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_INITFIR_H +#define OPTIMIZER_SUPPORT_INITFIR_H + +#include "flang/Optimizer/Dialect/FIRDialect.h" +#include "mlir/Conversion/Passes.h" +#include "mlir/Dialect/Affine/Passes.h" +#include "mlir/InitAllDialects.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Pass/PassRegistry.h" +#include "mlir/Transforms/LocationSnapshot.h" +#include "mlir/Transforms/Passes.h" + +namespace fir::support { + +/// Register and load all the dialects used by flang. +inline void registerAndLoadDialects(mlir::DialectRegistry ®istry) { + // clang-format off + registry.insert(); + // clang-format on +} + +/// Register the standard passes we use. This comes from registerAllPasses(), +/// but is a smaller set since we aren't using many of the passes found there. +inline void registerGeneralPasses() { + mlir::registerCanonicalizerPass(); + mlir::registerCSEPass(); + mlir::registerAffineLoopFusionPass(); + mlir::registerLoopInvariantCodeMotionPass(); + mlir::registerLoopCoalescingPass(); + mlir::registerStripDebugInfoPass(); + mlir::registerPrintOpStatsPass(); + mlir::registerInlinerPass(); + mlir::registerSCCPPass(); + mlir::registerMemRefDataFlowOptPass(); + mlir::registerSymbolDCEPass(); + mlir::registerLocationSnapshotPass(); + mlir::registerAffinePipelineDataTransferPass(); + + mlir::registerAffineVectorizePass(); + mlir::registerAffineLoopUnrollPass(); + mlir::registerAffineLoopUnrollAndJamPass(); + mlir::registerSimplifyAffineStructuresPass(); + mlir::registerAffineLoopInvariantCodeMotionPass(); + mlir::registerAffineLoopTilingPass(); + mlir::registerAffineDataCopyGenerationPass(); + + mlir::registerConvertAffineToStandardPass(); +} + +inline void registerFIRPasses() { registerGeneralPasses(); } + +} // namespace fir::support + +#endif // OPTIMIZER_SUPPORT_INITFIR_H 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/CMakeLists.txt =================================================================== --- flang/lib/Optimizer/CMakeLists.txt +++ flang/lib/Optimizer/CMakeLists.txt @@ -6,6 +6,7 @@ Dialect/FIROps.cpp Dialect/FIRType.cpp + Support/FIRContext.cpp Support/InternalNames.cpp Support/KindMapping.cpp Index: flang/lib/Optimizer/Support/FIRContext.cpp =================================================================== --- /dev/null +++ flang/lib/Optimizer/Support/FIRContext.cpp @@ -0,0 +1,65 @@ +//===-- FIRContext.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/tools/tco/tco.cpp =================================================================== --- flang/tools/tco/tco.cpp +++ flang/tools/tco/tco.cpp @@ -11,8 +11,12 @@ // //===----------------------------------------------------------------------===// -#include "flang/Optimizer/Dialect/FIRDialect.h" +#include "flang/Optimizer/Support/FIRContext.h" +#include "flang/Optimizer/Support/InitFIR.h" +#include "flang/Optimizer/Support/InternalNames.h" #include "flang/Optimizer/Support/KindMapping.h" +#include "mlir/Conversion/SCFToStandard/SCFToStandard.h" +#include "mlir/IR/AsmState.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/MLIRContext.h" #include "mlir/Parser.h" @@ -24,6 +28,7 @@ #include "llvm/Support/InitLLVM.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" @@ -41,6 +46,10 @@ cl::desc("Parse and pretty-print the input"), cl::init(false)); +static cl::opt targetTriple("target", + cl::desc("specify a target triple"), + cl::init("native")); + static void printModuleBody(mlir::ModuleOp mod, raw_ostream &output) { for (auto &op : mod.getBody()->without_terminator()) output << op << '\n'; @@ -62,8 +71,9 @@ SourceMgr sourceMgr; sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), SMLoc()); mlir::DialectRegistry registry; - fir::registerFIRDialects(registry); + fir::support::registerAndLoadDialects(registry); mlir::MLIRContext context(registry); + auto owningRef = mlir::parseSourceFile(sourceMgr, &context); if (!owningRef) { @@ -79,7 +89,14 @@ ToolOutputFile out(outputFilename, ec, sys::fs::OF_None); // run passes - mlir::PassManager pm{&context}; + llvm::Triple triple(fir::determineTargetTriple(targetTriple)); + fir::NameUniquer uniquer; + fir::KindMapping kindMap{&context}; + fir::setTargetTriple(*owningRef, triple); + fir::setNameUniquer(*owningRef, uniquer); + fir::setKindMapping(*owningRef, kindMap); + mlir::PassManager pm(&context, mlir::OpPassManager::Nesting::Implicit); + pm.enableVerifier(/*verifyPasses=*/true); mlir::applyPassManagerCLOptions(pm); if (emitFir) { // parse the input and pretty-print it back out @@ -106,7 +123,8 @@ } int main(int argc, char **argv) { - fir::registerFIRPasses(); + fir::support::registerFIRPasses(); + [[maybe_unused]] InitLLVM y(argc, argv); mlir::registerPassManagerCLOptions(); mlir::PassPipelineCLParser passPipe("", "Compiler passes to run");