| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 1 | //===-- BPFInstrInfo.cpp - BPF Instruction Information ----------*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file contains the BPF implementation of the TargetInstrInfo class. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 14 | #include "BPFInstrInfo.h" |
| Chandler Carruth | 6bda14b | 2017-06-06 11:49:48 +0000 | [diff] [blame] | 15 | #include "BPF.h" |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 16 | #include "llvm/ADT/SmallVector.h" |
| Eugene Zelenko | 4282c40 | 2017-01-06 23:06:25 +0000 | [diff] [blame] | 17 | #include "llvm/CodeGen/MachineBasicBlock.h" |
| 18 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
| 19 | #include "llvm/IR/DebugLoc.h" |
| 20 | #include "llvm/Support/ErrorHandling.h" |
| 21 | #include <cassert> |
| 22 | #include <iterator> |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 23 | |
| 24 | #define GET_INSTRINFO_CTOR_DTOR |
| 25 | #include "BPFGenInstrInfo.inc" |
| 26 | |
| 27 | using namespace llvm; |
| 28 | |
| 29 | BPFInstrInfo::BPFInstrInfo() |
| 30 | : BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {} |
| 31 | |
| 32 | void BPFInstrInfo::copyPhysReg(MachineBasicBlock &MBB, |
| Benjamin Kramer | bdc4956 | 2016-06-12 15:39:02 +0000 | [diff] [blame] | 33 | MachineBasicBlock::iterator I, |
| 34 | const DebugLoc &DL, unsigned DestReg, |
| 35 | unsigned SrcReg, bool KillSrc) const { |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 36 | if (BPF::GPRRegClass.contains(DestReg, SrcReg)) |
| 37 | BuildMI(MBB, I, DL, get(BPF::MOV_rr), DestReg) |
| 38 | .addReg(SrcReg, getKillRegState(KillSrc)); |
| Yonghong Song | fcd1e0f | 2018-02-23 23:49:29 +0000 | [diff] [blame] | 39 | else if (BPF::GPR32RegClass.contains(DestReg, SrcReg)) |
| 40 | BuildMI(MBB, I, DL, get(BPF::MOV_rr_32), DestReg) |
| 41 | .addReg(SrcReg, getKillRegState(KillSrc)); |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 42 | else |
| 43 | llvm_unreachable("Impossible reg-to-reg copy"); |
| 44 | } |
| 45 | |
| Yonghong Song | 71d81e5 | 2018-07-25 22:40:02 +0000 | [diff] [blame] | 46 | void BPFInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const { |
| 47 | unsigned DstReg = MI->getOperand(0).getReg(); |
| 48 | unsigned SrcReg = MI->getOperand(1).getReg(); |
| 49 | uint64_t CopyLen = MI->getOperand(2).getImm(); |
| 50 | uint64_t Alignment = MI->getOperand(3).getImm(); |
| 51 | unsigned 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)) |
| Yonghong Song | 04ccfda | 2018-07-27 16:58:52 +0000 | [diff] [blame] | 80 | .addReg(ScratchReg, RegState::Define).addReg(SrcReg) |
| 81 | .addImm(I * Alignment); |
| Yonghong Song | 71d81e5 | 2018-07-25 22:40:02 +0000 | [diff] [blame] | 82 | BuildMI(*BB, MI, dl, get(StOpc)) |
| Yonghong Song | 04ccfda | 2018-07-27 16:58:52 +0000 | [diff] [blame] | 83 | .addReg(ScratchReg, RegState::Kill).addReg(DstReg) |
| 84 | .addImm(I * Alignment); |
| Yonghong Song | 71d81e5 | 2018-07-25 22:40:02 +0000 | [diff] [blame] | 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)) |
| Yonghong Song | 04ccfda | 2018-07-27 16:58:52 +0000 | [diff] [blame] | 94 | .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); |
| Yonghong Song | 71d81e5 | 2018-07-25 22:40:02 +0000 | [diff] [blame] | 95 | BuildMI(*BB, MI, dl, get(BPF::STW)) |
| Yonghong Song | 04ccfda | 2018-07-27 16:58:52 +0000 | [diff] [blame] | 96 | .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); |
| Yonghong Song | 71d81e5 | 2018-07-25 22:40:02 +0000 | [diff] [blame] | 97 | Offset += 4; |
| 98 | } |
| 99 | if (Hanging2Byte) { |
| 100 | BuildMI(*BB, MI, dl, get(BPF::LDH)) |
| Yonghong Song | 04ccfda | 2018-07-27 16:58:52 +0000 | [diff] [blame] | 101 | .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); |
| Yonghong Song | 71d81e5 | 2018-07-25 22:40:02 +0000 | [diff] [blame] | 102 | BuildMI(*BB, MI, dl, get(BPF::STH)) |
| Yonghong Song | 04ccfda | 2018-07-27 16:58:52 +0000 | [diff] [blame] | 103 | .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); |
| Yonghong Song | 71d81e5 | 2018-07-25 22:40:02 +0000 | [diff] [blame] | 104 | Offset += 2; |
| 105 | } |
| 106 | if (Hanging1Byte) { |
| 107 | BuildMI(*BB, MI, dl, get(BPF::LDB)) |
| Yonghong Song | 04ccfda | 2018-07-27 16:58:52 +0000 | [diff] [blame] | 108 | .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); |
| Yonghong Song | 71d81e5 | 2018-07-25 22:40:02 +0000 | [diff] [blame] | 109 | BuildMI(*BB, MI, dl, get(BPF::STB)) |
| Yonghong Song | 04ccfda | 2018-07-27 16:58:52 +0000 | [diff] [blame] | 110 | .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); |
| Yonghong Song | 71d81e5 | 2018-07-25 22:40:02 +0000 | [diff] [blame] | 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 | |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 125 | void BPFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, |
| 126 | MachineBasicBlock::iterator I, |
| 127 | unsigned SrcReg, bool IsKill, int FI, |
| 128 | const TargetRegisterClass *RC, |
| 129 | const TargetRegisterInfo *TRI) const { |
| 130 | DebugLoc DL; |
| 131 | if (I != MBB.end()) |
| 132 | DL = I->getDebugLoc(); |
| 133 | |
| 134 | if (RC == &BPF::GPRRegClass) |
| 135 | BuildMI(MBB, I, DL, get(BPF::STD)) |
| 136 | .addReg(SrcReg, getKillRegState(IsKill)) |
| 137 | .addFrameIndex(FI) |
| 138 | .addImm(0); |
| Yonghong Song | fcd1e0f | 2018-02-23 23:49:29 +0000 | [diff] [blame] | 139 | else if (RC == &BPF::GPR32RegClass) |
| 140 | BuildMI(MBB, I, DL, get(BPF::STW32)) |
| 141 | .addReg(SrcReg, getKillRegState(IsKill)) |
| 142 | .addFrameIndex(FI) |
| 143 | .addImm(0); |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 144 | else |
| 145 | llvm_unreachable("Can't store this register to stack slot"); |
| 146 | } |
| 147 | |
| 148 | void BPFInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, |
| 149 | MachineBasicBlock::iterator I, |
| 150 | unsigned DestReg, int FI, |
| 151 | const TargetRegisterClass *RC, |
| 152 | const TargetRegisterInfo *TRI) const { |
| 153 | DebugLoc DL; |
| 154 | if (I != MBB.end()) |
| 155 | DL = I->getDebugLoc(); |
| 156 | |
| 157 | if (RC == &BPF::GPRRegClass) |
| 158 | BuildMI(MBB, I, DL, get(BPF::LDD), DestReg).addFrameIndex(FI).addImm(0); |
| Yonghong Song | fcd1e0f | 2018-02-23 23:49:29 +0000 | [diff] [blame] | 159 | else if (RC == &BPF::GPR32RegClass) |
| 160 | BuildMI(MBB, I, DL, get(BPF::LDW32), DestReg).addFrameIndex(FI).addImm(0); |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 161 | else |
| 162 | llvm_unreachable("Can't load this register from stack slot"); |
| 163 | } |
| 164 | |
| Jacques Pienaar | 71c30a1 | 2016-07-15 14:41:04 +0000 | [diff] [blame] | 165 | bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB, |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 166 | MachineBasicBlock *&TBB, |
| 167 | MachineBasicBlock *&FBB, |
| 168 | SmallVectorImpl<MachineOperand> &Cond, |
| 169 | bool AllowModify) const { |
| 170 | // Start from the bottom of the block and work up, examining the |
| 171 | // terminator instructions. |
| 172 | MachineBasicBlock::iterator I = MBB.end(); |
| 173 | while (I != MBB.begin()) { |
| 174 | --I; |
| Shiva Chen | 801bf7e | 2018-05-09 02:42:00 +0000 | [diff] [blame] | 175 | if (I->isDebugInstr()) |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 176 | continue; |
| 177 | |
| 178 | // Working from the bottom, when we see a non-terminator |
| 179 | // instruction, we're done. |
| Duncan P. N. Exon Smith | 6307eb5 | 2016-02-23 02:46:52 +0000 | [diff] [blame] | 180 | if (!isUnpredicatedTerminator(*I)) |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 181 | break; |
| 182 | |
| 183 | // A terminator that isn't a branch can't easily be handled |
| 184 | // by this analysis. |
| 185 | if (!I->isBranch()) |
| 186 | return true; |
| 187 | |
| 188 | // Handle unconditional branches. |
| 189 | if (I->getOpcode() == BPF::JMP) { |
| 190 | if (!AllowModify) { |
| 191 | TBB = I->getOperand(0).getMBB(); |
| 192 | continue; |
| 193 | } |
| 194 | |
| 195 | // If the block has any instructions after a J, delete them. |
| 196 | while (std::next(I) != MBB.end()) |
| 197 | std::next(I)->eraseFromParent(); |
| 198 | Cond.clear(); |
| Eugene Zelenko | 4282c40 | 2017-01-06 23:06:25 +0000 | [diff] [blame] | 199 | FBB = nullptr; |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 200 | |
| 201 | // Delete the J if it's equivalent to a fall-through. |
| 202 | if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { |
| Eugene Zelenko | 4282c40 | 2017-01-06 23:06:25 +0000 | [diff] [blame] | 203 | TBB = nullptr; |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 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 | |
| Matt Arsenault | e8e0f5c | 2016-09-14 17:24:15 +0000 | [diff] [blame] | 220 | unsigned BPFInstrInfo::insertBranch(MachineBasicBlock &MBB, |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 221 | MachineBasicBlock *TBB, |
| 222 | MachineBasicBlock *FBB, |
| Ahmed Bougacha | c88bf54 | 2015-06-11 19:30:37 +0000 | [diff] [blame] | 223 | ArrayRef<MachineOperand> Cond, |
| Matt Arsenault | a2b036e | 2016-09-14 17:23:48 +0000 | [diff] [blame] | 224 | const DebugLoc &DL, |
| 225 | int *BytesAdded) const { |
| 226 | assert(!BytesAdded && "code size not handled"); |
| 227 | |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 228 | // Shouldn't be a fall through. |
| Matt Arsenault | e8e0f5c | 2016-09-14 17:24:15 +0000 | [diff] [blame] | 229 | assert(TBB && "insertBranch must not be told to insert a fallthrough"); |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 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 | |
| Matt Arsenault | 1b9fc8e | 2016-09-14 20:43:16 +0000 | [diff] [blame] | 241 | unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB, |
| Matt Arsenault | a2b036e | 2016-09-14 17:23:48 +0000 | [diff] [blame] | 242 | int *BytesRemoved) const { |
| 243 | assert(!BytesRemoved && "code size not handled"); |
| 244 | |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 245 | MachineBasicBlock::iterator I = MBB.end(); |
| 246 | unsigned Count = 0; |
| 247 | |
| 248 | while (I != MBB.begin()) { |
| 249 | --I; |
| Shiva Chen | 801bf7e | 2018-05-09 02:42:00 +0000 | [diff] [blame] | 250 | if (I->isDebugInstr()) |
| Alexei Starovoitov | e4c8c80 | 2015-01-24 17:51:26 +0000 | [diff] [blame] | 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 | } |