12cab237bSDimitry Andric //===- SafeStackColoring.cpp - SafeStack frame coloring -------------------===//
23ca95b02SDimitry Andric //
33ca95b02SDimitry Andric //                     The LLVM Compiler Infrastructure
43ca95b02SDimitry Andric //
53ca95b02SDimitry Andric // This file is distributed under the University of Illinois Open Source
63ca95b02SDimitry Andric // License. See LICENSE.TXT for details.
73ca95b02SDimitry Andric //
83ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
93ca95b02SDimitry Andric 
103ca95b02SDimitry Andric #include "SafeStackColoring.h"
112cab237bSDimitry Andric #include "llvm/ADT/BitVector.h"
122cab237bSDimitry Andric #include "llvm/ADT/DenseMap.h"
133ca95b02SDimitry Andric #include "llvm/ADT/DepthFirstIterator.h"
142cab237bSDimitry Andric #include "llvm/ADT/SmallVector.h"
154ba319b5SDimitry Andric #include "llvm/Config/llvm-config.h"
162cab237bSDimitry Andric #include "llvm/IR/BasicBlock.h"
173ca95b02SDimitry Andric #include "llvm/IR/CFG.h"
182cab237bSDimitry Andric #include "llvm/IR/Instruction.h"
193ca95b02SDimitry Andric #include "llvm/IR/Instructions.h"
203ca95b02SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
212cab237bSDimitry Andric #include "llvm/IR/Intrinsics.h"
222cab237bSDimitry Andric #include "llvm/IR/User.h"
232cab237bSDimitry Andric #include "llvm/Support/Casting.h"
242cab237bSDimitry Andric #include "llvm/Support/CommandLine.h"
252cab237bSDimitry Andric #include "llvm/Support/Compiler.h"
263ca95b02SDimitry Andric #include "llvm/Support/Debug.h"
272cab237bSDimitry Andric #include "llvm/Support/raw_ostream.h"
282cab237bSDimitry Andric #include <cassert>
292cab237bSDimitry Andric #include <tuple>
302cab237bSDimitry Andric #include <utility>
313ca95b02SDimitry Andric 
323ca95b02SDimitry Andric using namespace llvm;
333ca95b02SDimitry Andric using namespace llvm::safestack;
343ca95b02SDimitry Andric 
353ca95b02SDimitry Andric #define DEBUG_TYPE "safestackcoloring"
363ca95b02SDimitry Andric 
37d8866befSDimitry Andric // Disabled by default due to PR32143.
383ca95b02SDimitry Andric static cl::opt<bool> ClColoring("safe-stack-coloring",
393ca95b02SDimitry Andric                                 cl::desc("enable safe stack coloring"),
40d8866befSDimitry Andric                                 cl::Hidden, cl::init(false));
413ca95b02SDimitry Andric 
getLiveRange(AllocaInst * AI)423ca95b02SDimitry Andric const StackColoring::LiveRange &StackColoring::getLiveRange(AllocaInst *AI) {
436c4bc1bdSDimitry Andric   const auto IT = AllocaNumbering.find(AI);
446c4bc1bdSDimitry Andric   assert(IT != AllocaNumbering.end());
456c4bc1bdSDimitry Andric   return LiveRanges[IT->second];
463ca95b02SDimitry Andric }
473ca95b02SDimitry Andric 
readMarker(Instruction * I,bool * IsStart)483ca95b02SDimitry Andric bool StackColoring::readMarker(Instruction *I, bool *IsStart) {
49*b5893f02SDimitry Andric   if (!I->isLifetimeStartOrEnd())
503ca95b02SDimitry Andric     return false;
513ca95b02SDimitry Andric 
52*b5893f02SDimitry Andric   auto *II = cast<IntrinsicInst>(I);
533ca95b02SDimitry Andric   *IsStart = II->getIntrinsicID() == Intrinsic::lifetime_start;
543ca95b02SDimitry Andric   return true;
553ca95b02SDimitry Andric }
563ca95b02SDimitry Andric 
removeAllMarkers()573ca95b02SDimitry Andric void StackColoring::removeAllMarkers() {
583ca95b02SDimitry Andric   for (auto *I : Markers) {
593ca95b02SDimitry Andric     auto *Op = dyn_cast<Instruction>(I->getOperand(1));
603ca95b02SDimitry Andric     I->eraseFromParent();
613ca95b02SDimitry Andric     // Remove the operand bitcast, too, if it has no more uses left.
623ca95b02SDimitry Andric     if (Op && Op->use_empty())
633ca95b02SDimitry Andric       Op->eraseFromParent();
643ca95b02SDimitry Andric   }
653ca95b02SDimitry Andric }
663ca95b02SDimitry Andric 
collectMarkers()673ca95b02SDimitry Andric void StackColoring::collectMarkers() {
683ca95b02SDimitry Andric   InterestingAllocas.resize(NumAllocas);
693ca95b02SDimitry Andric   DenseMap<BasicBlock *, SmallDenseMap<Instruction *, Marker>> BBMarkerSet;
703ca95b02SDimitry Andric 
713ca95b02SDimitry Andric   // Compute the set of start/end markers per basic block.
723ca95b02SDimitry Andric   for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) {
733ca95b02SDimitry Andric     AllocaInst *AI = Allocas[AllocaNo];
743ca95b02SDimitry Andric     SmallVector<Instruction *, 8> WorkList;
753ca95b02SDimitry Andric     WorkList.push_back(AI);
763ca95b02SDimitry Andric     while (!WorkList.empty()) {
773ca95b02SDimitry Andric       Instruction *I = WorkList.pop_back_val();
783ca95b02SDimitry Andric       for (User *U : I->users()) {
793ca95b02SDimitry Andric         if (auto *BI = dyn_cast<BitCastInst>(U)) {
803ca95b02SDimitry Andric           WorkList.push_back(BI);
813ca95b02SDimitry Andric           continue;
823ca95b02SDimitry Andric         }
833ca95b02SDimitry Andric         auto *UI = dyn_cast<Instruction>(U);
843ca95b02SDimitry Andric         if (!UI)
853ca95b02SDimitry Andric           continue;
863ca95b02SDimitry Andric         bool IsStart;
873ca95b02SDimitry Andric         if (!readMarker(UI, &IsStart))
883ca95b02SDimitry Andric           continue;
893ca95b02SDimitry Andric         if (IsStart)
903ca95b02SDimitry Andric           InterestingAllocas.set(AllocaNo);
913ca95b02SDimitry Andric         BBMarkerSet[UI->getParent()][UI] = {AllocaNo, IsStart};
923ca95b02SDimitry Andric         Markers.push_back(UI);
933ca95b02SDimitry Andric       }
943ca95b02SDimitry Andric     }
953ca95b02SDimitry Andric   }
963ca95b02SDimitry Andric 
973ca95b02SDimitry Andric   // Compute instruction numbering. Only the following instructions are
983ca95b02SDimitry Andric   // considered:
993ca95b02SDimitry Andric   // * Basic block entries
1003ca95b02SDimitry Andric   // * Lifetime markers
1013ca95b02SDimitry Andric   // For each basic block, compute
1023ca95b02SDimitry Andric   // * the list of markers in the instruction order
1033ca95b02SDimitry Andric   // * the sets of allocas whose lifetime starts or ends in this BB
1044ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "Instructions:\n");
1053ca95b02SDimitry Andric   unsigned InstNo = 0;
1063ca95b02SDimitry Andric   for (BasicBlock *BB : depth_first(&F)) {
1074ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "  " << InstNo << ": BB " << BB->getName() << "\n");
1083ca95b02SDimitry Andric     unsigned BBStart = InstNo++;
1093ca95b02SDimitry Andric 
1103ca95b02SDimitry Andric     BlockLifetimeInfo &BlockInfo = BlockLiveness[BB];
1113ca95b02SDimitry Andric     BlockInfo.Begin.resize(NumAllocas);
1123ca95b02SDimitry Andric     BlockInfo.End.resize(NumAllocas);
1133ca95b02SDimitry Andric     BlockInfo.LiveIn.resize(NumAllocas);
1143ca95b02SDimitry Andric     BlockInfo.LiveOut.resize(NumAllocas);
1153ca95b02SDimitry Andric 
1163ca95b02SDimitry Andric     auto &BlockMarkerSet = BBMarkerSet[BB];
1173ca95b02SDimitry Andric     if (BlockMarkerSet.empty()) {
1183ca95b02SDimitry Andric       unsigned BBEnd = InstNo;
1193ca95b02SDimitry Andric       BlockInstRange[BB] = std::make_pair(BBStart, BBEnd);
1203ca95b02SDimitry Andric       continue;
1213ca95b02SDimitry Andric     }
1223ca95b02SDimitry Andric 
1233ca95b02SDimitry Andric     auto ProcessMarker = [&](Instruction *I, const Marker &M) {
1244ba319b5SDimitry Andric       LLVM_DEBUG(dbgs() << "  " << InstNo << ":  "
1254ba319b5SDimitry Andric                         << (M.IsStart ? "start " : "end   ") << M.AllocaNo
1264ba319b5SDimitry Andric                         << ", " << *I << "\n");
1273ca95b02SDimitry Andric 
1283ca95b02SDimitry Andric       BBMarkers[BB].push_back({InstNo, M});
1293ca95b02SDimitry Andric 
1303ca95b02SDimitry Andric       InstructionNumbering[I] = InstNo++;
1313ca95b02SDimitry Andric 
1323ca95b02SDimitry Andric       if (M.IsStart) {
1333ca95b02SDimitry Andric         if (BlockInfo.End.test(M.AllocaNo))
1343ca95b02SDimitry Andric           BlockInfo.End.reset(M.AllocaNo);
1353ca95b02SDimitry Andric         BlockInfo.Begin.set(M.AllocaNo);
1363ca95b02SDimitry Andric       } else {
1373ca95b02SDimitry Andric         if (BlockInfo.Begin.test(M.AllocaNo))
1383ca95b02SDimitry Andric           BlockInfo.Begin.reset(M.AllocaNo);
1393ca95b02SDimitry Andric         BlockInfo.End.set(M.AllocaNo);
1403ca95b02SDimitry Andric       }
1413ca95b02SDimitry Andric     };
1423ca95b02SDimitry Andric 
1433ca95b02SDimitry Andric     if (BlockMarkerSet.size() == 1) {
1443ca95b02SDimitry Andric       ProcessMarker(BlockMarkerSet.begin()->getFirst(),
1453ca95b02SDimitry Andric                     BlockMarkerSet.begin()->getSecond());
1463ca95b02SDimitry Andric     } else {
1473ca95b02SDimitry Andric       // Scan the BB to determine the marker order.
1483ca95b02SDimitry Andric       for (Instruction &I : *BB) {
1493ca95b02SDimitry Andric         auto It = BlockMarkerSet.find(&I);
1503ca95b02SDimitry Andric         if (It == BlockMarkerSet.end())
1513ca95b02SDimitry Andric           continue;
1523ca95b02SDimitry Andric         ProcessMarker(&I, It->getSecond());
1533ca95b02SDimitry Andric       }
1543ca95b02SDimitry Andric     }
1553ca95b02SDimitry Andric 
1563ca95b02SDimitry Andric     unsigned BBEnd = InstNo;
1573ca95b02SDimitry Andric     BlockInstRange[BB] = std::make_pair(BBStart, BBEnd);
1583ca95b02SDimitry Andric   }
1593ca95b02SDimitry Andric   NumInst = InstNo;
1603ca95b02SDimitry Andric }
1613ca95b02SDimitry Andric 
calculateLocalLiveness()1623ca95b02SDimitry Andric void StackColoring::calculateLocalLiveness() {
1633ca95b02SDimitry Andric   bool changed = true;
1643ca95b02SDimitry Andric   while (changed) {
1653ca95b02SDimitry Andric     changed = false;
1663ca95b02SDimitry Andric 
1673ca95b02SDimitry Andric     for (BasicBlock *BB : depth_first(&F)) {
1683ca95b02SDimitry Andric       BlockLifetimeInfo &BlockInfo = BlockLiveness[BB];
1693ca95b02SDimitry Andric 
1703ca95b02SDimitry Andric       // Compute LiveIn by unioning together the LiveOut sets of all preds.
1713ca95b02SDimitry Andric       BitVector LocalLiveIn;
1723ca95b02SDimitry Andric       for (auto *PredBB : predecessors(BB)) {
1733ca95b02SDimitry Andric         LivenessMap::const_iterator I = BlockLiveness.find(PredBB);
174*b5893f02SDimitry Andric         // If a predecessor is unreachable, ignore it.
175*b5893f02SDimitry Andric         if (I == BlockLiveness.end())
176*b5893f02SDimitry Andric           continue;
1773ca95b02SDimitry Andric         LocalLiveIn |= I->second.LiveOut;
1783ca95b02SDimitry Andric       }
1793ca95b02SDimitry Andric 
1803ca95b02SDimitry Andric       // Compute LiveOut by subtracting out lifetimes that end in this
1813ca95b02SDimitry Andric       // block, then adding in lifetimes that begin in this block.  If
1823ca95b02SDimitry Andric       // we have both BEGIN and END markers in the same basic block
1833ca95b02SDimitry Andric       // then we know that the BEGIN marker comes after the END,
1843ca95b02SDimitry Andric       // because we already handle the case where the BEGIN comes
1853ca95b02SDimitry Andric       // before the END when collecting the markers (and building the
1863ca95b02SDimitry Andric       // BEGIN/END vectors).
1873ca95b02SDimitry Andric       BitVector LocalLiveOut = LocalLiveIn;
1883ca95b02SDimitry Andric       LocalLiveOut.reset(BlockInfo.End);
1893ca95b02SDimitry Andric       LocalLiveOut |= BlockInfo.Begin;
1903ca95b02SDimitry Andric 
1913ca95b02SDimitry Andric       // Update block LiveIn set, noting whether it has changed.
1923ca95b02SDimitry Andric       if (LocalLiveIn.test(BlockInfo.LiveIn)) {
1933ca95b02SDimitry Andric         changed = true;
1943ca95b02SDimitry Andric         BlockInfo.LiveIn |= LocalLiveIn;
1953ca95b02SDimitry Andric       }
1963ca95b02SDimitry Andric 
1973ca95b02SDimitry Andric       // Update block LiveOut set, noting whether it has changed.
1983ca95b02SDimitry Andric       if (LocalLiveOut.test(BlockInfo.LiveOut)) {
1993ca95b02SDimitry Andric         changed = true;
2003ca95b02SDimitry Andric         BlockInfo.LiveOut |= LocalLiveOut;
2013ca95b02SDimitry Andric       }
2023ca95b02SDimitry Andric     }
2033ca95b02SDimitry Andric   } // while changed.
2043ca95b02SDimitry Andric }
2053ca95b02SDimitry Andric 
calculateLiveIntervals()2063ca95b02SDimitry Andric void StackColoring::calculateLiveIntervals() {
2073ca95b02SDimitry Andric   for (auto IT : BlockLiveness) {
2083ca95b02SDimitry Andric     BasicBlock *BB = IT.getFirst();
2093ca95b02SDimitry Andric     BlockLifetimeInfo &BlockInfo = IT.getSecond();
2103ca95b02SDimitry Andric     unsigned BBStart, BBEnd;
2113ca95b02SDimitry Andric     std::tie(BBStart, BBEnd) = BlockInstRange[BB];
2123ca95b02SDimitry Andric 
2133ca95b02SDimitry Andric     BitVector Started, Ended;
2143ca95b02SDimitry Andric     Started.resize(NumAllocas);
2153ca95b02SDimitry Andric     Ended.resize(NumAllocas);
2163ca95b02SDimitry Andric     SmallVector<unsigned, 8> Start;
2173ca95b02SDimitry Andric     Start.resize(NumAllocas);
2183ca95b02SDimitry Andric 
2193ca95b02SDimitry Andric     // LiveIn ranges start at the first instruction.
2203ca95b02SDimitry Andric     for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) {
2213ca95b02SDimitry Andric       if (BlockInfo.LiveIn.test(AllocaNo)) {
2223ca95b02SDimitry Andric         Started.set(AllocaNo);
2233ca95b02SDimitry Andric         Start[AllocaNo] = BBStart;
2243ca95b02SDimitry Andric       }
2253ca95b02SDimitry Andric     }
2263ca95b02SDimitry Andric 
2273ca95b02SDimitry Andric     for (auto &It : BBMarkers[BB]) {
2283ca95b02SDimitry Andric       unsigned InstNo = It.first;
2293ca95b02SDimitry Andric       bool IsStart = It.second.IsStart;
2303ca95b02SDimitry Andric       unsigned AllocaNo = It.second.AllocaNo;
2313ca95b02SDimitry Andric 
2323ca95b02SDimitry Andric       if (IsStart) {
233d88c1a5aSDimitry Andric         assert(!Started.test(AllocaNo) || Start[AllocaNo] == BBStart);
234d88c1a5aSDimitry Andric         if (!Started.test(AllocaNo)) {
2353ca95b02SDimitry Andric           Started.set(AllocaNo);
2363ca95b02SDimitry Andric           Ended.reset(AllocaNo);
2373ca95b02SDimitry Andric           Start[AllocaNo] = InstNo;
238d88c1a5aSDimitry Andric         }
2393ca95b02SDimitry Andric       } else {
2403ca95b02SDimitry Andric         assert(!Ended.test(AllocaNo));
2413ca95b02SDimitry Andric         if (Started.test(AllocaNo)) {
2423ca95b02SDimitry Andric           LiveRanges[AllocaNo].AddRange(Start[AllocaNo], InstNo);
2433ca95b02SDimitry Andric           Started.reset(AllocaNo);
2443ca95b02SDimitry Andric         }
2453ca95b02SDimitry Andric         Ended.set(AllocaNo);
2463ca95b02SDimitry Andric       }
2473ca95b02SDimitry Andric     }
2483ca95b02SDimitry Andric 
2493ca95b02SDimitry Andric     for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo)
2503ca95b02SDimitry Andric       if (Started.test(AllocaNo))
2513ca95b02SDimitry Andric         LiveRanges[AllocaNo].AddRange(Start[AllocaNo], BBEnd);
2523ca95b02SDimitry Andric   }
2533ca95b02SDimitry Andric }
2543ca95b02SDimitry Andric 
2557a7e6055SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dumpAllocas()2563ca95b02SDimitry Andric LLVM_DUMP_METHOD void StackColoring::dumpAllocas() {
2573ca95b02SDimitry Andric   dbgs() << "Allocas:\n";
2583ca95b02SDimitry Andric   for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo)
2593ca95b02SDimitry Andric     dbgs() << "  " << AllocaNo << ": " << *Allocas[AllocaNo] << "\n";
2603ca95b02SDimitry Andric }
2613ca95b02SDimitry Andric 
dumpBlockLiveness()2623ca95b02SDimitry Andric LLVM_DUMP_METHOD void StackColoring::dumpBlockLiveness() {
2633ca95b02SDimitry Andric   dbgs() << "Block liveness:\n";
2643ca95b02SDimitry Andric   for (auto IT : BlockLiveness) {
2653ca95b02SDimitry Andric     BasicBlock *BB = IT.getFirst();
2663ca95b02SDimitry Andric     BlockLifetimeInfo &BlockInfo = BlockLiveness[BB];
2673ca95b02SDimitry Andric     auto BlockRange = BlockInstRange[BB];
2683ca95b02SDimitry Andric     dbgs() << "  BB [" << BlockRange.first << ", " << BlockRange.second
2693ca95b02SDimitry Andric            << "): begin " << BlockInfo.Begin << ", end " << BlockInfo.End
2703ca95b02SDimitry Andric            << ", livein " << BlockInfo.LiveIn << ", liveout "
2713ca95b02SDimitry Andric            << BlockInfo.LiveOut << "\n";
2723ca95b02SDimitry Andric   }
2733ca95b02SDimitry Andric }
2743ca95b02SDimitry Andric 
dumpLiveRanges()2753ca95b02SDimitry Andric LLVM_DUMP_METHOD void StackColoring::dumpLiveRanges() {
2763ca95b02SDimitry Andric   dbgs() << "Alloca liveness:\n";
2773ca95b02SDimitry Andric   for (unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) {
2783ca95b02SDimitry Andric     LiveRange &Range = LiveRanges[AllocaNo];
2793ca95b02SDimitry Andric     dbgs() << "  " << AllocaNo << ": " << Range << "\n";
2803ca95b02SDimitry Andric   }
2813ca95b02SDimitry Andric }
2827a7e6055SDimitry Andric #endif
2833ca95b02SDimitry Andric 
run()2843ca95b02SDimitry Andric void StackColoring::run() {
2854ba319b5SDimitry Andric   LLVM_DEBUG(dumpAllocas());
2863ca95b02SDimitry Andric 
2873ca95b02SDimitry Andric   for (unsigned I = 0; I < NumAllocas; ++I)
2883ca95b02SDimitry Andric     AllocaNumbering[Allocas[I]] = I;
2893ca95b02SDimitry Andric   LiveRanges.resize(NumAllocas);
2903ca95b02SDimitry Andric 
2913ca95b02SDimitry Andric   collectMarkers();
2923ca95b02SDimitry Andric 
2933ca95b02SDimitry Andric   if (!ClColoring) {
2943ca95b02SDimitry Andric     for (auto &R : LiveRanges) {
2953ca95b02SDimitry Andric       R.SetMaximum(1);
2963ca95b02SDimitry Andric       R.AddRange(0, 1);
2973ca95b02SDimitry Andric     }
2983ca95b02SDimitry Andric     return;
2993ca95b02SDimitry Andric   }
3003ca95b02SDimitry Andric 
3013ca95b02SDimitry Andric   for (auto &R : LiveRanges)
3023ca95b02SDimitry Andric     R.SetMaximum(NumInst);
3033ca95b02SDimitry Andric   for (unsigned I = 0; I < NumAllocas; ++I)
3043ca95b02SDimitry Andric     if (!InterestingAllocas.test(I))
3053ca95b02SDimitry Andric       LiveRanges[I] = getFullLiveRange();
3063ca95b02SDimitry Andric 
3073ca95b02SDimitry Andric   calculateLocalLiveness();
3084ba319b5SDimitry Andric   LLVM_DEBUG(dumpBlockLiveness());
3093ca95b02SDimitry Andric   calculateLiveIntervals();
3104ba319b5SDimitry Andric   LLVM_DEBUG(dumpLiveRanges());
3113ca95b02SDimitry Andric }
312