xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIChecking.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-------------- BPFMIChecking.cpp - MI Checking Legality -------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This pass performs checking to signal errors for certain illegal usages at
100b57cec5SDimitry Andric // MachineInstruction layer. Specially, the result of XADD{32,64} insn should
110b57cec5SDimitry Andric // not be used. The pass is done at the PreEmit pass right before the
120b57cec5SDimitry Andric // machine code is emitted at which point the register liveness information
130b57cec5SDimitry Andric // is still available.
140b57cec5SDimitry Andric //
150b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "BPF.h"
180b57cec5SDimitry Andric #include "BPFInstrInfo.h"
190b57cec5SDimitry Andric #include "BPFTargetMachine.h"
2081ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
23*0fca6ea1SDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
248bcb0991SDimitry Andric #include "llvm/Support/Debug.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric using namespace llvm;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #define DEBUG_TYPE "bpf-mi-checking"
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric namespace {
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric struct BPFMIPreEmitChecking : public MachineFunctionPass {
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric   static char ID;
350b57cec5SDimitry Andric   MachineFunction *MF;
360b57cec5SDimitry Andric   const TargetRegisterInfo *TRI;
370b57cec5SDimitry Andric 
BPFMIPreEmitChecking__anon6cf72cb70111::BPFMIPreEmitChecking380b57cec5SDimitry Andric   BPFMIPreEmitChecking() : MachineFunctionPass(ID) {
390b57cec5SDimitry Andric     initializeBPFMIPreEmitCheckingPass(*PassRegistry::getPassRegistry());
400b57cec5SDimitry Andric   }
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric private:
430b57cec5SDimitry Andric   // Initialize class variables.
440b57cec5SDimitry Andric   void initialize(MachineFunction &MFParm);
450b57cec5SDimitry Andric 
4604eeddc0SDimitry Andric   bool processAtomicInsts();
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric public:
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   // Main entry point for this pass.
runOnMachineFunction__anon6cf72cb70111::BPFMIPreEmitChecking510b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override {
520b57cec5SDimitry Andric     if (!skipFunction(MF.getFunction())) {
530b57cec5SDimitry Andric       initialize(MF);
54e8d8bef9SDimitry Andric       return processAtomicInsts();
550b57cec5SDimitry Andric     }
560b57cec5SDimitry Andric     return false;
570b57cec5SDimitry Andric   }
580b57cec5SDimitry Andric };
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric // Initialize class variables.
initialize(MachineFunction & MFParm)610b57cec5SDimitry Andric void BPFMIPreEmitChecking::initialize(MachineFunction &MFParm) {
620b57cec5SDimitry Andric   MF = &MFParm;
630b57cec5SDimitry Andric   TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo();
640b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "*** BPF PreEmit checking pass ***\n\n");
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric // Make sure all Defs of XADD are dead, meaning any result of XADD insn is not
680b57cec5SDimitry Andric // used.
690b57cec5SDimitry Andric //
700b57cec5SDimitry Andric // NOTE: BPF backend hasn't enabled sub-register liveness track, so when the
710b57cec5SDimitry Andric // source and destination operands of XADD are GPR32, there is no sub-register
720b57cec5SDimitry Andric // dead info. If we rely on the generic MachineInstr::allDefsAreDead, then we
730b57cec5SDimitry Andric // will raise false alarm on GPR32 Def.
740b57cec5SDimitry Andric //
750b57cec5SDimitry Andric // To support GPR32 Def, ideally we could just enable sub-registr liveness track
760b57cec5SDimitry Andric // on BPF backend, then allDefsAreDead could work on GPR32 Def. This requires
770b57cec5SDimitry Andric // implementing TargetSubtargetInfo::enableSubRegLiveness on BPF.
780b57cec5SDimitry Andric //
790b57cec5SDimitry Andric // However, sub-register liveness tracking module inside LLVM is actually
800b57cec5SDimitry Andric // designed for the situation where one register could be split into more than
810b57cec5SDimitry Andric // one sub-registers for which case each sub-register could have their own
820b57cec5SDimitry Andric // liveness and kill one of them doesn't kill others. So, tracking liveness for
830b57cec5SDimitry Andric // each make sense.
840b57cec5SDimitry Andric //
850b57cec5SDimitry Andric // For BPF, each 64-bit register could only have one 32-bit sub-register. This
860b57cec5SDimitry Andric // is exactly the case which LLVM think brings no benefits for doing
870b57cec5SDimitry Andric // sub-register tracking, because the live range of sub-register must always
880b57cec5SDimitry Andric // equal to its parent register, therefore liveness tracking is disabled even
890b57cec5SDimitry Andric // the back-end has implemented enableSubRegLiveness. The detailed information
900b57cec5SDimitry Andric // is at r232695:
910b57cec5SDimitry Andric //
920b57cec5SDimitry Andric //   Author: Matthias Braun <matze@braunis.de>
930b57cec5SDimitry Andric //   Date:   Thu Mar 19 00:21:58 2015 +0000
940b57cec5SDimitry Andric //   Do not track subregister liveness when it brings no benefits
950b57cec5SDimitry Andric //
960b57cec5SDimitry Andric // Hence, for BPF, we enhance MachineInstr::allDefsAreDead. Given the solo
970b57cec5SDimitry Andric // sub-register always has the same liveness as its parent register, LLVM is
980b57cec5SDimitry Andric // already attaching a implicit 64-bit register Def whenever the there is
990b57cec5SDimitry Andric // a sub-register Def. The liveness of the implicit 64-bit Def is available.
1000b57cec5SDimitry Andric // For example, for "lock *(u32 *)(r0 + 4) += w9", the MachineOperand info could
1010b57cec5SDimitry Andric // be:
1020b57cec5SDimitry Andric //
1030b57cec5SDimitry Andric //   $w9 = XADDW32 killed $r0, 4, $w9(tied-def 0),
1040b57cec5SDimitry Andric //                        implicit killed $r9, implicit-def dead $r9
1050b57cec5SDimitry Andric //
1060b57cec5SDimitry Andric // Even though w9 is not marked as Dead, the parent register r9 is marked as
1070b57cec5SDimitry Andric // Dead correctly, and it is safe to use such information or our purpose.
hasLiveDefs(const MachineInstr & MI,const TargetRegisterInfo * TRI)1080b57cec5SDimitry Andric static bool hasLiveDefs(const MachineInstr &MI, const TargetRegisterInfo *TRI) {
1090b57cec5SDimitry Andric   const MCRegisterClass *GPR64RegClass =
1100b57cec5SDimitry Andric     &BPFMCRegisterClasses[BPF::GPRRegClassID];
1110b57cec5SDimitry Andric   std::vector<unsigned> GPR32LiveDefs;
1120b57cec5SDimitry Andric   std::vector<unsigned> GPR64DeadDefs;
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   for (const MachineOperand &MO : MI.operands()) {
1150b57cec5SDimitry Andric     bool RegIsGPR64;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric     if (!MO.isReg() || MO.isUse())
1180b57cec5SDimitry Andric       continue;
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric     RegIsGPR64 = GPR64RegClass->contains(MO.getReg());
1210b57cec5SDimitry Andric     if (!MO.isDead()) {
1220b57cec5SDimitry Andric       // It is a GPR64 live Def, we are sure it is live. */
1230b57cec5SDimitry Andric       if (RegIsGPR64)
1240b57cec5SDimitry Andric         return true;
1250b57cec5SDimitry Andric       // It is a GPR32 live Def, we are unsure whether it is really dead due to
1260b57cec5SDimitry Andric       // no sub-register liveness tracking. Push it to vector for deferred
1270b57cec5SDimitry Andric       // check.
1280b57cec5SDimitry Andric       GPR32LiveDefs.push_back(MO.getReg());
1290b57cec5SDimitry Andric       continue;
1300b57cec5SDimitry Andric     }
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric     // Record any GPR64 dead Def as some unmarked GPR32 could be alias of its
1330b57cec5SDimitry Andric     // low 32-bit.
1340b57cec5SDimitry Andric     if (RegIsGPR64)
1350b57cec5SDimitry Andric       GPR64DeadDefs.push_back(MO.getReg());
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   // No GPR32 live Def, safe to return false.
1390b57cec5SDimitry Andric   if (GPR32LiveDefs.empty())
1400b57cec5SDimitry Andric     return false;
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   // No GPR64 dead Def, so all those GPR32 live Def can't have alias, therefore
1430b57cec5SDimitry Andric   // must be truely live, safe to return true.
1440b57cec5SDimitry Andric   if (GPR64DeadDefs.empty())
1450b57cec5SDimitry Andric     return true;
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   // Otherwise, return true if any aliased SuperReg of GPR32 is not dead.
1480b57cec5SDimitry Andric   for (auto I : GPR32LiveDefs)
14906c3fb27SDimitry Andric     for (MCPhysReg SR : TRI->superregs(I))
15006c3fb27SDimitry Andric       if (!llvm::is_contained(GPR64DeadDefs, SR))
1510b57cec5SDimitry Andric         return true;
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   return false;
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric 
processAtomicInsts()15604eeddc0SDimitry Andric bool BPFMIPreEmitChecking::processAtomicInsts() {
1570b57cec5SDimitry Andric   for (MachineBasicBlock &MBB : *MF) {
1580b57cec5SDimitry Andric     for (MachineInstr &MI : MBB) {
1590b57cec5SDimitry Andric       if (MI.getOpcode() != BPF::XADDW &&
1600b57cec5SDimitry Andric           MI.getOpcode() != BPF::XADDD &&
1610b57cec5SDimitry Andric           MI.getOpcode() != BPF::XADDW32)
1620b57cec5SDimitry Andric         continue;
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric       LLVM_DEBUG(MI.dump());
1650b57cec5SDimitry Andric       if (hasLiveDefs(MI, TRI)) {
1660b57cec5SDimitry Andric         DebugLoc Empty;
1670b57cec5SDimitry Andric         const DebugLoc &DL = MI.getDebugLoc();
168*0fca6ea1SDimitry Andric         const Function &F = MF->getFunction();
169*0fca6ea1SDimitry Andric         F.getContext().diagnose(DiagnosticInfoUnsupported{
170*0fca6ea1SDimitry Andric             F, "Invalid usage of the XADD return value", DL});
1710b57cec5SDimitry Andric       }
1720b57cec5SDimitry Andric     }
1730b57cec5SDimitry Andric   }
1740b57cec5SDimitry Andric 
175e8d8bef9SDimitry Andric   // Check return values of atomic_fetch_and_{add,and,or,xor}.
176e8d8bef9SDimitry Andric   // If the return is not used, the atomic_fetch_and_<op> instruction
177e8d8bef9SDimitry Andric   // is replaced with atomic_<op> instruction.
178e8d8bef9SDimitry Andric   MachineInstr *ToErase = nullptr;
179e8d8bef9SDimitry Andric   bool Changed = false;
180e8d8bef9SDimitry Andric   const BPFInstrInfo *TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
181e8d8bef9SDimitry Andric   for (MachineBasicBlock &MBB : *MF) {
182e8d8bef9SDimitry Andric     for (MachineInstr &MI : MBB) {
183e8d8bef9SDimitry Andric       if (ToErase) {
184e8d8bef9SDimitry Andric         ToErase->eraseFromParent();
185e8d8bef9SDimitry Andric         ToErase = nullptr;
186e8d8bef9SDimitry Andric       }
187e8d8bef9SDimitry Andric 
188e8d8bef9SDimitry Andric       if (MI.getOpcode() != BPF::XFADDW32 && MI.getOpcode() != BPF::XFADDD &&
189e8d8bef9SDimitry Andric           MI.getOpcode() != BPF::XFANDW32 && MI.getOpcode() != BPF::XFANDD &&
190e8d8bef9SDimitry Andric           MI.getOpcode() != BPF::XFXORW32 && MI.getOpcode() != BPF::XFXORD &&
191e8d8bef9SDimitry Andric           MI.getOpcode() != BPF::XFORW32 && MI.getOpcode() != BPF::XFORD)
192e8d8bef9SDimitry Andric         continue;
193e8d8bef9SDimitry Andric 
194e8d8bef9SDimitry Andric       if (hasLiveDefs(MI, TRI))
195e8d8bef9SDimitry Andric         continue;
196e8d8bef9SDimitry Andric 
197e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "Transforming "; MI.dump());
198e8d8bef9SDimitry Andric       unsigned newOpcode;
199e8d8bef9SDimitry Andric       switch (MI.getOpcode()) {
200e8d8bef9SDimitry Andric       case BPF::XFADDW32:
201e8d8bef9SDimitry Andric         newOpcode = BPF::XADDW32;
202e8d8bef9SDimitry Andric         break;
203e8d8bef9SDimitry Andric       case BPF::XFADDD:
204e8d8bef9SDimitry Andric         newOpcode = BPF::XADDD;
205e8d8bef9SDimitry Andric         break;
206e8d8bef9SDimitry Andric       case BPF::XFANDW32:
207e8d8bef9SDimitry Andric         newOpcode = BPF::XANDW32;
208e8d8bef9SDimitry Andric         break;
209e8d8bef9SDimitry Andric       case BPF::XFANDD:
210e8d8bef9SDimitry Andric         newOpcode = BPF::XANDD;
211e8d8bef9SDimitry Andric         break;
212e8d8bef9SDimitry Andric       case BPF::XFXORW32:
213e8d8bef9SDimitry Andric         newOpcode = BPF::XXORW32;
214e8d8bef9SDimitry Andric         break;
215e8d8bef9SDimitry Andric       case BPF::XFXORD:
216e8d8bef9SDimitry Andric         newOpcode = BPF::XXORD;
217e8d8bef9SDimitry Andric         break;
218e8d8bef9SDimitry Andric       case BPF::XFORW32:
219e8d8bef9SDimitry Andric         newOpcode = BPF::XORW32;
220e8d8bef9SDimitry Andric         break;
221e8d8bef9SDimitry Andric       case BPF::XFORD:
222e8d8bef9SDimitry Andric         newOpcode = BPF::XORD;
223e8d8bef9SDimitry Andric         break;
224e8d8bef9SDimitry Andric       default:
225e8d8bef9SDimitry Andric         llvm_unreachable("Incorrect Atomic Instruction Opcode");
226e8d8bef9SDimitry Andric       }
227e8d8bef9SDimitry Andric 
228e8d8bef9SDimitry Andric       BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(newOpcode))
229e8d8bef9SDimitry Andric           .add(MI.getOperand(0))
230e8d8bef9SDimitry Andric           .add(MI.getOperand(1))
231e8d8bef9SDimitry Andric           .add(MI.getOperand(2))
232e8d8bef9SDimitry Andric           .add(MI.getOperand(3));
233e8d8bef9SDimitry Andric 
234e8d8bef9SDimitry Andric       ToErase = &MI;
235e8d8bef9SDimitry Andric       Changed = true;
236e8d8bef9SDimitry Andric     }
237e8d8bef9SDimitry Andric   }
238e8d8bef9SDimitry Andric 
239e8d8bef9SDimitry Andric   return Changed;
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric } // end default namespace
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric INITIALIZE_PASS(BPFMIPreEmitChecking, "bpf-mi-pemit-checking",
2450b57cec5SDimitry Andric                 "BPF PreEmit Checking", false, false)
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric char BPFMIPreEmitChecking::ID = 0;
createBPFMIPreEmitCheckingPass()2480b57cec5SDimitry Andric FunctionPass* llvm::createBPFMIPreEmitCheckingPass()
2490b57cec5SDimitry Andric {
2500b57cec5SDimitry Andric   return new BPFMIPreEmitChecking();
2510b57cec5SDimitry Andric }
252