[llvm] r274162 - StackColoring for SafeStack.

Evgeniy Stepanov via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 29 13:37:43 PDT 2016


Author: eugenis
Date: Wed Jun 29 15:37:43 2016
New Revision: 274162

URL: http://llvm.org/viewvc/llvm-project?rev=274162&view=rev
Log:
StackColoring for SafeStack.

This is a fix for PR27842.

An IR-level implementation of stack coloring tailored to work with
SafeStack. It is a bit weaker than the MI implementation in that it
does not the "lifetime start at first access" logic. This can be
improved in the future.

This patch also replaces the naive implementation of stack frame
layout with a greedy algorithm that can split existing stack slots
and even fit small objects inside the alignment padding of other
objects.

Added:
    llvm/trunk/lib/CodeGen/SafeStackColoring.cpp
    llvm/trunk/lib/CodeGen/SafeStackColoring.h
    llvm/trunk/lib/CodeGen/SafeStackLayout.cpp
    llvm/trunk/lib/CodeGen/SafeStackLayout.h
    llvm/trunk/test/Transforms/SafeStack/coloring.ll
    llvm/trunk/test/Transforms/SafeStack/coloring2.ll
Modified:
    llvm/trunk/lib/CodeGen/CMakeLists.txt
    llvm/trunk/lib/CodeGen/SafeStack.cpp

Modified: llvm/trunk/lib/CodeGen/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CMakeLists.txt?rev=274162&r1=274161&r2=274162&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/CMakeLists.txt (original)
+++ llvm/trunk/lib/CodeGen/CMakeLists.txt Wed Jun 29 15:37:43 2016
@@ -105,6 +105,8 @@ add_llvm_library(LLVMCodeGen
   RegUsageInfoCollector.cpp
   RegUsageInfoPropagate.cpp
   SafeStack.cpp
+  SafeStackColoring.cpp
+  SafeStackLayout.cpp
   ScheduleDAG.cpp
   ScheduleDAGInstrs.cpp
   ScheduleDAGPrinter.cpp

Modified: llvm/trunk/lib/CodeGen/SafeStack.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SafeStack.cpp?rev=274162&r1=274161&r2=274162&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SafeStack.cpp (original)
+++ llvm/trunk/lib/CodeGen/SafeStack.cpp Wed Jun 29 15:37:43 2016
@@ -15,6 +15,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "SafeStackColoring.h"
+#include "SafeStackLayout.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Analysis/BranchProbabilityInfo.h"
@@ -46,6 +48,7 @@
 #include "llvm/Transforms/Utils/ModuleUtils.h"
 
 using namespace llvm;
+using namespace llvm::safestack;
 
 #define DEBUG_TYPE "safestack"
 
@@ -516,40 +519,66 @@ Value *SafeStack::moveStaticAllocasToUns
 
   DIBuilder DIB(*F.getParent());
 
-  // Compute maximum alignment among static objects on the unsafe stack.
-  unsigned MaxAlignment = 0;
+  StackColoring SSC(F, StaticAllocas);
+  SSC.run();
+  SSC.removeAllMarkers();
+
+  // Unsafe stack always grows down.
+  StackLayout SSL(StackAlignment);
+  if (StackGuardSlot) {
+    Type *Ty = StackGuardSlot->getAllocatedType();
+    unsigned Align =
+        std::max(DL->getPrefTypeAlignment(Ty), StackGuardSlot->getAlignment());
+    SSL.addObject(StackGuardSlot, getStaticAllocaAllocationSize(StackGuardSlot),
+                  Align, SSC.getLiveRange(StackGuardSlot));
+  }
+
   for (Argument *Arg : ByValArguments) {
     Type *Ty = Arg->getType()->getPointerElementType();
+    uint64_t Size = DL->getTypeStoreSize(Ty);
+    if (Size == 0)
+      Size = 1; // Don't create zero-sized stack objects.
+
+    // Ensure the object is properly aligned.
     unsigned Align = std::max((unsigned)DL->getPrefTypeAlignment(Ty),
                               Arg->getParamAlignment());
-    if (Align > MaxAlignment)
-      MaxAlignment = Align;
+    SSL.addObject(Arg, Size, Align, SSC.getFullLiveRange());
   }
+
   for (AllocaInst *AI : StaticAllocas) {
     Type *Ty = AI->getAllocatedType();
+    uint64_t Size = getStaticAllocaAllocationSize(AI);
+    if (Size == 0)
+      Size = 1; // Don't create zero-sized stack objects.
+
+    // Ensure the object is properly aligned.
     unsigned Align =
         std::max((unsigned)DL->getPrefTypeAlignment(Ty), AI->getAlignment());
-    if (Align > MaxAlignment)
-      MaxAlignment = Align;
+
+    SSL.addObject(AI, Size, Align, SSC.getLiveRange(AI));
   }
 
-  if (MaxAlignment > StackAlignment) {
+  SSL.computeLayout();
+  unsigned FrameAlignment = SSL.getFrameAlignment();
+
+  // FIXME: tell SSL that we start at a less-then-MaxAlignment aligned location
+  // (AlignmentSkew).
+  if (FrameAlignment > StackAlignment) {
     // Re-align the base pointer according to the max requested alignment.
-    assert(isPowerOf2_32(MaxAlignment));
+    assert(isPowerOf2_32(FrameAlignment));
     IRB.SetInsertPoint(BasePointer->getNextNode());
     BasePointer = cast<Instruction>(IRB.CreateIntToPtr(
         IRB.CreateAnd(IRB.CreatePtrToInt(BasePointer, IntPtrTy),
-                      ConstantInt::get(IntPtrTy, ~uint64_t(MaxAlignment - 1))),
+                      ConstantInt::get(IntPtrTy, ~uint64_t(FrameAlignment - 1))),
         StackPtrTy));
   }
 
-  int64_t StaticOffset = 0; // Current stack top.
   IRB.SetInsertPoint(BasePointer->getNextNode());
 
   if (StackGuardSlot) {
-    StaticOffset += getStaticAllocaAllocationSize(StackGuardSlot);
+    unsigned Offset = SSL.getObjectOffset(StackGuardSlot);
     Value *Off = IRB.CreateGEP(BasePointer, // BasePointer is i8*
-                               ConstantInt::get(Int32Ty, -StaticOffset));
+                               ConstantInt::get(Int32Ty, -Offset));
     Value *NewAI =
         IRB.CreateBitCast(Off, StackGuardSlot->getType(), "StackGuardSlot");
 
@@ -559,29 +588,21 @@ Value *SafeStack::moveStaticAllocasToUns
   }
 
   for (Argument *Arg : ByValArguments) {
+    unsigned Offset = SSL.getObjectOffset(Arg);
     Type *Ty = Arg->getType()->getPointerElementType();
 
     uint64_t Size = DL->getTypeStoreSize(Ty);
     if (Size == 0)
       Size = 1; // Don't create zero-sized stack objects.
 
-    // Ensure the object is properly aligned.
-    unsigned Align = std::max((unsigned)DL->getPrefTypeAlignment(Ty),
-                              Arg->getParamAlignment());
-
-    // Add alignment.
-    // NOTE: we ensure that BasePointer itself is aligned to >= Align.
-    StaticOffset += Size;
-    StaticOffset = alignTo(StaticOffset, Align);
-
     Value *Off = IRB.CreateGEP(BasePointer, // BasePointer is i8*
-                               ConstantInt::get(Int32Ty, -StaticOffset));
+                               ConstantInt::get(Int32Ty, -Offset));
     Value *NewArg = IRB.CreateBitCast(Off, Arg->getType(),
                                      Arg->getName() + ".unsafe-byval");
 
     // Replace alloc with the new location.
     replaceDbgDeclare(Arg, BasePointer, BasePointer->getNextNode(), DIB,
-                      /*Deref=*/true, -StaticOffset);
+                      /*Deref=*/true, -Offset);
     Arg->replaceAllUsesWith(NewArg);
     IRB.SetInsertPoint(cast<Instruction>(NewArg)->getNextNode());
     IRB.CreateMemCpy(Off, Arg, Size, Arg->getParamAlignment());
