blob: 5280fc293c874c5be28f7eb3cec7633d1af86e86 [file] [log] [blame]
//===- 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