Skip to content

Commit

Permalink
[cloning] Do not duplicate types when cloning functions
Browse files Browse the repository at this point in the history
Summary:
This is an addon to the change rl304488 cloning fixes. (Originally rl304226 reverted rl304228 and reapplied rl304488 https://reviews.llvm.org/D33655)

rl304488 works great when DILocalVariables that comes from the inlined function has a 'unique-ed' type, but,
in the case when the variable type is distinct we will create a second DILocalVariable in the scope of the original function that was inlined.

Consider cloning of the following function:
```
define private void @f() !dbg !5 {
  %1 = alloca i32, !dbg !11
  call void @llvm.dbg.declare(metadata i32* %1, metadata !14, metadata !12), !dbg !18
  ret void, !dbg !18
}

!14 = !DILocalVariable(name: "inlined", scope: !15, file: !6, line: 5, type: !17) ; came from an inlined function
!15 = distinct !DISubprogram(name: "inlined", linkageName: "inlined", scope: null, file: !6, line: 8, type: !7, isLocal: true, isDefinition: true, scopeLine: 9, isOptimized: false, unit: !0, variables: !16)
!16 = !{!14}
!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "some_struct", size: 32, align: 32)
```

Without this fix, when function 'f' is cloned, we will create another DILocalVariable for "inlined", due to its type being distinct.

```
define private void @f.1() !dbg !23 {
  %1 = alloca i32, !dbg !26
  call void @llvm.dbg.declare(metadata i32* %1, metadata !28, metadata !12), !dbg !30
  ret void, !dbg !30
}

!14 = !DILocalVariable(name: "inlined", scope: !15, file: !6, line: 5, type: !17)
!15 = distinct !DISubprogram(name: "inlined", linkageName: "inlined", scope: null, file: !6, line: 8, type: !7, isLocal: true, isDefinition: true, scopeLine: 9, isOptimized: false, unit: !0, variables: !16)
!16 = !{!14}
!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "some_struct", size: 32, align: 32)
 ;
!28 = !DILocalVariable(name: "inlined", scope: !15, file: !6, line: 5, type: !29) ; OOPS second DILocalVariable
!29 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "some_struct", size: 32, align: 32)
```

Now we have two DILocalVariable for "inlined" within the same scope. This result in assert in AsmPrinter/DwarfDebug.h:131: void llvm::DbgVariable::addMMIEntry(const llvm::DbgVariable &): Assertion `V.Var == Var && "conflicting variable"' failed.
(Full example: See: https://bugs.llvm.org/show_bug.cgi?id=33492)

In this change we prevent duplication of types so that when a metadata for DILocalVariable is cloned it will get uniqued to the same metadate node as an original variable.

Reviewers: loladiro, dblaikie, aprantl, echristo

Reviewed By: loladiro

Subscribers: EricWF, llvm-commits

Differential Revision: https://reviews.llvm.org/D35106

llvm-svn: 307418
  • Loading branch information
GorNishanov committed Jul 7, 2017
1 parent 734ab3f commit 8cdf648
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 5 deletions.
20 changes: 17 additions & 3 deletions llvm/lib/Transforms/Utils/CloneFunction.cpp
Expand Up @@ -46,13 +46,21 @@ BasicBlock *llvm::CloneBasicBlock(const BasicBlock *BB, ValueToValueMapTy &VMap,
if (BB->hasName()) NewBB->setName(BB->getName()+NameSuffix);

bool hasCalls = false, hasDynamicAllocas = false, hasStaticAllocas = false;

Module *TheModule = F ? F->getParent() : nullptr;

// Loop over all instructions, and copy them over.
for (BasicBlock::const_iterator II = BB->begin(), IE = BB->end();
II != IE; ++II) {

if (DIFinder && F->getParent() && II->getDebugLoc())
DIFinder->processLocation(*F->getParent(), II->getDebugLoc().get());
if (DIFinder && TheModule) {
if (auto *DDI = dyn_cast<DbgDeclareInst>(II))
DIFinder->processDeclare(*TheModule, DDI);
else if (auto *DVI = dyn_cast<DbgValueInst>(II))
DIFinder->processValue(*TheModule, DVI);

if (auto DbgLoc = II->getDebugLoc())
DIFinder->processLocation(*TheModule, DbgLoc.get());
}

Instruction *NewInst = II->clone();
if (II->hasName())
Expand Down Expand Up @@ -153,6 +161,8 @@ void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc,
// When we remap instructions, we want to avoid duplicating inlined
// DISubprograms, so record all subprograms we find as we duplicate
// instructions and then freeze them in the MD map.
// We also record information about dbg.value and dbg.declare to avoid
// duplicating the types.
DebugInfoFinder DIFinder;

// Loop over all of the basic blocks in the function, cloning them as
Expand Down Expand Up @@ -193,6 +203,10 @@ void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc,
}
}

for (auto *Type : DIFinder.types()) {
VMap.MD()[Type].reset(Type);
}

// Loop over all of the instructions in the function, fixing up operand
// references as we go. This uses VMap to do all the hard work.
for (Function::iterator BB =
Expand Down
13 changes: 11 additions & 2 deletions llvm/unittests/Transforms/Utils/Cloning.cpp
Expand Up @@ -312,11 +312,16 @@ class CloneFunc : public ::testing::Test {
DBuilder.insertDbgValueIntrinsic(AllocaContent, 0, Variable, E, DL,
Entry);
// Also create an inlined variable.
// Create a distinct struct type that we should not duplicate during
// cloning).
auto *StructType = DICompositeType::getDistinct(
C, dwarf::DW_TAG_structure_type, "some_struct", nullptr, 0, nullptr,
nullptr, 32, 32, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr);
auto *InlinedSP =
DBuilder.createFunction(CU, "inlined", "inlined", File, 8, FuncType,
true, true, 9, DINode::FlagZero, false);
auto *InlinedVar =
DBuilder.createAutoVariable(InlinedSP, "inlined", File, 5, IntType, true);
DBuilder.createAutoVariable(InlinedSP, "inlined", File, 5, StructType, true);
auto *Scope = DBuilder.createLexicalBlock(
DBuilder.createLexicalBlockFile(InlinedSP, File), File, 1, 1);
auto InlinedDL =
Expand Down Expand Up @@ -426,7 +431,11 @@ TEST_F(CloneFunc, DebugIntrinsics) {
EXPECT_EQ(NewFunc, cast<AllocaInst>(NewIntrin->getAddress())->
getParent()->getParent());

if (!OldIntrin->getDebugLoc()->getInlinedAt()) {
if (OldIntrin->getDebugLoc()->getInlinedAt()) {
// Inlined variable should refer to the same DILocalVariable as in the
// Old Function
EXPECT_EQ(OldIntrin->getVariable(), NewIntrin->getVariable());
} else {
// Old variable must belong to the old function.
EXPECT_EQ(OldFunc->getSubprogram(),
cast<DISubprogram>(OldIntrin->getVariable()->getScope()));
Expand Down

0 comments on commit 8cdf648

Please sign in to comment.