@@ -590,23 +611,14 @@ Value *SafeStack::moveStaticAllocasToUns
   // Allocate space for every unsafe static AllocaInst on the unsafe stack.
   for (AllocaInst *AI : StaticAllocas) {
     IRB.SetInsertPoint(AI);
+    unsigned Offset = SSL.getObjectOffset(AI);
 
-    Type *Ty = AI->getAllocatedType();
     uint64_t Size = getStaticAllocaAllocationSize(AI);
     if (Size == 0)
       Size = 1; // Don't create zero-sized stack objects.
 
-    // Ensure the object is properly aligned.
-    unsigned Align =
-        std::max((unsigned)DL->getPrefTypeAlignment(Ty), AI->getAlignment());
-
-    // Add alignment.
-    // NOTE: we ensure that BasePointer itself is aligned to >= Align.
-    StaticOffset += Size;
-    StaticOffset = alignTo(StaticOffset, Align);
-
-    replaceDbgDeclareForAlloca(AI, BasePointer, DIB, /*Deref=*/true, -StaticOffset);
-    replaceDbgValueForAlloca(AI, BasePointer, DIB, -StaticOffset);
+    replaceDbgDeclareForAlloca(AI, BasePointer, DIB, /*Deref=*/true, -Offset);
+    replaceDbgValueForAlloca(AI, BasePointer, DIB, -Offset);
 
     // Replace uses of the alloca with the new location.
     // Insert address calculation close to each use to work around PR27844.
@@ -623,7 +635,7 @@ Value *SafeStack::moveStaticAllocasToUns
 
       IRBuilder<> IRBUser(InsertBefore);
       Value *Off = IRBUser.CreateGEP(BasePointer, // BasePointer is i8*
-                                     ConstantInt::get(Int32Ty, -StaticOffset));
+                                     ConstantInt::get(Int32Ty, -Offset));
       Value *Replacement = IRBUser.CreateBitCast(Off, AI->getType(), Name);
 
       if (auto *PHI = dyn_cast<PHINode>(User)) {
@@ -644,13 +656,13 @@ Value *SafeStack::moveStaticAllocasToUns
   // Re-align BasePointer so that our callees would see it aligned as
   // expected.
   // FIXME: no need to update BasePointer in leaf functions.
-  StaticOffset = alignTo(StaticOffset, StackAlignment);
+  unsigned FrameSize = alignTo(SSL.getFrameSize(), StackAlignment);
 
   // Update shadow stack pointer in the function epilogue.
   IRB.SetInsertPoint(BasePointer->getNextNode());
 
   Value *StaticTop =
-      IRB.CreateGEP(BasePointer, ConstantInt::get(Int32Ty, -StaticOffset),
+      IRB.CreateGEP(BasePointer, ConstantInt::get(Int32Ty, -FrameSize),
                     "unsafe_stack_static_top");
   IRB.CreateStore(StaticTop, UnsafeStackPtr);
   return StaticTop;

Added: llvm/trunk/lib/CodeGen/SafeStackColoring.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SafeStackColoring.cpp?rev=274162&view=auto
==============================================================================
--- llvm/trunk/lib/CodeGen/SafeStackColoring.cpp (added)
+++ llvm/trunk/lib/CodeGen/SafeStackColoring.cpp Wed Jun 29 15:37:43 2016
@@ -0,0 +1,289 @@
+//===-- SafeStackColoring.cpp - SafeStack frame coloring -------*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SafeStackColoring.h"
+
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+using namespace llvm::safestack;
+
+#define DEBUG_TYPE "safestackcoloring"
+
+static cl::opt<bool> ClColoring("safe-stack-coloring",
+                                cl::desc("enable safe stack coloring"),
+                                cl::Hidden, cl::init(true));
+
+const StackColoring::LiveRange &StackColoring::getLiveRange(AllocaInst *AI) {
+  return LiveRanges[AllocaNumbering[AI]];
+}
+
+bool StackColoring::readMarker(Instruction *I, bool *IsStart) {
+  auto *II = dyn_cast<IntrinsicInst>(I);
+  if (!II || (II->getIntrinsicID() != Intrinsic::lifetime_start &&
+              II->getIntrinsicID() != Intrinsic::lifetime_end))
+    return false;
+
+  *IsStart = II->getIntrinsicID() == Intrinsic::lifetime_start;
+  return true;
+}
+
+void StackColoring::removeAllMarkers() {
+  for (auto *I : Markers) {
+    auto *Op = dyn_cast<Instruction>(I->getOperand(1));
+    I->eraseFromParent();
+    // Remove the operand bitcast, too, if it has no more uses left.
+    if (Op && Op->use_empty())
+      Op->eraseFromParent();
+  }
+}
+
+void StackColoring::collectMarkers() {
+  InterestingAllocas.resize(NumAllocas);
+  DenseMap<BasicBlock *, SmallDenseMap<Instruction *, Marker>> BBMarkerSet;
+
+  // Compute the set of start/end markers per basic block.
+  for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) {
+    AllocaInst *AI = Allocas[AllocaNo];
+    SmallVector<Instruction *, 8> WorkList;
+    WorkList.push_back(AI);
+    while (!WorkList.empty()) {
+      Instruction *I = WorkList.pop_back_val();
+      for (User *U : I->users()) {
+        if (auto *BI = dyn_cast<BitCastInst>(U)) {
+          WorkList.push_back(BI);
+          continue;
+        }
+        auto *UI = dyn_cast<Instruction>(U);
+        if (!UI)
+          continue;
+        bool IsStart;
+        if (!readMarker(UI, &IsStart))
+          continue;
+        if (IsStart)
+          InterestingAllocas.set(AllocaNo);
+        BBMarkerSet[UI->getParent()][UI] = {AllocaNo, IsStart};
+        Markers.push_back(UI);
+      }
+    }
+  }
+
+  // Compute instruction numbering. Only the following instructions are
+  // considered:
+  // * Basic block entries
+  // * Lifetime markers
+  // For each basic block, compute
+  // * the list of markers in the instruction order
+  // * the sets of allocas whose lifetime starts or ends in this BB
+  DEBUG(dbgs() << "Instructions:\n");
+  unsigned InstNo = 0;
+  for (BasicBlock *BB : depth_first(&F)) {
+    DEBUG(dbgs() << "  " << InstNo << ": BB " << BB->getName() << "\n");
+    unsigned BBStart = InstNo++;
+
+    BlockLifetimeInfo &BlockInfo = BlockLiveness[BB];
+    BlockInfo.Begin.resize(NumAllocas);
+    BlockInfo.End.resize(NumAllocas);
+    BlockInfo.LiveIn.resize(NumAllocas);
+    BlockInfo.LiveOut.resize(NumAllocas);
+
+    auto &BlockMarkerSet = BBMarkerSet[BB];
+    if (BlockMarkerSet.empty()) {
+      unsigned BBEnd = InstNo;
+      BlockInstRange[BB] = std::make_pair(BBStart, BBEnd);
+      continue;
+    }
+
+    auto ProcessMarker = [&](Instruction *I, const Marker &M) {
+      DEBUG(dbgs() << "  " << InstNo << ":  "
+                   << (M.IsStart ? "start " : "end   ") << M.AllocaNo << ", "
+                   << *I << "\n");
+
+      BBMarkers[BB].push_back({InstNo, M});
+
+      InstructionNumbering[I] = InstNo++;
+
+      if (M.IsStart) {
+        if (BlockInfo.End.test(M.AllocaNo))
+          BlockInfo.End.reset(M.AllocaNo);
+        BlockInfo.Begin.set(M.AllocaNo);
+      } else {
+        if (BlockInfo.Begin.test(M.AllocaNo))
+          BlockInfo.Begin.reset(M.AllocaNo);
+        BlockInfo.End.set(M.AllocaNo);
+      }
+    };
+
+    if (BlockMarkerSet.size() == 1) {
+      ProcessMarker(BlockMarkerSet.begin()->getFirst(),
+                    BlockMarkerSet.begin()->getSecond());
+    } else {
+      // Scan the BB to determine the marker order.
+      for (Instruction &I : *BB) {
+        auto It = BlockMarkerSet.find(&I);
+        if (It == BlockMarkerSet.end())
+          continue;
+        ProcessMarker(&I, It->getSecond());
+      }
+    }
+
+    unsigned BBEnd = InstNo;
+    BlockInstRange[BB] = std::make_pair(BBStart, BBEnd);
+  }
+  NumInst = InstNo;
+}
+
+void StackColoring::calculateLocalLiveness() {
+  bool changed = true;
+  while (changed) {
+    changed = false;
+
+    for (BasicBlock *BB : depth_first(&F)) {
+      BlockLifetimeInfo &BlockInfo = BlockLiveness[BB];
+
+      // Compute LiveIn by unioning together the LiveOut sets of all preds.
+      BitVector LocalLiveIn;
+      for (auto *PredBB : predecessors(BB)) {
+        LivenessMap::const_iterator I = BlockLiveness.find(PredBB);
+        assert(I != BlockLiveness.end() && "Predecessor not found");
+        LocalLiveIn |= I->second.LiveOut;
+      }
+
+      // Compute LiveOut by subtracting out lifetimes that end in this
+      // block, then adding in lifetimes that begin in this block.  If
+      // we have both BEGIN and END markers in the same basic block
+      // then we know that the BEGIN marker comes after the END,
+      // because we already handle the case where the BEGIN comes
+      // before the END when collecting the markers (and building the
+      // BEGIN/END vectors).
+      BitVector LocalLiveOut = LocalLiveIn;
+      LocalLiveOut.reset(BlockInfo.End);
+      LocalLiveOut |= BlockInfo.Begin;
+
+      // Update block LiveIn set, noting whether it has changed.
+      if (LocalLiveIn.test(BlockInfo.LiveIn)) {
+        changed = true;
+        BlockInfo.LiveIn |= LocalLiveIn;
+      }
+
+      // Update block LiveOut set, noting whether it has changed.
+      if (LocalLiveOut.test(BlockInfo.LiveOut)) {
+        changed = true;
+        BlockInfo.LiveOut |= LocalLiveOut;
+      }
+    }
+  } // while changed.
+}
+
+void StackColoring::calculateLiveIntervals() {
+  for (auto IT : BlockLiveness) {
+    BasicBlock *BB = IT.getFirst();
+    BlockLifetimeInfo &BlockInfo = IT.getSecond();
+    unsigned BBStart, BBEnd;
+    std::tie(BBStart, BBEnd) = BlockInstRange[BB];
+
+    BitVector Started, Ended;
+    Started.resize(NumAllocas);
+    Ended.resize(NumAllocas);
+    SmallVector<unsigned, 8> Start;
+    Start.resize(NumAllocas);
+
+    // LiveIn ranges start at the first instruction.
+    for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) {
+      if (BlockInfo.LiveIn.test(AllocaNo)) {
+        Started.set(AllocaNo);
+        Start[AllocaNo] = BBStart;
+      }
+    }
+
+    for (auto &It : BBMarkers[BB]) {
+      unsigned InstNo = It.first;
+      bool IsStart = It.second.IsStart;
+      unsigned AllocaNo = It.second.AllocaNo;
+
+      if (IsStart) {
+        assert(!Started.test(AllocaNo));
+        Started.set(AllocaNo);
+        Ended.reset(AllocaNo);
+        Start[AllocaNo] = InstNo;
+      } else {
+        assert(!Ended.test(AllocaNo));
+        if (Started.test(AllocaNo)) {
+          LiveRanges[AllocaNo].AddRange(Start[AllocaNo], InstNo);
+          Started.reset(AllocaNo);
+        }
+        Ended.set(AllocaNo);
+      }
+    }
+
+    for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo)
+      if (Started.test(AllocaNo))
+        LiveRanges[AllocaNo].AddRange(Start[AllocaNo], BBEnd);
+  }
+}
+
+LLVM_DUMP_METHOD void StackColoring::dumpAllocas() {
+  dbgs() << "Allocas:\n";
+  for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo)
+    dbgs() << "  " << AllocaNo << ": " << *Allocas[AllocaNo] << "\n";
+}
+
+LLVM_DUMP_METHOD void StackColoring::dumpBlockLiveness() {
+  dbgs() << "Block liveness:\n";
+  for (auto IT : BlockLiveness) {
+    BasicBlock *BB = IT.getFirst();
+    BlockLifetimeInfo &BlockInfo = BlockLiveness[BB];
+    auto BlockRange = BlockInstRange[BB];
+    dbgs() << "  BB [" << BlockRange.first << ", " << BlockRange.second
+           << "): begin " << BlockInfo.Begin << ", end " << BlockInfo.End
+           << ", livein " << BlockInfo.LiveIn << ", liveout "
+           << BlockInfo.LiveOut << "\n";
+  }
+}
+
+LLVM_DUMP_METHOD void StackColoring::dumpLiveRanges() {
+  dbgs() << "Alloca liveness:\n";
+  for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) {
+    LiveRange &Range = LiveRanges[AllocaNo];
+    dbgs() << "  " << AllocaNo << ": " << Range << "\n";
+  }
+}
+
+void StackColoring::run() {
+  DEBUG(dumpAllocas());
+
+  for (unsigned I = 0; I < NumAllocas; ++I)
+    AllocaNumbering[Allocas[I]] = I;
+  LiveRanges.resize(NumAllocas);
+
+  collectMarkers();
+
+  if (!ClColoring) {
+    for (auto &R : LiveRanges) {
+      R.SetMaximum(1);
+      R.AddRange(0, 1);
+    }
+    return;
+  }
+
+  for (auto &R : LiveRanges)
+    R.SetMaximum(NumInst);
+  for (unsigned I = 0; I < NumAllocas; ++I)
+    if (!InterestingAllocas.test(I))
+      LiveRanges[I] = getFullLiveRange();
+
+  calculateLocalLiveness();
+  DEBUG(dumpBlockLiveness());
+  calculateLiveIntervals();
+  DEBUG(dumpLiveRanges());
+}

