diff --git a/modules/compiler/spirv-ll/include/spirv-ll/builder.h b/modules/compiler/spirv-ll/include/spirv-ll/builder.h index c2681cf7a..ed5a4953d 100644 --- a/modules/compiler/spirv-ll/include/spirv-ll/builder.h +++ b/modules/compiler/spirv-ll/include/spirv-ll/builder.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -230,8 +231,57 @@ class Builder { /// being translated void accessChain(OpCode const &opc); - /// @brief Check if an OpLine range is in progress and end it if there is - void checkEndOpLineRange(); + /// @brief Represents a lexical scope, used for debug information. + struct LexicalScopeTy { + /// @brief The scope, represented in LLVM metadata; could be a function or + /// block scope but is not specified here. Must not be nullptr in a valid + /// scope. + llvm::Metadata *scope = nullptr; + /// @brief An optional scope, representing where the scope was inlined. May + /// be nullptr. + llvm::Metadata *inlined_at = nullptr; + }; + + /// @brief Get the currently active debug scope in the current function the + /// builder is currently working on + /// + /// @return The function if one has been declared, otherwise std::nullopt + std::optional getCurrentFunctionLexicalScope() const; + + /// @brief Set the currently active lexical scope in the current function the + /// builder is currently working on; std::nullopt signals no active scope, or + /// the closing of an open one. + void setCurrentFunctionLexicalScope(std::optional); + + /// @brief Called at the end of a lexical scope for book-keeping. + /// @param closing_line_range True if any open line range should be closed at + /// the same time. + void closeCurrentLexicalScope(bool closing_line_range = true); + + /// @brief A type containing an OpLine line range and the beginning of the + /// range it corresponds to. + struct LineRangeBeginTy { + /// @brief A pointer to the OpLine that this line range corresponds to. + const OpLine *op_line = nullptr; + /// @brief An optional iterator pointing to the first instruction the range + /// applies to. Ranges may be open before a block has begun, in which case + /// this will be std::nullopt. + std::optional range_begin = std::nullopt; + }; + + /// @brief Get the currently active debug scope in the current function the + /// builder is currently working on + /// + /// @return The function if one has been declared, otherwise std::nullopt + std::optional getCurrentOpLineRange() const; + + /// @brief Set the currently active OpLine range; std::nullopt signals no + /// active OpLine range, or the closing of an open one. + void setCurrentOpLineRange(std::optional); + + /// @brief At the closing of a scope, apply debug information to instructions + /// within the closed scope. + void applyDebugInfoAtClosedRangeOrScope(); /// @brief Return a `DIType` object that represents the given type /// @@ -248,13 +298,13 @@ class Builder { /// @brief Gets (or creates) a DISubprogram for the given function and /// OpLine. - llvm::DISubprogram *getOrCreateDebugFunctionScope(llvm::Function *function, + llvm::DISubprogram *getOrCreateDebugFunctionScope(llvm::Function &function, const OpLine *op_line); - /// @brief Creates the beginning of a line range for the given OpLine, - /// contained within the basic block. - Module::LineRangeBeginTy createLineRangeBegin(const OpLine *op_line, - llvm::BasicBlock &bb); + /// @brief Gets (or creates) a DILexicalBlock for the given function and + /// OpLine. + llvm::DILexicalBlock *getOrCreateDebugBasicBlockScope(llvm::BasicBlock &bb, + const OpLine *op_line); /// @brief Called once all instructions in the module have been visited in /// order during the first pass through the SPIR-V binary. @@ -756,6 +806,12 @@ class Builder { llvm::Function *CurrentFunction; /// @brief A copy of the current function's argument list llvm::SmallVector CurrentFunctionArgs; + /// @brief Current debug scope of the function the builder is currently + /// working on (or std::nullopt if no debug scope is active) + std::optional CurrentFunctionLexicalScope; + /// @brief Current line range - marked by the beginning of an OpLine + /// instruction - (or std::nullopt if no line range is active) + std::optional CurrentOpLineRange; /// @brief A list of the builtin IDs specified at `CurrentFunction`'s creation BuiltinIDList CurrentFunctionBuiltinIDs; /// @brief Registered extended instruction set handlers. diff --git a/modules/compiler/spirv-ll/include/spirv-ll/module.h b/modules/compiler/spirv-ll/include/spirv-ll/module.h index 3a39ed6c6..dcbb3f716 100644 --- a/modules/compiler/spirv-ll/include/spirv-ll/module.h +++ b/modules/compiler/spirv-ll/include/spirv-ll/module.h @@ -395,50 +395,6 @@ class Module : public ModuleHeader { /// @return The string or std::nullopt if the ID isn't found. std::optional getDebugString(spv::Id id) const; - /// @brief A type containing an LLVM debug location and the beginning of the - /// range it corresponds to. - struct LineRangeBeginTy { - const OpLine *op_line; - llvm::DILocation *loc; - llvm::BasicBlock::iterator range_begin = llvm::BasicBlock::iterator(); - }; - - /// @brief Opens up a new OpLine range, setting it to the current one. - /// - /// Does *not* close the current one. Call closeCurrentOpLineRange() first. - /// - /// @param range_begin LineRangeBeginTy information about the range to begin. - void setCurrentOpLineRange(const LineRangeBeginTy &range_begin); - - /// @brief Closes (i.e., clears) the current OpLine range. - void closeCurrentOpLineRange(); - - /// @brief Add a completed OpLine range to the module. - /// - /// @param location DILocation that represents the OpLine instruction. - /// @param range Iterator range over which the debug metadata will be applied. - void addCompleteOpLineRange( - llvm::DILocation *location, - std::pair range); - - /// @brief A list of basic block ranges (begin/end). - using OpLineRangeVec = std::vector< - std::pair>; - - /// @brief A map from a debug location to the list of ranges it covers. - using OpLineRangeMap = llvm::MapVector; - - /// @brief Get reference to complete OpLine range list. - /// - /// @return Reference to map of `DILocation`/iterator range pairs - OpLineRangeMap &getOpLineRanges(); - - /// @brief Get `DILocation`/iterator pair for current OpLine range - /// - /// @return Pair containing `DILocation` and iterator range, location will be - /// nullptr if there isn't an ongoing range - std::optional getCurrentOpLineRange() const; - /// @brief Add a basic block and associated lexical block to the module. /// /// @param b_block Basic block to associate the lexical block with. @@ -1047,16 +1003,6 @@ class Module : public ModuleHeader { llvm::DenseMap DebugStrings; /// @brief `DIFile` object specified by the module currently being translated. llvm::DIFile *File; - /// @brief Map of DILocation to sets of basic block iterator ranges. - /// - /// Storing `std::pair`s of iterators instead of `llvm::iterator_range` - /// because the iterators need to be manipulated after the module has been - /// translated in its entirety, so we can't construct the `iterator_range` - /// until that's happened but we still need to store the range. - OpLineRangeMap OpLineRanges; - /// @brief DILocation/basic block iterator pair to store the beginning of the - /// current OpLine range. - std::optional CurrentOpLineRange; /// @brief Map of BasicBlock to associated `DILexicalBlock`. llvm::DenseMap LexicalBlocks; /// @brief Map of function IDs to their associated `DISubprogram`s. diff --git a/modules/compiler/spirv-ll/source/builder.cpp b/modules/compiler/spirv-ll/source/builder.cpp index e93a57ecf..575ca48c0 100644 --- a/modules/compiler/spirv-ll/source/builder.cpp +++ b/modules/compiler/spirv-ll/source/builder.cpp @@ -36,7 +36,8 @@ spirv_ll::Builder::Builder(spirv_ll::Context &context, spirv_ll::Module &module, deviceInfo(deviceInfo), IRBuilder(*context.llvmContext), DIBuilder(*module.llvmModule), - CurrentFunction(nullptr) {} + CurrentFunction(nullptr), + CurrentFunctionLexicalScope(std::nullopt) {} llvm::IRBuilder<> &spirv_ll::Builder::getIRBuilder() { return IRBuilder; } @@ -155,26 +156,32 @@ llvm::Error spirv_ll::Builder::finishModuleProcessing() { return llvm::Error::success(); } +std::optional +spirv_ll::Builder::getCurrentFunctionLexicalScope() const { + return CurrentFunctionLexicalScope; +} + +void spirv_ll::Builder::setCurrentFunctionLexicalScope( + std::optional scope) { + CurrentFunctionLexicalScope = scope; +} + +std::optional +spirv_ll::Builder::getCurrentOpLineRange() const { + return CurrentOpLineRange; +} + +void spirv_ll::Builder::setCurrentOpLineRange( + std::optional scope) { + CurrentOpLineRange = scope; +} + void spirv_ll::Builder::addDebugInfoToModule() { // If any debug info was added to the module we will have at least a // `DICompileUnit` if (module.getCompileUnit()) { DIBuilder.finalize(); } - - for (auto &[loc, op_line_ranges] : module.getOpLineRanges()) { - llvm::DebugLoc location(loc); - for (auto [range_begin, range_end] : op_line_ranges) { - ++range_begin; - if (range_end != range_begin->getParent()->end()) { - ++range_end; - } - - for (auto &inst : make_range(range_begin, range_end)) { - inst.setDebugLoc(location); - } - } - } } namespace { diff --git a/modules/compiler/spirv-ll/source/builder_core.cpp b/modules/compiler/spirv-ll/source/builder_core.cpp index 9a89f0793..23ad645e0 100644 --- a/modules/compiler/spirv-ll/source/builder_core.cpp +++ b/modules/compiler/spirv-ll/source/builder_core.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -163,12 +164,25 @@ llvm::DICompileUnit *Builder::getOrCreateDICompileUnit(const OpLine *op_line) { return compile_unit; } -llvm::DISubprogram *Builder::getOrCreateDebugFunctionScope( - llvm::Function *function, const OpLine *op_line) { - if (!function) { - return nullptr; +llvm::DILexicalBlock *Builder::getOrCreateDebugBasicBlockScope( + llvm::BasicBlock &bb, const OpLine *op_line) { + if (auto *const di_block = module.getLexicalBlock(&bb)) { + return di_block; } - const OpFunction *opFunction = module.get(function); + + auto *const di_file = getOrCreateDIFile(op_line); + auto *const function_scope = + getOrCreateDebugFunctionScope(*bb.getParent(), op_line); + auto *const di_block = DIBuilder.createLexicalBlock( + function_scope, di_file, op_line->Line(), op_line->Column()); + module.addLexicalBlock(&bb, di_block); + + return di_block; +} + +llvm::DISubprogram *Builder::getOrCreateDebugFunctionScope( + llvm::Function &function, const OpLine *op_line) { + const OpFunction *opFunction = module.get(&function); // If we have a llvm::Function we should have an OpFunction. SPIRV_LL_ASSERT_PTR(opFunction); spv::Id function_id = opFunction->IdResult(); @@ -176,8 +190,8 @@ llvm::DISubprogram *Builder::getOrCreateDebugFunctionScope( if (auto *function_scope = module.getDebugFunctionScope(function_id)) { // If we've created the scope before creating the function, link the two // together here if we haven't already. - if (!function->getSubprogram()) { - function->setSubprogram(function_scope); + if (!function.getSubprogram()) { + function.setSubprogram(function_scope); } return function_scope; } @@ -199,12 +213,12 @@ llvm::DISubprogram *Builder::getOrCreateDebugFunctionScope( // TODO: pass mangled name here when we're mangling names auto *function_scope = DIBuilder.createFunction( - di_compile_unit, function->getName(), function->getName(), di_file, + di_compile_unit, function.getName(), function.getName(), di_file, op_line->Line(), dbg_function_type, 1, llvm::DINode::FlagZero, llvm::DISubprogram::SPFlagDefinition); // Set the function's debug sub-program - function->setSubprogram(function_scope); + function.setSubprogram(function_scope); // Track this sub-program for later module.addDebugFunctionScope(function_id, function_scope); @@ -212,93 +226,101 @@ llvm::DISubprogram *Builder::getOrCreateDebugFunctionScope( return function_scope; } -Module::LineRangeBeginTy Builder::createLineRangeBegin(const OpLine *op_line, - llvm::BasicBlock &bb) { - // Get or create the DILexicalBlock for this basic block. - llvm::DILexicalBlock *di_block = module.getLexicalBlock(&bb); +template <> +llvm::Error Builder::create(const OpLine *op) { + // Close the current range, if applicable. + // Note we don't close the current range afterwards, since we'll just + // overwrite it with a new one a few lines down. + applyDebugInfoAtClosedRangeOrScope(); - if (!di_block) { - auto *di_file = getOrCreateDIFile(op_line); - auto *function_scope = - getOrCreateDebugFunctionScope(bb.getParent(), op_line); - di_block = DIBuilder.createLexicalBlock(function_scope, di_file, - op_line->Line(), op_line->Column()); + llvm::Function *current_function = getCurrentFunction(); - module.addLexicalBlock(&bb, di_block); + if (!current_function || !IRBuilder.GetInsertBlock()) { + setCurrentOpLineRange(LineRangeBeginTy{op, /*range_begin*/ std::nullopt}); + return llvm::Error::success(); } + llvm::BasicBlock &bb = *IRBuilder.GetInsertBlock(); + // If there aren't any instructions in the basic block yet just go from the // start of the block. llvm::BasicBlock::iterator iter = bb.empty() ? bb.begin() : bb.back().getIterator(); - auto *di_loc = llvm::DILocation::get(di_block->getContext(), op_line->Line(), - op_line->Column(), di_block); + setCurrentOpLineRange(LineRangeBeginTy{op, iter}); - return Module::LineRangeBeginTy{op_line, di_loc, iter}; + return llvm::Error::success(); } -template <> -llvm::Error Builder::create(const OpLine *op) { - // Close the current range, if applicable. - checkEndOpLineRange(); - - llvm::Function *current_function = getCurrentFunction(); - - // Having an OpLine before you start a function is valid. We'll attach the - // current range onto the function when we create it. - if (!current_function) { - // Create a location within the current file - auto *loc = llvm::DILocation::get(*context.llvmContext, op->Line(), - op->Column(), module.getDIFile()); - module.setCurrentOpLineRange(Module::LineRangeBeginTy{op, loc}); - - return llvm::Error::success(); +void Builder::closeCurrentLexicalScope(bool closing_line_range) { + // Apply debug info to the previous scope. + applyDebugInfoAtClosedRangeOrScope(); + // Close the current op line range, unless this is a lexical scope. In this + // case, we keep any OpLine/OpNoLine range that's active, as we may later + // open a new lexical scope inside the same range: + // OpLine + // DebugScope + // DebugNoScope <- we may be here + // ... + // DebugScope + // DebugNoScope + // OpNoLine + if (closing_line_range) { + setCurrentOpLineRange(std::nullopt); } + // Close any lexical scope that's active + setCurrentFunctionLexicalScope(std::nullopt); +} - llvm::DISubprogram *function_scope = - getOrCreateDebugFunctionScope(current_function, op); - - auto *current_block = IRBuilder.GetInsertBlock(); - - // Having an OpLine before you start a block is valid. We'll attach the - // current range onto the block when we create it. - if (!current_block) { - // Create a location within the current function. - auto *loc = llvm::DILocation::get(*context.llvmContext, op->Line(), - op->Column(), function_scope); - module.setCurrentOpLineRange(Module::LineRangeBeginTy{op, loc}); - - return llvm::Error::success(); +void Builder::applyDebugInfoAtClosedRangeOrScope() { + auto line_range = getCurrentOpLineRange(); + // If we don't have line information, we can bail here. + if (!line_range) { + return; } - module.setCurrentOpLineRange(createLineRangeBegin(op, *current_block)); + const auto *op_line = line_range->op_line; + llvm::BasicBlock *bb = IRBuilder.GetInsertBlock(); - return llvm::Error::success(); -} - -void Builder::checkEndOpLineRange() { - auto line_range = module.getCurrentOpLineRange(); - if (!line_range) { + // If we don't have a block of instructions to apply + // debug information to, we can bail here. + if (!bb || bb->empty()) { + // If we have a function but haven't attached a sub-program to it, manifest + // and attach one now. It's arguable how useful this is (in the case that + // we only have empty line ranges in a function but attach a sub-program to + // it anyway). + if (auto *f = getCurrentFunction()) { + getOrCreateDebugFunctionScope(*f, op_line); + } return; } - auto [op_line, loc, begin_iter] = *line_range; + llvm::Metadata *scope = nullptr; + llvm::Metadata *inlined_at = nullptr; - llvm::BasicBlock *current_block = IRBuilder.GetInsertBlock(); + if (auto lexical_scope = getCurrentFunctionLexicalScope()) { + scope = lexical_scope->scope; + inlined_at = lexical_scope->inlined_at; + } else { + scope = getOrCreateDebugBasicBlockScope(*bb, op_line); + } - // A closed range on an empty block means nothing. - if (current_block && !current_block->empty()) { - llvm::BasicBlock::iterator end_iter = - IRBuilder.GetInsertBlock()->back().getIterator(); + auto *const di_loc = + llvm::DILocation::get(*context.llvmContext, op_line->Line(), + op_line->Column(), scope, inlined_at); - auto range = std::make_pair(begin_iter, end_iter); + llvm::BasicBlock::iterator range_begin = + std::next(line_range->range_begin.value_or(bb->begin())); + llvm::BasicBlock::iterator range_end = IRBuilder.GetInsertPoint(); - module.addCompleteOpLineRange(loc, range); + for (auto &inst : make_range(range_begin, range_end)) { + inst.setDebugLoc(di_loc); } - // Close off the current range. - module.closeCurrentOpLineRange(); + // Update the current line range to start where the range currently ends - + // we've added debug info to everything before this point. + setCurrentOpLineRange( + LineRangeBeginTy{line_range->op_line, std::prev(range_end)}); } template <> @@ -2112,9 +2134,10 @@ llvm::Error Builder::create(const OpFunction *op) { // If there's a line range currently open at this point, create and attach // the DISubprogram for this function. If there isn't, we'll generate one on - // the fly when we hit an OpLine. - if (auto current_range = module.getCurrentOpLineRange()) { - getOrCreateDebugFunctionScope(function, current_range->op_line); + // the fly when we hit an OpLine but it'll have that OpLine's line/column + // information. + if (auto current_range = getCurrentOpLineRange()) { + getOrCreateDebugFunctionScope(*function, current_range->op_line); } return llvm::Error::success(); @@ -2435,7 +2458,7 @@ llvm::Error Builder::create(const OpFunctionEnd *) { } setCurrentFunction(nullptr); - checkEndOpLineRange(); + return llvm::Error::success(); } @@ -6022,9 +6045,20 @@ llvm::Error Builder::create(const OpLabel *op) { generateSpecConstantOps(); } - if (auto current_range = module.getCurrentOpLineRange()) { - module.setCurrentOpLineRange( - createLineRangeBegin(current_range->op_line, *bb)); + // If there's a line range currently open at this point, create and register + // a DILexicalBlock for this function. If there isn't, we'll generate one on + // the fly when we hit an OpLine but it'll have that OpLine's line/column + // information. + // Note that it's legal for there to be an open line range before the first + // basic block in a function, but not any subsequent ones, because all blocks + // must end in a block termination instruction, and those close line ranges. + // OpLine <- new line range opens here + // OpFunction + // OpLine <- new line range opens here; old one closes + // OpLabel + // OpBranch <- line range closes here + if (auto current_range = getCurrentOpLineRange()) { + getOrCreateDebugBasicBlockScope(*bb, current_range->op_line); } module.addID(op->IdResult(), op, bb); @@ -6038,8 +6072,8 @@ llvm::Error Builder::create(const OpBranch *op) { IRBuilder.CreateBr(bb); - // This instruction ends a block. - checkEndOpLineRange(); + // This instruction ends a block, and thus a scope. + closeCurrentLexicalScope(); return llvm::Error::success(); } @@ -6086,8 +6120,8 @@ llvm::Error Builder::create( } } - // This instruction ends a block. - checkEndOpLineRange(); + // This instruction ends a block, and thus a scope. + closeCurrentLexicalScope(); return llvm::Error::success(); } @@ -6115,8 +6149,8 @@ llvm::Error Builder::create(const OpSwitch *op) { switchInst->addCase(llvm::cast(caseVal), caseBB); } - // This instruction ends a block. - checkEndOpLineRange(); + // This instruction ends a block, and thus a scope. + closeCurrentLexicalScope(); return llvm::Error::success(); } @@ -6126,8 +6160,8 @@ llvm::Error Builder::create(const OpKill *) { // This instruction is only valid in the Fragment execuction model, which is // not supported. - // This instruction ends a block. - checkEndOpLineRange(); + // This instruction ends a block, and thus a scope. + closeCurrentLexicalScope(); return llvm::Error::success(); } @@ -6137,8 +6171,8 @@ llvm::Error Builder::create(const OpReturn *) { SPIRV_LL_ASSERT_PTR(getCurrentFunction()); IRBuilder.CreateRetVoid(); - // This instruction ends a block. - checkEndOpLineRange(); + // This instruction ends a block, and thus a scope. + closeCurrentLexicalScope(); return llvm::Error::success(); } @@ -6152,8 +6186,8 @@ llvm::Error Builder::create(const OpReturnValue *op) { IRBuilder.CreateRet(value); - // This instruction ends a block. - checkEndOpLineRange(); + // This instruction ends a block, and thus a scope. + closeCurrentLexicalScope(); return llvm::Error::success(); } @@ -6162,8 +6196,8 @@ template <> llvm::Error Builder::create(const OpUnreachable *) { IRBuilder.CreateUnreachable(); - // This instruction ends a block. - checkEndOpLineRange(); + // This instruction ends a block, and thus a scope. + closeCurrentLexicalScope(); return llvm::Error::success(); } @@ -7205,7 +7239,8 @@ llvm::Error Builder::create( template <> llvm::Error Builder::create(const OpNoLine *) { - checkEndOpLineRange(); + applyDebugInfoAtClosedRangeOrScope(); + setCurrentOpLineRange(std::nullopt); return llvm::Error::success(); } diff --git a/modules/compiler/spirv-ll/source/module.cpp b/modules/compiler/spirv-ll/source/module.cpp index 28461eeb1..620d8d5a6 100644 --- a/modules/compiler/spirv-ll/source/module.cpp +++ b/modules/compiler/spirv-ll/source/module.cpp @@ -65,7 +65,6 @@ spirv_ll::Module::Module( sourceMetadataString(), CompileUnit(nullptr), File(nullptr), - CurrentOpLineRange(std::nullopt), LoopControl(), specInfo(specInfo), PushConstantStructVariable(nullptr), @@ -90,7 +89,6 @@ spirv_ll::Module::Module(spirv_ll::Context &context, sourceMetadataString(), CompileUnit(nullptr), File(nullptr), - CurrentOpLineRange(std::nullopt), LoopControl(), specInfo(), PushConstantStructVariable(nullptr), @@ -223,28 +221,6 @@ std::optional spirv_ll::Module::getDebugString(spv::Id id) const { return std::nullopt; } -void spirv_ll::Module::setCurrentOpLineRange( - const LineRangeBeginTy &range_begin) { - CurrentOpLineRange = range_begin; -} - -void spirv_ll::Module::closeCurrentOpLineRange() { CurrentOpLineRange.reset(); } - -void spirv_ll::Module::addCompleteOpLineRange( - llvm::DILocation *location, - std::pair range) { - OpLineRanges[location].push_back(range); -} - -spirv_ll::Module::OpLineRangeMap &spirv_ll::Module::getOpLineRanges() { - return OpLineRanges; -} - -std::optional -spirv_ll::Module::getCurrentOpLineRange() const { - return CurrentOpLineRange; -} - void spirv_ll::Module::addLexicalBlock(llvm::BasicBlock *b_block, llvm::DILexicalBlock *lex_block) { LexicalBlocks.insert({b_block, lex_block}); diff --git a/modules/compiler/spirv-ll/test/spvasm/debug_info.spvasm b/modules/compiler/spirv-ll/test/spvasm/debug_info.spvasm index c2e09616a..7a015e980 100644 --- a/modules/compiler/spirv-ll/test/spvasm/debug_info.spvasm +++ b/modules/compiler/spirv-ll/test/spvasm/debug_info.spvasm @@ -28,8 +28,10 @@ OpSource GLSL 450 %file = OpString "modules/spirv-ll-tool/test/spvasm/debug_info.comp" OpName %main "main" + OpName %testfn2 "testfn2" OpName %a "a" OpName %b "b" + OpName %c "c" OpName %file "file" %void = OpTypeVoid %3 = OpTypeFunction %void @@ -81,7 +83,26 @@ ; CHECK: ret void OpFunctionEnd ; CHECK: } -; + + %testfn2 = OpFunction %void None %3 +; CHECK: define private spir_func void @testfn2(){{.*}} !dbg [[testfn2Subprogram:![0-9]+]] + OpLine %file 5 2 + %19 = OpLabel + OpLine %file 6 3 + %c = OpVariable %_ptr_Function_bool Function +; CHECK: %c = alloca i1{{(, align [0-9])?}}, !dbg [[cLocation:![0-9]+]] + OpBranch %20 + %20 = OpLabel + %21 = OpLoad %bool %c +; Check we're not mistakenly adding debug locations to the instructions in this +; block; the range should have ended at the last block terminator instruction +; (the OpBranch) +; CHECK: = load i1, ptr %c{{(, align [0-9])?$}} + OpReturn +; CHECK: ret void{{$}} + OpFunctionEnd +; CHECK: } + ; CHECK: !llvm.dbg.cu = !{[[CompileUnit:![0-9]+]]} ; CHECK: !llvm.ident = !{!{{[0-9]+}}} ; @@ -103,3 +124,9 @@ ; CHECK: [[ifTrueBlockLocation]] = !DILocation(line: 8, column: 3, scope: [[ifLexicalBlock:![0-9]+]]) ; CHECK: [[ifLexicalBlock]] = distinct !DILexicalBlock(scope: [[mainSubprogram]], file: !{{[0-9]+}}, line: 8, column: 3) ; CHECK: [[ifJoinLocation]] = !DILocation(line: 9, column: 5, scope: [[ifLexicalBlock]]) + +; CHECK: [[testfn2Subprogram]] = distinct !DISubprogram(name: "testfn2", linkageName: "testfn2", +; CHECK-SAME: scope: null, file: [[File]], +; CHECK-SAME: line: 5, type: [[mainSubroutineType]], +; CHECK-SAME: scopeLine: 1, spFlags: DISPFlagDefinition, +; CHECK-SAME: unit: {{![0-9]+}}{{(, retainedNodes: ![0-9]+)?}})