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 26 using namespace llvm; 27 28 BPFInstrInfo::BPFInstrInfo() 29 : BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {} 30 31 void 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(DestReg, SrcReg)) 37 BuildMI(MBB, I, DL, get(BPF::MOV_rr), DestReg) 38 .addReg(SrcReg, getKillRegState(KillSrc)); 39 else if (BPF::GPR32RegClass.contains(DestReg, SrcReg)) 40 BuildMI(MBB, I, DL, get(BPF::MOV_rr_32), DestReg) 41 .addReg(SrcReg, getKillRegState(KillSrc)); 42 else 43 llvm_unreachable("Impossible reg-to-reg copy"); 44 } 45 46 void BPFInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const { 47 Register DstReg = MI->getOperand(0).getReg(); 48 Register SrcReg = MI->getOperand(1).getReg(); 49 uint64_t CopyLen = MI->getOperand(2).getImm(); 50 uint64_t Alignment = MI->getOperand(3).getImm(); 51 Register ScratchReg = MI->getOperand(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(Alignment); 78 for(unsigned I = 0; I < IterationNum; ++I) { 79 BuildMI(*BB, MI, dl, get(LdOpc)) 80 .addReg(ScratchReg, RegState::Define).addReg(SrcReg) 81 .addImm(I * Alignment); 82 BuildMI(*BB, MI, dl, get(StOpc)) 83 .addReg(ScratchReg, RegState::Kill).addReg(DstReg) 84 .addImm(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, MI, dl, get(BPF::LDW)) 94 .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); 95 BuildMI(*BB, MI, dl, get(BPF::STW)) 96 .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); 97 Offset += 4; 98 } 99 if (Hanging2Byte) { 100 BuildMI(*BB, MI, dl, get(BPF::LDH)) 101 .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); 102 BuildMI(*BB, MI, dl, get(BPF::STH)) 103 .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); 104 Offset += 2; 105 } 106 if (Hanging1Byte) { 107 BuildMI(*BB, MI, dl, get(BPF::LDB)) 108 .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); 109 BuildMI(*BB, MI, dl, get(BPF::STB)) 110 .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); 111 } 112 113 BB->erase(MI); 114 } 115 116 bool BPFInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { 117 if (MI.getOpcode() == BPF::MEMCPY) { 118 expandMEMCPY(MI); 119 return true; 120 } 121 122 return false; 123 } 124 125 void 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(MBB, I, DL, get(BPF::STD)) 138 .addReg(SrcReg, getKillRegState(IsKill)) 139 .addFrameIndex(FI) 140 .addImm(0); 141 else if (RC == &BPF::GPR32RegClass) 142 BuildMI(MBB, I, DL, get(BPF::STW32)) 143 .addReg(SrcReg, getKillRegState(IsKill)) 144 .addFrameIndex(FI) 145 .addImm(0); 146 else 147 llvm_unreachable("Can't store this register to stack slot"); 148 } 149 150 void 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(MBB, I, DL, get(BPF::LDD), DestReg).addFrameIndex(FI).addImm(0); 160 else if (RC == &BPF::GPR32RegClass) 161 BuildMI(MBB, I, DL, get(BPF::LDW32), DestReg).addFrameIndex(FI).addImm(0); 162 else 163 llvm_unreachable("Can't load this register from stack slot"); 164 } 165 166 bool 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(*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(0).getMBB(); 193 continue; 194 } 195 196 // If the block has any instructions after a J, delete them. 197 MBB.erase(std::next(I), 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(I->getOperand(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(0).getMBB(); 211 continue; 212 } 213 // Cannot handle conditional branches 214 return true; 215 } 216 217 return false; 218 } 219 220 unsigned 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(&MBB, DL, get(BPF::JMP)).addMBB(TBB); 235 return 1; 236 } 237 238 llvm_unreachable("Unexpected conditional branch"); 239 } 240 241 unsigned 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