Added: llvm/trunk/lib/CodeGen/SafeStackColoring.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SafeStackColoring.h?rev=274162&view=auto
==============================================================================
--- llvm/trunk/lib/CodeGen/SafeStackColoring.h (added)
+++ llvm/trunk/lib/CodeGen/SafeStackColoring.h Wed Jun 29 15:37:43 2016
@@ -0,0 +1,149 @@
+//===-- SafeStackColoring.h - SafeStack frame coloring ---------*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_CODEGEN_SAFESTACKCOLORING_H
+#define LLVM_LIB_CODEGEN_SAFESTACKCOLORING_H
+
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/raw_os_ostream.h"
+
+namespace llvm {
+class AllocaInst;
+
+namespace safestack {
+/// Compute live ranges of allocas.
+/// Live ranges are represented as sets of "interesting" instructions, which are
+/// defined as instructions that may start or end an alloca's lifetime. These
+/// are:
+/// * lifetime.start and lifetime.end intrinsics
+/// * first instruction of any basic block
+/// Interesting instructions are numbered in the depth-first walk of the CFG,
+/// and in the program order inside each basic block.
+class StackColoring {
+  /// A class representing liveness information for a single basic block.
+  /// Each bit in the BitVector represents the liveness property
+  /// for a different stack slot.
+  struct BlockLifetimeInfo {
+    /// Which slots BEGINs in each basic block.
+    BitVector Begin;
+    /// Which slots ENDs in each basic block.
+    BitVector End;
+    /// Which slots are marked as LIVE_IN, coming into each basic block.
+    BitVector LiveIn;
+    /// Which slots are marked as LIVE_OUT, coming out of each basic block.
+    BitVector LiveOut;
+  };
+
+public:
+  /// This class represents a set of interesting instructions where an alloca is
+  /// live.
+  struct LiveRange {
+    BitVector bv;
+    void SetMaximum(int size) { bv.resize(size); }
+    void AddRange(unsigned start, unsigned end) { bv.set(start, end); }
+    bool Overlaps(const LiveRange &Other) const {
+      return bv.anyCommon(Other.bv);
+    }
+    void Join(const LiveRange &Other) { bv |= Other.bv; }
+  };
+
+private:
+  Function &F;
+
+  /// Maps active slots (per bit) for each basic block.
+  typedef DenseMap<BasicBlock *, BlockLifetimeInfo> LivenessMap;
+  LivenessMap BlockLiveness;
+
+  /// Number of interesting instructions.
+  int NumInst;
+  /// Numeric ids for interesting instructions.
+  DenseMap<Instruction *, unsigned> InstructionNumbering;
+  /// A range [Start, End) of instruction ids for each basic block.
+  /// Instructions inside each BB have monotonic and consecutive ids.
+  DenseMap<const BasicBlock *, std::pair<unsigned, unsigned>> BlockInstRange;
+
+  ArrayRef<AllocaInst *> Allocas;
+  unsigned NumAllocas;
+  DenseMap<AllocaInst *, unsigned> AllocaNumbering;
+  /// LiveRange for allocas.
+  SmallVector<LiveRange, 8> LiveRanges;
+
+  /// The set of allocas that have at least one lifetime.start. All other
+  /// allocas get LiveRange that corresponds to the entire function.
+  BitVector InterestingAllocas;
+  SmallVector<Instruction *, 8> Markers;
+
+  struct Marker {
+    unsigned AllocaNo;
+    bool IsStart;
+  };
+
+  /// List of {InstNo, {AllocaNo, IsStart}} for each BB, ordered by InstNo.
+  DenseMap<BasicBlock *, SmallVector<std::pair<unsigned, Marker>, 4>> BBMarkers;
+
+  void dumpAllocas();
+  void dumpBlockLiveness();
+  void dumpLiveRanges();
+
+  bool readMarker(Instruction *I, bool *IsStart);
+  void collectMarkers();
+  void calculateLocalLiveness();
+  void calculateLiveIntervals();
+
+public:
+  StackColoring(Function &F, ArrayRef<AllocaInst *> Allocas)
+      : F(F), NumInst(-1), Allocas(Allocas), NumAllocas(Allocas.size()) {}
+
+  void run();
+  void removeAllMarkers();
+
+  /// Returns a set of "interesting" instructions where the given alloca is
+  /// live. Not all instructions in a function are interesting: we pick a set
+  /// that is large enough for LiveRange::Overlaps to be correct.
+  const LiveRange &getLiveRange(AllocaInst *AI);
+
+  /// Returns a live range that represents an alloca that is live throughout the
+  /// entire function.
+  LiveRange getFullLiveRange() {
+    assert(NumInst >= 0);
+    LiveRange R;
+    R.SetMaximum(NumInst);
+    R.AddRange(0, NumInst);
+    return R;
+  }
+};
+
+static inline raw_ostream &operator<<(raw_ostream &OS, const BitVector &V) {
+  OS << "{";
+  int idx = V.find_first();
+  bool first = true;
+  while (idx >= 0) {
+    if (!first) {
+      OS << ", ";
+    }
+    first = false;
+    OS << idx;
+    idx = V.find_next(idx);
+  }
+  OS << "}";
+  return OS;
+}
+
+static inline raw_ostream &operator<<(raw_ostream &OS,
+                                      const StackColoring::LiveRange &R) {
+  return OS << R.bv;
+}
+
+} // namespace safestack
+} // namespace llvm
+
+#endif // LLVM_LIB_CODEGEN_SAFESTACKCOLORING_H

