xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIChecking.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===-------------- BPFMIChecking.cpp - MI Checking Legality -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This pass performs checking to signal errors for certain illegal usages at
10 // MachineInstruction layer. Specially, the result of XADD{32,64} insn should
11 // not be used. The pass is done at the PreEmit pass right before the
12 // machine code is emitted at which point the register liveness information
13 // is still available.
14 //
15 //===----------------------------------------------------------------------===//
16 
17 #include "BPF.h"
18 #include "BPFInstrInfo.h"
19 #include "BPFTargetMachine.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstrBuilder.h"
22 #include "llvm/CodeGen/MachineRegisterInfo.h"
23 #include "llvm/IR/DiagnosticInfo.h"
24 #include "llvm/Support/Debug.h"
25 
26 using namespace llvm;
27 
28 #define DEBUG_TYPE "bpf-mi-checking"
29 
30 namespace {
31 
32 struct BPFMIPreEmitChecking : public MachineFunctionPass {
33 
34   static char ID;
35   MachineFunction *MF;
36   const TargetRegisterInfo *TRI;
37 
BPFMIPreEmitChecking__anon6cf72cb70111::BPFMIPreEmitChecking38   BPFMIPreEmitChecking() : MachineFunctionPass(ID) {
39     initializeBPFMIPreEmitCheckingPass(*PassRegistry::getPassRegistry());
40   }
41 
42 private:
43   // Initialize class variables.
44   void initialize(MachineFunction &MFParm);
45 
46   bool processAtomicInsts();
47 
48 public:
49 
50   // Main entry point for this pass.
runOnMachineFunction__anon6cf72cb70111::BPFMIPreEmitChecking51   bool runOnMachineFunction(MachineFunction &MF) override {
52     if (!skipFunction(MF.getFunction())) {
53       initialize(MF);
54       return processAtomicInsts();
55     }
56     return false;
57   }
58 };
59 
60 // Initialize class variables.
initialize(MachineFunction & MFParm)61 void BPFMIPreEmitChecking::initialize(MachineFunction &MFParm) {
62   MF = &MFParm;
63   TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo();
64   LLVM_DEBUG(dbgs() << "*** BPF PreEmit checking pass ***\n\n");
65 }
66 
67 // Make sure all Defs of XADD are dead, meaning any result of XADD insn is not
68 // used.
69 //
70 // NOTE: BPF backend hasn't enabled sub-register liveness track, so when the
71 // source and destination operands of XADD are GPR32, there is no sub-register
72 // dead info. If we rely on the generic MachineInstr::allDefsAreDead, then we
73 // will raise false alarm on GPR32 Def.
74 //
75 // To support GPR32 Def, ideally we could just enable sub-registr liveness track
76 // on BPF backend, then allDefsAreDead could work on GPR32 Def. This requires
77 // implementing TargetSubtargetInfo::enableSubRegLiveness on BPF.
78 //
79 // However, sub-register liveness tracking module inside LLVM is actually
80 // designed for the situation where one register could be split into more than
81 // one sub-registers for which case each sub-register could have their own
82 // liveness and kill one of them doesn't kill others. So, tracking liveness for
83 // each make sense.
84 //
85 // For BPF, each 64-bit register could only have one 32-bit sub-register. This
86 // is exactly the case which LLVM think brings no benefits for doing
87 // sub-register tracking, because the live range of sub-register must always
88 // equal to its parent register, therefore liveness tracking is disabled even
89 // the back-end has implemented enableSubRegLiveness. The detailed information
90 // is at r232695:
91 //
92 //   Author: Matthias Braun <matze@braunis.de>
93 //   Date:   Thu Mar 19 00:21:58 2015 +0000
94 //   Do not track subregister liveness when it brings no benefits
95 //
96 // Hence, for BPF, we enhance MachineInstr::allDefsAreDead. Given the solo
97 // sub-register always has the same liveness as its parent register, LLVM is
98 // already attaching a implicit 64-bit register Def whenever the there is
99 // a sub-register Def. The liveness of the implicit 64-bit Def is available.
100 // For example, for "lock *(u32 *)(r0 + 4) += w9", the MachineOperand info could
101 // be:
102 //
103 //   $w9 = XADDW32 killed $r0, 4, $w9(tied-def 0),
104 //                        implicit killed $r9, implicit-def dead $r9
105 //
106 // Even though w9 is not marked as Dead, the parent register r9 is marked as
107 // Dead correctly, and it is safe to use such information or our purpose.
hasLiveDefs(const MachineInstr & MI,const TargetRegisterInfo * TRI)108 static bool hasLiveDefs(const MachineInstr &MI, const TargetRegisterInfo *TRI) {
109   const MCRegisterClass *GPR64RegClass =
110     &BPFMCRegisterClasses[BPF::GPRRegClassID];
111   std::vector<unsigned> GPR32LiveDefs;
112   std::vector<unsigned> GPR64DeadDefs;
113 
114   for (const MachineOperand &MO : MI.operands()) {
115     bool RegIsGPR64;
116 
117     if (!MO.isReg() || MO.isUse())
118       continue;
119 
120     RegIsGPR64 = GPR64RegClass->contains(MO.getReg());
121     if (!MO.isDead()) {
122       // It is a GPR64 live Def, we are sure it is live. */
123       if (RegIsGPR64)
124         return true;
125       // It is a GPR32 live Def, we are unsure whether it is really dead due to
126       // no sub-register liveness tracking. Push it to vector for deferred
127       // check.
128       GPR32LiveDefs.push_back(MO.getReg());
129       continue;
130     }
131 
132     // Record any GPR64 dead Def as some unmarked GPR32 could be alias of its
133     // low 32-bit.
134     if (RegIsGPR64)
135       GPR64DeadDefs.push_back(MO.getReg());
136   }
137 
138   // No GPR32 live Def, safe to return false.
139   if (GPR32LiveDefs.empty())
140     return false;
141 
142   // No GPR64 dead Def, so all those GPR32 live Def can't have alias, therefore
143   // must be truely live, safe to return true.
144   if (GPR64DeadDefs.empty())
145     return true;
146 
147   // Otherwise, return true if any aliased SuperReg of GPR32 is not dead.
148   for (auto I : GPR32LiveDefs)
149     for (MCPhysReg SR : TRI->superregs(I))
150       if (!llvm::is_contained(GPR64DeadDefs, SR))
151         return true;
152 
153   return false;
154 }
155 
processAtomicInsts()156 bool BPFMIPreEmitChecking::processAtomicInsts() {
157   for (MachineBasicBlock &MBB : *MF) {
158     for (MachineInstr &MI : MBB) {
159       if (MI.getOpcode() != BPF::XADDW &&
160           MI.getOpcode() != BPF::XADDD &&
161           MI.getOpcode() != BPF::XADDW32)
162         continue;
163 
164       LLVM_DEBUG(MI.dump());
165       if (hasLiveDefs(MI, TRI)) {
166         DebugLoc Empty;
167         const DebugLoc &DL = MI.getDebugLoc();
168         const Function &F = MF->getFunction();
169         F.getContext().diagnose(DiagnosticInfoUnsupported{
170             F, "Invalid usage of the XADD return value", DL});
171       }
172     }
173   }
174 
175   // Check return values of atomic_fetch_and_{add,and,or,xor}.
176   // If the return is not used, the atomic_fetch_and_<op> instruction
177   // is replaced with atomic_<op> instruction.
178   MachineInstr *ToErase = nullptr;
179   bool Changed = false;
180   const BPFInstrInfo *TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
181   for (MachineBasicBlock &MBB : *MF) {
182     for (MachineInstr &MI : MBB) {
183       if (ToErase) {
184         ToErase->eraseFromParent();
185         ToErase = nullptr;
186       }
187 
188       if (MI.getOpcode() != BPF::XFADDW32 && MI.getOpcode() != BPF::XFADDD &&
189           MI.getOpcode() != BPF::XFANDW32 && MI.getOpcode() != BPF::XFANDD &&
190           MI.getOpcode() != BPF::XFXORW32 && MI.getOpcode() != BPF::XFXORD &&
191           MI.getOpcode() != BPF::XFORW32 && MI.getOpcode() != BPF::XFORD)
192         continue;
193 
194       if (hasLiveDefs(MI, TRI))
195         continue;
196 
197       LLVM_DEBUG(dbgs() << "Transforming "; MI.dump());
198       unsigned newOpcode;
199       switch (MI.getOpcode()) {
200       case BPF::XFADDW32:
201         newOpcode = BPF::XADDW32;
202         break;
203       case BPF::XFADDD:
204         newOpcode = BPF::XADDD;
205         break;
206       case BPF::XFANDW32:
207         newOpcode = BPF::XANDW32;
208         break;
209       case BPF::XFANDD:
210         newOpcode = BPF::XANDD;
211         break;
212       case BPF::XFXORW32:
213         newOpcode = BPF::XXORW32;
214         break;
215       case BPF::XFXORD:
216         newOpcode = BPF::XXORD;
217         break;
218       case BPF::XFORW32:
219         newOpcode = BPF::XORW32;
220         break;
221       case BPF::XFORD:
222         newOpcode = BPF::XORD;
223         break;
224       default:
225         llvm_unreachable("Incorrect Atomic Instruction Opcode");
226       }
227 
228       BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(newOpcode))
229           .add(MI.getOperand(0))
230           .add(MI.getOperand(1))
231           .add(MI.getOperand(2))
232           .add(MI.getOperand(3));
233 
234       ToErase = &MI;
235       Changed = true;
236     }
237   }
238 
239   return Changed;
240 }
241 
242 } // end default namespace
243 
244 INITIALIZE_PASS(BPFMIPreEmitChecking, "bpf-mi-pemit-checking",
245                 "BPF PreEmit Checking", false, false)
246 
247 char BPFMIPreEmitChecking::ID = 0;
createBPFMIPreEmitCheckingPass()248 FunctionPass* llvm::createBPFMIPreEmitCheckingPass()
249 {
250   return new BPFMIPreEmitChecking();
251 }
252