llvm-project/bolt/include/bolt/Passes/StackPointerTracking.h
Rafael Auler c09cd64e5c [BOLT] Fix AND evaluation bug in shrink wrapping
Fix a bug where shrink-wrapping would use wrong stack offsets
because the stack was being aligned with an AND instruction, hence,
making its true offsets only available during runtime (we can't
statically determine where are the stack elements and we must give up
on this case).

Reviewed By: Amir

Differential Revision: https://reviews.llvm.org/D126110
2022-05-26 14:59:28 -07:00

210 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;
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->evaluateStackOffsetExpr(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->evaluateStackOffsetExpr(Point, Output, SP, FP)) {
if (SPVal == EMPTY && FPVal == EMPTY)
return FPVal;
return SUPERPOSITION;
}
if (!HasFramePointer && 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