diff --git a/.github/golden/hls-test-suite/decoupled/mergesort_decouple.cycles b/.github/golden/hls-test-suite/decoupled/mergesort_decouple.cycles index 8cf24d613..2606a9111 100644 --- a/.github/golden/hls-test-suite/decoupled/mergesort_decouple.cycles +++ b/.github/golden/hls-test-suite/decoupled/mergesort_decouple.cycles @@ -1 +1 @@ -193558 \ No newline at end of file +193602 \ No newline at end of file diff --git a/.github/golden/hls-test-suite/decoupled/mergesort_decouple4.cycles b/.github/golden/hls-test-suite/decoupled/mergesort_decouple4.cycles index 9e538f3c6..8a5316ba7 100644 --- a/.github/golden/hls-test-suite/decoupled/mergesort_decouple4.cycles +++ b/.github/golden/hls-test-suite/decoupled/mergesort_decouple4.cycles @@ -1 +1 @@ -13766 \ No newline at end of file +13813 \ No newline at end of file diff --git a/jlm/llvm/backend/IpGraphToLlvmConverter.cpp b/jlm/llvm/backend/IpGraphToLlvmConverter.cpp index c69d1abd4..42ef30ddd 100644 --- a/jlm/llvm/backend/IpGraphToLlvmConverter.cpp +++ b/jlm/llvm/backend/IpGraphToLlvmConverter.cpp @@ -31,6 +31,8 @@ #include #include +#include +#include #include #include @@ -45,10 +47,28 @@ class IpGraphToLlvmConverter::Context final std::unordered_map::const_iterator; public: + ~Context() + { + diBuilder_.finalize(); + } + Context(InterProceduralGraphModule & ipGraphModule, ::llvm::Module & llvmModule) - : LlvmModule_(llvmModule), - IpGraphModule_(ipGraphModule) - {} + : llvmModule_(llvmModule), + IpGraphModule_(ipGraphModule), + diBuilder_(llvmModule) + { + auto sourceFile = llvmModule.getSourceFileName(); + if (sourceFile.empty()) + sourceFile = "unknown"; + + diBuilder_.createCompileUnit( + ::llvm::dwarf::DW_LANG_C, + diBuilder_.createFile(sourceFile, "."), + "jlm", + false, + "", + 0); + } Context(const Context &) = delete; @@ -71,7 +91,24 @@ class IpGraphToLlvmConverter::Context final ::llvm::Module & llvm_module() const noexcept { - return LlvmModule_; + return llvmModule_; + } + + [[nodiscard]] ::llvm::DIBuilder & + getDIBuilder() noexcept + { + return diBuilder_; + } + + [[nodiscard]] ::llvm::DICompileUnit & + getDICompileUnit() const noexcept + { + JLM_ASSERT( + std::distance( + llvmModule_.debug_compile_units().begin(), + llvmModule_.debug_compile_units().end()) + == 1); + return **llvmModule_.debug_compile_units().begin(); } const_iterator @@ -127,8 +164,9 @@ class IpGraphToLlvmConverter::Context final } private: - ::llvm::Module & LlvmModule_; + ::llvm::Module & llvmModule_; InterProceduralGraphModule & IpGraphModule_; + ::llvm::DIBuilder diBuilder_; std::unordered_map variables_; std::unordered_map nodes_; TypeConverter TypeConverter_; @@ -1741,13 +1779,23 @@ IpGraphToLlvmConverter::convert_operation( void IpGraphToLlvmConverter::convert_instruction( const llvm::ThreeAddressCode & tac, - const llvm::ControlFlowGraphNode * node) + const llvm::ControlFlowGraphNode * node, + ::llvm::DISubprogram & diSubprogram) { std::vector operands; for (size_t n = 0; n < tac.noperands(); n++) operands.push_back(tac.operand(n)); ::llvm::IRBuilder<> builder(Context_->basic_block(node)); + if (const auto rvsdgNodeLocation = tac.getRvsdgNodeLocation(); rvsdgNodeLocation.has_value()) + { + auto debugLoc = ::llvm::DILocation::get( + Context_->llvm_module().getContext(), + rvsdgNodeLocation.value().regionId, + rvsdgNodeLocation.value().nodeId, + &diSubprogram); + builder.SetCurrentDebugLocation(debugLoc); + } const auto & op = tac.operation(); auto r = convert_operation(op, op, operands, builder); if (r != nullptr) @@ -1824,7 +1872,9 @@ IpGraphToLlvmConverter::create_unconditional_branch(const ControlFlowGraphNode * } void -IpGraphToLlvmConverter::create_conditional_branch(const ControlFlowGraphNode * node) +IpGraphToLlvmConverter::create_conditional_branch( + const ControlFlowGraphNode * node, + ::llvm::DISubprogram & diSubprogram) { JLM_ASSERT(node->NumOutEdges() == 2); JLM_ASSERT(node->OutEdge(0)->sink() != node->cfg().exit()); @@ -1834,6 +1884,15 @@ IpGraphToLlvmConverter::create_conditional_branch(const ControlFlowGraphNode * n auto branch = static_cast(node)->tacs().last(); JLM_ASSERT(branch && is(branch)); JLM_ASSERT(Context_->value(branch->operand(0))->getType()->isIntegerTy(1)); + if (const auto rvsdgNodeLocation = branch->getRvsdgNodeLocation(); rvsdgNodeLocation.has_value()) + { + auto debugLoc = ::llvm::DILocation::get( + Context_->llvm_module().getContext(), + rvsdgNodeLocation.value().regionId, + rvsdgNodeLocation.value().nodeId, + &diSubprogram); + builder.SetCurrentDebugLocation(debugLoc); + } auto condition = Context_->value(branch->operand(0)); auto bbfalse = Context_->basic_block(node->OutEdge(0)->sink()); @@ -1883,7 +1942,9 @@ IpGraphToLlvmConverter::create_switch(const ControlFlowGraphNode * node) } void -IpGraphToLlvmConverter::create_terminator_instruction(const llvm::ControlFlowGraphNode * node) +IpGraphToLlvmConverter::create_terminator_instruction( + const llvm::ControlFlowGraphNode * node, + ::llvm::DISubprogram & diSubprogram) { JLM_ASSERT(is(node)); auto & tacs = static_cast(node)->tacs(); @@ -1904,7 +1965,7 @@ IpGraphToLlvmConverter::create_terminator_instruction(const llvm::ControlFlowGra // conditional branch if (Context_->value(branch->operand(0))->getType()->isIntegerTy(1)) - return create_conditional_branch(node); + return create_conditional_branch(node, diSubprogram); // switch create_switch(node); @@ -2173,7 +2234,7 @@ IpGraphToLlvmConverter::convert_cfg(ControlFlowGraph & cfg, ::llvm::Function & f JLM_ASSERT(is(node)); auto & tacs = static_cast(node)->tacs(); for (const auto & tac : tacs) - convert_instruction(*tac, node); + convert_instruction(*tac, node, *f.getSubprogram()); } // create cfg structure @@ -2182,7 +2243,7 @@ IpGraphToLlvmConverter::convert_cfg(ControlFlowGraph & cfg, ::llvm::Function & f if (node == cfg.entry() || node == cfg.exit()) continue; - create_terminator_instruction(node); + create_terminator_instruction(node, *f.getSubprogram()); } // patch phi instructions @@ -2225,7 +2286,6 @@ IpGraphToLlvmConverter::convert_function(const FunctionNode & node) // Type, name, attributes and calling convention have already been set on the LLVM Function. // The only conversion that remains is the function body. - convert_cfg(*node.cfg(), *f); } @@ -2304,6 +2364,27 @@ IpGraphToLlvmConverter::convert_ipgraph() auto attributes = convert_attributes(*n); f->setAttributes(attributes); + // Create and attach debug info only for function *definitions*. + // For declarations (e.g. libc functions like printf), attaching multiple distinct + // DISubprograms across translation units/passes can easily create invalid IR. + if (n->cfg()) + { + auto & diBuilder = Context_->getDIBuilder(); + auto diTypeArray = diBuilder.getOrCreateTypeArray({}); + auto * subroutineType = diBuilder.createSubroutineType(diTypeArray); + auto * sp = diBuilder.createFunction( + Context_->getDICompileUnit().getFile(), + n->name(), + n->name(), + Context_->getDICompileUnit().getFile(), + 1, + subroutineType, + 1, + ::llvm::DINode::FlagZero, + ::llvm::DISubprogram::SPFlagDefinition); + f->setSubprogram(sp); + } + Context_->insert(v, f); } else @@ -2335,6 +2416,10 @@ IpGraphToLlvmConverter::ConvertModule( llvmModule->setSourceFileName(ipGraphModule.source_filename().to_str()); llvmModule->setTargetTriple(ipGraphModule.target_triple()); llvmModule->setDataLayout(ipGraphModule.data_layout()); + llvmModule->addModuleFlag( + ::llvm::Module::Warning, + "Debug Info Version", + ::llvm::DEBUG_METADATA_VERSION); Context_ = Context::Create(ipGraphModule, *llvmModule); convert_ipgraph(); diff --git a/jlm/llvm/backend/IpGraphToLlvmConverter.hpp b/jlm/llvm/backend/IpGraphToLlvmConverter.hpp index ee9673156..e7fdeece0 100644 --- a/jlm/llvm/backend/IpGraphToLlvmConverter.hpp +++ b/jlm/llvm/backend/IpGraphToLlvmConverter.hpp @@ -139,13 +139,15 @@ class IpGraphToLlvmConverter final ConvertEnumAttribute(const llvm::EnumAttribute & attribute); void - create_terminator_instruction(const llvm::ControlFlowGraphNode * node); + create_terminator_instruction( + const llvm::ControlFlowGraphNode * node, + ::llvm::DISubprogram & diSubprogram); void create_switch(const ControlFlowGraphNode * node); void - create_conditional_branch(const ControlFlowGraphNode * node); + create_conditional_branch(const ControlFlowGraphNode * node, ::llvm::DISubprogram & diSubprogram); void create_unconditional_branch(const ControlFlowGraphNode * node); @@ -157,7 +159,10 @@ class IpGraphToLlvmConverter final convert_tacs(const tacsvector_t & tacs); void - convert_instruction(const llvm::ThreeAddressCode & tac, const llvm::ControlFlowGraphNode * node); + convert_instruction( + const llvm::ThreeAddressCode & tac, + const llvm::ControlFlowGraphNode * node, + ::llvm::DISubprogram & diSubprogram); /** * Converts the given operation, with the given arguments, to an LLVM instruction.