214 lines
6.4 KiB
C++
214 lines
6.4 KiB
C++
//===- bolt/Passes/StackPointerTracking.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_STACKPOINTERTRACKING_H
|
|
#define BOLT_PASSES_STACKPOINTERTRACKING_H
|
|
|
|
#include "bolt/Passes/DataflowAnalysis.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
namespace opts {
|
|
extern llvm::cl::opt<bool> TimeOpts;
|
|
} // namespace opts
|
|
|
|
namespace llvm {
|
|
namespace bolt {
|
|
|
|
/// Perform a dataflow analysis to track the value of SP as an offset relative
|
|
/// to the CFA.
|
|
template <typename Derived>
|
|
class StackPointerTrackingBase
|
|
: public DataflowAnalysis<Derived, std::pair<int, int>> {
|
|
friend class DataflowAnalysis<Derived, std::pair<int, int>>;
|
|
|
|
protected:
|
|
void preflight() {}
|
|
|
|
int getEmpty() { return EMPTY; }
|
|
|
|
std::pair<int, int> getStartingStateAtBB(const BinaryBasicBlock &BB) {
|
|
// Entry BB start with offset 8 from CFA.
|
|
// All others start with EMPTY (meaning we don't know anything).
|
|
if (BB.isEntryPoint())
|
|
return std::make_pair(-8, getEmpty());
|
|
return std::make_pair(getEmpty(), getEmpty());
|
|
}
|
|
|
|
std::pair<int, int> getStartingStateAtPoint(const MCInst &Point) {
|
|
return std::make_pair(getEmpty(), getEmpty());
|
|
}
|
|
|
|
void doConfluenceSingleReg(int &StateOut, const int &StateIn) {
|
|
if (StateOut == EMPTY) {
|
|
StateOut = StateIn;
|
|
return;
|
|
}
|
|
if (StateIn == EMPTY || StateIn == StateOut)
|
|
return;
|
|
|
|
// We can't agree on a specific value from this point on
|
|
StateOut = SUPERPOSITION;
|
|
}
|
|
|
|
void doConfluence(std::pair<int, int> &StateOut,
|
|
const std::pair<int, int> &StateIn) {
|
|
doConfluenceSingleReg(StateOut.first, StateIn.first);
|
|
doConfluenceSingleReg(StateOut.second, StateIn.second);
|
|
}
|
|
|
|
void doConfluenceWithLP(std::pair<int, int> &StateOut,
|
|
const std::pair<int, int> &StateIn,
|
|
const MCInst &Invoke) {
|
|
int SPVal = StateIn.first;
|
|
if (SPVal != EMPTY && SPVal != SUPERPOSITION) {
|
|
const int64_t GnuArgsSize = this->BC.MIB->getGnuArgsSize(Invoke);
|
|
if (GnuArgsSize > 0)
|
|
SPVal += GnuArgsSize;
|
|
}
|
|
doConfluenceSingleReg(StateOut.first, SPVal);
|
|
doConfluenceSingleReg(StateOut.second, StateIn.second);
|
|
}
|
|
|
|
int computeNextSP(const MCInst &Point, int SPVal, int FPVal) {
|
|
const auto &MIB = this->BC.MIB;
|
|
|
|
if (int Sz = MIB->getPushSize(Point)) {
|
|
if (SPVal == EMPTY || SPVal == SUPERPOSITION)
|
|
return SPVal;
|
|
|
|
return SPVal - Sz;
|
|
}
|
|
|
|
if (int Sz = MIB->getPopSize(Point)) {
|
|
if (SPVal == EMPTY || SPVal == SUPERPOSITION)
|
|
return SPVal;
|
|
|
|
return SPVal + Sz;
|
|
}
|
|
|
|
MCPhysReg From, To;
|
|
if (MIB->isRegToRegMove(Point, From, To) && To == MIB->getStackPointer() &&
|
|
From == MIB->getFramePointer()) {
|
|
if (FPVal == EMPTY || FPVal == SUPERPOSITION)
|
|
return FPVal;
|
|
|
|
if (MIB->isLeave(Point))
|
|
return FPVal + 8;
|
|
else
|
|
return FPVal;
|
|
}
|
|
|
|
if (this->BC.MII->get(Point.getOpcode())
|
|
.hasDefOfPhysReg(Point, MIB->getStackPointer(), *this->BC.MRI)) {
|
|
std::pair<MCPhysReg, int64_t> SP;
|
|
if (SPVal != EMPTY && SPVal != SUPERPOSITION)
|
|
SP = std::make_pair(MIB->getStackPointer(), SPVal);
|
|
else
|
|
SP = std::make_pair(0, 0);
|
|
std::pair<MCPhysReg, int64_t> FP;
|
|
if (FPVal != EMPTY && FPVal != SUPERPOSITION)
|
|
FP = std::make_pair(MIB->getFramePointer(), FPVal);
|
|
else
|
|
FP = std::make_pair(0, 0);
|
|
int64_t Output;
|
|
if (!MIB->evaluateSimple(Point, Output, SP, FP)) {
|
|
if (SPVal == EMPTY && FPVal == EMPTY)
|
|
return SPVal;
|
|
return SUPERPOSITION;
|
|
}
|
|
|
|
return static_cast<int>(Output);
|
|
}
|
|
|
|
return SPVal;
|
|
}
|
|
|
|
int computeNextFP(const MCInst &Point, int SPVal, int FPVal) {
|
|
const auto &MIB = this->BC.MIB;
|
|
|
|
MCPhysReg From, To;
|
|
if (MIB->isRegToRegMove(Point, From, To) && To == MIB->getFramePointer() &&
|
|
From == MIB->getStackPointer()) {
|
|
HasFramePointer = true;
|
|
return SPVal;
|
|
}
|
|
|
|
if (this->BC.MII->get(Point.getOpcode())
|
|
.hasDefOfPhysReg(Point, MIB->getFramePointer(), *this->BC.MRI)) {
|
|
std::pair<MCPhysReg, int64_t> FP;
|
|
if (FPVal != EMPTY && FPVal != SUPERPOSITION)
|
|
FP = std::make_pair(MIB->getFramePointer(), FPVal);
|
|
else
|
|
FP = std::make_pair(0, 0);
|
|
std::pair<MCPhysReg, int64_t> SP;
|
|
if (SPVal != EMPTY && SPVal != SUPERPOSITION)
|
|
SP = std::make_pair(MIB->getStackPointer(), SPVal);
|
|
else
|
|
SP = std::make_pair(0, 0);
|
|
int64_t Output;
|
|
if (!MIB->evaluateSimple(Point, Output, SP, FP)) {
|
|
if (SPVal == EMPTY && FPVal == EMPTY)
|
|
return FPVal;
|
|
return SUPERPOSITION;
|
|
}
|
|
|
|
if (!HasFramePointer) {
|
|
if (MIB->escapesVariable(Point, false)) {
|
|
HasFramePointer = true;
|
|
}
|
|
}
|
|
return static_cast<int>(Output);
|
|
}
|
|
|
|
return FPVal;
|
|
}
|
|
|
|
std::pair<int, int> computeNext(const MCInst &Point,
|
|
const std::pair<int, int> &Cur) {
|
|
return std::make_pair(computeNextSP(Point, Cur.first, Cur.second),
|
|
computeNextFP(Point, Cur.first, Cur.second));
|
|
}
|
|
|
|
StringRef getAnnotationName() const {
|
|
return StringRef("StackPointerTracking");
|
|
}
|
|
|
|
public:
|
|
StackPointerTrackingBase(BinaryFunction &BF,
|
|
MCPlusBuilder::AllocatorIdTy AllocatorId = 0)
|
|
: DataflowAnalysis<Derived, std::pair<int, int>>(BF, AllocatorId) {}
|
|
|
|
virtual ~StackPointerTrackingBase() {}
|
|
|
|
bool HasFramePointer{false};
|
|
|
|
static constexpr int SUPERPOSITION = std::numeric_limits<int>::max();
|
|
static constexpr int EMPTY = std::numeric_limits<int>::min();
|
|
};
|
|
|
|
class StackPointerTracking
|
|
: public StackPointerTrackingBase<StackPointerTracking> {
|
|
friend class DataflowAnalysis<StackPointerTracking, std::pair<int, int>>;
|
|
|
|
public:
|
|
StackPointerTracking(BinaryFunction &BF,
|
|
MCPlusBuilder::AllocatorIdTy AllocatorId = 0);
|
|
virtual ~StackPointerTracking() {}
|
|
|
|
void run() { StackPointerTrackingBase<StackPointerTracking>::run(); }
|
|
};
|
|
|
|
} // end namespace bolt
|
|
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
|
|
const std::pair<int, int> &Val);
|
|
|
|
} // end namespace llvm
|
|
|
|
#endif
|