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 "BPFRegisterInfo.h"
19#include "BPFTargetMachine.h"
20#include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
21#include "llvm/CodeGen/MachineFunctionPass.h"
22#include "llvm/IR/Analysis.h"
23#include "llvm/IR/DiagnosticInfo.h"
24#include "llvm/Support/Debug.h"
25
26using namespace llvm;
27
28#define DEBUG_TYPE "bpf-mi-checking"
29
30namespace {
31
32struct BPFMIPreEmitCheckingLegacy : public MachineFunctionPass {
33
34 static char ID;
35
36 BPFMIPreEmitCheckingLegacy() : MachineFunctionPass(ID) {}
37
38public:
39 // Main entry point for this pass.
40 bool runOnMachineFunction(MachineFunction &MF) override;
41};
42
43// Make sure all Defs of XADD are dead, meaning any result of XADD insn is not
44// used.
45//
46// NOTE: BPF backend hasn't enabled sub-register liveness track, so when the
47// source and destination operands of XADD are GPR32, there is no sub-register
48// dead info. If we rely on the generic MachineInstr::allDefsAreDead, then we
49// will raise false alarm on GPR32 Def.
50//
51// To support GPR32 Def, ideally we could just enable sub-registr liveness track
52// on BPF backend, then allDefsAreDead could work on GPR32 Def. This requires
53// implementing TargetSubtargetInfo::enableSubRegLiveness on BPF.
54//
55// However, sub-register liveness tracking module inside LLVM is actually
56// designed for the situation where one register could be split into more than
57// one sub-registers for which case each sub-register could have their own
58// liveness and kill one of them doesn't kill others. So, tracking liveness for
59// each make sense.
60//
61// For BPF, each 64-bit register could only have one 32-bit sub-register. This
62// is exactly the case which LLVM think brings no benefits for doing
63// sub-register tracking, because the live range of sub-register must always
64// equal to its parent register, therefore liveness tracking is disabled even
65// the back-end has implemented enableSubRegLiveness. The detailed information
66// is at r232695:
67//
68// Author: Matthias Braun <matze@braunis.de>
69// Date: Thu Mar 19 00:21:58 2015 +0000
70// Do not track subregister liveness when it brings no benefits
71//
72// Hence, for BPF, we enhance MachineInstr::allDefsAreDead. Given the solo
73// sub-register always has the same liveness as its parent register, LLVM is
74// already attaching a implicit 64-bit register Def whenever the there is
75// a sub-register Def. The liveness of the implicit 64-bit Def is available.
76// For example, for "lock *(u32 *)(r0 + 4) += w9", the MachineOperand info could
77// be:
78//
79// $w9 = XADDW32 killed $r0, 4, $w9(tied-def 0),
80// implicit killed $r9, implicit-def dead $r9
81//
82// Even though w9 is not marked as Dead, the parent register r9 is marked as
83// Dead correctly, and it is safe to use such information or our purpose.
84static bool hasLiveDefs(const MachineInstr &MI, const TargetRegisterInfo *TRI) {
85 const MCRegisterClass *GPR64RegClass =
86 &getBPFMCRegisterClass(RC: BPF::GPRRegClassID);
87 std::vector<unsigned> GPR32LiveDefs;
88 std::vector<unsigned> GPR64DeadDefs;
89
90 for (const MachineOperand &MO : MI.operands()) {
91 bool RegIsGPR64;
92
93 if (!MO.isReg() || MO.isUse())
94 continue;
95
96 RegIsGPR64 = GPR64RegClass->contains(Reg: MO.getReg());
97 if (!MO.isDead()) {
98 // It is a GPR64 live Def, we are sure it is live.
99 if (RegIsGPR64)
100 return true;
101 // It is a GPR32 live Def, we are unsure whether it is really dead due to
102 // no sub-register liveness tracking. Push it to vector for deferred
103 // check.
104 GPR32LiveDefs.push_back(x: MO.getReg());
105 continue;
106 }
107
108 // Record any GPR64 dead Def as some unmarked GPR32 could be alias of its
109 // low 32-bit.
110 if (RegIsGPR64)
111 GPR64DeadDefs.push_back(x: MO.getReg());
112 }
113
114 // No GPR32 live Def, safe to return false.
115 if (GPR32LiveDefs.empty())
116 return false;
117
118 // No GPR64 dead Def, so all those GPR32 live Def can't have alias, therefore
119 // must be truely live, safe to return true.
120 if (GPR64DeadDefs.empty())
121 return true;
122
123 // Otherwise, return true if any aliased SuperReg of GPR32 is not dead.
124 for (auto I : GPR32LiveDefs)
125 for (MCPhysReg SR : TRI->superregs(Reg: I))
126 if (!llvm::is_contained(Range&: GPR64DeadDefs, Element: SR))
127 return true;
128
129 return false;
130}
131
132} // namespace
133
134static void processAtomicInsts(MachineFunction &MF) {
135 LLVM_DEBUG(dbgs() << "*** BPF PreEmit checking pass ***\n\n");
136
137 if (MF.getSubtarget<BPFSubtarget>().getHasJmp32())
138 return;
139
140 const BPFRegisterInfo *TRI =
141 MF.getSubtarget<BPFSubtarget>().getRegisterInfo();
142 // Only check for cpu version 1 and 2.
143 for (MachineBasicBlock &MBB : MF) {
144 for (MachineInstr &MI : MBB) {
145 if (MI.getOpcode() != BPF::XADDW && MI.getOpcode() != BPF::XADDD)
146 continue;
147
148 LLVM_DEBUG(MI.dump());
149 if (hasLiveDefs(MI, TRI)) {
150 const DebugLoc &DL = MI.getDebugLoc();
151 const Function &F = MF.getFunction();
152 F.getContext().diagnose(DI: DiagnosticInfoUnsupported{
153 F, "Invalid usage of the XADD return value", DL});
154 }
155 }
156 }
157}
158
159bool BPFMIPreEmitCheckingLegacy::runOnMachineFunction(MachineFunction &MF) {
160 if (skipFunction(F: MF.getFunction()))
161 return false;
162 processAtomicInsts(MF);
163 return false;
164}
165
166PreservedAnalyses
167BPFMIPreEmitCheckingPass::run(MachineFunction &MF,
168 MachineFunctionAnalysisManager &MFAM) {
169 processAtomicInsts(MF);
170 return PreservedAnalyses::all();
171}
172
173INITIALIZE_PASS(BPFMIPreEmitCheckingLegacy, "bpf-mi-checking",
174 "BPF PreEmit Checking", false, false)
175
176char BPFMIPreEmitCheckingLegacy::ID = 0;
177FunctionPass *llvm::createBPFMIPreEmitCheckingLegacyPass() {
178 return new BPFMIPreEmitCheckingLegacy();
179}
180