Added: llvm/trunk/lib/CodeGen/SafeStackLayout.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SafeStackLayout.cpp?rev=274162&view=auto
==============================================================================
--- llvm/trunk/lib/CodeGen/SafeStackLayout.cpp (added)
+++ llvm/trunk/lib/CodeGen/SafeStackLayout.cpp Wed Jun 29 15:37:43 2016
@@ -0,0 +1,138 @@
+//===-- SafeStackLayout.cpp - SafeStack frame layout -----------*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SafeStackLayout.h"
+
+#include "llvm/IR/Instructions.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+using namespace llvm::safestack;
+
+#define DEBUG_TYPE "safestacklayout"
+
+static cl::opt<bool> ClLayout("safe-stack-layout",
+                              cl::desc("enable safe stack layout"), cl::Hidden,
+                              cl::init(true));
+
+LLVM_DUMP_METHOD void StackLayout::print(raw_ostream &OS) {
+  OS << "Stack regions:\n";
+  for (unsigned i = 0; i < Regions.size(); ++i) {
+    OS << "  " << i << ": [" << Regions[i].Start << ", " << Regions[i].End
+       << "), range " << Regions[i].Range << "\n";
+  }
+  OS << "Stack objects:\n";
+  for (auto &IT : ObjectOffsets) {
+    OS << "  at " << IT.getSecond() << ": " << *IT.getFirst() << "\n";
+  }
+}
+
+void StackLayout::addObject(const Value *V, unsigned Size, unsigned Alignment,
+                            const StackColoring::LiveRange &Range) {
+  StackObjects.push_back({V, Size, Alignment, Range});
+  MaxAlignment = std::max(MaxAlignment, Alignment);
+}
+
+static unsigned AdjustStackOffset(unsigned Offset, unsigned Size,
+                                  unsigned Alignment) {
+  return alignTo(Offset + Size, Alignment) - Size;
+}
+
+void StackLayout::layoutObject(StackObject &Obj) {
+  if (!ClLayout) {
+    // If layout is disabled, just grab the next aligned address.
+    // This effectively disables stack coloring as well.
+    unsigned LastRegionEnd = Regions.empty() ? 0 : Regions.back().End;
+    unsigned Start = AdjustStackOffset(LastRegionEnd, Obj.Size, Obj.Alignment);
+    unsigned End = Start + Obj.Size;
+    Regions.emplace_back(Start, End, Obj.Range);
+    ObjectOffsets[Obj.Handle] = End;
+    return;
+  }
+
+  DEBUG(dbgs() << "Layout: size " << Obj.Size << ", align " << Obj.Alignment
+               << ", range " << Obj.Range << "\n");
+  assert(Obj.Alignment <= MaxAlignment);
+  unsigned Start = AdjustStackOffset(0, Obj.Size, Obj.Alignment);
+  unsigned End = Start + Obj.Size;
+  DEBUG(dbgs() << "  First candidate: " << Start << " .. " << End << "\n");
+  for (const StackRegion &R : Regions) {
+    DEBUG(dbgs() << "  Examining region: " << R.Start << " .. " << R.End
+                 << ", range " << R.Range << "\n");
+    assert(End >= R.Start);
+    if (Start >= R.End) {
+      DEBUG(dbgs() << "  Does not intersect, skip.\n");
+      continue;
+    }
+    if (Obj.Range.Overlaps(R.Range)) {
+      // Find the next appropriate location.
+      Start = AdjustStackOffset(R.End, Obj.Size, Obj.Alignment);
+      End = Start + Obj.Size;
+      DEBUG(dbgs() << "  Overlaps. Next candidate: " << Start << " .. " << End
+                   << "\n");
+      continue;
+    }
+    if (End <= R.End) {
+      DEBUG(dbgs() << "  Reusing region(s).\n");
+      break;
+    }
+  }
+
+  unsigned LastRegionEnd = Regions.empty() ? 0 : Regions.back().End;
+  if (End > LastRegionEnd) {
+    // Insert a new region at the end. Maybe two.
+    if (Start > LastRegionEnd) {
+      DEBUG(dbgs() << "  Creating gap region: " << LastRegionEnd << " .. "
+                   << Start << "\n");
+      Regions.emplace_back(LastRegionEnd, Start, StackColoring::LiveRange());
+      LastRegionEnd = Start;
+    }
+    DEBUG(dbgs() << "  Creating new region: " << LastRegionEnd << " .. " << End
+                 << ", range " << Obj.Range << "\n");
+    Regions.emplace_back(LastRegionEnd, End, Obj.Range);
+    LastRegionEnd = End;
+  }
+
+  // Split starting and ending regions if necessary.
+  for (StackRegion &R : Regions) {
+    if (Start > R.Start && Start < R.End) {
+      StackRegion R0 = R;
+      R.Start = R0.End = Start;
+      Regions.insert(&R, R0);
+      continue;
+    }
+    if (End > R.Start && End < R.End) {
+      StackRegion R0 = R;
+      R0.End = R.Start = End;
+      Regions.insert(&R, R0);
+      break;
+    }
+  }
+
+  // Update live ranges for all affected regions.
+  for (StackRegion &R : Regions) {
+    if (Start < R.End && End > R.Start)
+      R.Range.Join(Obj.Range);
+    if (End <= R.End)
+      break;
+  }
+
+  ObjectOffsets[Obj.Handle] = End;
+}
+
+void StackLayout::computeLayout() {
+  // Simple greedy algorithm.
+  // If this is replaced with something smarter, it must preserve the property
+  // that the first object is always at the offset 0 in the stack frame (for
+  // StackProtectorSlot), or handle stack protector in some other way.
+  for (auto &Obj : StackObjects)
+    layoutObject(Obj);
+
+  DEBUG(print(dbgs()));
+}

