diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h --- a/flang/include/flang/Optimizer/Transforms/Passes.h +++ b/flang/include/flang/Optimizer/Transforms/Passes.h @@ -55,6 +55,8 @@ std::unique_ptr createPromoteToAffinePass(); std::unique_ptr createMemoryAllocationPass(); std::unique_ptr createSimplifyIntrinsicsPass(); +std::unique_ptr createAddDebugFoundationPass(); +std::unique_ptr createAddDebugFoundationPass(llvm::StringRef inputFilePath); std::unique_ptr createMemoryAllocationPass(bool dynOnHeap, std::size_t maxStackSize); diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td --- a/flang/include/flang/Optimizer/Transforms/Passes.td +++ b/flang/include/flang/Optimizer/Transforms/Passes.td @@ -178,6 +178,24 @@ ]; } +// This needs to be a "mlir::ModuleOp" pass, because we are creating debug for +// the module in this pass. +def AddDebugFoundation : Pass<"add-debug-foundation", "mlir::ModuleOp"> { + let summary = "Add the foundation for debug info"; + let description = [{ + Add the foundation for emitting debug info that can be understood by llvm. + }]; + let constructor = "::fir::createAddDebugFoundationPass()"; + let dependentDialects = [ + "fir::FIROpsDialect", "mlir::func::FuncDialect", "mlir::LLVM::LLVMDialect" + ]; + let options = [ + Option<"inputFilePath", "input-file-path", "std::string", + /*default=*/"", + "Full Path to input file."> + ]; +} + // This needs to be a "mlir::ModuleOp" pass, because it inserts simplified // functions into the module, which is invalid if a finer grain mlir::Operation // is used as the pass specification says to not touch things outside hte scope diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc --- a/flang/include/flang/Tools/CLOptions.inc +++ b/flang/include/flang/Tools/CLOptions.inc @@ -191,7 +191,7 @@ } #if !defined(FLANG_EXCLUDE_CODEGEN) -inline void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm) { +inline void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm, llvm::StringRef inputFilePath) { fir::addBoxedProcedurePass(pm); pm.addNestedPass( fir::createAbstractResultOnFuncOptPass()); @@ -200,6 +200,7 @@ fir::addCodeGenRewritePass(pm); fir::addTargetRewritePass(pm); fir::addExternalNameConversionPass(pm); + pm.addPass(fir::createAddDebugFoundationPass(inputFilePath)); fir::addFIRToLLVMPass(pm); } @@ -209,12 +210,12 @@ /// \param optLevel - optimization level used for creating FIR optimization /// passes pipeline inline void createMLIRToLLVMPassPipeline( - mlir::PassManager &pm, llvm::OptimizationLevel optLevel = defaultOptLevel) { + mlir::PassManager &pm, llvm::StringRef inputFilePath, llvm::OptimizationLevel optLevel = defaultOptLevel) { // Add default optimizer pass pipeline. fir::createDefaultFIROptimizerPassPipeline(pm, optLevel); // Add codegen pass pipeline. - fir::createDefaultFIRCodeGenPassPipeline(pm); + fir::createDefaultFIRCodeGenPassPipeline(pm, inputFilePath); } #undef FLANG_EXCLUDE_CODEGEN #endif diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -540,8 +540,9 @@ pm.addPass(std::make_unique()); pm.enableVerifier(/*verifyPasses=*/true); + std::string filePath{getCurrentFileOrBufferName()}; // Create the pass pipeline - fir::createMLIRToLLVMPassPipeline(pm, level); + fir::createMLIRToLLVMPassPipeline(pm, filePath, level); mlir::applyPassManagerCLOptions(pm); // run the pass manager diff --git a/flang/lib/Optimizer/Transforms/AddDebugFoundation.cpp b/flang/lib/Optimizer/Transforms/AddDebugFoundation.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Optimizer/Transforms/AddDebugFoundation.cpp @@ -0,0 +1,92 @@ +//===- SimplifyIntrinsics.cpp -- replace intrinsics with simpler form -----===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +/// \file +/// This pass populates some debug information for the module and functions. +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/Todo.h" +#include "flang/Optimizer/Dialect/FIRDialect.h" +#include "flang/Optimizer/Dialect/FIROps.h" +#include "flang/Optimizer/Dialect/FIRType.h" +#include "flang/Optimizer/Support/FIRContext.h" +#include "flang/Optimizer/Transforms/Passes.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/IR/Matchers.h" +#include "mlir/IR/TypeUtilities.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/DialectConversion.h" +#include "mlir/Transforms/GreedyPatternRewriteDriver.h" +#include "mlir/Transforms/RegionUtils.h" +#include "llvm/ADT/Optional.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +namespace fir { +#define GEN_PASS_DEF_ADDDEBUGFOUNDATION +#define GEN_PASS_DECL_ADDDEBUGFOUNDATION +#include "flang/Optimizer/Transforms/Passes.h.inc" +} // namespace fir + +#define DEBUG_TYPE "flang-add-debug-foundation" + +namespace { + +class AddDebugFoundationPass + : public fir::impl::AddDebugFoundationBase { +public: + AddDebugFoundationPass(llvm::StringRef inputFilePath) + : inputFilePath(inputFilePath) {} + void runOnOperation() override; + +private: + std::string inputFilePath; +}; + +} // namespace + +void AddDebugFoundationPass::runOnOperation() { + mlir::ModuleOp module = getOperation(); + mlir::MLIRContext *context = &getContext(); + mlir::OpBuilder builder(context); + mlir::LLVM::DIFileAttr fileAttr = mlir::LLVM::DIFileAttr::get( + context, llvm::sys::path::filename(inputFilePath), + llvm::sys::path::parent_path(inputFilePath)); + mlir::StringAttr producer = mlir::StringAttr::get(context, "Flang"); + mlir::LLVM::DICompileUnitAttr cuAttr = mlir::LLVM::DICompileUnitAttr::get( + context, llvm::dwarf::getLanguage("DW_LANG_Fortran95"), fileAttr, + producer, false, mlir::LLVM::DIEmissionKind::LineTablesOnly); + module.walk([&](mlir::func::FuncOp funcOp) { + mlir::StringAttr funcName = + mlir::StringAttr::get(context, funcOp.getName()); + mlir::LLVM::DIScopeAttr scopeAttr; + mlir::LLVM::DIBasicTypeAttr bT = mlir::LLVM::DIBasicTypeAttr::get( + context, llvm::dwarf::DW_TAG_base_type, "void", 0, 1); + mlir::LLVM::DISubroutineTypeAttr subTypeAttr = + mlir::LLVM::DISubroutineTypeAttr::get( + context, llvm::dwarf::getCallingConvention("DW_CC_normal"), bT, {bT}); + mlir::LLVM::DISubprogramAttr spAttr = mlir::LLVM::DISubprogramAttr::get( + context, cuAttr, fileAttr, funcName, funcName, fileAttr, 1, 1, + mlir::LLVM::DISubprogramFlags::Definition, subTypeAttr); + funcOp->setLoc(builder.getFusedLoc({funcOp->getLoc()}, spAttr)); + }); +} + +std::unique_ptr +fir::createAddDebugFoundationPass(llvm::StringRef inputFilePath) { + return std::make_unique(inputFilePath); +} + +std::unique_ptr fir::createAddDebugFoundationPass() { + return std::make_unique(""); +} diff --git a/flang/lib/Optimizer/Transforms/CMakeLists.txt b/flang/lib/Optimizer/Transforms/CMakeLists.txt --- a/flang/lib/Optimizer/Transforms/CMakeLists.txt +++ b/flang/lib/Optimizer/Transforms/CMakeLists.txt @@ -12,6 +12,7 @@ SimplifyRegionLite.cpp AlgebraicSimplification.cpp SimplifyIntrinsics.cpp + AddDebugFoundation.cpp DEPENDS FIRBuilder diff --git a/flang/tools/tco/tco.cpp b/flang/tools/tco/tco.cpp --- a/flang/tools/tco/tco.cpp +++ b/flang/tools/tco/tco.cpp @@ -119,10 +119,10 @@ } else { if (codeGenLLVM) { // Run only CodeGen passes. - fir::createDefaultFIRCodeGenPassPipeline(pm); + fir::createDefaultFIRCodeGenPassPipeline(pm, inputFilename.c_str()); } else { // Run tco with O2 by default. - fir::createMLIRToLLVMPassPipeline(pm, llvm::OptimizationLevel::O2); + fir::createMLIRToLLVMPassPipeline(pm, inputFilename.c_str(), llvm::OptimizationLevel::O2); } fir::addLLVMDialectToLLVMPass(pm, out.os()); }