Skip to content

Handle #dbg_values in SROA. (#94070) #9169

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions llvm/include/llvm/IR/DebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class Module;
TinyPtrVector<DbgDeclareInst *> findDbgDeclares(Value *V);
/// As above, for DVRDeclares.
TinyPtrVector<DbgVariableRecord *> findDVRDeclares(Value *V);
/// As above, for DVRValues.
TinyPtrVector<DbgVariableRecord *> findDVRValues(Value *V);

/// Finds the llvm.dbg.value intrinsics describing a value.
void findDbgValues(
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/IR/DebugProgramInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,11 @@ class DbgVariableRecord : public DbgRecord, protected DebugValueUser {
/// Does this describe the address of a local variable. True for dbg.addr
/// and dbg.declare, but not dbg.value, which describes its value.
bool isAddressOfVariable() const { return Type == LocationType::Declare; }

/// Determine if this describes the value of a local variable. It is false for
/// dbg.declare, but true for dbg.value, which describes its value.
bool isValueOfVariable() const { return Type == LocationType::Value; }

LocationType getType() const { return Type; }

void setKillLocation();
Expand Down
8 changes: 8 additions & 0 deletions llvm/include/llvm/IR/IntrinsicInst.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,14 @@ class DbgVariableIntrinsic : public DbgInfoIntrinsic {
return getIntrinsicID() == Intrinsic::dbg_declare;
}

/// Determine if this describes the value of a local variable. It is true for
/// dbg.value, but false for dbg.declare, which describes its address, and
/// false for dbg.assign, which describes a combination of the variable's
/// value and address.
bool isValueOfVariable() const {
return getIntrinsicID() == Intrinsic::dbg_value;
}

void setKillLocation() {
// TODO: When/if we remove duplicate values from DIArgLists, we don't need
// this set anymore.
Expand Down
10 changes: 10 additions & 0 deletions llvm/include/llvm/Transforms/Utils/Local.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,16 @@ CallInst *changeToCall(InvokeInst *II, DomTreeUpdater *DTU = nullptr);
/// Dbg Intrinsic utilities
///

/// Creates and inserts a dbg_value record intrinsic before a store
/// that has an associated llvm.dbg.value intrinsic.
void InsertDebugValueAtStoreLoc(DbgVariableRecord *DVR, StoreInst *SI,
DIBuilder &Builder);

/// Creates and inserts an llvm.dbg.value intrinsic before a store
/// that has an associated llvm.dbg.value intrinsic.
void InsertDebugValueAtStoreLoc(DbgVariableIntrinsic *DII, StoreInst *SI,
DIBuilder &Builder);

/// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value
/// that has an associated llvm.dbg.declare intrinsic.
void ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII,
Expand Down
21 changes: 19 additions & 2 deletions llvm/lib/IR/DebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ using namespace llvm::dwarf;

TinyPtrVector<DbgDeclareInst *> llvm::findDbgDeclares(Value *V) {
// This function is hot. Check whether the value has any metadata to avoid a
// DenseMap lookup.
// DenseMap lookup. This check is a bitfield datamember lookup.
if (!V->isUsedByMetadata())
return {};
auto *L = LocalAsMetadata::getIfExists(V);
Expand All @@ -65,7 +65,7 @@ TinyPtrVector<DbgDeclareInst *> llvm::findDbgDeclares(Value *V) {
}
TinyPtrVector<DbgVariableRecord *> llvm::findDVRDeclares(Value *V) {
// This function is hot. Check whether the value has any metadata to avoid a
// DenseMap lookup.
// DenseMap lookup. This check is a bitfield datamember lookup.
if (!V->isUsedByMetadata())
return {};
auto *L = LocalAsMetadata::getIfExists(V);
Expand All @@ -80,6 +80,23 @@ TinyPtrVector<DbgVariableRecord *> llvm::findDVRDeclares(Value *V) {
return Declares;
}

TinyPtrVector<DbgVariableRecord *> llvm::findDVRValues(Value *V) {
// This function is hot. Check whether the value has any metadata to avoid a
// DenseMap lookup. This check is a bitfield datamember lookup.
if (!V->isUsedByMetadata())
return {};
auto *L = LocalAsMetadata::getIfExists(V);
if (!L)
return {};

TinyPtrVector<DbgVariableRecord *> Values;
for (DbgVariableRecord *DVR : L->getAllDbgVariableRecordUsers())
if (DVR->isValueOfVariable())
Values.push_back(DVR);

return Values;
}

template <typename IntrinsicT, bool DbgAssignAndValuesOnly>
static void
findDbgIntrinsics(SmallVectorImpl<IntrinsicT *> &Result, Value *V,
Expand Down
23 changes: 15 additions & 8 deletions llvm/lib/Transforms/Scalar/SROA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4977,8 +4977,6 @@ const Value *getAddress(const DbgVariableIntrinsic *DVI) {
}

const Value *getAddress(const DbgVariableRecord *DVR) {
assert(DVR->getType() == DbgVariableRecord::LocationType::Declare ||
DVR->getType() == DbgVariableRecord::LocationType::Assign);
return DVR->getAddress();
}

Expand All @@ -4989,8 +4987,6 @@ bool isKillAddress(const DbgVariableIntrinsic *DVI) {
}

bool isKillAddress(const DbgVariableRecord *DVR) {
assert(DVR->getType() == DbgVariableRecord::LocationType::Declare ||
DVR->getType() == DbgVariableRecord::LocationType::Assign);
if (DVR->getType() == DbgVariableRecord::LocationType::Assign)
return DVR->isKillAddress();
return DVR->isKillLocation();
Expand All @@ -5003,8 +4999,6 @@ const DIExpression *getAddressExpression(const DbgVariableIntrinsic *DVI) {
}

const DIExpression *getAddressExpression(const DbgVariableRecord *DVR) {
assert(DVR->getType() == DbgVariableRecord::LocationType::Declare ||
DVR->getType() == DbgVariableRecord::LocationType::Assign);
if (DVR->getType() == DbgVariableRecord::LocationType::Assign)
return DVR->getAddressExpression();
return DVR->getExpression();
Expand Down Expand Up @@ -5187,6 +5181,19 @@ insertNewDbgInst(DIBuilder &DIB, DbgVariableRecord *Orig, AllocaInst *NewAddr,
return;
}

if (Orig->isDbgValue()) {
DbgVariableRecord *DVR = DbgVariableRecord::createDbgVariableRecord(
NewAddr, Orig->getVariable(), NewFragmentExpr, Orig->getDebugLoc());
// Drop debug information if the expression doesn't start with a
// DW_OP_deref. This is because without a DW_OP_deref, the #dbg_value
// describes the address of alloca rather than the value inside the alloca.
if (!NewFragmentExpr->startsWithDeref())
DVR->setKillAddress();
BeforeInst->getParent()->insertDbgRecordBefore(DVR,
BeforeInst->getIterator());
return;
}

// Apply a DIAssignID to the store if it doesn't already have it.
if (!NewAddr->hasMetadata(LLVMContext::MD_DIAssignID)) {
NewAddr->setMetadata(LLVMContext::MD_DIAssignID,
Expand Down Expand Up @@ -5389,7 +5396,7 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
};
for_each(findDbgDeclares(Fragment.Alloca), RemoveOne);
for_each(findDVRDeclares(Fragment.Alloca), RemoveOne);

for_each(findDVRValues(Fragment.Alloca), RemoveOne);
insertNewDbgInst(DIB, DbgVariable, Fragment.Alloca, NewExpr, &AI,
NewDbgFragment, BitExtractOffset);
}
Expand All @@ -5399,6 +5406,7 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
// and the individual partitions.
for_each(findDbgDeclares(&AI), MigrateOne);
for_each(findDVRDeclares(&AI), MigrateOne);
for_each(findDVRValues(&AI), MigrateOne);
for_each(at::getAssignmentMarkers(&AI), MigrateOne);
for_each(at::getDVRAssignmentMarkers(&AI), MigrateOne);

Expand Down Expand Up @@ -5545,7 +5553,6 @@ bool SROA::deleteDeadInstructions(
}
return Changed;
}

/// Promote the allocas, using the best available technique.
///
/// This attempts to promote whatever allocas have been identified as viable in
Expand Down
34 changes: 34 additions & 0 deletions llvm/lib/Transforms/Utils/Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1731,6 +1731,26 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII,
SI->getIterator());
}

static DIExpression *dropInitialDeref(const DIExpression *DIExpr) {
int NumEltDropped = DIExpr->getElements()[0] == dwarf::DW_OP_LLVM_arg ? 3 : 1;
return DIExpression::get(DIExpr->getContext(),
DIExpr->getElements().drop_front(NumEltDropped));
}

void llvm::InsertDebugValueAtStoreLoc(DbgVariableIntrinsic *DII, StoreInst *SI,
DIBuilder &Builder) {
auto *DIVar = DII->getVariable();
assert(DIVar && "Missing variable");
auto *DIExpr = DII->getExpression();
DIExpr = dropInitialDeref(DIExpr);
Value *DV = SI->getValueOperand();

DebugLoc NewLoc = getDebugValueLoc(DII);

insertDbgValueOrDbgVariableRecord(Builder, DV, DIVar, DIExpr, NewLoc,
SI->getIterator());
}

/// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value
/// that has an associated llvm.dbg.declare intrinsic.
void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII,
Expand Down Expand Up @@ -1805,6 +1825,20 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgVariableRecord *DVR,
SI->getParent()->insertDbgRecordBefore(NewDVR, SI->getIterator());
}

void llvm::InsertDebugValueAtStoreLoc(DbgVariableRecord *DVR, StoreInst *SI,
DIBuilder &Builder) {
auto *DIVar = DVR->getVariable();
assert(DIVar && "Missing variable");
auto *DIExpr = DVR->getExpression();
DIExpr = dropInitialDeref(DIExpr);
Value *DV = SI->getValueOperand();

DebugLoc NewLoc = getDebugValueLoc(DVR);

insertDbgValueOrDbgVariableRecord(Builder, DV, DIVar, DIExpr, NewLoc,
SI->getIterator());
}

/// Inserts a llvm.dbg.value intrinsic after a phi that has an associated
/// llvm.dbg.declare intrinsic.
void llvm::ConvertDebugDeclareToDebugValue(DbgVariableIntrinsic *DII,
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,10 @@ rewriteSingleStoreAlloca(AllocaInst *AI, AllocaInfo &Info, LargeBlockInfo &LBI,
if (DbgItem->isAddressOfVariable()) {
ConvertDebugDeclareToDebugValue(DbgItem, Info.OnlyStore, DIB);
DbgItem->eraseFromParent();
} else if (DbgItem->isValueOfVariable() &&
DbgItem->getExpression()->startsWithDeref()) {
InsertDebugValueAtStoreLoc(DbgItem, Info.OnlyStore, DIB);
DbgItem->eraseFromParent();
} else if (DbgItem->getExpression()->startsWithDeref()) {
DbgItem->eraseFromParent();
}
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/DebugInfo/Generic/mem2reg-promote-alloca-1.ll
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
; CHECK: define dso_local void @fun(i32 %param)
; CHECK-NEXT: entry:
; CHECK-NEXT: #dbg_value(i32 %param, ![[PARAM:[0-9]+]], !DIExpression(),
; CHECK-NOT: #dbg_value({{.*}}, ![[PARAM]]
; CHECK-NEXT: #dbg_value(i32 %param, ![[PARAM]], !DIExpression(),
; CHECK: ![[PARAM]] = !DILocalVariable(name: "param",

@g = dso_local global i32 0, align 4, !dbg !0
Expand Down
110 changes: 110 additions & 0 deletions llvm/test/DebugInfo/sroa-handle-dbg-value.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
; This test was obtained from swift source code and then automatically reducing it via Delta.
; The swift source code was from the test test/DebugInfo/debug_scope_distinct.swift.

; RUN: opt %s -S -p=sroa -o - | FileCheck %s

; CHECK: [[SROA_5_SROA_21:%.*]] = alloca [7 x i8], align 8
; CHECK-NEXT: #dbg_value(ptr [[SROA_5_SROA_21]], !59, !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 72, 56), [[DBG72:![0-9]+]])

; CHECK: #dbg_value(ptr [[REG1:%[0-9]+]], [[META54:![0-9]+]], !DIExpression(DW_OP_deref), [[DBG78:![0-9]+]])
; CHECK-NEXT: #dbg_value(ptr [[REG2:%[0-9]+]], [[META56:![0-9]+]], !DIExpression(DW_OP_deref), [[DBG78]])
; CHECK-NEXT: #dbg_value(i64 0, [[META57:![0-9]+]], !DIExpression(), [[DBG78]])

; CHECK: [[SROA_418_SROA_COPYLOAD:%.*]] = load i8, ptr [[SROA_418_0_U1_IDX:%.*]], align 8, !dbg [[DBG78]]
; CHECK-NEXT #dbg_value(i8 [[SROA_418_SROA_COPYLOAD]], [[META59]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 64, 8), [[DBG72]])

%T4main1TV13TangentVectorV = type <{ %T4main1UV13TangentVectorV, [7 x i8], %T4main1UV13TangentVectorV }>
%T4main1UV13TangentVectorV = type <{ %T1M1SVySfG, [7 x i8], %T4main1VV13TangentVectorV }>
%T1M1SVySfG = type <{ ptr, %Ts4Int8V }>
%Ts4Int8V = type <{ i8 }>
%T4main1VV13TangentVectorV = type <{ %T1M1SVySfG }>
define hidden swiftcc void @"$s4main1TV13TangentVectorV1poiyA2E_AEtFZ"(ptr noalias nocapture sret(%T4main1TV13TangentVectorV) %0, ptr noalias nocapture dereferenceable(57) %1, ptr noalias nocapture dereferenceable(57) %2) #0 !dbg !44 {
entry:
%3 = alloca %T4main1VV13TangentVectorV
%4 = alloca %T4main1UV13TangentVectorV
call void @llvm.dbg.value(metadata ptr %1, metadata !54, metadata !DIExpression(DW_OP_deref)), !dbg !61
call void @llvm.dbg.value(metadata ptr %2, metadata !56, metadata !DIExpression(DW_OP_deref)), !dbg !61
call void @llvm.dbg.value(metadata i64 0, metadata !57, metadata !DIExpression()), !dbg !61
%.u1 = getelementptr inbounds %T4main1TV13TangentVectorV, ptr %1, i32 0, i32 0
call void @llvm.memcpy.p0.p0.i64(ptr align 8 %4, ptr align 8 %.u1, i64 25, i1 false), !dbg !61
call void @llvm.dbg.value(metadata ptr %4, metadata !62, metadata !DIExpression(DW_OP_deref)), !dbg !75
%.s = getelementptr inbounds %T4main1UV13TangentVectorV, ptr %4, i32 0, i32 0
%.s.b = getelementptr inbounds %T1M1SVySfG, ptr %.s, i32 0, i32 1
%.s.b._value = getelementptr inbounds %Ts4Int8V, ptr %.s.b, i32 0, i32 0
%12 = load i8, ptr %.s.b._value
%.v = getelementptr inbounds %T4main1UV13TangentVectorV, ptr %4, i32 0, i32 2
call void @llvm.memcpy.p0.p0.i64(ptr align 8 %3, ptr align 8 %.v, i64 9, i1 false)
%.s4 = getelementptr inbounds %T4main1VV13TangentVectorV, ptr %3, i32 0, i32 0
%.s4.c = getelementptr inbounds %T1M1SVySfG, ptr %.s4, i32 0, i32 0
%18 = load ptr, ptr %.s4.c
ret void
}
!llvm.module.flags = !{!0, !1, !2, !3, !4, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15}
!swift.module.flags = !{!33}
!llvm.linker.options = !{!34, !35, !36, !37, !38, !39, !40, !41, !42, !43}
!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 14, i32 4]}
!1 = !{i32 1, !"Objective-C Version", i32 2}
!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,no_dead_strip"}
!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
!6 = !{i32 7, !"Dwarf Version", i32 4}
!7 = !{i32 2, !"Debug Info Version", i32 3}
!8 = !{i32 1, !"wchar_size", i32 4}
!9 = !{i32 8, !"PIC Level", i32 2}
!10 = !{i32 7, !"uwtable", i32 1}
!11 = !{i32 7, !"frame-pointer", i32 1}
!12 = !{i32 1, !"Swift Version", i32 7}
!13 = !{i32 1, !"Swift ABI Version", i32 7}
!14 = !{i32 1, !"Swift Major Version", i8 6}
!15 = !{i32 1, !"Swift Minor Version", i8 0}
!16 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !17, imports: !18, sdk: "MacOSX14.4.sdk")
!17 = !DIFile(filename: "swift/swift/test/IRGen/debug_scope_distinct.swift", directory: "swift")
!18 = !{!19, !21, !23, !25, !27, !29, !31}
!19 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !17, entity: !20, file: !17)
!20 = !DIModule(scope: null, name: "main", includePath: "swift/swift/test/IRGen")
!21 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !17, entity: !22, file: !17)
!22 = !DIModule(scope: null, name: "Swift", includePath: "swift/_build/Ninja-RelWithDebInfoAssert+stdlib-RelWithDebInfo/swift-macosx-arm64/lib/swift/macosx/Swift.swiftmodule/arm64-apple-macos.swiftmodule")
!23 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !17, entity: !24, line: 60)
!24 = !DIModule(scope: null, name: "_Differentiation", includePath: "swift/_build/Ninja-RelWithDebInfoAssert+stdlib-RelWithDebInfo/swift-macosx-arm64/lib/swift/macosx/_Differentiation.swiftmodule/arm64-apple-macos.swiftmodule")
!25 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !17, entity: !26, line: 61)
!26 = !DIModule(scope: null, name: "M", includePath: "swift/_build/Ninja-RelWithDebInfoAssert+stdlib-RelWithDebInfo/swift-macosx-arm64/test-macosx-arm64/IRGen/Output/debug_scope_distinct.swift.tmp/M.swiftmodule")
!27 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !17, entity: !28, file: !17)
!28 = !DIModule(scope: null, name: "_StringProcessing", includePath: "swift/_build/Ninja-RelWithDebInfoAssert+stdlib-RelWithDebInfo/swift-macosx-arm64/lib/swift/macosx/_StringProcessing.swiftmodule/arm64-apple-macos.swiftmodule")
!29 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !17, entity: !30, file: !17)
!30 = !DIModule(scope: null, name: "_SwiftConcurrencyShims", includePath: "swift/_build/Ninja-RelWithDebInfoAssert+stdlib-RelWithDebInfo/swift-macosx-arm64/lib/swift/shims")
!31 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !17, entity: !32, file: !17)
!32 = !DIModule(scope: null, name: "_Concurrency", includePath: "swift/_build/Ninja-RelWithDebInfoAssert+stdlib-RelWithDebInfo/swift-macosx-arm64/lib/swift/macosx/_Concurrency.swiftmodule/arm64-apple-macos.swiftmodule")
!33 = !{ i1 false}
!34 = !{!"-lswiftCore"}
!35 = !{!"-lswift_StringProcessing"}
!36 = !{!"-lswift_Differentiation"}
!37 = !{!"-lswiftDarwin"}
!38 = !{!"-lswift_Concurrency"}
!39 = !{!"-lswiftSwiftOnoneSupport"}
!40 = !{!"-lobjc"}
!41 = !{!"-lswiftCompatibilityConcurrency"}
!42 = !{!"-lswiftCompatibility56"}
!43 = !{!"-lswiftCompatibilityPacks"}
!44 = distinct !DISubprogram(file: !45, type: !49, unit: !16, declaration: !52, retainedNodes: !53)
!45 = !DIFile(filename: "<compiler-generated>", directory: "/")
!46 = !DICompositeType(tag: DW_TAG_structure_type, scope: !47, elements: !48, identifier: "$s4main1TV13TangentVectorVD")
!47 = !DICompositeType(tag: DW_TAG_structure_type, identifier: "$s4main1TVD")
!48 = !{}
!49 = !DISubroutineType(types: !50)
!50 = !{ !51}
!51 = !DICompositeType(tag: DW_TAG_structure_type, identifier: "$s4main1TV13TangentVectorVXMtD")
!52 = !DISubprogram(spFlags: DISPFlagOptimized)
!53 = !{!54, !56, !57}
!54 = !DILocalVariable(name: "a", scope: !44, flags: DIFlagArtificial)
!55 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !46)
!56 = !DILocalVariable(name: "b", scope: !44, type: !55, flags: DIFlagArtificial)
!57 = !DILocalVariable(name: "c", scope: !44, type: !58, flags: DIFlagArtificial)
!58 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !51)
!61 = !DILocation(scope: !44)
!62 = !DILocalVariable(name: "d", scope: !63, type: !72, flags: DIFlagArtificial)
!63 = distinct !DISubprogram(unit: !16, retainedNodes: !70)
!64 = !DICompositeType(tag: DW_TAG_structure_type, size: 200, identifier: "$s4main1UV13TangentVectorVD")
!70 = !{}
!72 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !64)
!75 = !DILocation(scope: !63, inlinedAt: !76)
!76 = distinct !DILocation(scope: !44)
Loading