-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[CodeExtractor] Improve debug info for input values. #136016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 7 commits
4adba9b
f209196
f08fe28
1a28e55
f0ad59a
4180e9f
73c78cb
393108c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -1239,11 +1239,19 @@ static void eraseDebugIntrinsicsWithNonLocalRefs(Function &F) { | |||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
/// Fix up the debug info in the old and new functions by pointing line | ||||||||||||||||||||
/// locations and debug intrinsics to the new subprogram scope, and by deleting | ||||||||||||||||||||
/// intrinsics which point to values outside of the new function. | ||||||||||||||||||||
/// Fix up the debug info in the old and new functions. Following changes are | ||||||||||||||||||||
/// done. | ||||||||||||||||||||
/// 1. If a debug record points to a value that has been replaced, update the | ||||||||||||||||||||
/// record to use the new value. | ||||||||||||||||||||
/// 2. If an Input value that has been replaced was used as a location of a | ||||||||||||||||||||
/// debug record in the Parent function, then materealize a similar record in | ||||||||||||||||||||
/// the new function. | ||||||||||||||||||||
/// 3. Point line locations and debug intrinsics to the new subprogram scope | ||||||||||||||||||||
/// 4. Remove intrinsics which point to values outside of the new function. | ||||||||||||||||||||
static void fixupDebugInfoPostExtraction(Function &OldFunc, Function &NewFunc, | ||||||||||||||||||||
CallInst &TheCall) { | ||||||||||||||||||||
CallInst &TheCall, | ||||||||||||||||||||
const SetVector<Value *> &Inputs, | ||||||||||||||||||||
ArrayRef<Value *> NewValues) { | ||||||||||||||||||||
DISubprogram *OldSP = OldFunc.getSubprogram(); | ||||||||||||||||||||
LLVMContext &Ctx = OldFunc.getContext(); | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -1270,14 +1278,48 @@ static void fixupDebugInfoPostExtraction(Function &OldFunc, Function &NewFunc, | |||||||||||||||||||
/*LineNo=*/0, SPType, /*ScopeLine=*/0, DINode::FlagZero, SPFlags); | ||||||||||||||||||||
NewFunc.setSubprogram(NewSP); | ||||||||||||||||||||
|
||||||||||||||||||||
auto UpdateOrInsertDebugRecord = [&](auto *DR, Value *OldLoc, Value *NewLoc, | ||||||||||||||||||||
DIExpression *Expr, bool Declare) { | ||||||||||||||||||||
if (DR->getParent()->getParent() == &NewFunc) | ||||||||||||||||||||
DR->replaceVariableLocationOp(OldLoc, NewLoc); | ||||||||||||||||||||
else { | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
https://llvm.org/docs/CodingStandards.html#use-early-exits-and-continue-to-simplify-code |
||||||||||||||||||||
if (Declare) | ||||||||||||||||||||
DIB.insertDeclare(NewLoc, DR->getVariable(), Expr, DR->getDebugLoc(), | ||||||||||||||||||||
&NewFunc.getEntryBlock()); | ||||||||||||||||||||
else | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
llvm.org/docs/CodingStandards.html#use-early-exits-and-continue-to-simplify-code |
||||||||||||||||||||
DIB.insertDbgValueIntrinsic( | ||||||||||||||||||||
NewLoc, DR->getVariable(), Expr, DR->getDebugLoc(), | ||||||||||||||||||||
NewFunc.getEntryBlock().getTerminator()->getIterator()); | ||||||||||||||||||||
} | ||||||||||||||||||||
}; | ||||||||||||||||||||
for (auto [Input, NewVal] : zip_equal(Inputs, NewValues)) { | ||||||||||||||||||||
SmallVector<DbgVariableIntrinsic *, 1> DbgUsers; | ||||||||||||||||||||
SmallVector<DbgVariableRecord *, 1> DPUsers; | ||||||||||||||||||||
findDbgUsers(DbgUsers, Input, &DPUsers); | ||||||||||||||||||||
DIExpression *Expr = DIB.createExpression(); | ||||||||||||||||||||
|
||||||||||||||||||||
// Iterate the debud users of the Input values. If they are in the extracted | ||||||||||||||||||||
// function then update their location with the new value. If they are in | ||||||||||||||||||||
// the parent function then create a similar debug record. | ||||||||||||||||||||
for (auto *DVI : DbgUsers) | ||||||||||||||||||||
UpdateOrInsertDebugRecord(DVI, Input, NewVal, Expr, | ||||||||||||||||||||
isa<DbgDeclareInst>(DVI)); | ||||||||||||||||||||
for (auto *DVR : DPUsers) | ||||||||||||||||||||
UpdateOrInsertDebugRecord(DVR, Input, NewVal, Expr, DVR->isDbgDeclare()); | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
auto IsInvalidLocation = [&NewFunc](Value *Location) { | ||||||||||||||||||||
// Location is invalid if it isn't a constant or an instruction, or is an | ||||||||||||||||||||
// instruction but isn't in the new function. | ||||||||||||||||||||
if (!Location || | ||||||||||||||||||||
(!isa<Constant>(Location) && !isa<Instruction>(Location))) | ||||||||||||||||||||
// Location is invalid if it isn't a constant, an instruction or an | ||||||||||||||||||||
// argument, or is an instruction/argument but isn't in the new function. | ||||||||||||||||||||
if (!Location || (!isa<Constant>(Location) && !isa<Argument>(Location) && | ||||||||||||||||||||
!isa<Instruction>(Location))) | ||||||||||||||||||||
return true; | ||||||||||||||||||||
Instruction *LocationInst = dyn_cast<Instruction>(Location); | ||||||||||||||||||||
return LocationInst && LocationInst->getFunction() != &NewFunc; | ||||||||||||||||||||
|
||||||||||||||||||||
if (Argument *Arg = dyn_cast<Argument>(Location)) | ||||||||||||||||||||
return Arg->getParent() != &NewFunc; | ||||||||||||||||||||
else if (Instruction *LocationInst = dyn_cast<Instruction>(Location)) | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||
return LocationInst->getFunction() != &NewFunc; | ||||||||||||||||||||
return false; | ||||||||||||||||||||
}; | ||||||||||||||||||||
|
||||||||||||||||||||
// Debug intrinsics in the new function need to be updated in one of two | ||||||||||||||||||||
|
@@ -1506,9 +1548,10 @@ CodeExtractor::extractCodeRegion(const CodeExtractorAnalysisCache &CEAC, | |||||||||||||||||||
inputs, outputs, EntryFreq, oldFunction->getName() + "." + SuffixToUse, | ||||||||||||||||||||
StructValues, StructTy); | ||||||||||||||||||||
newFunction->IsNewDbgInfoFormat = oldFunction->IsNewDbgInfoFormat; | ||||||||||||||||||||
SmallVector<Value *> NewValues; | ||||||||||||||||||||
|
||||||||||||||||||||
emitFunctionBody(inputs, outputs, StructValues, newFunction, StructTy, header, | ||||||||||||||||||||
SinkingCands); | ||||||||||||||||||||
SinkingCands, NewValues); | ||||||||||||||||||||
|
||||||||||||||||||||
std::vector<Value *> Reloads; | ||||||||||||||||||||
CallInst *TheCall = emitReplacerCall( | ||||||||||||||||||||
|
@@ -1518,7 +1561,8 @@ CodeExtractor::extractCodeRegion(const CodeExtractorAnalysisCache &CEAC, | |||||||||||||||||||
insertReplacerCall(oldFunction, header, TheCall->getParent(), outputs, | ||||||||||||||||||||
Reloads, ExitWeights); | ||||||||||||||||||||
|
||||||||||||||||||||
fixupDebugInfoPostExtraction(*oldFunction, *newFunction, *TheCall); | ||||||||||||||||||||
fixupDebugInfoPostExtraction(*oldFunction, *newFunction, *TheCall, inputs, | ||||||||||||||||||||
NewValues); | ||||||||||||||||||||
|
||||||||||||||||||||
LLVM_DEBUG(if (verifyFunction(*newFunction, &errs())) { | ||||||||||||||||||||
newFunction->dump(); | ||||||||||||||||||||
|
@@ -1583,7 +1627,8 @@ Type *CodeExtractor::getSwitchType() { | |||||||||||||||||||
void CodeExtractor::emitFunctionBody( | ||||||||||||||||||||
const ValueSet &inputs, const ValueSet &outputs, | ||||||||||||||||||||
const ValueSet &StructValues, Function *newFunction, | ||||||||||||||||||||
StructType *StructArgTy, BasicBlock *header, const ValueSet &SinkingCands) { | ||||||||||||||||||||
StructType *StructArgTy, BasicBlock *header, const ValueSet &SinkingCands, | ||||||||||||||||||||
SmallVectorImpl<Value *> &NewValues) { | ||||||||||||||||||||
Function *oldFunction = header->getParent(); | ||||||||||||||||||||
LLVMContext &Context = oldFunction->getContext(); | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -1615,7 +1660,6 @@ void CodeExtractor::emitFunctionBody( | |||||||||||||||||||
|
||||||||||||||||||||
// Rewrite all users of the inputs in the extracted region to use the | ||||||||||||||||||||
// arguments (or appropriate addressing into struct) instead. | ||||||||||||||||||||
SmallVector<Value *> NewValues; | ||||||||||||||||||||
for (unsigned i = 0, e = inputs.size(), aggIdx = 0; i != e; ++i) { | ||||||||||||||||||||
Value *RewriteVal; | ||||||||||||||||||||
if (StructValues.contains(inputs[i])) { | ||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
; RUN: opt -passes=hotcoldsplit -hotcoldsplit-threshold=0 -S < %s | FileCheck %s | ||
|
||
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" | ||
target triple = "x86_64-unknown-linux-gnu" | ||
|
||
define void @foo(i32 %a, i32 %b) !dbg !2 { | ||
entry: | ||
%1 = alloca i32, i64 1, align 4 | ||
%2 = alloca i32, i64 1, align 4 | ||
store i32 %a, ptr %1, align 4 | ||
#dbg_declare(ptr %1, !8, !DIExpression(), !1) | ||
#dbg_value(i32 %b, !9, !DIExpression(), !1) | ||
%tobool = icmp eq i32 %a, 0 | ||
br i1 %tobool, label %if.then, label %if.end | ||
if.then: ; preds = %entry | ||
ret void | ||
|
||
if.end: ; preds = %entry | ||
store i32 10, ptr %1, align 4 | ||
%3 = add i32 %b, 1 | ||
store i32 1, ptr %2, align 4 | ||
call void @sink(i32 %3) | ||
#dbg_declare(ptr %2, !10, !DIExpression(), !1) | ||
ret void | ||
} | ||
|
||
declare void @sink(i32) cold | ||
|
||
!llvm.dbg.cu = !{!6} | ||
!llvm.module.flags = !{!0} | ||
!0 = !{i32 2, !"Debug Info Version", i32 3} | ||
!1 = !DILocation(line: 11, column: 7, scope: !2) | ||
!2 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, type: !4, spFlags: DISPFlagDefinition, unit: !6) | ||
!3 = !DIFile(filename: "test.c", directory: "") | ||
!4 = !DISubroutineType(cc: DW_CC_program, types: !5) | ||
!5 = !{} | ||
!6 = distinct !DICompileUnit(language: DW_LANG_C, file: !3) | ||
!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) | ||
!8 = !DILocalVariable(name: "a", scope: !2, file: !3, type: !7) | ||
!9 = !DILocalVariable(name: "b", scope: !2, file: !3, type: !7) | ||
!10 = !DILocalVariable(name: "c", scope: !2, file: !3, type: !7) | ||
|
||
; CHECK: define {{.*}}@foo.cold.1(ptr %[[ARG0:.*]], i32 %[[ARG1:.*]], ptr %[[ARG2:.*]]){{.*}} !dbg ![[FN:.*]] { | ||
; CHECK-NEXT: newFuncRoot: | ||
; CHECK-NEXT: #dbg_declare(ptr %[[ARG0]], ![[V1:[0-9]+]], {{.*}}) | ||
; CHECK-NEXT: #dbg_value(i32 %[[ARG1]], ![[V2:[0-9]+]], {{.*}}) | ||
; CHECK-NEXT: br | ||
; CHECK: if.end: | ||
; CHECK: #dbg_declare(ptr %[[ARG2]], ![[V3:[0-9]+]], {{.*}}) | ||
; CHECK: } | ||
|
||
; CHECK: ![[V1]] = !DILocalVariable(name: "a", scope: ![[FN]]{{.*}}) | ||
; CHECK: ![[V2]] = !DILocalVariable(name: "b", scope: ![[FN]]{{.*}}) | ||
; CHECK: ![[V3]] = !DILocalVariable(name: "c", scope: ![[FN]]{{.*}}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] indention