1//===-- BPFInstrInfo.cpp - BPF Instruction Information ----------*- C++ -*-===//
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 file contains the BPF implementation of the TargetInstrInfo class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "BPFInstrInfo.h"
14#include "BPF.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/CodeGen/MachineBasicBlock.h"
17#include "llvm/CodeGen/MachineInstrBuilder.h"
18#include "llvm/IR/DebugLoc.h"
19#include "llvm/Support/ErrorHandling.h"
20#include <cassert>
21#include <iterator>
22
23#define GET_INSTRINFO_CTOR_DTOR
24#include "BPFGenInstrInfo.inc"
25
26using namespace llvm;
27
28BPFInstrInfo::BPFInstrInfo()
29 : BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {}
30
31void BPFInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
32 MachineBasicBlock::iterator I,
33 const DebugLoc &DL, Register DestReg,
34 Register SrcReg, bool KillSrc,
35 bool RenamableDest, bool RenamableSrc) const {
36 if (BPF::GPRRegClass.contains(Reg1: DestReg, Reg2: SrcReg))
37 BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: BPF::MOV_rr), DestReg)
38 .addReg(RegNo: SrcReg, flags: getKillRegState(B: KillSrc));
39 else if (BPF::GPR32RegClass.contains(Reg1: DestReg, Reg2: SrcReg))
40 BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: BPF::MOV_rr_32), DestReg)
41 .addReg(RegNo: SrcReg, flags: getKillRegState(B: KillSrc));
42 else
43 llvm_unreachable("Impossible reg-to-reg copy");
44}
45
46void BPFInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const {
47 Register DstReg = MI->getOperand(i: 0).getReg();
48 Register SrcReg = MI->getOperand(i: 1).getReg();
49 uint64_t CopyLen = MI->getOperand(i: 2).getImm();
50 uint64_t Alignment = MI->getOperand(i: 3).getImm();
51 Register ScratchReg = MI->getOperand(i: 4).getReg();
52 MachineBasicBlock *BB = MI->getParent();
53 DebugLoc dl = MI->getDebugLoc();
54 unsigned LdOpc, StOpc;
55
56 switch (Alignment) {
57 case 1:
58 LdOpc = BPF::LDB;
59 StOpc = BPF::STB;
60 break;
61 case 2:
62 LdOpc = BPF::LDH;
63 StOpc = BPF::STH;
64 break;
65 case 4:
66 LdOpc = BPF::LDW;
67 StOpc = BPF::STW;
68 break;
69 case 8:
70 LdOpc = BPF::LDD;
71 StOpc = BPF::STD;
72 break;
73 default:
74 llvm_unreachable("unsupported memcpy alignment");
75 }
76
77 unsigned IterationNum = CopyLen >> Log2_64(Value: Alignment);
78 for(unsigned I = 0; I < IterationNum; ++I) {
79 BuildMI(BB&: *BB, I: MI, MIMD: dl, MCID: get(Opcode: LdOpc))
80 .addReg(RegNo: ScratchReg, flags: RegState::Define).addReg(RegNo: SrcReg)
81 .addImm(Val: I * Alignment);
82 BuildMI(BB&: *BB, I: MI, MIMD: dl, MCID: get(Opcode: StOpc))
83 .addReg(RegNo: ScratchReg, flags: RegState::Kill).addReg(RegNo: DstReg)
84 .addImm(Val: I * Alignment);
85 }
86
87 unsigned BytesLeft = CopyLen & (Alignment - 1);
88 unsigned Offset = IterationNum * Alignment;
89 bool Hanging4Byte = BytesLeft & 0x4;
90 bool Hanging2Byte = BytesLeft & 0x2;
91 bool Hanging1Byte = BytesLeft & 0x1;
92 if (Hanging4Byte) {
93 BuildMI(BB&: *BB, I: MI, MIMD: dl, MCID: get(Opcode: BPF::LDW))
94 .addReg(RegNo: ScratchReg, flags: RegState::Define).addReg(RegNo: SrcReg).addImm(Val: Offset);
95 BuildMI(BB&: *BB, I: MI, MIMD: dl, MCID: get(Opcode: BPF::STW))
96 .addReg(RegNo: ScratchReg, flags: RegState::Kill).addReg(RegNo: DstReg).addImm(Val: Offset);
97 Offset += 4;
98 }
99 if (Hanging2Byte) {
100 BuildMI(BB&: *BB, I: MI, MIMD: dl, MCID: get(Opcode: BPF::LDH))
101 .addReg(RegNo: ScratchReg, flags: RegState::Define).addReg(RegNo: SrcReg).addImm(Val: Offset);
102 BuildMI(BB&: *BB, I: MI, MIMD: dl, MCID: get(Opcode: BPF::STH))
103 .addReg(RegNo: ScratchReg, flags: RegState::Kill).addReg(RegNo: DstReg).addImm(Val: Offset);
104 Offset += 2;
105 }
106 if (Hanging1Byte) {
107 BuildMI(BB&: *BB, I: MI, MIMD: dl, MCID: get(Opcode: BPF::LDB))
108 .addReg(RegNo: ScratchReg, flags: RegState::Define).addReg(RegNo: SrcReg).addImm(Val: Offset);
109 BuildMI(BB&: *BB, I: MI, MIMD: dl, MCID: get(Opcode: BPF::STB))
110 .addReg(RegNo: ScratchReg, flags: RegState::Kill).addReg(RegNo: DstReg).addImm(Val: Offset);
111 }
112
113 BB->erase(I: MI);
114}
115
116bool BPFInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
117 if (MI.getOpcode() == BPF::MEMCPY) {
118 expandMEMCPY(MI);
119 return true;
120 }
121
122 return false;
123}
124
125void BPFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
126 MachineBasicBlock::iterator I,
127 Register SrcReg, bool IsKill, int FI,
128 const TargetRegisterClass *RC,
129 const TargetRegisterInfo *TRI,
130 Register VReg,
131 MachineInstr::MIFlag Flags) const {
132 DebugLoc DL;
133 if (I != MBB.end())
134 DL = I->getDebugLoc();
135
136 if (RC == &BPF::GPRRegClass)
137 BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: BPF::STD))
138 .addReg(RegNo: SrcReg, flags: getKillRegState(B: IsKill))
139 .addFrameIndex(Idx: FI)
140 .addImm(Val: 0);
141 else if (RC == &BPF::GPR32RegClass)
142 BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: BPF::STW32))
143 .addReg(RegNo: SrcReg, flags: getKillRegState(B: IsKill))
144 .addFrameIndex(Idx: FI)
145 .addImm(Val: 0);
146 else
147 llvm_unreachable("Can't store this register to stack slot");
148}
149
150void BPFInstrInfo::loadRegFromStackSlot(
151 MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register DestReg,
152 int FI, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI,
153 Register VReg, MachineInstr::MIFlag Flags) const {
154 DebugLoc DL;
155 if (I != MBB.end())
156 DL = I->getDebugLoc();
157
158 if (RC == &BPF::GPRRegClass)
159 BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: BPF::LDD), DestReg).addFrameIndex(Idx: FI).addImm(Val: 0);
160 else if (RC == &BPF::GPR32RegClass)
161 BuildMI(BB&: MBB, I, MIMD: DL, MCID: get(Opcode: BPF::LDW32), DestReg).addFrameIndex(Idx: FI).addImm(Val: 0);
162 else
163 llvm_unreachable("Can't load this register from stack slot");
164}
165
166bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
167 MachineBasicBlock *&TBB,
168 MachineBasicBlock *&FBB,
169 SmallVectorImpl<MachineOperand> &Cond,
170 bool AllowModify) const {
171 // Start from the bottom of the block and work up, examining the
172 // terminator instructions.
173 MachineBasicBlock::iterator I = MBB.end();
174 while (I != MBB.begin()) {
175 --I;
176 if (I->isDebugInstr())
177 continue;
178
179 // Working from the bottom, when we see a non-terminator
180 // instruction, we're done.
181 if (!isUnpredicatedTerminator(MI: *I))
182 break;
183
184 // A terminator that isn't a branch can't easily be handled
185 // by this analysis.
186 if (!I->isBranch())
187 return true;
188
189 // Handle unconditional branches.
190 if (I->getOpcode() == BPF::JMP) {
191 if (!AllowModify) {
192 TBB = I->getOperand(i: 0).getMBB();
193 continue;
194 }
195
196 // If the block has any instructions after a J, delete them.
197 MBB.erase(I: std::next(x: I), E: MBB.end());
198 Cond.clear();
199 FBB = nullptr;
200
201 // Delete the J if it's equivalent to a fall-through.
202 if (MBB.isLayoutSuccessor(MBB: I->getOperand(i: 0).getMBB())) {
203 TBB = nullptr;
204 I->eraseFromParent();
205 I = MBB.end();
206 continue;
207 }
208
209 // TBB is used to indicate the unconditinal destination.
210 TBB = I->getOperand(i: 0).getMBB();
211 continue;
212 }
213 // Cannot handle conditional branches
214 return true;
215 }
216
217 return false;
218}
219
220unsigned BPFInstrInfo::insertBranch(MachineBasicBlock &MBB,
221 MachineBasicBlock *TBB,
222 MachineBasicBlock *FBB,
223 ArrayRef<MachineOperand> Cond,
224 const DebugLoc &DL,
225 int *BytesAdded) const {
226 assert(!BytesAdded && "code size not handled");
227
228 // Shouldn't be a fall through.
229 assert(TBB && "insertBranch must not be told to insert a fallthrough");
230
231 if (Cond.empty()) {
232 // Unconditional branch
233 assert(!FBB && "Unconditional branch with multiple successors!");
234 BuildMI(BB: &MBB, MIMD: DL, MCID: get(Opcode: BPF::JMP)).addMBB(MBB: TBB);
235 return 1;
236 }
237
238 llvm_unreachable("Unexpected conditional branch");
239}
240
241unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB,
242 int *BytesRemoved) const {
243 assert(!BytesRemoved && "code size not handled");
244
245 MachineBasicBlock::iterator I = MBB.end();
246 unsigned Count = 0;
247
248 while (I != MBB.begin()) {
249 --I;
250 if (I->isDebugInstr())
251 continue;
252 if (I->getOpcode() != BPF::JMP)
253 break;
254 // Remove the branch.
255 I->eraseFromParent();
256 I = MBB.end();
257 ++Count;
258 }
259
260 return Count;
261}
262