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