123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- //===-------------- 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 XADD{32,64} insn should
- // not be used. 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 "BPFInstrInfo.h"
- #include "BPFTargetMachine.h"
- #include "llvm/CodeGen/MachineInstrBuilder.h"
- #include "llvm/CodeGen/MachineRegisterInfo.h"
- #include "llvm/Support/Debug.h"
- using namespace llvm;
- #define DEBUG_TYPE "bpf-mi-checking"
- namespace {
- struct BPFMIPreEmitChecking : public MachineFunctionPass {
- static char ID;
- MachineFunction *MF;
- const TargetRegisterInfo *TRI;
- BPFMIPreEmitChecking() : MachineFunctionPass(ID) {
- initializeBPFMIPreEmitCheckingPass(*PassRegistry::getPassRegistry());
- }
- private:
- // Initialize class variables.
- void initialize(MachineFunction &MFParm);
- bool processAtomicInsts();
- public:
- // Main entry point for this pass.
- bool runOnMachineFunction(MachineFunction &MF) override {
- if (!skipFunction(MF.getFunction())) {
- initialize(MF);
- return processAtomicInsts();
- }
- return false;
- }
- };
- // Initialize class variables.
- void BPFMIPreEmitChecking::initialize(MachineFunction &MFParm) {
- MF = &MFParm;
- TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo();
- LLVM_DEBUG(dbgs() << "*** BPF PreEmit checking pass ***\n\n");
- }
- // 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 =
- &BPFMCRegisterClasses[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 (MCSuperRegIterator SR(I, TRI); SR.isValid(); ++SR)
- if (!llvm::is_contained(GPR64DeadDefs, *SR))
- return true;
- return false;
- }
- bool BPFMIPreEmitChecking::processAtomicInsts() {
- for (MachineBasicBlock &MBB : *MF) {
- for (MachineInstr &MI : MBB) {
- if (MI.getOpcode() != BPF::XADDW &&
- MI.getOpcode() != BPF::XADDD &&
- MI.getOpcode() != BPF::XADDW32)
- continue;
- LLVM_DEBUG(MI.dump());
- if (hasLiveDefs(MI, TRI)) {
- DebugLoc Empty;
- const DebugLoc &DL = MI.getDebugLoc();
- if (DL != Empty)
- report_fatal_error(Twine("line ") + std::to_string(DL.getLine()) +
- ": Invalid usage of the XADD return value", false);
- else
- report_fatal_error("Invalid usage of the XADD return value", false);
- }
- }
- }
- // Check return values of atomic_fetch_and_{add,and,or,xor}.
- // If the return is not used, the atomic_fetch_and_<op> instruction
- // is replaced with atomic_<op> instruction.
- MachineInstr *ToErase = nullptr;
- bool Changed = false;
- const BPFInstrInfo *TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
- for (MachineBasicBlock &MBB : *MF) {
- for (MachineInstr &MI : MBB) {
- if (ToErase) {
- ToErase->eraseFromParent();
- ToErase = nullptr;
- }
- if (MI.getOpcode() != BPF::XFADDW32 && MI.getOpcode() != BPF::XFADDD &&
- MI.getOpcode() != BPF::XFANDW32 && MI.getOpcode() != BPF::XFANDD &&
- MI.getOpcode() != BPF::XFXORW32 && MI.getOpcode() != BPF::XFXORD &&
- MI.getOpcode() != BPF::XFORW32 && MI.getOpcode() != BPF::XFORD)
- continue;
- if (hasLiveDefs(MI, TRI))
- continue;
- LLVM_DEBUG(dbgs() << "Transforming "; MI.dump());
- unsigned newOpcode;
- switch (MI.getOpcode()) {
- case BPF::XFADDW32:
- newOpcode = BPF::XADDW32;
- break;
- case BPF::XFADDD:
- newOpcode = BPF::XADDD;
- break;
- case BPF::XFANDW32:
- newOpcode = BPF::XANDW32;
- break;
- case BPF::XFANDD:
- newOpcode = BPF::XANDD;
- break;
- case BPF::XFXORW32:
- newOpcode = BPF::XXORW32;
- break;
- case BPF::XFXORD:
- newOpcode = BPF::XXORD;
- break;
- case BPF::XFORW32:
- newOpcode = BPF::XORW32;
- break;
- case BPF::XFORD:
- newOpcode = BPF::XORD;
- break;
- default:
- llvm_unreachable("Incorrect Atomic Instruction Opcode");
- }
- BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(newOpcode))
- .add(MI.getOperand(0))
- .add(MI.getOperand(1))
- .add(MI.getOperand(2))
- .add(MI.getOperand(3));
- ToErase = &MI;
- Changed = true;
- }
- }
- return Changed;
- }
- } // end default namespace
- INITIALIZE_PASS(BPFMIPreEmitChecking, "bpf-mi-pemit-checking",
- "BPF PreEmit Checking", false, false)
- char BPFMIPreEmitChecking::ID = 0;
- FunctionPass* llvm::createBPFMIPreEmitCheckingPass()
- {
- return new BPFMIPreEmitChecking();
- }
|