Reapply: Teach SROA how to update debug info for fragmented variables.
[opencl/llvm.git] / lib / Transforms / Scalar / SROA.cpp
index ed161fd4af3e9fcfc34da7f255b700a89fad9b2d..d0c6bd056352210144b77ffed025c26814598f4c 100644 (file)
@@ -1240,6 +1240,10 @@ class SROA : public FunctionPass {
   /// currently in the promotable queue.
   SetVector<SelectInst *, SmallVector<SelectInst *, 2>> SpeculatableSelects;
 
+  /// Debug intrinsics do not show up as regular uses in the
+  /// IR. This side-table holds the missing use edges.
+  DenseMap<AllocaInst *, DbgDeclareInst *> DbgDeclares;
+
 public:
   SROA(bool RequiresDomTree = true)
       : FunctionPass(ID), RequiresDomTree(RequiresDomTree), C(nullptr),
@@ -1257,8 +1261,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 +3968,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 +4007,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 +4103,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 +4142,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 +4167,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 = DbgDeclares.lookup(&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);
+      Instruction *NewDDI = DIB.insertDeclare(Piece.Alloca, Var, Expr, &AI);
+      NewDDI->setDebugLoc(DbgDecl->getDebugLoc());
+      assert((!DbgDeclares.count(Piece.Alloca) ||
+              DbgDeclares[Piece.Alloca] == cast<DbgDeclareInst>(NewDDI)
+             ) && "alloca already described");
+      DbgDeclares.insert(std::make_pair(Piece.Alloca,
+                                        cast<DbgDeclareInst>(NewDDI)));
+    }
+  }
   return Changed;
 }
 
@@ -4258,8 +4300,13 @@ 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 = DbgDeclares.lookup(AI)) {
+        DbgDecl->eraseFromParent();
+        DbgDeclares.erase(AI);
+      }
+    }
 
     ++NumDeleted;
     I->eraseFromParent();
@@ -4374,11 +4421,16 @@ bool SROA::runOnFunction(Function &F) {
   DT = DTWP ? &DTWP->getDomTree() : nullptr;
   AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
 
+  DbgDeclares.clear();
   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);
+    else if (DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(I))
+      if (auto AI = dyn_cast_or_null<AllocaInst>(DDI->getAddress()))
+        DbgDeclares.insert(std::make_pair(AI, DDI));
+  }
 
   bool Changed = false;
   // A set of deleted alloca instruction pointers which should be removed from