Path: blob/main/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIChecking.cpp
35266 views
//===-------------- BPFMIChecking.cpp - MI Checking Legality -------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This pass performs checking to signal errors for certain illegal usages at9// MachineInstruction layer. Specially, the result of XADD{32,64} insn should10// not be used. The pass is done at the PreEmit pass right before the11// machine code is emitted at which point the register liveness information12// is still available.13//14//===----------------------------------------------------------------------===//1516#include "BPF.h"17#include "BPFInstrInfo.h"18#include "BPFTargetMachine.h"19#include "llvm/CodeGen/MachineFunctionPass.h"20#include "llvm/CodeGen/MachineInstrBuilder.h"21#include "llvm/CodeGen/MachineRegisterInfo.h"22#include "llvm/IR/DiagnosticInfo.h"23#include "llvm/Support/Debug.h"2425using namespace llvm;2627#define DEBUG_TYPE "bpf-mi-checking"2829namespace {3031struct BPFMIPreEmitChecking : public MachineFunctionPass {3233static char ID;34MachineFunction *MF;35const TargetRegisterInfo *TRI;3637BPFMIPreEmitChecking() : MachineFunctionPass(ID) {38initializeBPFMIPreEmitCheckingPass(*PassRegistry::getPassRegistry());39}4041private:42// Initialize class variables.43void initialize(MachineFunction &MFParm);4445bool processAtomicInsts();4647public:4849// Main entry point for this pass.50bool runOnMachineFunction(MachineFunction &MF) override {51if (!skipFunction(MF.getFunction())) {52initialize(MF);53return processAtomicInsts();54}55return false;56}57};5859// Initialize class variables.60void BPFMIPreEmitChecking::initialize(MachineFunction &MFParm) {61MF = &MFParm;62TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo();63LLVM_DEBUG(dbgs() << "*** BPF PreEmit checking pass ***\n\n");64}6566// Make sure all Defs of XADD are dead, meaning any result of XADD insn is not67// used.68//69// NOTE: BPF backend hasn't enabled sub-register liveness track, so when the70// source and destination operands of XADD are GPR32, there is no sub-register71// dead info. If we rely on the generic MachineInstr::allDefsAreDead, then we72// will raise false alarm on GPR32 Def.73//74// To support GPR32 Def, ideally we could just enable sub-registr liveness track75// on BPF backend, then allDefsAreDead could work on GPR32 Def. This requires76// implementing TargetSubtargetInfo::enableSubRegLiveness on BPF.77//78// However, sub-register liveness tracking module inside LLVM is actually79// designed for the situation where one register could be split into more than80// one sub-registers for which case each sub-register could have their own81// liveness and kill one of them doesn't kill others. So, tracking liveness for82// each make sense.83//84// For BPF, each 64-bit register could only have one 32-bit sub-register. This85// is exactly the case which LLVM think brings no benefits for doing86// sub-register tracking, because the live range of sub-register must always87// equal to its parent register, therefore liveness tracking is disabled even88// the back-end has implemented enableSubRegLiveness. The detailed information89// is at r232695:90//91// Author: Matthias Braun <[email protected]>92// Date: Thu Mar 19 00:21:58 2015 +000093// Do not track subregister liveness when it brings no benefits94//95// Hence, for BPF, we enhance MachineInstr::allDefsAreDead. Given the solo96// sub-register always has the same liveness as its parent register, LLVM is97// already attaching a implicit 64-bit register Def whenever the there is98// a sub-register Def. The liveness of the implicit 64-bit Def is available.99// For example, for "lock *(u32 *)(r0 + 4) += w9", the MachineOperand info could100// be:101//102// $w9 = XADDW32 killed $r0, 4, $w9(tied-def 0),103// implicit killed $r9, implicit-def dead $r9104//105// Even though w9 is not marked as Dead, the parent register r9 is marked as106// Dead correctly, and it is safe to use such information or our purpose.107static bool hasLiveDefs(const MachineInstr &MI, const TargetRegisterInfo *TRI) {108const MCRegisterClass *GPR64RegClass =109&BPFMCRegisterClasses[BPF::GPRRegClassID];110std::vector<unsigned> GPR32LiveDefs;111std::vector<unsigned> GPR64DeadDefs;112113for (const MachineOperand &MO : MI.operands()) {114bool RegIsGPR64;115116if (!MO.isReg() || MO.isUse())117continue;118119RegIsGPR64 = GPR64RegClass->contains(MO.getReg());120if (!MO.isDead()) {121// It is a GPR64 live Def, we are sure it is live. */122if (RegIsGPR64)123return true;124// It is a GPR32 live Def, we are unsure whether it is really dead due to125// no sub-register liveness tracking. Push it to vector for deferred126// check.127GPR32LiveDefs.push_back(MO.getReg());128continue;129}130131// Record any GPR64 dead Def as some unmarked GPR32 could be alias of its132// low 32-bit.133if (RegIsGPR64)134GPR64DeadDefs.push_back(MO.getReg());135}136137// No GPR32 live Def, safe to return false.138if (GPR32LiveDefs.empty())139return false;140141// No GPR64 dead Def, so all those GPR32 live Def can't have alias, therefore142// must be truely live, safe to return true.143if (GPR64DeadDefs.empty())144return true;145146// Otherwise, return true if any aliased SuperReg of GPR32 is not dead.147for (auto I : GPR32LiveDefs)148for (MCPhysReg SR : TRI->superregs(I))149if (!llvm::is_contained(GPR64DeadDefs, SR))150return true;151152return false;153}154155bool BPFMIPreEmitChecking::processAtomicInsts() {156for (MachineBasicBlock &MBB : *MF) {157for (MachineInstr &MI : MBB) {158if (MI.getOpcode() != BPF::XADDW &&159MI.getOpcode() != BPF::XADDD &&160MI.getOpcode() != BPF::XADDW32)161continue;162163LLVM_DEBUG(MI.dump());164if (hasLiveDefs(MI, TRI)) {165DebugLoc Empty;166const DebugLoc &DL = MI.getDebugLoc();167const Function &F = MF->getFunction();168F.getContext().diagnose(DiagnosticInfoUnsupported{169F, "Invalid usage of the XADD return value", DL});170}171}172}173174// Check return values of atomic_fetch_and_{add,and,or,xor}.175// If the return is not used, the atomic_fetch_and_<op> instruction176// is replaced with atomic_<op> instruction.177MachineInstr *ToErase = nullptr;178bool Changed = false;179const BPFInstrInfo *TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();180for (MachineBasicBlock &MBB : *MF) {181for (MachineInstr &MI : MBB) {182if (ToErase) {183ToErase->eraseFromParent();184ToErase = nullptr;185}186187if (MI.getOpcode() != BPF::XFADDW32 && MI.getOpcode() != BPF::XFADDD &&188MI.getOpcode() != BPF::XFANDW32 && MI.getOpcode() != BPF::XFANDD &&189MI.getOpcode() != BPF::XFXORW32 && MI.getOpcode() != BPF::XFXORD &&190MI.getOpcode() != BPF::XFORW32 && MI.getOpcode() != BPF::XFORD)191continue;192193if (hasLiveDefs(MI, TRI))194continue;195196LLVM_DEBUG(dbgs() << "Transforming "; MI.dump());197unsigned newOpcode;198switch (MI.getOpcode()) {199case BPF::XFADDW32:200newOpcode = BPF::XADDW32;201break;202case BPF::XFADDD:203newOpcode = BPF::XADDD;204break;205case BPF::XFANDW32:206newOpcode = BPF::XANDW32;207break;208case BPF::XFANDD:209newOpcode = BPF::XANDD;210break;211case BPF::XFXORW32:212newOpcode = BPF::XXORW32;213break;214case BPF::XFXORD:215newOpcode = BPF::XXORD;216break;217case BPF::XFORW32:218newOpcode = BPF::XORW32;219break;220case BPF::XFORD:221newOpcode = BPF::XORD;222break;223default:224llvm_unreachable("Incorrect Atomic Instruction Opcode");225}226227BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(newOpcode))228.add(MI.getOperand(0))229.add(MI.getOperand(1))230.add(MI.getOperand(2))231.add(MI.getOperand(3));232233ToErase = &MI;234Changed = true;235}236}237238return Changed;239}240241} // end default namespace242243INITIALIZE_PASS(BPFMIPreEmitChecking, "bpf-mi-pemit-checking",244"BPF PreEmit Checking", false, false)245246char BPFMIPreEmitChecking::ID = 0;247FunctionPass* llvm::createBPFMIPreEmitCheckingPass()248{249return new BPFMIPreEmitChecking();250}251252253