| //===-------------- BPFMIChecking.cpp - MI Checking Legality -------------===// | |
| // | |
| // 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 performs checking to signal errors for certain illegal usages at | |
| // MachineInstruction layer. Specially, the result of the locked atomic insns | |
| // (XADD, XAND, XOR and XXOR, 32 and 64 bit) should not be used, since they do | |
| // not return the old value. The pass is done at the PreEmit pass right before | |
| // the machine code is emitted at which point the register liveness information | |
| // is still available. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "BPF.h" | |
| #include "BPFRegisterInfo.h" | |
| #include "BPFTargetMachine.h" | |
| #include "llvm/CodeGen/MachineFunctionAnalysisManager.h" | |
| #include "llvm/CodeGen/MachineFunctionPass.h" | |
| #include "llvm/IR/Analysis.h" | |
| #include "llvm/IR/DiagnosticInfo.h" | |
| #include "llvm/Support/Debug.h" | |
| using namespace llvm; | |
| #define DEBUG_TYPE "bpf-mi-checking" | |
| namespace { | |
| struct BPFMIPreEmitCheckingLegacy : public MachineFunctionPass { | |
| static char ID; | |
| BPFMIPreEmitCheckingLegacy() : MachineFunctionPass(ID) {} | |
| public: | |
| // Main entry point for this pass. | |
| bool runOnMachineFunction(MachineFunction &MF) override; | |
| }; | |
| // Make sure all Defs of XADD are dead, meaning any result of XADD insn is not | |
| // used. | |
| // | |
| // NOTE: BPF backend hasn't enabled sub-register liveness track, so when the | |
| // source and destination operands of XADD are GPR32, there is no sub-register | |
| // dead info. If we rely on the generic MachineInstr::allDefsAreDead, then we | |
| // will raise false alarm on GPR32 Def. | |
| // | |
| // To support GPR32 Def, ideally we could just enable sub-registr liveness track | |
| // on BPF backend, then allDefsAreDead could work on GPR32 Def. This requires | |
| // implementing TargetSubtargetInfo::enableSubRegLiveness on BPF. | |
| // | |
| // However, sub-register liveness tracking module inside LLVM is actually | |
| // designed for the situation where one register could be split into more than | |
| // one sub-registers for which case each sub-register could have their own | |
| // liveness and kill one of them doesn't kill others. So, tracking liveness for | |
| // each make sense. | |
| // | |
| // For BPF, each 64-bit register could only have one 32-bit sub-register. This | |
| // is exactly the case which LLVM think brings no benefits for doing | |
| // sub-register tracking, because the live range of sub-register must always | |
| // equal to its parent register, therefore liveness tracking is disabled even | |
| // the back-end has implemented enableSubRegLiveness. The detailed information | |
| // is at r232695: | |
| // | |
| // Author: Matthias Braun <matze@braunis.de> | |
| // Date: Thu Mar 19 00:21:58 2015 +0000 | |
| // Do not track subregister liveness when it brings no benefits | |
| // | |
| // Hence, for BPF, we enhance MachineInstr::allDefsAreDead. Given the solo | |
| // sub-register always has the same liveness as its parent register, LLVM is | |
| // already attaching a implicit 64-bit register Def whenever the there is | |
| // a sub-register Def. The liveness of the implicit 64-bit Def is available. | |
| // For example, for "lock *(u32 *)(r0 + 4) += w9", the MachineOperand info could | |
| // be: | |
| // | |
| // $w9 = XADDW32 killed $r0, 4, $w9(tied-def 0), | |
| // implicit killed $r9, implicit-def dead $r9 | |
| // | |
| // Even though w9 is not marked as Dead, the parent register r9 is marked as | |
| // Dead correctly, and it is safe to use such information or our purpose. | |
| static bool hasLiveDefs(const MachineInstr &MI, const TargetRegisterInfo *TRI) { | |
| const MCRegisterClass *GPR64RegClass = | |
| &getBPFMCRegisterClass(BPF::GPRRegClassID); | |
| std::vector<unsigned> GPR32LiveDefs; | |
| std::vector<unsigned> GPR64DeadDefs; | |
| for (const MachineOperand &MO : MI.operands()) { | |
| bool RegIsGPR64; | |
| if (!MO.isReg() || MO.isUse()) | |
| continue; | |
| RegIsGPR64 = GPR64RegClass->contains(MO.getReg()); | |
| if (!MO.isDead()) { | |
| // It is a GPR64 live Def, we are sure it is live. | |
| if (RegIsGPR64) | |
| return true; | |
| // It is a GPR32 live Def, we are unsure whether it is really dead due to | |
| // no sub-register liveness tracking. Push it to vector for deferred | |
| // check. | |
| GPR32LiveDefs.push_back(MO.getReg()); | |
| continue; | |
| } | |
| // Record any GPR64 dead Def as some unmarked GPR32 could be alias of its | |
| // low 32-bit. | |
| if (RegIsGPR64) | |
| GPR64DeadDefs.push_back(MO.getReg()); | |
| } | |
| // No GPR32 live Def, safe to return false. | |
| if (GPR32LiveDefs.empty()) | |
| return false; | |
| // No GPR64 dead Def, so all those GPR32 live Def can't have alias, therefore | |
| // must be truely live, safe to return true. | |
| if (GPR64DeadDefs.empty()) | |
| return true; | |
| // Otherwise, return true if any aliased SuperReg of GPR32 is not dead. | |
| for (auto I : GPR32LiveDefs) | |
| for (MCPhysReg SR : TRI->superregs(I)) | |
| if (!llvm::is_contained(GPR64DeadDefs, SR)) | |
| return true; | |
| return false; | |
| } | |
| } // namespace | |
| // The locked atomic insns do not return the old value, so a live result is a | |
| // selection bug regardless of the cpu version: for v1/v2 there is no fetching | |
| // insn, and for v3+ instruction selection must pick the atomic_fetch_*() insn | |
| // whenever the result is used. | |
| static bool isLockedAtomicInsn(unsigned Opcode) { | |
| switch (Opcode) { | |
| default: | |
| return false; | |
| case BPF::XADDW: | |
| case BPF::XADDD: | |
| case BPF::XANDD: | |
| case BPF::XORD: | |
| case BPF::XXORD: | |
| case BPF::XADDW32: | |
| case BPF::XANDW32: | |
| case BPF::XORW32: | |
| case BPF::XXORW32: | |
| return true; | |
| } | |
| } | |
| static void processAtomicInsts(MachineFunction &MF) { | |
| LLVM_DEBUG(dbgs() << "*** BPF PreEmit checking pass ***\n\n"); | |
| const BPFRegisterInfo *TRI = | |
| MF.getSubtarget<BPFSubtarget>().getRegisterInfo(); | |
| for (MachineBasicBlock &MBB : MF) { | |
| for (MachineInstr &MI : MBB) { | |
| if (!isLockedAtomicInsn(MI.getOpcode())) | |
| continue; | |
| LLVM_DEBUG(MI.dump()); | |
| if (hasLiveDefs(MI, TRI)) { | |
| const DebugLoc &DL = MI.getDebugLoc(); | |
| const Function &F = MF.getFunction(); | |
| F.getContext().diagnose(DiagnosticInfoUnsupported{ | |
| F, "Invalid usage of the XADD return value", DL}); | |
| } | |
| } | |
| } | |
| } | |
| bool BPFMIPreEmitCheckingLegacy::runOnMachineFunction(MachineFunction &MF) { | |
| if (skipFunction(MF.getFunction())) | |
| return false; | |
| processAtomicInsts(MF); | |
| return false; | |
| } | |
| PreservedAnalyses | |
| BPFMIPreEmitCheckingPass::run(MachineFunction &MF, | |
| MachineFunctionAnalysisManager &MFAM) { | |
| processAtomicInsts(MF); | |
| return PreservedAnalyses::all(); | |
| } | |
| INITIALIZE_PASS(BPFMIPreEmitCheckingLegacy, "bpf-mi-checking", | |
| "BPF PreEmit Checking", false, false) | |
| char BPFMIPreEmitCheckingLegacy::ID = 0; | |
| FunctionPass *llvm::createBPFMIPreEmitCheckingLegacyPass() { | |
| return new BPFMIPreEmitCheckingLegacy(); | |
| } |