forked from OSchip/llvm-project
164 lines
4.9 KiB
C++
164 lines
4.9 KiB
C++
//===----- BPFMISimplifyPatchable.cpp - MI Simplify Patchable Insts -------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This pass targets a subset of instructions like below
|
|
// ld_imm64 r1, @global
|
|
// ldd r2, r1, 0
|
|
// add r3, struct_base_reg, r2
|
|
//
|
|
// Here @global should either present a AMA (abstruct member access) or
|
|
// a patchable extern variable. And these two kinds of accesses
|
|
// are subject to bpf load time patching. After this pass, the
|
|
// code becomes
|
|
// ld_imm64 r1, @global
|
|
// add r3, struct_base_reg, r1
|
|
//
|
|
// Eventually, at BTF output stage, a relocation record will be generated
|
|
// for ld_imm64 which should be replaced later by bpf loader:
|
|
// r1 = <calculated offset> or <to_be_patched_extern_val>
|
|
// add r3, struct_base_reg, r1
|
|
// or
|
|
// ld_imm64 r1, <to_be_patched_extern_val>
|
|
// add r3, struct_base_reg, r1
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "BPF.h"
|
|
#include "BPFCORE.h"
|
|
#include "BPFInstrInfo.h"
|
|
#include "BPFTargetMachine.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "bpf-mi-simplify-patchable"
|
|
|
|
namespace {
|
|
|
|
struct BPFMISimplifyPatchable : public MachineFunctionPass {
|
|
|
|
static char ID;
|
|
const BPFInstrInfo *TII;
|
|
MachineFunction *MF;
|
|
|
|
BPFMISimplifyPatchable() : MachineFunctionPass(ID) {
|
|
initializeBPFMISimplifyPatchablePass(*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
private:
|
|
// Initialize class variables.
|
|
void initialize(MachineFunction &MFParm);
|
|
|
|
bool removeLD(void);
|
|
|
|
public:
|
|
// Main entry point for this pass.
|
|
bool runOnMachineFunction(MachineFunction &MF) override {
|
|
if (!skipFunction(MF.getFunction())) {
|
|
initialize(MF);
|
|
}
|
|
return removeLD();
|
|
}
|
|
};
|
|
|
|
// Initialize class variables.
|
|
void BPFMISimplifyPatchable::initialize(MachineFunction &MFParm) {
|
|
MF = &MFParm;
|
|
TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
|
|
LLVM_DEBUG(dbgs() << "*** BPF simplify patchable insts pass ***\n\n");
|
|
}
|
|
|
|
/// Remove unneeded Load instructions.
|
|
bool BPFMISimplifyPatchable::removeLD() {
|
|
MachineRegisterInfo *MRI = &MF->getRegInfo();
|
|
MachineInstr *ToErase = nullptr;
|
|
bool Changed = false;
|
|
|
|
for (MachineBasicBlock &MBB : *MF) {
|
|
for (MachineInstr &MI : MBB) {
|
|
if (ToErase) {
|
|
ToErase->eraseFromParent();
|
|
ToErase = nullptr;
|
|
}
|
|
|
|
// Ensure the register format is LOAD <reg>, <reg>, 0
|
|
if (MI.getOpcode() != BPF::LDD && MI.getOpcode() != BPF::LDW &&
|
|
MI.getOpcode() != BPF::LDH && MI.getOpcode() != BPF::LDB &&
|
|
MI.getOpcode() != BPF::LDW32 && MI.getOpcode() != BPF::LDH32 &&
|
|
MI.getOpcode() != BPF::LDB32)
|
|
continue;
|
|
|
|
if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg())
|
|
continue;
|
|
|
|
if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm())
|
|
continue;
|
|
|
|
Register DstReg = MI.getOperand(0).getReg();
|
|
Register SrcReg = MI.getOperand(1).getReg();
|
|
int64_t ImmVal = MI.getOperand(2).getImm();
|
|
|
|
MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg);
|
|
if (!DefInst)
|
|
continue;
|
|
|
|
bool IsCandidate = false;
|
|
if (DefInst->getOpcode() == BPF::LD_imm64) {
|
|
const MachineOperand &MO = DefInst->getOperand(1);
|
|
if (MO.isGlobal()) {
|
|
const GlobalValue *GVal = MO.getGlobal();
|
|
auto *GVar = dyn_cast<GlobalVariable>(GVal);
|
|
if (GVar) {
|
|
// Global variables representing structure offset or
|
|
// patchable extern globals.
|
|
if (GVar->hasAttribute(BPFCoreSharedInfo::AmaAttr)) {
|
|
assert(ImmVal == 0);
|
|
IsCandidate = true;
|
|
} else if (!GVar->hasInitializer() && GVar->hasExternalLinkage() &&
|
|
GVar->getSection() ==
|
|
BPFCoreSharedInfo::PatchableExtSecName) {
|
|
if (ImmVal == 0)
|
|
IsCandidate = true;
|
|
else
|
|
errs() << "WARNING: unhandled patchable extern "
|
|
<< GVar->getName() << " with load offset " << ImmVal
|
|
<< "\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!IsCandidate)
|
|
continue;
|
|
|
|
auto Begin = MRI->use_begin(DstReg), End = MRI->use_end();
|
|
decltype(End) NextI;
|
|
for (auto I = Begin; I != End; I = NextI) {
|
|
NextI = std::next(I);
|
|
I->setReg(SrcReg);
|
|
}
|
|
|
|
ToErase = &MI;
|
|
Changed = true;
|
|
}
|
|
}
|
|
|
|
return Changed;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
INITIALIZE_PASS(BPFMISimplifyPatchable, DEBUG_TYPE,
|
|
"BPF PreEmit SimplifyPatchable", false, false)
|
|
|
|
char BPFMISimplifyPatchable::ID = 0;
|
|
FunctionPass *llvm::createBPFMISimplifyPatchablePass() {
|
|
return new BPFMISimplifyPatchable();
|
|
}
|