LLVM 24.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 the locked atomic insns
11// (XADD, XAND, XOR and XXOR, 32 and 64 bit) should not be used, since they do
12// not return the old value. The pass is done at the PreEmit pass right before
13// the machine code is emitted at which point the register liveness information
14// is still available.
15//
16//===----------------------------------------------------------------------===//
17
18#include "BPF.h"
19#include "BPFRegisterInfo.h"
20#include "BPFTargetMachine.h"
23#include "llvm/IR/Analysis.h"
25#include "llvm/Support/Debug.h"
26
27using namespace llvm;
28
29#define DEBUG_TYPE "bpf-mi-checking"
30
31namespace {
32
33struct BPFMIPreEmitCheckingLegacy : public MachineFunctionPass {
34
35 static char ID;
36
37 BPFMIPreEmitCheckingLegacy() : MachineFunctionPass(ID) {}
38
39public:
40 // Main entry point for this pass.
41 bool runOnMachineFunction(MachineFunction &MF) override;
42};
43
44// Make sure all Defs of XADD are dead, meaning any result of XADD insn is not
45// used.
46//
47// NOTE: BPF backend hasn't enabled sub-register liveness track, so when the
48// source and destination operands of XADD are GPR32, there is no sub-register
49// dead info. If we rely on the generic MachineInstr::allDefsAreDead, then we
50// will raise false alarm on GPR32 Def.
51//
52// To support GPR32 Def, ideally we could just enable sub-registr liveness track
53// on BPF backend, then allDefsAreDead could work on GPR32 Def. This requires
54// implementing TargetSubtargetInfo::enableSubRegLiveness on BPF.
55//
56// However, sub-register liveness tracking module inside LLVM is actually
57// designed for the situation where one register could be split into more than
58// one sub-registers for which case each sub-register could have their own
59// liveness and kill one of them doesn't kill others. So, tracking liveness for
60// each make sense.
61//
62// For BPF, each 64-bit register could only have one 32-bit sub-register. This
63// is exactly the case which LLVM think brings no benefits for doing
64// sub-register tracking, because the live range of sub-register must always
65// equal to its parent register, therefore liveness tracking is disabled even
66// the back-end has implemented enableSubRegLiveness. The detailed information
67// is at r232695:
68//
69// Author: Matthias Braun <matze@braunis.de>
70// Date: Thu Mar 19 00:21:58 2015 +0000
71// Do not track subregister liveness when it brings no benefits
72//
73// Hence, for BPF, we enhance MachineInstr::allDefsAreDead. Given the solo
74// sub-register always has the same liveness as its parent register, LLVM is
75// already attaching a implicit 64-bit register Def whenever the there is
76// a sub-register Def. The liveness of the implicit 64-bit Def is available.
77// For example, for "lock *(u32 *)(r0 + 4) += w9", the MachineOperand info could
78// be:
79//
80// $w9 = XADDW32 killed $r0, 4, $w9(tied-def 0),
81// implicit killed $r9, implicit-def dead $r9
82//
83// Even though w9 is not marked as Dead, the parent register r9 is marked as
84// Dead correctly, and it is safe to use such information or our purpose.
85static bool hasLiveDefs(const MachineInstr &MI, const TargetRegisterInfo *TRI) {
86 const MCRegisterClass *GPR64RegClass =
87 &getBPFMCRegisterClass(BPF::GPRRegClassID);
88 std::vector<unsigned> GPR32LiveDefs;
89 std::vector<unsigned> GPR64DeadDefs;
90
91 for (const MachineOperand &MO : MI.operands()) {
92 bool RegIsGPR64;
93
94 if (!MO.isReg() || MO.isUse())
95 continue;
96
97 RegIsGPR64 = GPR64RegClass->contains(MO.getReg());
98 if (!MO.isDead()) {
99 // It is a GPR64 live Def, we are sure it is live.
100 if (RegIsGPR64)
101 return true;
102 // It is a GPR32 live Def, we are unsure whether it is really dead due to
103 // no sub-register liveness tracking. Push it to vector for deferred
104 // check.
105 GPR32LiveDefs.push_back(MO.getReg());
106 continue;
107 }
108
109 // Record any GPR64 dead Def as some unmarked GPR32 could be alias of its
110 // low 32-bit.
111 if (RegIsGPR64)
112 GPR64DeadDefs.push_back(MO.getReg());
113 }
114
115 // No GPR32 live Def, safe to return false.
116 if (GPR32LiveDefs.empty())
117 return false;
118
119 // No GPR64 dead Def, so all those GPR32 live Def can't have alias, therefore
120 // must be truely live, safe to return true.
121 if (GPR64DeadDefs.empty())
122 return true;
123
124 // Otherwise, return true if any aliased SuperReg of GPR32 is not dead.
125 for (auto I : GPR32LiveDefs)
126 for (MCPhysReg SR : TRI->superregs(I))
127 if (!llvm::is_contained(GPR64DeadDefs, SR))
128 return true;
129
130 return false;
131}
132
133} // namespace
134
135// The locked atomic insns do not return the old value, so a live result is a
136// selection bug regardless of the cpu version: for v1/v2 there is no fetching
137// insn, and for v3+ instruction selection must pick the atomic_fetch_*() insn
138// whenever the result is used.
139static bool isLockedAtomicInsn(unsigned Opcode) {
140 switch (Opcode) {
141 default:
142 return false;
143 case BPF::XADDW:
144 case BPF::XADDD:
145 case BPF::XANDD:
146 case BPF::XORD:
147 case BPF::XXORD:
148 case BPF::XADDW32:
149 case BPF::XANDW32:
150 case BPF::XORW32:
151 case BPF::XXORW32:
152 return true;
153 }
154}
155
157 LLVM_DEBUG(dbgs() << "*** BPF PreEmit checking pass ***\n\n");
158
159 const BPFRegisterInfo *TRI =
160 MF.getSubtarget<BPFSubtarget>().getRegisterInfo();
161 for (MachineBasicBlock &MBB : MF) {
162 for (MachineInstr &MI : MBB) {
163 if (!isLockedAtomicInsn(MI.getOpcode()))
164 continue;
165
166 LLVM_DEBUG(MI.dump());
167 if (hasLiveDefs(MI, TRI)) {
168 const DebugLoc &DL = MI.getDebugLoc();
169 const Function &F = MF.getFunction();
170 F.getContext().diagnose(DiagnosticInfoUnsupported{
171 F, "Invalid usage of the XADD return value", DL});
172 }
173 }
174 }
175}
176
177bool BPFMIPreEmitCheckingLegacy::runOnMachineFunction(MachineFunction &MF) {
178 if (skipFunction(MF.getFunction()))
179 return false;
181 return false;
182}
183
184PreservedAnalyses
190
191INITIALIZE_PASS(BPFMIPreEmitCheckingLegacy, "bpf-mi-checking",
192 "BPF PreEmit Checking", false, false)
193
194char BPFMIPreEmitCheckingLegacy::ID = 0;
196 return new BPFMIPreEmitCheckingLegacy();
197}
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static void processAtomicInsts(MachineFunction &MF)
static bool isLockedAtomicInsn(unsigned Opcode)
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define LLVM_DEBUG(...)
Definition Debug.h:119
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
A debug info location.
Definition DebugLoc.h:126
Diagnostic information for unsupported feature in backend.
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
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...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
Representation of each machine instruction.
MachineOperand class - Representation of each machine instruction operand.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
Pass manager infrastructure for declaring and invalidating analyses.
This is an optimization pass for GlobalISel generic memory operations.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
FunctionPass * createBPFMIPreEmitCheckingLegacyPass()
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963