Added: llvm/trunk/lib/CodeGen/SafeStackLayout.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SafeStackLayout.h?rev=274162&view=auto
==============================================================================
--- llvm/trunk/lib/CodeGen/SafeStackLayout.h (added)
+++ llvm/trunk/lib/CodeGen/SafeStackLayout.h Wed Jun 29 15:37:43 2016
@@ -0,0 +1,68 @@
+//===-- SafeStackLayout.h - SafeStack frame layout -------------*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_CODEGEN_SAFESTACKLAYOUT_H
+#define LLVM_LIB_CODEGEN_SAFESTACKLAYOUT_H
+
+#include "SafeStackColoring.h"
+
+namespace llvm {
+namespace safestack {
+
+/// Compute the layout of an unsafe stack frame.
+class StackLayout {
+  unsigned MaxAlignment;
+
+  struct StackRegion {
+    unsigned Start;
+    unsigned End;
+    StackColoring::LiveRange Range;
+    StackRegion(unsigned Start, unsigned End,
+                const StackColoring::LiveRange &Range)
+        : Start(Start), End(End), Range(Range) {}
+  };
+  /// The list of current stack regions, sorted by StackRegion::Start.
+  SmallVector<StackRegion, 16> Regions;
+
+  struct StackObject {
+    const Value *Handle;
+    unsigned Size, Alignment;
+    StackColoring::LiveRange Range;
+  };
+  SmallVector<StackObject, 8> StackObjects;
+
+  DenseMap<const Value *, unsigned> ObjectOffsets;
+
+  void layoutObject(StackObject &Obj);
+
+public:
+  StackLayout(unsigned StackAlignment) : MaxAlignment(StackAlignment) {}
+  /// Add an object to the stack frame. Value pointer is opaque and used as a
+  /// handle to retrieve the object's offset in the frame later.
+  void addObject(const Value *V, unsigned Size, unsigned Alignment,
+                 const StackColoring::LiveRange &Range);
+
+  /// Run the layout computation for all previously added objects.
+  void computeLayout();
+
+  /// Returns the offset to the object start in the stack frame.
+  unsigned getObjectOffset(const Value *V) { return ObjectOffsets[V]; }
+
+  /// Returns the size of the entire frame.
+  unsigned getFrameSize() { return Regions.empty() ? 0 : Regions.back().End; }
+
+  /// Returns the alignment of the frame.
+  unsigned getFrameAlignment() { return MaxAlignment; }
+  void print(raw_ostream &OS);
+};
+
+} // namespace safestack
+} // namespace llvm
+
+#endif // LLVM_LIB_CODEGEN_SAFESTACKLAYOUT_H

