LLVM 20.0.0git
BPFMIChecking.cpp
Go to the documentation of this file.
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 "BPFTargetMachine.h"
21#include "llvm/Support/Debug.h"
22
23using namespace llvm;
24
25#define DEBUG_TYPE "bpf-mi-checking"
26
27namespace {
28
29struct BPFMIPreEmitChecking : public MachineFunctionPass {
30
31 static char ID;
34
35 BPFMIPreEmitChecking() : MachineFunctionPass(ID) {
37 }
38
39private:
40 // Initialize class variables.
41 void initialize(MachineFunction &MFParm);
42
43 void processAtomicInsts();
44
45public:
46 // Main entry point for this pass.
47 bool runOnMachineFunction(MachineFunction &MF) override {
48 if (!skipFunction(MF.getFunction())) {
49 initialize(MF);
50 processAtomicInsts();
51 }
52 return false;
53 }
54};
55
56// Initialize class variables.
57void BPFMIPreEmitChecking::initialize(MachineFunction &MFParm) {
58 MF = &MFParm;
59 TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo();
60 LLVM_DEBUG(dbgs() << "*** BPF PreEmit checking pass ***\n\n");
61}
62
63// Make sure all Defs of XADD are dead, meaning any result of XADD insn is not
64// used.
65//
66// NOTE: BPF backend hasn't enabled sub-register liveness track, so when the
67// source and destination operands of XADD are GPR32, there is no sub-register
68// dead info. If we rely on the generic MachineInstr::allDefsAreDead, then we
69// will raise false alarm on GPR32 Def.
70//
71// To support GPR32 Def, ideally we could just enable sub-registr liveness track
72// on BPF backend, then allDefsAreDead could work on GPR32 Def. This requires
73// implementing TargetSubtargetInfo::enableSubRegLiveness on BPF.
74//
75// However, sub-register liveness tracking module inside LLVM is actually
76// designed for the situation where one register could be split into more than
77// one sub-registers for which case each sub-register could have their own
78// liveness and kill one of them doesn't kill others. So, tracking liveness for
79// each make sense.
80//
81// For BPF, each 64-bit register could only have one 32-bit sub-register. This
82// is exactly the case which LLVM think brings no benefits for doing
83// sub-register tracking, because the live range of sub-register must always
84// equal to its parent register, therefore liveness tracking is disabled even
85// the back-end has implemented enableSubRegLiveness. The detailed information
86// is at r232695:
87//
88// Author: Matthias Braun <matze@braunis.de>
89// Date: Thu Mar 19 00:21:58 2015 +0000
90// Do not track subregister liveness when it brings no benefits
91//
92// Hence, for BPF, we enhance MachineInstr::allDefsAreDead. Given the solo
93// sub-register always has the same liveness as its parent register, LLVM is
94// already attaching a implicit 64-bit register Def whenever the there is
95// a sub-register Def. The liveness of the implicit 64-bit Def is available.
96// For example, for "lock *(u32 *)(r0 + 4) += w9", the MachineOperand info could
97// be:
98//
99// $w9 = XADDW32 killed $r0, 4, $w9(tied-def 0),
100// implicit killed $r9, implicit-def dead $r9
101//
102// Even though w9 is not marked as Dead, the parent register r9 is marked as
103// Dead correctly, and it is safe to use such information or our purpose.
104static bool hasLiveDefs(const MachineInstr &MI, const TargetRegisterInfo *TRI) {
105 const MCRegisterClass *GPR64RegClass =
106 &BPFMCRegisterClasses[BPF::GPRRegClassID];
107 std::vector<unsigned> GPR32LiveDefs;
108 std::vector<unsigned> GPR64DeadDefs;
109
110 for (const MachineOperand &MO : MI.operands()) {
111 bool RegIsGPR64;
112
113 if (!MO.isReg() || MO.isUse())
114 continue;
115
116 RegIsGPR64 = GPR64RegClass->contains(MO.getReg());
117 if (!MO.isDead()) {
118 // It is a GPR64 live Def, we are sure it is live.
119 if (RegIsGPR64)
120 return true;
121 // It is a GPR32 live Def, we are unsure whether it is really dead due to
122 // no sub-register liveness tracking. Push it to vector for deferred
123 // check.
124 GPR32LiveDefs.push_back(MO.getReg());
125 continue;
126 }
127
128 // Record any GPR64 dead Def as some unmarked GPR32 could be alias of its
129 // low 32-bit.
130 if (RegIsGPR64)
131 GPR64DeadDefs.push_back(MO.getReg());
132 }
133
134 // No GPR32 live Def, safe to return false.
135 if (GPR32LiveDefs.empty())
136 return false;
137
138 // No GPR64 dead Def, so all those GPR32 live Def can't have alias, therefore
139 // must be truely live, safe to return true.
140 if (GPR64DeadDefs.empty())
141 return true;
142
143 // Otherwise, return true if any aliased SuperReg of GPR32 is not dead.
144 for (auto I : GPR32LiveDefs)
145 for (MCPhysReg SR : TRI->superregs(I))
146 if (!llvm::is_contained(GPR64DeadDefs, SR))
147 return true;
148
149 return false;
150}
151
152void BPFMIPreEmitChecking::processAtomicInsts() {
153 if (MF->getSubtarget<BPFSubtarget>().getHasJmp32())
154 return;
155
156 // Only check for cpu version 1 and 2.
157 for (MachineBasicBlock &MBB : *MF) {
158 for (MachineInstr &MI : MBB) {
159 if (MI.getOpcode() != BPF::XADDW && MI.getOpcode() != BPF::XADDD)
160 continue;
161
162 LLVM_DEBUG(MI.dump());
163 if (hasLiveDefs(MI, TRI)) {
164 DebugLoc Empty;
165 const DebugLoc &DL = MI.getDebugLoc();
166 const Function &F = MF->getFunction();
167 F.getContext().diagnose(DiagnosticInfoUnsupported{
168 F, "Invalid usage of the XADD return value", DL});
169 }
170 }
171 }
172}
173
174} // namespace
175
176INITIALIZE_PASS(BPFMIPreEmitChecking, "bpf-mi-pemit-checking",
177 "BPF PreEmit Checking", false, false)
178
179char BPFMIPreEmitChecking::ID = 0;
181 return new BPFMIPreEmitChecking();
182}
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define LLVM_DEBUG(...)
Definition: Debug.h:106
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
unsigned const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, ArrayRef< StringLiteral > StandardNames)
Initialize the set of available library functions based on the specified target triple.
bool getHasJmp32() const
Definition: BPFSubtarget.h:86
A debug info location.
Definition: DebugLoc.h:33
Diagnostic information for unsupported feature in backend.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
bool skipFunction(const Function &F) const
Optional passes call this function to check whether the pass should be skipped.
Definition: Pass.cpp:178
MCRegisterClass - Base class of TargetRegisterClass.
bool contains(MCRegister Reg) const
contains - Return true if the specified register is included in this register class.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
Function & getFunction()
Return the LLVM function that this machine code represents.
Representation of each machine instruction.
Definition: MachineInstr.h:69
MachineOperand class - Representation of each machine instruction operand.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
void dump() const
Definition: Pass.cpp:136
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
FunctionPass * createBPFMIPreEmitCheckingPass()
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
void initializeBPFMIPreEmitCheckingPass(PassRegistry &)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition: STLExtras.h:1903