| //===- bolt/Passes/LivenessAnalysis.h ---------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef BOLT_PASSES_LIVENESSANALYSIS_H |
| #define BOLT_PASSES_LIVENESSANALYSIS_H |
| |
| #include "bolt/Passes/DataflowAnalysis.h" |
| #include "bolt/Passes/RegAnalysis.h" |
| #include "llvm/MC/MCRegisterInfo.h" |
| #include "llvm/Support/CommandLine.h" |
| |
| namespace opts { |
| extern llvm::cl::opt<bool> AssumeABI; |
| extern llvm::cl::opt<bool> TimeOpts; |
| } // namespace opts |
| |
| namespace llvm { |
| namespace bolt { |
| |
| class LivenessAnalysis : public DataflowAnalysis<LivenessAnalysis, BitVector, |
| true, RegStatePrinter> { |
| using Parent = |
| DataflowAnalysis<LivenessAnalysis, BitVector, true, RegStatePrinter>; |
| friend class DataflowAnalysis<LivenessAnalysis, BitVector, true, |
| RegStatePrinter>; |
| |
| public: |
| LivenessAnalysis(const RegAnalysis &RA, BinaryFunction &BF, |
| MCPlusBuilder::AllocatorIdTy AllocId) |
| : Parent(BF, AllocId), RA(RA), |
| NumRegs(BF.getBinaryContext().MRI->getNumRegs()) {} |
| virtual ~LivenessAnalysis(); |
| |
| bool isAlive(ProgramPoint PP, MCPhysReg Reg) const { |
| BitVector BV = (*this->getStateAt(PP)); |
| const BitVector &RegAliases = BC.MIB->getAliases(Reg); |
| BV &= RegAliases; |
| return BV.any(); |
| } |
| |
| void run() { Parent::run(); } |
| |
| // Return a usable general-purpose reg after point P. Return 0 if no reg is |
| // available. |
| MCPhysReg scavengeRegAfter(ProgramPoint P) { |
| BitVector BV = *this->getStateAt(P); |
| BV.flip(); |
| BitVector GPRegs(NumRegs, false); |
| this->BC.MIB->getGPRegs(GPRegs, /*IncludeAlias=*/false); |
| // Ignore the register used for frame pointer even if it is not alive (it |
| // may be used by CFI which is not represented in our dataflow). |
| BitVector FP = BC.MIB->getAliases(BC.MIB->getFramePointer()); |
| FP.flip(); |
| BV &= GPRegs; |
| BV &= FP; |
| int Reg = BV.find_first(); |
| return Reg != -1 ? Reg : 0; |
| } |
| |
| protected: |
| /// Reference to the result of reg analysis |
| const RegAnalysis &RA; |
| const uint16_t NumRegs; |
| |
| void preflight() {} |
| |
| BitVector getStartingStateAtBB(const BinaryBasicBlock &BB) { |
| // Entry points start with default live out (registers used as return |
| // values). |
| if (BB.succ_size() == 0) { |
| BitVector State(NumRegs, false); |
| if (opts::AssumeABI) { |
| BC.MIB->getDefaultLiveOut(State); |
| BC.MIB->getCalleeSavedRegs(State); |
| } else { |
| State.set(); |
| State.reset(BC.MIB->getFlagsReg()); |
| } |
| return State; |
| } |
| return BitVector(NumRegs, false); |
| } |
| |
| BitVector getStartingStateAtPoint(const MCInst &Point) { |
| return BitVector(NumRegs, false); |
| } |
| |
| void doConfluence(BitVector &StateOut, const BitVector &StateIn) { |
| StateOut |= StateIn; |
| } |
| |
| BitVector computeNext(const MCInst &Point, const BitVector &Cur) { |
| BitVector Next = Cur; |
| bool IsCall = this->BC.MIB->isCall(Point); |
| // Kill |
| BitVector Written = BitVector(NumRegs, false); |
| if (!IsCall) { |
| this->BC.MIB->getWrittenRegs(Point, Written); |
| } else { |
| RA.getInstClobberList(Point, Written); |
| // When clobber list is conservative, it is clobbering all/most registers, |
| // a conservative estimate because it knows nothing about this call. |
| // For our purposes, assume it kills no registers/callee-saved regs |
| // because we don't really know what's going on. |
| if (RA.isConservative(Written)) { |
| Written.reset(); |
| BC.MIB->getDefaultLiveOut(Written); |
| // If ABI is respected, everything except CSRs should be dead after a |
| // call |
| if (opts::AssumeABI) { |
| BitVector CSR = BitVector(NumRegs, false); |
| BC.MIB->getCalleeSavedRegs(CSR); |
| CSR.flip(); |
| Written |= CSR; |
| } |
| } |
| } |
| Written.flip(); |
| Next &= Written; |
| // Gen |
| if (!this->BC.MIB->isCFI(Point)) { |
| if (BC.MIB->isCleanRegXOR(Point)) |
| return Next; |
| |
| BitVector Used = BitVector(NumRegs, false); |
| if (IsCall) { |
| RA.getInstUsedRegsList(Point, Used, /*GetClobbers*/ true); |
| if (RA.isConservative(Used)) { |
| Used = BC.MIB->getRegsUsedAsParams(); |
| BC.MIB->getDefaultLiveOut(Used); |
| } |
| } |
| const MCInstrDesc &InstInfo = BC.MII->get(Point.getOpcode()); |
| for (unsigned I = 0, E = Point.getNumOperands(); I != E; ++I) { |
| if (!Point.getOperand(I).isReg() || I < InstInfo.getNumDefs()) |
| continue; |
| Used |= BC.MIB->getAliases(Point.getOperand(I).getReg(), |
| /*OnlySmaller=*/false); |
| } |
| for (MCPhysReg ImplicitUse : InstInfo.implicit_uses()) |
| Used |= BC.MIB->getAliases(ImplicitUse, false); |
| if (IsCall && |
| (!BC.MIB->isTailCall(Point) || !BC.MIB->isConditionalBranch(Point))) { |
| // Never gen FLAGS from a non-conditional call... this is overly |
| // conservative |
| Used.reset(BC.MIB->getFlagsReg()); |
| } |
| Next |= Used; |
| } |
| return Next; |
| } |
| |
| StringRef getAnnotationName() const { return StringRef("LivenessAnalysis"); } |
| }; |
| |
| } // end namespace bolt |
| } // end namespace llvm |
| |
| #endif |