Added: llvm/trunk/test/Transforms/SafeStack/coloring.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SafeStack/coloring.ll?rev=274162&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/SafeStack/coloring.ll (added)
+++ llvm/trunk/test/Transforms/SafeStack/coloring.ll Wed Jun 29 15:37:43 2016
@@ -0,0 +1,44 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+define void @f() safestack {
+entry:
+; CHECK:  %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK:  %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+
+  %x = alloca i32, align 4
+  %x1 = alloca i32, align 4
+  %x2 = alloca i32, align 4
+  %0 = bitcast i32* %x to i8*
+  call void @llvm.lifetime.start(i64 4, i8* %0)
+
+; CHECK:  %[[A1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK:  %[[A2:.*]] = bitcast i8* %[[A1]] to i32*
+; CHECK:  call void @capture(i32* nonnull %[[A2]])
+
+  call void @capture(i32* nonnull %x)
+  call void @llvm.lifetime.end(i64 4, i8* %0)
+  %1 = bitcast i32* %x1 to i8*
+  call void @llvm.lifetime.start(i64 4, i8* %1)
+
+; CHECK:  %[[B1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK:  %[[B2:.*]] = bitcast i8* %[[B1]] to i32*
+; CHECK:  call void @capture(i32* nonnull %[[B2]])
+
+  call void @capture(i32* nonnull %x1)
+  call void @llvm.lifetime.end(i64 4, i8* %1)
+  %2 = bitcast i32* %x2 to i8*
+  call void @llvm.lifetime.start(i64 4, i8* %2)
+
+; CHECK:  %[[C1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK:  %[[C2:.*]] = bitcast i8* %[[C1]] to i32*
+; CHECK:  call void @capture(i32* nonnull %[[C2]])
+
+  call void @capture(i32* nonnull %x2)
+  call void @llvm.lifetime.end(i64 4, i8* %2)
+  ret void
+}
+
+declare void @llvm.lifetime.start(i64, i8* nocapture)
+declare void @llvm.lifetime.end(i64, i8* nocapture)
+declare void @capture(i32*)

Added: llvm/trunk/test/Transforms/SafeStack/coloring2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SafeStack/coloring2.ll?rev=274162&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/SafeStack/coloring2.ll (added)
+++ llvm/trunk/test/Transforms/SafeStack/coloring2.ll Wed Jun 29 15:37:43 2016
@@ -0,0 +1,482 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+; x and y share the stack slot.
+define void @f() safestack {
+; CHECK-LABEL: define void @f
+entry:
+; CHECK:  %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -16
+
+  %x = alloca i32, align 4
+  %y = alloca i32, align 4
+  %z = alloca i32, align 4
+  %x0 = bitcast i32* %x to i8*
+  %y0 = bitcast i32* %y to i8*
+  %z0 = bitcast i32* %z to i8*
+
+  call void @llvm.lifetime.start(i64 -1, i8* %z0)
+  call void @llvm.lifetime.start(i64 -1, i8* %x0)
+
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+  call void @capture32(i32* %x)
+  call void @llvm.lifetime.end(i64 -1, i8* %x0)
+  call void @llvm.lifetime.start(i64 -1, i8* %y0)
+
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+  call void @capture32(i32* %y)
+  call void @llvm.lifetime.end(i64 -1, i8* %y0)
+
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -8
+  call void @capture32(i32* %z)
+  call void @llvm.lifetime.end(i64 -1, i8* %z0)
+
+  ret void
+}
+
+define void @no_markers() safestack {
+; CHECK-LABEL: define void @no_markers(
+entry:
+; CHECK:  %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -16
+
+  %x = alloca i32, align 4
+  %y = alloca i32, align 4
+  %x0 = bitcast i32* %x to i8*
+
+  call void @llvm.lifetime.start(i64 -1, i8* %x0)
+
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+  call void @capture32(i32* %x)
+  call void @llvm.lifetime.end(i64 -1, i8* %x0)
+
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -8
+  call void @capture32(i32* %y)
+
+  ret void
+}
+
+; x and y can't share memory, but they can split z's storage.
+define void @g() safestack {
+; CHECK-LABEL: define void @g
+entry:
+; CHECK:  %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -16
+
+  %x = alloca i32, align 4
+  %y = alloca i32, align 4
+  %z = alloca i64, align 4
+  %x0 = bitcast i32* %x to i8*
+  %y0 = bitcast i32* %y to i8*
+  %z0 = bitcast i64* %z to i8*
+
+  call void @llvm.lifetime.start(i64 -1, i8* %x0)
+  call void @llvm.lifetime.start(i64 -1, i8* %y0)
+
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+  call void @capture32(i32* %x)
+  call void @llvm.lifetime.end(i64 -1, i8* %x0)
+
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -8
+  call void @capture32(i32* %y)
+  call void @llvm.lifetime.end(i64 -1, i8* %y0)
+  call void @llvm.lifetime.start(i64 -1, i8* %z0)
+
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -8
+  call void @capture64(i64* %z)
+  call void @llvm.lifetime.end(i64 -1, i8* %z0)
+
+  ret void
+}
+
+; Both y and z fit in x's alignment gap.
+define void @h() safestack {
+; CHECK-LABEL: define void @h
+entry:
+; CHECK:  %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -16
+
+  %x = alloca i32, align 16
+  %z = alloca i64, align 4
+  %y = alloca i32, align 4
+  %x0 = bitcast i32* %x to i8*
+  %y0 = bitcast i32* %y to i8*
+  %z0 = bitcast i64* %z to i8*
+
+  call void @llvm.lifetime.start(i64 -1, i8* %x0)
+  call void @llvm.lifetime.start(i64 -1, i8* %y0)
+  call void @llvm.lifetime.start(i64 -1, i8* %z0)
+
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -16
+  call void @capture32(i32* %x)
+
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -12
+  call void @capture32(i32* %y)
+
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -8
+  call void @capture64(i64* %z)
+
+  call void @llvm.lifetime.end(i64 -1, i8* %x0)
+  call void @llvm.lifetime.end(i64 -1, i8* %y0)
+  call void @llvm.lifetime.end(i64 -1, i8* %z0)
+
+  ret void
+}
+
+; void f(bool a, bool b) {
+;   long x1, x2; capture64(&x1); capture64(&x2);
+;   if (a) {
+;     long y; capture64(&y);
+;     if (b) {
+;       long y1; capture64(&y1);
+;     } else {
+;       long y2; capture64(&y2);
+;     }
+;   } else {
+;     long z; capture64(&z);
+;     if (b) {
+;       long z1; capture64(&z1);
+;     } else {
+;       long z2; capture64(&z2);
+;     }
+;   }
+; }
+; Everything fits in 4 x 64-bit slots.
+define void @i(i1 zeroext %a, i1 zeroext %b) safestack {
+; CHECK-LABEL: define void @i
+entry:
+; CHECK:        %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT:   getelementptr i8, i8* %[[USP]], i32 -32
+  %x1 = alloca i64, align 8
+  %x2 = alloca i64, align 8
+  %y = alloca i64, align 8
+  %y1 = alloca i64, align 8
+  %y2 = alloca i64, align 8
+  %z = alloca i64, align 8
+  %z1 = alloca i64, align 8
+  %z2 = alloca i64, align 8
+  %0 = bitcast i64* %x1 to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %0)
+  %1 = bitcast i64* %x2 to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %1)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -8
+; CHECK:   call void @capture64(
+  call void @capture64(i64* nonnull %x1)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -16
+; CHECK:   call void @capture64(
+  call void @capture64(i64* nonnull %x2)
+  br i1 %a, label %if.then, label %if.else4
+
+if.then:                                          ; preds = %entry
+  %2 = bitcast i64* %y to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %2)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -24
+; CHECK:   call void @capture64(
+  call void @capture64(i64* nonnull %y)
+  br i1 %b, label %if.then3, label %if.else
+
+if.then3:                                         ; preds = %if.then
+  %3 = bitcast i64* %y1 to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %3)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -32
+; CHECK:   call void @capture64(
+  call void @capture64(i64* nonnull %y1)
+  call void @llvm.lifetime.end(i64 -1, i8* %3)
+  br label %if.end
+
+if.else:                                          ; preds = %if.then
+  %4 = bitcast i64* %y2 to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %4)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -32
+; CHECK:   call void @capture64(
+  call void @capture64(i64* nonnull %y2)
+  call void @llvm.lifetime.end(i64 -1, i8* %4)
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then3
+  call void @llvm.lifetime.end(i64 -1, i8* %2)
+  br label %if.end9
+
+if.else4:                                         ; preds = %entry
+  %5 = bitcast i64* %z to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %5)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -24
+; CHECK:   call void @capture64(
+  call void @capture64(i64* nonnull %z)
+  br i1 %b, label %if.then6, label %if.else7
+
+if.then6:                                         ; preds = %if.else4
+  %6 = bitcast i64* %z1 to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %6)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -32
+; CHECK:   call void @capture64(
+  call void @capture64(i64* nonnull %z1)
+  call void @llvm.lifetime.end(i64 -1, i8* %6)
+  br label %if.end8
+
+if.else7:                                         ; preds = %if.else4
+  %7 = bitcast i64* %z2 to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %7)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -32
+; CHECK:   call void @capture64(
+  call void @capture64(i64* nonnull %z2)
+  call void @llvm.lifetime.end(i64 -1, i8* %7)
+  br label %if.end8
+
+if.end8:                                          ; preds = %if.else7, %if.then6
+  call void @llvm.lifetime.end(i64 -1, i8* %5)
+  br label %if.end9
+
+if.end9:                                          ; preds = %if.end8, %if.end
+  call void @llvm.lifetime.end(i64 -1, i8* %1)
+  call void @llvm.lifetime.end(i64 -1, i8* %0)
+  ret void
+}
+
+; lifetime for x ends in 2 different BBs
+define void @no_merge1(i1 %d) safestack {
+; CHECK-LABEL: define void @no_merge1(
+entry:
+; CHECK:        %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT:   getelementptr i8, i8* %[[USP]], i32 -16
+  %x = alloca i32, align 4
+  %y = alloca i32, align 4
+  %x0 = bitcast i32* %x to i8*
+  %y0 = bitcast i32* %y to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %x0)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK:   call void @capture32(
+  call void @capture32(i32* %x)
+  br i1 %d, label %bb2, label %bb3
+bb2:
+  call void @llvm.lifetime.start(i64 -1, i8* %y0)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -8
+; CHECK:   call void @capture32(
+  call void @capture32(i32* %y)
+  call void @llvm.lifetime.end(i64 -1, i8* %y0)
+  call void @llvm.lifetime.end(i64 -1, i8* %x0)
+  ret void
+bb3:
+  call void @llvm.lifetime.end(i64 -1, i8* %x0)
+  ret void
+}
+
+define void @merge1(i1 %d) safestack {
+; CHECK-LABEL: define void @merge1(
+entry:
+; CHECK:        %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT:   getelementptr i8, i8* %[[USP]], i32 -16
+  %x = alloca i32, align 4
+  %y = alloca i32, align 4
+  %x0 = bitcast i32* %x to i8*
+  %y0 = bitcast i32* %y to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %x0)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK:   call void @capture32(
+  call void @capture32(i32* %x)
+  call void @llvm.lifetime.end(i64 -1, i8* %x0)
+  br i1 %d, label %bb2, label %bb3
+bb2:
+  call void @llvm.lifetime.start(i64 -1, i8* %y0)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK:   call void @capture32(
+  call void @capture32(i32* %y)
+  call void @llvm.lifetime.end(i64 -1, i8* %y0)
+  ret void
+bb3:
+  ret void
+}
+
+; Missing lifetime.end
+define void @merge2_noend(i1 %d) safestack {
+; CHECK-LABEL: define void @merge2_noend(
+entry:
+; CHECK:        %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT:   getelementptr i8, i8* %[[USP]], i32 -16
+  %x = alloca i32, align 4
+  %y = alloca i32, align 4
+  %x0 = bitcast i32* %x to i8*
+  %y0 = bitcast i32* %y to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %x0)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK:   call void @capture32(
+  call void @capture32(i32* %x)
+  call void @llvm.lifetime.end(i64 -1, i8* %x0)
+  br i1 %d, label %bb2, label %bb3
+bb2:
+  call void @llvm.lifetime.start(i64 -1, i8* %y0)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK:   call void @capture32(
+  call void @capture32(i32* %y)
+  ret void
+bb3:
+  ret void
+}
+
+; Missing lifetime.end
+define void @merge3_noend(i1 %d) safestack {
+; CHECK-LABEL: define void @merge3_noend(
+entry:
+; CHECK:        %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT:   getelementptr i8, i8* %[[USP]], i32 -16
+  %x = alloca i32, align 4
+  %y = alloca i32, align 4
+  %x0 = bitcast i32* %x to i8*
+  %y0 = bitcast i32* %y to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %x0)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK:   call void @capture32(
+  call void @capture32(i32* %x)
+  br i1 %d, label %bb2, label %bb3
+bb2:
+  call void @llvm.lifetime.end(i64 -1, i8* %x0)
+  call void @llvm.lifetime.start(i64 -1, i8* %y0)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK:   call void @capture32(
+  call void @capture32(i32* %y)
+  ret void
+bb3:
+  ret void
+}
+
+; Missing lifetime.start
+define void @nomerge4_nostart(i1 %d) safestack {
+; CHECK-LABEL: define void @nomerge4_nostart(
+entry:
+; CHECK:        %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT:   getelementptr i8, i8* %[[USP]], i32 -16
+  %x = alloca i32, align 4
+  %y = alloca i32, align 4
+  %x0 = bitcast i32* %x to i8*
+  %y0 = bitcast i32* %y to i8*
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -4
+; CHECK:   call void @capture32(
+  call void @capture32(i32* %x)
+  call void @llvm.lifetime.end(i64 -1, i8* %x0)
+  br i1 %d, label %bb2, label %bb3
+bb2:
+  call void @llvm.lifetime.start(i64 -1, i8* %y0)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -8
+; CHECK:   call void @capture32(
+  call void @capture32(i32* %y)
+  ret void
+bb3:
+  ret void
+}
+
+define void @array_merge() safestack {
+; CHECK-LABEL: define void @array_merge(
+entry:
+; CHECK:        %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT:   getelementptr i8, i8* %[[USP]], i32 -800
+  %A.i1 = alloca [100 x i32], align 4
+  %B.i2 = alloca [100 x i32], align 4
+  %A.i = alloca [100 x i32], align 4
+  %B.i = alloca [100 x i32], align 4
+  %0 = bitcast [100 x i32]* %A.i to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %0)
+  %1 = bitcast [100 x i32]* %B.i to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %1)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -400
+; CHECK:   call void @capture100x32(
+  call void @capture100x32([100 x i32]* %A.i)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -800
+; CHECK:   call void @capture100x32(
+  call void @capture100x32([100 x i32]* %B.i)
+  call void @llvm.lifetime.end(i64 -1, i8* %0)
+  call void @llvm.lifetime.end(i64 -1, i8* %1)
+  %2 = bitcast [100 x i32]* %A.i1 to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %2)
+  %3 = bitcast [100 x i32]* %B.i2 to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %3)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -400
+; CHECK:   call void @capture100x32(
+  call void @capture100x32([100 x i32]* %A.i1)
+; CHECK:   getelementptr i8, i8* %[[USP]], i32 -800
+; CHECK:   call void @capture100x32(
+  call void @capture100x32([100 x i32]* %B.i2)
+  call void @llvm.lifetime.end(i64 -1, i8* %2)
+  call void @llvm.lifetime.end(i64 -1, i8* %3)
+  ret void
+}
+
+define void @myCall_pr15707() safestack {
+; CHECK-LABEL: define void @myCall_pr15707(
+entry:
+; CHECK:        %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT:   getelementptr i8, i8* %[[USP]], i32 -200000
+  %buf1 = alloca i8, i32 100000, align 16
+  %buf2 = alloca i8, i32 100000, align 16
+
+  call void @llvm.lifetime.start(i64 -1, i8* %buf1)
+  call void @llvm.lifetime.end(i64 -1, i8* %buf1)
+
+  call void @llvm.lifetime.start(i64 -1, i8* %buf1)
+  call void @llvm.lifetime.start(i64 -1, i8* %buf2)
+  call void @capture8(i8* %buf1)
+  call void @capture8(i8* %buf2)
+  ret void
+}
+
+; Check that we don't assert and crash even when there are allocas
+; outside the declared lifetime regions.
+define void @bad_range() safestack {
+; CHECK-LABEL: define void @bad_range(
+entry:
+; CHECK:        %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; A.i and B.i unsafe, not merged
+; CHECK-NEXT:   getelementptr i8, i8* %[[USP]], i32 -800
+; A.i1 and B.i2 safe
+; CHECK: = alloca [100 x i32], align 4
+; CHECK: = alloca [100 x i32], align 4
+
+  %A.i1 = alloca [100 x i32], align 4
+  %B.i2 = alloca [100 x i32], align 4
+  %A.i = alloca [100 x i32], align 4
+  %B.i = alloca [100 x i32], align 4
+  %0 = bitcast [100 x i32]* %A.i to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %0) nounwind
+  %1 = bitcast [100 x i32]* %B.i to i8*
+  call void @llvm.lifetime.start(i64 -1, i8* %1) nounwind
+  call void @capture100x32([100 x i32]* %A.i)
+  call void @capture100x32([100 x i32]* %B.i)
+  call void @llvm.lifetime.end(i64 -1, i8* %0) nounwind
+  call void @llvm.lifetime.end(i64 -1, i8* %1) nounwind
+  br label %block2
+
+block2:
+  ; I am used outside the marked lifetime.
+  call void @capture100x32([100 x i32]* %A.i)
+  call void @capture100x32([100 x i32]* %B.i)
+  ret void
+}
+
+%struct.Klass = type { i32, i32 }
+
+define i32 @shady_range(i32 %argc, i8** nocapture %argv) safestack {
+; CHECK-LABEL: define i32 @shady_range(
+entry:
+; CHECK:        %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; CHECK-NEXT:   getelementptr i8, i8* %[[USP]], i32 -64
+  %a.i = alloca [4 x %struct.Klass], align 16
+  %b.i = alloca [4 x %struct.Klass], align 16
+  %a8 = bitcast [4 x %struct.Klass]* %a.i to i8*
+  %b8 = bitcast [4 x %struct.Klass]* %b.i to i8*
+  ; I am used outside the lifetime zone below:
+  %z2 = getelementptr inbounds [4 x %struct.Klass], [4 x %struct.Klass]* %a.i, i64 0, i64 0, i32 0
+  call void @llvm.lifetime.start(i64 -1, i8* %a8)
+  call void @llvm.lifetime.start(i64 -1, i8* %b8)
+  call void @capture8(i8* %a8)
+  call void @capture8(i8* %b8)
+  %z3 = load i32, i32* %z2, align 16
+  call void @llvm.lifetime.end(i64 -1, i8* %a8)
+  call void @llvm.lifetime.end(i64 -1, i8* %b8)
+  ret i32 %z3
+}
+
+declare void @llvm.lifetime.start(i64, i8* nocapture)
+declare void @llvm.lifetime.end(i64, i8* nocapture)
+declare void @capture8(i8*)
+declare void @capture32(i32*)
+declare void @capture64(i64*)
+declare void @capture100x32([100 x i32]*)




More information about the llvm-commits mailing list