Reapply: Teach SROA how to update debug info for fragmented variables.

This reapplies r225379.

ChangeLog:
- The assertion that this commit previously ran into about the inability
  to handle indirect variables has since been removed and the backend
  can handle this now.
- Testcases were upgrade to the new MDLocation format.
- Instead of keeping a DebugDeclares map, we now use
  llvm::FindAllocaDbgDeclare().

Original commit message follows.

Debug info: Teach SROA how to update debug info for fragmented variables.
This allows us to generate debug info for extremely advanced code such as

 typedef struct { long int a; int b;} S;

 int foo(S s) {
   return s.b;
 }

which at -O1 on x86_64 is codegen'd into

 define i32 @foo(i64 %s.coerce0, i32 %s.coerce1) #0 {
   ret i32 %s.coerce1, !dbg !24
 }

with this patch we emit the following debug info for this

 TAG_formal_parameter [3]
   AT_location( 0x00000000
                0x0000000000000000 - 0x0000000000000006: rdi, piece 0x00000008, rsi, piece 0x00000004
                0x0000000000000006 - 0x0000000000000008: rdi, piece 0x00000008, rax, piece 0x00000004 )
                AT_name( "s" )
                AT_decl_file( "/Volumes/Data/llvm/_build.ninja.release/test.c" )

Thanks to chandlerc, dblaikie, and echristo for their feedback on all
previous iterations of this patch!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@226598 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Adrian Prantl
2015-01-20 19:42:22 +00:00
parent 46846844ee
commit a65da70a54
5 changed files with 316 additions and 12 deletions

View File

@ -1257,8 +1257,8 @@ private:
friend class AllocaSliceRewriter;
bool presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS);
bool rewritePartition(AllocaInst &AI, AllocaSlices &AS,
AllocaSlices::Partition &P);
AllocaInst *rewritePartition(AllocaInst &AI, AllocaSlices &AS,
AllocaSlices::Partition &P);
bool splitAlloca(AllocaInst &AI, AllocaSlices &AS);
bool runOnAlloca(AllocaInst &AI);
void clobberUse(Use &U);
@ -3964,8 +3964,8 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
/// appropriate new offsets. It also evaluates how successful the rewrite was
/// at enabling promotion and if it was successful queues the alloca to be
/// promoted.
bool SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS,
AllocaSlices::Partition &P) {
AllocaInst *SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS,
AllocaSlices::Partition &P) {
// Try to compute a friendly type for this partition of the alloca. This
// won't always succeed, in which case we fall back to a legal integer type
// or an i8 array of an appropriate size.
@ -4003,6 +4003,7 @@ bool SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS,
NewAI = &AI;
// FIXME: We should be able to bail at this point with "nothing changed".
// FIXME: We might want to defer PHI speculation until after here.
// FIXME: return nullptr;
} else {
unsigned Alignment = AI.getAlignment();
if (!Alignment) {
@ -4098,7 +4099,7 @@ bool SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS,
PostPromotionWorklist.pop_back();
}
return true;
return NewAI;
}
/// \brief Walks the slices of an alloca and form partitions based on them,
@ -4137,9 +4138,24 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
if (!IsSorted)
std::sort(AS.begin(), AS.end());
/// \brief Describes the allocas introduced by rewritePartition
/// in order to migrate the debug info.
struct Piece {
AllocaInst *Alloca;
uint64_t Offset;
uint64_t Size;
Piece(AllocaInst *AI, uint64_t O, uint64_t S)
: Alloca(AI), Offset(O), Size(S) {}
};
SmallVector<Piece, 4> Pieces;
// Rewrite each partition.
for (auto &P : AS.partitions()) {
Changed |= rewritePartition(AI, AS, P);
if (AllocaInst *NewAI = rewritePartition(AI, AS, P)) {
Changed = true;
if (NewAI != &AI)
Pieces.push_back(Piece(NewAI, P.beginOffset(), P.size()));
}
++NumPartitions;
}
@ -4147,6 +4163,28 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
MaxPartitionsPerAlloca =
std::max<unsigned>(NumPartitions, MaxPartitionsPerAlloca);
// Migrate debug information from the old alloca to the new alloca(s)
// and the individial partitions.
if (DbgDeclareInst *DbgDecl = FindAllocaDbgDeclare(&AI)) {
DIVariable Var(DbgDecl->getVariable());
DIExpression Expr(DbgDecl->getExpression());
DIBuilder DIB(*AI.getParent()->getParent()->getParent(),
/*AllowUnresolved*/ false);
bool IsSplit = Pieces.size() > 1;
for (auto Piece : Pieces) {
// Create a piece expression describing the new partition or reuse AI's
// expression if there is only one partition.
if (IsSplit)
Expr = DIB.createPieceExpression(Piece.Offset, Piece.Size);
// Remove any existing dbg.declare intrinsic describing the same alloca.
if (DbgDeclareInst *OldDDI = FindAllocaDbgDeclare(Piece.Alloca))
OldDDI->eraseFromParent();
Instruction *NewDDI = DIB.insertDeclare(Piece.Alloca, Var, Expr, &AI);
NewDDI->setDebugLoc(DbgDecl->getDebugLoc());
}
}
return Changed;
}
@ -4258,8 +4296,11 @@ void SROA::deleteDeadInstructions(
DeadInsts.insert(U);
}
if (AllocaInst *AI = dyn_cast<AllocaInst>(I))
if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) {
DeletedAllocas.insert(AI);
if (DbgDeclareInst *DbgDecl = FindAllocaDbgDeclare(AI))
DbgDecl->eraseFromParent();
}
++NumDeleted;
I->eraseFromParent();
@ -4376,9 +4417,10 @@ bool SROA::runOnFunction(Function &F) {
BasicBlock &EntryBB = F.getEntryBlock();
for (BasicBlock::iterator I = EntryBB.begin(), E = std::prev(EntryBB.end());
I != E; ++I)
I != E; ++I) {
if (AllocaInst *AI = dyn_cast<AllocaInst>(I))
Worklist.insert(AI);
}
bool Changed = false;
// A set of deleted alloca instruction pointers which should be removed from