[llvm] r270559 - Rework/enhance stack coloring data flow analysis.

Than McIntosh via llvm-commits llvm-commits at lists.llvm.org
Fri May 27 08:13:34 PDT 2016


Submitted a patch http://reviews.llvm.org/D20731 to turn off the enhanced
stack coloring until I can incorporate a real fix.

Thanks, Than


On Fri, May 27, 2016 at 8:47 AM, Teresa Johnson <tejohnson at google.com>
wrote:

> Forgot to update on llvm-commits yesterday: I filed
> https://llvm.org/bugs/show_bug.cgi?id=27903, and Than has already made
> good progress on narrowing this down.
> Teresa
>
> On Thu, May 26, 2016 at 7:46 AM, Teresa Johnson <tejohnson at google.com>
> wrote:
>
>> I have a way to repro this now using llc on a bitcode file I got via
>> save-temps and linked with a bunch of native objects. The seg fault
>> disappears when passing -no-stack-coloring to llc. Than, I will package up
>> something and get it to you off-list.
>>
>> Thanks,
>> Teresa
>>
>> On Wed, May 25, 2016 at 6:55 PM, Teresa Johnson <tejohnson at google.com>
>> wrote:
>>
>>>
>>> On Wed, May 25, 2016 at 6:29 PM, Than McIntosh <thanm at google.com> wrote:
>>>
>>>> Hello Teresa,
>>>>
>>>> Thanks for the heads-up.  So far I have not seen any other issues.
>>>>
>>>> What is a "ThinLTO bootstrap using gold"?
>>>>
>>>
>>> Sorry, clang/llvm bootstrap using ThinLTO and the gold linker (since
>>> this was linux).
>>>
>>> The patch I referenced below just went in, but I will see if I can come
>>> up with something smaller to reproduce.
>>>
>>> Teresa
>>>
>>>
>>>>
>>>> Thanks, Than
>>>>
>>>>
>>>> On Wed, May 25, 2016 at 7:32 PM, Teresa Johnson <tejohnson at google.com>
>>>> wrote:
>>>>
>>>>> Hi Than,
>>>>>
>>>>> I started getting failures running llvm-tblgen yesterday in a ThinLTO
>>>>> bootstrap of clang. I just bisected it to this commit.
>>>>>
>>>>> I'll work on packaging up a reproducer (a ThinLTO bootstrap using gold
>>>>> requires D20559 to fix an issue handling archives, which I should be
>>>>> submitting soon since it just got approved). I had earlier today tracked
>>>>> this down to happening when we import a particular function, presumably
>>>>> exposed with the expanded optimization scope after the importing.
>>>>>
>>>>> I wanted to give you a heads up though in case any other issues have
>>>>> been reported.
>>>>>
>>>>> Thanks
>>>>> Teresa
>>>>>
>>>>> On Tue, May 24, 2016 at 6:23 AM, Than McIntosh via llvm-commits <
>>>>> llvm-commits at lists.llvm.org> wrote:
>>>>>
>>>>>> Author: thanm
>>>>>> Date: Tue May 24 08:23:44 2016
>>>>>> New Revision: 270559
>>>>>>
>>>>>> URL: http://llvm.org/viewvc/llvm-project?rev=270559&view=rev
>>>>>> Log:
>>>>>> Rework/enhance stack coloring data flow analysis.
>>>>>>
>>>>>> Replace bidirectional flow analysis to compute liveness with forward
>>>>>> analysis pass. Treat lifetimes as starting when there is a first
>>>>>> reference to the stack slot, as opposed to starting at the point of
>>>>>> the
>>>>>> lifetime.start intrinsic, so as to increase the number of stack
>>>>>> variables we can overlap.
>>>>>>
>>>>>> Reviewers: gbiv, qcolumbet, wmi
>>>>>> Differential Revision: http://reviews.llvm.org/D18827
>>>>>>
>>>>>> Bug: 25776
>>>>>>
>>>>>> Modified:
>>>>>>     llvm/trunk/lib/CodeGen/StackColoring.cpp
>>>>>>     llvm/trunk/test/CodeGen/X86/StackColoring.ll
>>>>>>     llvm/trunk/test/CodeGen/X86/misched-aa-colored.ll
>>>>>>
>>>>>> Modified: llvm/trunk/lib/CodeGen/StackColoring.cpp
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/StackColoring.cpp?rev=270559&r1=270558&r2=270559&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- llvm/trunk/lib/CodeGen/StackColoring.cpp (original)
>>>>>> +++ llvm/trunk/lib/CodeGen/StackColoring.cpp Tue May 24 08:23:44 2016
>>>>>> @@ -64,18 +64,180 @@ DisableColoring("no-stack-coloring",
>>>>>>  /// The user may write code that uses allocas outside of the
>>>>>> declared lifetime
>>>>>>  /// zone. This can happen when the user returns a reference to a
>>>>>> local
>>>>>>  /// data-structure. We can detect these cases and decide not to
>>>>>> optimize the
>>>>>> -/// code. If this flag is enabled, we try to save the user.
>>>>>> +/// code. If this flag is enabled, we try to save the user. This
>>>>>> option
>>>>>> +/// is treated as overriding LifetimeStartOnFirstUse below.
>>>>>>  static cl::opt<bool>
>>>>>>  ProtectFromEscapedAllocas("protect-from-escaped-allocas",
>>>>>>                            cl::init(false), cl::Hidden,
>>>>>>                            cl::desc("Do not optimize lifetime zones
>>>>>> that "
>>>>>>                                     "are broken"));
>>>>>>
>>>>>> +/// Enable enhanced dataflow scheme for lifetime analysis (treat
>>>>>> first
>>>>>> +/// use of stack slot as start of slot lifetime, as opposed to
>>>>>> looking
>>>>>> +/// for LIFETIME_START marker). See "Implementation notes" below for
>>>>>> +/// more info.
>>>>>> +static cl::opt<bool>
>>>>>> +LifetimeStartOnFirstUse("stackcoloring-lifetime-start-on-first-use",
>>>>>> +        cl::init(true), cl::Hidden,
>>>>>> +        cl::desc("Treat stack lifetimes as starting on first use,
>>>>>> not on START marker."));
>>>>>> +
>>>>>> +
>>>>>>  STATISTIC(NumMarkerSeen,  "Number of lifetime markers found.");
>>>>>>  STATISTIC(StackSpaceSaved, "Number of bytes saved due to merging
>>>>>> slots.");
>>>>>>  STATISTIC(StackSlotMerged, "Number of stack slot merged.");
>>>>>>  STATISTIC(EscapedAllocas, "Number of allocas that escaped the
>>>>>> lifetime region");
>>>>>>
>>>>>> +//
>>>>>> +// Implementation Notes:
>>>>>> +// ---------------------
>>>>>> +//
>>>>>> +// Consider the following motivating example:
>>>>>> +//
>>>>>> +//     int foo() {
>>>>>> +//       char b1[1024], b2[1024];
>>>>>> +//       if (...) {
>>>>>> +//         char b3[1024];
>>>>>> +//         <uses of b1, b3>;
>>>>>> +//         return x;
>>>>>> +//       } else {
>>>>>> +//         char b4[1024], b5[1024];
>>>>>> +//         <uses of b2, b4, b5>;
>>>>>> +//         return y;
>>>>>> +//       }
>>>>>> +//     }
>>>>>> +//
>>>>>> +// In the code above, "b3" and "b4" are declared in distinct lexical
>>>>>> +// scopes, meaning that it is easy to prove that they can share the
>>>>>> +// same stack slot. Variables "b1" and "b2" are declared in the same
>>>>>> +// scope, meaning that from a lexical point of view, their lifetimes
>>>>>> +// overlap. From a control flow pointer of view, however, the two
>>>>>> +// variables are accessed in disjoint regions of the CFG, thus it
>>>>>> +// should be possible for them to share the same stack slot. An ideal
>>>>>> +// stack allocation for the function above would look like:
>>>>>> +//
>>>>>> +//     slot 0: b1, b2
>>>>>> +//     slot 1: b3, b4
>>>>>> +//     slot 2: b5
>>>>>> +//
>>>>>> +// Achieving this allocation is tricky, however, due to the way
>>>>>> +// lifetime markers are inserted. Here is a simplified view of the
>>>>>> +// control flow graph for the code above:
>>>>>> +//
>>>>>> +//                +------  block 0 -------+
>>>>>> +//               0| LIFETIME_START b1, b2 |
>>>>>> +//               1| <test 'if' condition> |
>>>>>> +//                +-----------------------+
>>>>>> +//                   ./              \.
>>>>>> +//   +------  block 1 -------+   +------  block 2 -------+
>>>>>> +//  2| LIFETIME_START b3     |  5| LIFETIME_START b4, b5 |
>>>>>> +//  3| <uses of b1, b3>      |  6| <uses of b2, b4, b5>  |
>>>>>> +//  4| LIFETIME_END b3       |  7| LIFETIME_END b4, b5   |
>>>>>> +//   +-----------------------+   +-----------------------+
>>>>>> +//                   \.              /.
>>>>>> +//                +------  block 3 -------+
>>>>>> +//               8| <cleanupcode>         |
>>>>>> +//               9| LIFETIME_END b1, b2   |
>>>>>> +//              10| return                |
>>>>>> +//                +-----------------------+
>>>>>> +//
>>>>>> +// If we create live intervals for the variables above strictly based
>>>>>> +// on the lifetime markers, we'll get the set of intervals on the
>>>>>> +// left. If we ignore the lifetime start markers and instead treat a
>>>>>> +// variable's lifetime as beginning with the first reference to the
>>>>>> +// var, then we get the intervals on the right.
>>>>>> +//
>>>>>> +//            LIFETIME_START      First Use
>>>>>> +//     b1:    [0,9]               [3,4] [8,9]
>>>>>> +//     b2:    [0,9]               [6,9]
>>>>>> +//     b3:    [2,4]               [3,4]
>>>>>> +//     b4:    [5,7]               [6,7]
>>>>>> +//     b5:    [5,7]               [6,7]
>>>>>> +//
>>>>>> +// For the intervals on the left, the best we can do is overlap two
>>>>>> +// variables (b3 and b4, for example); this gives us a stack size of
>>>>>> +// 4*1024 bytes, not ideal. When treating first-use as the start of a
>>>>>> +// lifetime, we can additionally overlap b1 and b5, giving us a
>>>>>> 3*1024
>>>>>> +// byte stack (better).
>>>>>> +//
>>>>>> +// Relying entirely on first-use of stack slots is problematic,
>>>>>> +// however, due to the fact that optimizations can sometimes migrate
>>>>>> +// uses of a variable outside of its lifetime start/end region. Here
>>>>>> +// is an example:
>>>>>> +//
>>>>>> +//     int bar() {
>>>>>> +//       char b1[1024], b2[1024];
>>>>>> +//       if (...) {
>>>>>> +//         <uses of b2>
>>>>>> +//         return y;
>>>>>> +//       } else {
>>>>>> +//         <uses of b1>
>>>>>> +//         while (...) {
>>>>>> +//           char b3[1024];
>>>>>> +//           <uses of b3>
>>>>>> +//         }
>>>>>> +//       }
>>>>>> +//     }
>>>>>> +//
>>>>>> +// Before optimization, the control flow graph for the code above
>>>>>> +// might look like the following:
>>>>>> +//
>>>>>> +//                +------  block 0 -------+
>>>>>> +//               0| LIFETIME_START b1, b2 |
>>>>>> +//               1| <test 'if' condition> |
>>>>>> +//                +-----------------------+
>>>>>> +//                   ./              \.
>>>>>> +//   +------  block 1 -------+    +------- block 2 -------+
>>>>>> +//  2| <uses of b2>          |   3| <uses of b1>          |
>>>>>> +//   +-----------------------+    +-----------------------+
>>>>>> +//              |                            |
>>>>>> +//              |                 +------- block 3 -------+ <-\.
>>>>>> +//              |                4| <while condition>     |    |
>>>>>> +//              |                 +-----------------------+    |
>>>>>> +//              |               /          |                   |
>>>>>> +//              |              /  +------- block 4 -------+
>>>>>> +//              \             /  5| LIFETIME_START b3     |    |
>>>>>> +//               \           /   6| <uses of b3>          |    |
>>>>>> +//                \         /    7| LIFETIME_END b3       |    |
>>>>>> +//                 \        |    +------------------------+    |
>>>>>> +//                  \       |                 \                /
>>>>>> +//                +------  block 5 -----+      \---------------
>>>>>> +//               8| <cleanupcode>       |
>>>>>> +//               9| LIFETIME_END b1, b2 |
>>>>>> +//              10| return              |
>>>>>> +//                +---------------------+
>>>>>> +//
>>>>>> +// During optimization, however, it can happen that an instruction
>>>>>> +// computing an address in "b3" (for example, a loop-invariant GEP)
>>>>>> is
>>>>>> +// hoisted up out of the loop from block 4 to block 2.  [Note that
>>>>>> +// this is not an actual load from the stack, only an instruction
>>>>>> that
>>>>>> +// computes the address to be loaded]. If this happens, there is now
>>>>>> a
>>>>>> +// path leading from the first use of b3 to the return instruction
>>>>>> +// that does not encounter the b3 LIFETIME_END, hence b3's lifetime
>>>>>> is
>>>>>> +// now larger than if we were computing live intervals strictly based
>>>>>> +// on lifetime markers. In the example above, this lengthened
>>>>>> lifetime
>>>>>> +// would mean that it would appear illegal to overlap b3 with b2.
>>>>>> +//
>>>>>> +// To deal with this such cases, the code in ::collectMarkers() below
>>>>>> +// tries to identify "degenerate" slots -- those slots where on a
>>>>>> single
>>>>>> +// forward pass through the CFG we encounter a first reference to
>>>>>> slot
>>>>>> +// K before we hit the slot K lifetime start marker. For such slots,
>>>>>> +// we fall back on using the lifetime start marker as the beginning
>>>>>> of
>>>>>> +// the variable's lifetime.  NB: with this implementation, slots can
>>>>>> +// appear degenerate in cases where there is unstructured control
>>>>>> flow:
>>>>>> +//
>>>>>> +//    if (q) goto mid;
>>>>>> +//    if (x > 9) {
>>>>>> +//         int b[100];
>>>>>> +//         memcpy(&b[0], ...);
>>>>>> +//    mid: b[k] = ...;
>>>>>> +//         abc(&b);
>>>>>> +//    }
>>>>>> +//
>>>>>> +// If in RPO ordering chosen to walk the CFG  we happen to visit the
>>>>>> b[k]
>>>>>> +// before visiting the memcpy block (which will contain the lifetime
>>>>>> start
>>>>>> +// for "b" then it will appear that 'b' has a degenerate lifetime.
>>>>>> +//
>>>>>> +
>>>>>>
>>>>>>  //===----------------------------------------------------------------------===//
>>>>>>  //                           StackColoring Pass
>>>>>>
>>>>>>  //===----------------------------------------------------------------------===//
>>>>>> @@ -123,6 +285,17 @@ class StackColoring : public MachineFunc
>>>>>>    /// once the coloring is done.
>>>>>>    SmallVector<MachineInstr*, 8> Markers;
>>>>>>
>>>>>> +  /// Record the FI slots for which we have seen some sort of
>>>>>> +  /// lifetime marker (either start or end).
>>>>>> +  BitVector InterestingSlots;
>>>>>> +
>>>>>> +  /// Degenerate slots -- first use appears outside of start/end
>>>>>> +  /// lifetime markers.
>>>>>> +  BitVector DegenerateSlots;
>>>>>> +
>>>>>> +  /// Number of iterations taken during data flow analysis.
>>>>>> +  unsigned NumIterations;
>>>>>> +
>>>>>>  public:
>>>>>>    static char ID;
>>>>>>    StackColoring() : MachineFunctionPass(ID) {
>>>>>> @@ -153,6 +326,25 @@ private:
>>>>>>    /// in and out blocks.
>>>>>>    void calculateLocalLiveness();
>>>>>>
>>>>>> +  /// Returns TRUE if we're using the first-use-begins-lifetime
>>>>>> method for
>>>>>> +  /// this slot (if FALSE, then the start marker is treated as start
>>>>>> of lifetime).
>>>>>> +  bool applyFirstUse(int Slot) {
>>>>>> +    if (!LifetimeStartOnFirstUse || ProtectFromEscapedAllocas)
>>>>>> +      return false;
>>>>>> +    if (DegenerateSlots.test(Slot))
>>>>>> +      return false;
>>>>>> +    return true;
>>>>>> +  }
>>>>>> +
>>>>>> +  /// Examines the specified instruction and returns TRUE if the
>>>>>> instruction
>>>>>> +  /// represents the start or end of an interesting lifetime. The
>>>>>> slot or slots
>>>>>> +  /// starting or ending are added to the vector "slots" and
>>>>>> "isStart" is set
>>>>>> +  /// accordingly.
>>>>>> +  /// \returns True if inst contains a lifetime start or end
>>>>>> +  bool isLifetimeStartOrEnd(const MachineInstr &MI,
>>>>>> +                            SmallVector<int, 4> &slots,
>>>>>> +                            bool &isStart);
>>>>>> +
>>>>>>    /// Construct the LiveIntervals for the slots.
>>>>>>    void calculateLiveIntervals(unsigned NumSlots);
>>>>>>
>>>>>> @@ -170,7 +362,10 @@ private:
>>>>>>
>>>>>>    /// Map entries which point to other entries to their destination.
>>>>>>    ///   A->B->C becomes A->C.
>>>>>> -   void expungeSlotMap(DenseMap<int, int> &SlotRemap, unsigned
>>>>>> NumSlots);
>>>>>> +  void expungeSlotMap(DenseMap<int, int> &SlotRemap, unsigned
>>>>>> NumSlots);
>>>>>> +
>>>>>> +  /// Used in collectMarkers
>>>>>> +  typedef DenseMap<const MachineBasicBlock*, BitVector>
>>>>>> BlockBitVecMap;
>>>>>>  };
>>>>>>  } // end anonymous namespace
>>>>>>
>>>>>> @@ -228,9 +423,140 @@ LLVM_DUMP_METHOD void StackColoring::dum
>>>>>>
>>>>>>  #endif // not NDEBUG
>>>>>>
>>>>>> -unsigned StackColoring::collectMarkers(unsigned NumSlot) {
>>>>>> +static inline int getStartOrEndSlot(const MachineInstr &MI)
>>>>>> +{
>>>>>> +  assert((MI.getOpcode() == TargetOpcode::LIFETIME_START ||
>>>>>> +          MI.getOpcode() == TargetOpcode::LIFETIME_END) &&
>>>>>> +         "Expected LIFETIME_START or LIFETIME_END op");
>>>>>> +  const MachineOperand &MO = MI.getOperand(0);
>>>>>> +  int Slot = MO.getIndex();
>>>>>> +  if (Slot >= 0)
>>>>>> +    return Slot;
>>>>>> +  return -1;
>>>>>> +}
>>>>>> +
>>>>>> +//
>>>>>> +// At the moment the only way to end a variable lifetime is with
>>>>>> +// a VARIABLE_LIFETIME op (which can't contain a start). If things
>>>>>> +// change and the IR allows for a single inst that both begins
>>>>>> +// and ends lifetime(s), this interface will need to be reworked.
>>>>>> +//
>>>>>> +bool StackColoring::isLifetimeStartOrEnd(const MachineInstr &MI,
>>>>>> +                                         SmallVector<int, 4> &slots,
>>>>>> +                                         bool &isStart)
>>>>>> +{
>>>>>> +  if (MI.getOpcode() == TargetOpcode::LIFETIME_START ||
>>>>>> +      MI.getOpcode() == TargetOpcode::LIFETIME_END) {
>>>>>> +    int Slot = getStartOrEndSlot(MI);
>>>>>> +    if (Slot < 0)
>>>>>> +      return false;
>>>>>> +    if (!InterestingSlots.test(Slot))
>>>>>> +      return false;
>>>>>> +    slots.push_back(Slot);
>>>>>> +    if (MI.getOpcode() == TargetOpcode::LIFETIME_END) {
>>>>>> +      isStart = false;
>>>>>> +      return true;
>>>>>> +    }
>>>>>> +    if (! applyFirstUse(Slot)) {
>>>>>> +      isStart = true;
>>>>>> +      return true;
>>>>>> +    }
>>>>>> +  } else if (LifetimeStartOnFirstUse && !ProtectFromEscapedAllocas) {
>>>>>> +    if (! MI.isDebugValue()) {
>>>>>> +      bool found = false;
>>>>>> +      for (const MachineOperand &MO : MI.operands()) {
>>>>>> +        if (!MO.isFI())
>>>>>> +          continue;
>>>>>> +        int Slot = MO.getIndex();
>>>>>> +        if (Slot<0)
>>>>>> +          continue;
>>>>>> +        if (InterestingSlots.test(Slot) && applyFirstUse(Slot)) {
>>>>>> +          slots.push_back(Slot);
>>>>>> +          found = true;
>>>>>> +        }
>>>>>> +      }
>>>>>> +      if (found) {
>>>>>> +        isStart = true;
>>>>>> +        return true;
>>>>>> +      }
>>>>>> +    }
>>>>>> +  }
>>>>>> +  return false;
>>>>>> +}
>>>>>> +
>>>>>> +unsigned StackColoring::collectMarkers(unsigned NumSlot)
>>>>>> +{
>>>>>>    unsigned MarkersFound = 0;
>>>>>> -  // Scan the function to find all lifetime markers.
>>>>>> +  BlockBitVecMap SeenStartMap;
>>>>>> +  InterestingSlots.clear();
>>>>>> +  InterestingSlots.resize(NumSlot);
>>>>>> +  DegenerateSlots.clear();
>>>>>> +  DegenerateSlots.resize(NumSlot);
>>>>>> +
>>>>>> +  // Step 1: collect markers and populate the "InterestingSlots"
>>>>>> +  // and "DegenerateSlots" sets.
>>>>>> +  for (MachineBasicBlock *MBB : depth_first(MF)) {
>>>>>> +
>>>>>> +    // Compute the set of slots for which we've seen a START marker
>>>>>> but have
>>>>>> +    // not yet seen an END marker at this point in the walk (e.g. on
>>>>>> entry
>>>>>> +    // to this bb).
>>>>>> +    BitVector BetweenStartEnd;
>>>>>> +    BetweenStartEnd.resize(NumSlot);
>>>>>> +    for (MachineBasicBlock::const_pred_iterator PI =
>>>>>> MBB->pred_begin(),
>>>>>> +             PE = MBB->pred_end(); PI != PE; ++PI) {
>>>>>> +      BlockBitVecMap::const_iterator I = SeenStartMap.find(*PI);
>>>>>> +      if (I != SeenStartMap.end()) {
>>>>>> +        BetweenStartEnd |= I->second;
>>>>>> +      }
>>>>>> +    }
>>>>>> +
>>>>>> +    // Walk the instructions in the block to look for start/end ops.
>>>>>> +    for (MachineInstr &MI : *MBB) {
>>>>>> +      if (MI.getOpcode() == TargetOpcode::LIFETIME_START ||
>>>>>> +          MI.getOpcode() == TargetOpcode::LIFETIME_END) {
>>>>>> +        int Slot = getStartOrEndSlot(MI);
>>>>>> +        if (Slot < 0)
>>>>>> +          continue;
>>>>>> +        InterestingSlots.set(Slot);
>>>>>> +        if (MI.getOpcode() == TargetOpcode::LIFETIME_START)
>>>>>> +          BetweenStartEnd.set(Slot);
>>>>>> +        else
>>>>>> +          BetweenStartEnd.reset(Slot);
>>>>>> +        const AllocaInst *Allocation =
>>>>>> MFI->getObjectAllocation(Slot);
>>>>>> +        if (Allocation) {
>>>>>> +          DEBUG(dbgs() << "Found a lifetime ");
>>>>>> +          DEBUG(dbgs() << (MI.getOpcode() ==
>>>>>> TargetOpcode::LIFETIME_START
>>>>>> +                               ? "start"
>>>>>> +                               : "end"));
>>>>>> +          DEBUG(dbgs() << " marker for slot #" << Slot);
>>>>>> +          DEBUG(dbgs() << " with allocation: " <<
>>>>>> Allocation->getName()
>>>>>> +                       << "\n");
>>>>>> +        }
>>>>>> +        Markers.push_back(&MI);
>>>>>> +        MarkersFound += 1;
>>>>>> +      } else {
>>>>>> +        for (const MachineOperand &MO : MI.operands()) {
>>>>>> +          if (!MO.isFI())
>>>>>> +            continue;
>>>>>> +          int Slot = MO.getIndex();
>>>>>> +          if (Slot < 0)
>>>>>> +            continue;
>>>>>> +          if (! BetweenStartEnd.test(Slot)) {
>>>>>> +            DegenerateSlots.set(Slot);
>>>>>> +          }
>>>>>> +        }
>>>>>> +      }
>>>>>> +    }
>>>>>> +    BitVector &SeenStart = SeenStartMap[MBB];
>>>>>> +    SeenStart |= BetweenStartEnd;
>>>>>> +  }
>>>>>> +  if (!MarkersFound) {
>>>>>> +    return 0;
>>>>>> +  }
>>>>>> +  DEBUG(dumpBV("Degenerate slots", DegenerateSlots));
>>>>>> +
>>>>>> +  // Step 2: compute begin/end sets for each block
>>>>>> +
>>>>>>    // NOTE: We use a reverse-post-order iteration to ensure that we
>>>>>> obtain a
>>>>>>    // deterministic numbering, and because we'll need a post-order
>>>>>> iteration
>>>>>>    // later for solving the liveness dataflow problem.
>>>>>> @@ -246,37 +572,33 @@ unsigned StackColoring::collectMarkers(u
>>>>>>      BlockInfo.Begin.resize(NumSlot);
>>>>>>      BlockInfo.End.resize(NumSlot);
>>>>>>
>>>>>> +    SmallVector<int, 4> slots;
>>>>>>      for (MachineInstr &MI : *MBB) {
>>>>>> -      if (MI.getOpcode() != TargetOpcode::LIFETIME_START &&
>>>>>> -          MI.getOpcode() != TargetOpcode::LIFETIME_END)
>>>>>> -        continue;
>>>>>> -
>>>>>> -      bool IsStart = MI.getOpcode() == TargetOpcode::LIFETIME_START;
>>>>>> -      const MachineOperand &MO = MI.getOperand(0);
>>>>>> -      int Slot = MO.getIndex();
>>>>>> -      if (Slot < 0)
>>>>>> -        continue;
>>>>>> -
>>>>>> -      Markers.push_back(&MI);
>>>>>> -
>>>>>> -      MarkersFound++;
>>>>>> -
>>>>>> -      const AllocaInst *Allocation = MFI->getObjectAllocation(Slot);
>>>>>> -      if (Allocation) {
>>>>>> -        DEBUG(dbgs()<<"Found a lifetime marker for slot #"<<Slot<<
>>>>>> -              " with allocation: "<< Allocation->getName()<<"\n");
>>>>>> -      }
>>>>>> -
>>>>>> -      if (IsStart) {
>>>>>> -        BlockInfo.Begin.set(Slot);
>>>>>> -      } else {
>>>>>> -        if (BlockInfo.Begin.test(Slot)) {
>>>>>> -          // Allocas that start and end within a single block are
>>>>>> handled
>>>>>> -          // specially when computing the LiveIntervals to avoid
>>>>>> pessimizing
>>>>>> -          // the liveness propagation.
>>>>>> -          BlockInfo.Begin.reset(Slot);
>>>>>> -        } else {
>>>>>> +      bool isStart = false;
>>>>>> +      slots.clear();
>>>>>> +      if (isLifetimeStartOrEnd(MI, slots, isStart)) {
>>>>>> +        if (!isStart) {
>>>>>> +          assert(slots.size() == 1 && "unexpected: MI ends multiple
>>>>>> slots");
>>>>>> +          int Slot = slots[0];
>>>>>> +          if (BlockInfo.Begin.test(Slot)) {
>>>>>> +            BlockInfo.Begin.reset(Slot);
>>>>>> +          }
>>>>>>            BlockInfo.End.set(Slot);
>>>>>> +        } else {
>>>>>> +          for (auto Slot : slots) {
>>>>>> +            DEBUG(dbgs() << "Found a use of slot #" << Slot);
>>>>>> +            DEBUG(dbgs() << " at BB#" << MBB->getNumber() << " index
>>>>>> ");
>>>>>> +            DEBUG(Indexes->getInstructionIndex(MI).print(dbgs()));
>>>>>> +            const AllocaInst *Allocation =
>>>>>> MFI->getObjectAllocation(Slot);
>>>>>> +            if (Allocation) {
>>>>>> +              DEBUG(dbgs() << " with allocation: "<<
>>>>>> Allocation->getName());
>>>>>> +            }
>>>>>> +            DEBUG(dbgs() << "\n");
>>>>>> +            if (BlockInfo.End.test(Slot)) {
>>>>>> +              BlockInfo.End.reset(Slot);
>>>>>> +            }
>>>>>> +            BlockInfo.Begin.set(Slot);
>>>>>> +          }
>>>>>>          }
>>>>>>        }
>>>>>>      }
>>>>>> @@ -287,90 +609,56 @@ unsigned StackColoring::collectMarkers(u
>>>>>>    return MarkersFound;
>>>>>>  }
>>>>>>
>>>>>> -void StackColoring::calculateLocalLiveness() {
>>>>>> -  // Perform a standard reverse dataflow computation to solve for
>>>>>> -  // global liveness.  The BEGIN set here is equivalent to KILL in
>>>>>> the standard
>>>>>> -  // formulation, and END is equivalent to GEN.  The result of this
>>>>>> computation
>>>>>> -  // is a map from blocks to bitvectors where the bitvectors
>>>>>> represent which
>>>>>> -  // allocas are live in/out of that block.
>>>>>> -  SmallPtrSet<const MachineBasicBlock*, 8>
>>>>>> BBSet(BasicBlockNumbering.begin(),
>>>>>> -
>>>>>>  BasicBlockNumbering.end());
>>>>>> -  unsigned NumSSMIters = 0;
>>>>>> +void StackColoring::calculateLocalLiveness()
>>>>>> +{
>>>>>> +  unsigned NumIters = 0;
>>>>>>    bool changed = true;
>>>>>>    while (changed) {
>>>>>>      changed = false;
>>>>>> -    ++NumSSMIters;
>>>>>> -
>>>>>> -    SmallPtrSet<const MachineBasicBlock*, 8> NextBBSet;
>>>>>> +    ++NumIters;
>>>>>>
>>>>>>      for (const MachineBasicBlock *BB : BasicBlockNumbering) {
>>>>>> -      if (!BBSet.count(BB)) continue;
>>>>>>
>>>>>>        // Use an iterator to avoid repeated lookups.
>>>>>>        LivenessMap::iterator BI = BlockLiveness.find(BB);
>>>>>>        assert(BI != BlockLiveness.end() && "Block not found");
>>>>>>        BlockLifetimeInfo &BlockInfo = BI->second;
>>>>>>
>>>>>> +      // Compute LiveIn by unioning together the LiveOut sets of all
>>>>>> preds.
>>>>>>        BitVector LocalLiveIn;
>>>>>> -      BitVector LocalLiveOut;
>>>>>> -
>>>>>> -      // Forward propagation from begins to ends.
>>>>>>        for (MachineBasicBlock::const_pred_iterator PI =
>>>>>> BB->pred_begin(),
>>>>>>             PE = BB->pred_end(); PI != PE; ++PI) {
>>>>>>          LivenessMap::const_iterator I = BlockLiveness.find(*PI);
>>>>>>          assert(I != BlockLiveness.end() && "Predecessor not found");
>>>>>>          LocalLiveIn |= I->second.LiveOut;
>>>>>>        }
>>>>>> -      LocalLiveIn |= BlockInfo.End;
>>>>>> -      LocalLiveIn.reset(BlockInfo.Begin);
>>>>>> -
>>>>>> -      // Reverse propagation from ends to begins.
>>>>>> -      for (MachineBasicBlock::const_succ_iterator SI =
>>>>>> BB->succ_begin(),
>>>>>> -           SE = BB->succ_end(); SI != SE; ++SI) {
>>>>>> -        LivenessMap::const_iterator I = BlockLiveness.find(*SI);
>>>>>> -        assert(I != BlockLiveness.end() && "Successor not found");
>>>>>> -        LocalLiveOut |= I->second.LiveIn;
>>>>>> -      }
>>>>>> -      LocalLiveOut |= BlockInfo.Begin;
>>>>>> -      LocalLiveOut.reset(BlockInfo.End);
>>>>>> -
>>>>>> -      LocalLiveIn |= LocalLiveOut;
>>>>>> -      LocalLiveOut |= LocalLiveIn;
>>>>>>
>>>>>> -      // After adopting the live bits, we need to turn-off the bits
>>>>>> which
>>>>>> -      // are de-activated in this block.
>>>>>> +      // 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);
>>>>>> -      LocalLiveIn.reset(BlockInfo.Begin);
>>>>>> -
>>>>>> -      // 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 vectore).
>>>>>> -      // Want to enable the LIVE_IN and LIVE_OUT of slots that have
>>>>>> both
>>>>>> -      // BEGIN and END because it means that the value lives before
>>>>>> and after
>>>>>> -      // this basic block.
>>>>>> -      BitVector LocalEndBegin = BlockInfo.End;
>>>>>> -      LocalEndBegin &= BlockInfo.Begin;
>>>>>> -      LocalLiveIn |= LocalEndBegin;
>>>>>> -      LocalLiveOut |= LocalEndBegin;
>>>>>> +      LocalLiveOut |= BlockInfo.Begin;
>>>>>>
>>>>>> +      // Update block LiveIn set, noting whether it has changed.
>>>>>>        if (LocalLiveIn.test(BlockInfo.LiveIn)) {
>>>>>>          changed = true;
>>>>>>          BlockInfo.LiveIn |= LocalLiveIn;
>>>>>> -
>>>>>> -        NextBBSet.insert(BB->pred_begin(), BB->pred_end());
>>>>>>        }
>>>>>>
>>>>>> +      // Update block LiveOut set, noting whether it has changed.
>>>>>>        if (LocalLiveOut.test(BlockInfo.LiveOut)) {
>>>>>>          changed = true;
>>>>>>          BlockInfo.LiveOut |= LocalLiveOut;
>>>>>> -
>>>>>> -        NextBBSet.insert(BB->succ_begin(), BB->succ_end());
>>>>>>        }
>>>>>>      }
>>>>>> -
>>>>>> -    BBSet = std::move(NextBBSet);
>>>>>>    }// while changed.
>>>>>> +
>>>>>> +  NumIterations = NumIters;
>>>>>>  }
>>>>>>
>>>>>>  void StackColoring::calculateLiveIntervals(unsigned NumSlots) {
>>>>>> @@ -385,29 +673,22 @@ void StackColoring::calculateLiveInterva
>>>>>>      Finishes.clear();
>>>>>>      Finishes.resize(NumSlots);
>>>>>>
>>>>>> -    // Create the interval for the basic blocks with lifetime
>>>>>> markers in them.
>>>>>> -    for (const MachineInstr *MI : Markers) {
>>>>>> -      if (MI->getParent() != &MBB)
>>>>>> -        continue;
>>>>>> +    // Create the interval for the basic blocks containing lifetime
>>>>>> begin/end.
>>>>>> +    for (const MachineInstr &MI : MBB) {
>>>>>>
>>>>>> -      assert((MI->getOpcode() == TargetOpcode::LIFETIME_START ||
>>>>>> -              MI->getOpcode() == TargetOpcode::LIFETIME_END) &&
>>>>>> -             "Invalid Lifetime marker");
>>>>>> -
>>>>>> -      bool IsStart = MI->getOpcode() == TargetOpcode::LIFETIME_START;
>>>>>> -      const MachineOperand &Mo = MI->getOperand(0);
>>>>>> -      int Slot = Mo.getIndex();
>>>>>> -      if (Slot < 0)
>>>>>> +      SmallVector<int, 4> slots;
>>>>>> +      bool IsStart = false;
>>>>>> +      if (!isLifetimeStartOrEnd(MI, slots, IsStart))
>>>>>>          continue;
>>>>>> -
>>>>>> -      SlotIndex ThisIndex = Indexes->getInstructionIndex(*MI);
>>>>>> -
>>>>>> -      if (IsStart) {
>>>>>> -        if (!Starts[Slot].isValid() || Starts[Slot] > ThisIndex)
>>>>>> -          Starts[Slot] = ThisIndex;
>>>>>> -      } else {
>>>>>> -        if (!Finishes[Slot].isValid() || Finishes[Slot] < ThisIndex)
>>>>>> -          Finishes[Slot] = ThisIndex;
>>>>>> +      SlotIndex ThisIndex = Indexes->getInstructionIndex(MI);
>>>>>> +      for (auto Slot : slots) {
>>>>>> +        if (IsStart) {
>>>>>> +          if (!Starts[Slot].isValid() || Starts[Slot] > ThisIndex)
>>>>>> +            Starts[Slot] = ThisIndex;
>>>>>> +        } else {
>>>>>> +          if (!Finishes[Slot].isValid() || Finishes[Slot] <
>>>>>> ThisIndex)
>>>>>> +            Finishes[Slot] = ThisIndex;
>>>>>> +        }
>>>>>>        }
>>>>>>      }
>>>>>>
>>>>>> @@ -423,7 +704,29 @@ void StackColoring::calculateLiveInterva
>>>>>>      }
>>>>>>
>>>>>>      for (unsigned i = 0; i < NumSlots; ++i) {
>>>>>> -      assert(Starts[i].isValid() == Finishes[i].isValid() &&
>>>>>> "Unmatched range");
>>>>>> +      //
>>>>>> +      // When LifetimeStartOnFirstUse is turned on, data flow
>>>>>> analysis
>>>>>> +      // is forward (from starts to ends), not bidirectional. A
>>>>>> +      // consequence of this is that we can wind up in situations
>>>>>> +      // where Starts[i] is invalid but Finishes[i] is valid and vice
>>>>>> +      // versa. Example:
>>>>>> +      //
>>>>>> +      //     LIFETIME_START x
>>>>>> +      //     if (...) {
>>>>>> +      //       <use of x>
>>>>>> +      //       throw ...;
>>>>>> +      //     }
>>>>>> +      //     LIFETIME_END x
>>>>>> +      //     return 2;
>>>>>> +      //
>>>>>> +      //
>>>>>> +      // Here the slot for "x" will not be live into the block
>>>>>> +      // containing the "return 2" (since lifetimes start with first
>>>>>> +      // use, not at the dominating LIFETIME_START marker).
>>>>>> +      //
>>>>>> +      if (Starts[i].isValid() && !Finishes[i].isValid()) {
>>>>>> +        Finishes[i] = Indexes->getMBBEndIdx(&MBB);
>>>>>> +      }
>>>>>>        if (!Starts[i].isValid())
>>>>>>          continue;
>>>>>>
>>>>>> @@ -684,7 +987,6 @@ bool StackColoring::runOnMachineFunction
>>>>>>      return false;
>>>>>>
>>>>>>    SmallVector<int, 8> SortedSlots;
>>>>>> -
>>>>>>    SortedSlots.reserve(NumSlots);
>>>>>>    Intervals.reserve(NumSlots);
>>>>>>
>>>>>> @@ -717,9 +1019,12 @@ bool StackColoring::runOnMachineFunction
>>>>>>
>>>>>>    // Calculate the liveness of each block.
>>>>>>    calculateLocalLiveness();
>>>>>> +  DEBUG(dbgs() << "Dataflow iterations: " << NumIterations << "\n");
>>>>>> +  DEBUG(dump());
>>>>>>
>>>>>>    // Propagate the liveness information.
>>>>>>    calculateLiveIntervals(NumSlots);
>>>>>> +  DEBUG(dumpIntervals());
>>>>>>
>>>>>>    // Search for allocas which are used outside of the declared
>>>>>> lifetime
>>>>>>    // markers.
>>>>>>
>>>>>> Modified: llvm/trunk/test/CodeGen/X86/StackColoring.ll
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/StackColoring.ll?rev=270559&r1=270558&r2=270559&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- llvm/trunk/test/CodeGen/X86/StackColoring.ll (original)
>>>>>> +++ llvm/trunk/test/CodeGen/X86/StackColoring.ll Tue May 24 08:23:44
>>>>>> 2016
>>>>>> @@ -87,7 +87,7 @@ bb3:
>>>>>>  }
>>>>>>
>>>>>>  ;CHECK-LABEL: myCall_w4:
>>>>>> -;YESCOLOR: subq  $200, %rsp
>>>>>> +;YESCOLOR: subq  $120, %rsp
>>>>>>  ;NOCOLOR: subq  $408, %rsp
>>>>>>
>>>>>>  define i32 @myCall_w4(i32 %in) {
>>>>>> @@ -217,7 +217,7 @@ bb3:
>>>>>>
>>>>>>
>>>>>>  ;CHECK-LABEL: myCall2_nostart:
>>>>>> -;YESCOLOR: subq  $144, %rsp
>>>>>> +;YESCOLOR: subq  $272, %rsp
>>>>>>  ;NOCOLOR: subq  $272, %rsp
>>>>>>  define i32 @myCall2_nostart(i32 %in, i1 %d) {
>>>>>>  entry:
>>>>>> @@ -425,6 +425,120 @@ define i32 @shady_range(i32 %argc, i8**
>>>>>>    ret i32 9
>>>>>>  }
>>>>>>
>>>>>> +; In this case 'itar1' and 'itar2' can't be overlapped if we treat
>>>>>> +; lifetime.start as the beginning of the lifetime, but we can
>>>>>> +; overlap if we consider first use of the slot as lifetime
>>>>>> +; start. See llvm bug 25776.
>>>>>> +
>>>>>> +;CHECK-LABEL: ifthen_twoslots:
>>>>>> +;YESCOLOR: subq  $536, %rsp
>>>>>> +;NOCOLOR: subq  $1048, %rsp
>>>>>> +
>>>>>> +define i32 @ifthen_twoslots(i32 %x) #0 {
>>>>>> +entry:
>>>>>> +  %retval = alloca i32, align 4
>>>>>> +  %x.addr = alloca i32, align 4
>>>>>> +  %itar1 = alloca [128 x i32], align 16
>>>>>> +  %itar2 = alloca [128 x i32], align 16
>>>>>> +  %cleanup.dest.slot = alloca i32
>>>>>> +  store i32 %x, i32* %x.addr, align 4
>>>>>> +  %itar1_start_8 = bitcast [128 x i32]* %itar1 to i8*
>>>>>> +  call void @llvm.lifetime.start(i64 512, i8* %itar1_start_8) #3
>>>>>> +  %itar2_start_8 = bitcast [128 x i32]* %itar2 to i8*
>>>>>> +  call void @llvm.lifetime.start(i64 512, i8* %itar2_start_8) #3
>>>>>> +  %xval = load i32, i32* %x.addr, align 4
>>>>>> +  %and = and i32 %xval, 1
>>>>>> +  %tobool = icmp ne i32 %and, 0
>>>>>> +  br i1 %tobool, label %if.then, label %if.else
>>>>>> +
>>>>>> +if.then:                                          ; preds = %entry
>>>>>> +  %arraydecay = getelementptr inbounds [128 x i32], [128 x i32]*
>>>>>> %itar1, i32 0, i32 0
>>>>>> +  call void @inita(i32* %arraydecay)
>>>>>> +  store i32 1, i32* %retval, align 4
>>>>>> +  store i32 1, i32* %cleanup.dest.slot, align 4
>>>>>> +  %itar2_end_8 = bitcast [128 x i32]* %itar2 to i8*
>>>>>> +  call void @llvm.lifetime.end(i64 512, i8* %itar2_end_8) #3
>>>>>> +  %itar1_end_8 = bitcast [128 x i32]* %itar1 to i8*
>>>>>> +  call void @llvm.lifetime.end(i64 512, i8* %itar1_end_8) #3
>>>>>> +  br label %cleanup
>>>>>> +
>>>>>> +if.else:                                          ; preds = %entry
>>>>>> +  %arraydecay1 = getelementptr inbounds [128 x i32], [128 x i32]*
>>>>>> %itar2, i32 0, i32 0
>>>>>> +  call void @inita(i32* %arraydecay1)
>>>>>> +  store i32 0, i32* %retval, align 4
>>>>>> +  store i32 1, i32* %cleanup.dest.slot, align 4
>>>>>> +  %itar2_end2_8 = bitcast [128 x i32]* %itar2 to i8*
>>>>>> +  call void @llvm.lifetime.end(i64 512, i8* %itar2_end2_8) #3
>>>>>> +  %itar1_end2_8 = bitcast [128 x i32]* %itar1 to i8*
>>>>>> +  call void @llvm.lifetime.end(i64 512, i8* %itar1_end2_8) #3
>>>>>> +  br label %cleanup
>>>>>> +
>>>>>> +cleanup:                                          ; preds =
>>>>>> %if.else, %if.then
>>>>>> +  %final_retval = load i32,
>>>>>> + i32* %retval, align 4
>>>>>> +  ret i32 %final_retval
>>>>>> +}
>>>>>> +
>>>>>> +; This function is intended to test the case where you
>>>>>> +; have a reference to a stack slot that lies outside of
>>>>>> +; the START/END lifetime markers-- the flow analysis
>>>>>> +; should catch this and build the lifetime based on the
>>>>>> +; markers only.
>>>>>> +
>>>>>> +;CHECK-LABEL: while_loop:
>>>>>> +;YESCOLOR: subq  $1032, %rsp
>>>>>> +;NOCOLOR: subq  $1544, %rsp
>>>>>> +
>>>>>> +define i32 @while_loop(i32 %x) #0 {
>>>>>> +entry:
>>>>>> +  %b1 = alloca [128 x i32], align 16
>>>>>> +  %b2 = alloca [128 x i32], align 16
>>>>>> +  %b3 = alloca [128 x i32], align 16
>>>>>> +  %tmp = bitcast [128 x i32]* %b1 to i8*
>>>>>> +  call void @llvm.lifetime.start(i64 512, i8* %tmp) #3
>>>>>> +  %tmp1 = bitcast [128 x i32]* %b2 to i8*
>>>>>> +  call void @llvm.lifetime.start(i64 512, i8* %tmp1) #3
>>>>>> +  %and = and i32 %x, 1
>>>>>> +  %tobool = icmp eq i32 %and, 0
>>>>>> +  br i1 %tobool, label %if.else, label %if.then
>>>>>> +
>>>>>> +if.then:                                          ; preds = %entry
>>>>>> +  %arraydecay = getelementptr inbounds [128 x i32], [128 x i32]*
>>>>>> %b2, i64 0, i64 0
>>>>>> +  call void @inita(i32* %arraydecay) #3
>>>>>> +  br label %if.end
>>>>>> +
>>>>>> +if.else:                                          ; preds = %entry
>>>>>> +  %arraydecay1 = getelementptr inbounds [128 x i32], [128 x i32]*
>>>>>> %b1, i64 0, i64 0
>>>>>> +  call void @inita(i32* %arraydecay1) #3
>>>>>> +  %arraydecay3 = getelementptr inbounds [128 x i32], [128 x i32]*
>>>>>> %b3, i64 0, i64 0
>>>>>> +  call void @inita(i32* %arraydecay3) #3
>>>>>> +  %tobool25 = icmp eq i32 %x, 0
>>>>>> +  br i1 %tobool25, label %if.end, label %while.body.lr.ph
>>>>>> +
>>>>>> +while.body.lr.ph:                                 ; preds = %if.else
>>>>>> +  %tmp2 = bitcast [128 x i32]* %b3 to i8*
>>>>>> +  br label %while.body
>>>>>> +
>>>>>> +while.body:                                       ; preds = %
>>>>>> while.body.lr.ph, %while.body
>>>>>> +  %x.addr.06 = phi i32 [ %x, %while.body.lr.ph ], [ %dec,
>>>>>> %while.body ]
>>>>>> +  %dec = add nsw i32 %x.addr.06, -1
>>>>>> +  call void @llvm.lifetime.start(i64 512, i8* %tmp2) #3
>>>>>> +  call void @inita(i32* %arraydecay3) #3
>>>>>> +  call void @llvm.lifetime.end(i64 512, i8* %tmp2) #3
>>>>>> +  %tobool2 = icmp eq i32 %dec, 0
>>>>>> +  br i1 %tobool2, label %if.end.loopexit, label %while.body
>>>>>> +
>>>>>> +if.end.loopexit:                                  ; preds =
>>>>>> %while.body
>>>>>> +  br label %if.end
>>>>>> +
>>>>>> +if.end:                                           ; preds =
>>>>>> %if.end.loopexit, %if.else, %if.then
>>>>>> +  call void @llvm.lifetime.end(i64 512, i8* %tmp1) #3
>>>>>> +  call void @llvm.lifetime.end(i64 512, i8* %tmp) #3
>>>>>> +  ret i32 0
>>>>>> +}
>>>>>> +
>>>>>> +declare void @inita(i32*) #2
>>>>>> +
>>>>>>  declare void @bar([100 x i32]* , [100 x i32]*) nounwind
>>>>>>
>>>>>>  declare void @llvm.lifetime.start(i64, i8* nocapture) nounwind
>>>>>>
>>>>>> Modified: llvm/trunk/test/CodeGen/X86/misched-aa-colored.ll
>>>>>> URL:
>>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/misched-aa-colored.ll?rev=270559&r1=270558&r2=270559&view=diff
>>>>>>
>>>>>> ==============================================================================
>>>>>> --- llvm/trunk/test/CodeGen/X86/misched-aa-colored.ll (original)
>>>>>> +++ llvm/trunk/test/CodeGen/X86/misched-aa-colored.ll Tue May 24
>>>>>> 08:23:44 2016
>>>>>> @@ -155,6 +155,7 @@ entry:
>>>>>>    %ref.tmp.i = alloca
>>>>>> %"struct.std::pair.112.119.719.1079.2039.2159.2399.4199", align 8
>>>>>>    %Op.i = alloca
>>>>>> %"class.llvm::SDValue.3.603.963.1923.2043.2283.4083", align 8
>>>>>>    %0 = bitcast
>>>>>> %"struct.std::pair.112.119.719.1079.2039.2159.2399.4199"* %ref.tmp.i to i8*
>>>>>> +  call void @llvm.lifetime.start(i64 24, i8* %0) #1
>>>>>>    %retval.sroa.0.0.idx.i36 = getelementptr inbounds
>>>>>> %"struct.std::pair.112.119.719.1079.2039.2159.2399.4199",
>>>>>> %"struct.std::pair.112.119.719.1079.2039.2159.2399.4199"* %ref.tmp.i, i64
>>>>>> 0, i32 1, i32 0, i32 0
>>>>>>    %retval.sroa.0.0.copyload.i37 = load i32, i32*
>>>>>> %retval.sroa.0.0.idx.i36, align 8
>>>>>>    call void @llvm.lifetime.end(i64 24, i8* %0) #1
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> llvm-commits mailing list
>>>>>> llvm-commits at lists.llvm.org
>>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Teresa Johnson |  Software Engineer |  tejohnson at google.com |
>>>>> 408-460-2413
>>>>>
>>>>
>>>>
>>>
>>>
>>> --
>>> Teresa Johnson |  Software Engineer |  tejohnson at google.com |
>>> 408-460-2413
>>>
>>
>>
>>
>> --
>> Teresa Johnson |  Software Engineer |  tejohnson at google.com |
>> 408-460-2413
>>
>
>
>
> --
> Teresa Johnson |  Software Engineer |  tejohnson at google.com |
> 408-460-2413
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160527/7ceac860/attachment.html>


More information about the llvm-commits mailing list