1e4c8c807SAlexei Starovoitov //===-- BPFInstrInfo.cpp - BPF Instruction Information ----------*- C++ -*-===// 2e4c8c807SAlexei Starovoitov // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e4c8c807SAlexei Starovoitov // 7e4c8c807SAlexei Starovoitov //===----------------------------------------------------------------------===// 8e4c8c807SAlexei Starovoitov // 9e4c8c807SAlexei Starovoitov // This file contains the BPF implementation of the TargetInstrInfo class. 10e4c8c807SAlexei Starovoitov // 11e4c8c807SAlexei Starovoitov //===----------------------------------------------------------------------===// 12e4c8c807SAlexei Starovoitov 13e4c8c807SAlexei Starovoitov #include "BPFInstrInfo.h" 146bda14b3SChandler Carruth #include "BPF.h" 15e4c8c807SAlexei Starovoitov #include "llvm/ADT/SmallVector.h" 164282c404SEugene Zelenko #include "llvm/CodeGen/MachineBasicBlock.h" 174282c404SEugene Zelenko #include "llvm/CodeGen/MachineInstrBuilder.h" 184282c404SEugene Zelenko #include "llvm/IR/DebugLoc.h" 194282c404SEugene Zelenko #include "llvm/Support/ErrorHandling.h" 204282c404SEugene Zelenko #include <cassert> 214282c404SEugene Zelenko #include <iterator> 22e4c8c807SAlexei Starovoitov 23e4c8c807SAlexei Starovoitov #define GET_INSTRINFO_CTOR_DTOR 24e4c8c807SAlexei Starovoitov #include "BPFGenInstrInfo.inc" 25e4c8c807SAlexei Starovoitov 26e4c8c807SAlexei Starovoitov using namespace llvm; 27e4c8c807SAlexei Starovoitov 28e4c8c807SAlexei Starovoitov BPFInstrInfo::BPFInstrInfo() 29e4c8c807SAlexei Starovoitov : BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {} 30e4c8c807SAlexei Starovoitov 31e4c8c807SAlexei Starovoitov void BPFInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 32bdc4956bSBenjamin Kramer MachineBasicBlock::iterator I, 33bdc4956bSBenjamin Kramer const DebugLoc &DL, unsigned DestReg, 34bdc4956bSBenjamin Kramer unsigned SrcReg, bool KillSrc) const { 35e4c8c807SAlexei Starovoitov if (BPF::GPRRegClass.contains(DestReg, SrcReg)) 36e4c8c807SAlexei Starovoitov BuildMI(MBB, I, DL, get(BPF::MOV_rr), DestReg) 37e4c8c807SAlexei Starovoitov .addReg(SrcReg, getKillRegState(KillSrc)); 38fcd1e0f6SYonghong Song else if (BPF::GPR32RegClass.contains(DestReg, SrcReg)) 39fcd1e0f6SYonghong Song BuildMI(MBB, I, DL, get(BPF::MOV_rr_32), DestReg) 40fcd1e0f6SYonghong Song .addReg(SrcReg, getKillRegState(KillSrc)); 41e4c8c807SAlexei Starovoitov else 42e4c8c807SAlexei Starovoitov llvm_unreachable("Impossible reg-to-reg copy"); 43e4c8c807SAlexei Starovoitov } 44e4c8c807SAlexei Starovoitov 4571d81e5cSYonghong Song void BPFInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const { 4671d81e5cSYonghong Song unsigned DstReg = MI->getOperand(0).getReg(); 4771d81e5cSYonghong Song unsigned SrcReg = MI->getOperand(1).getReg(); 4871d81e5cSYonghong Song uint64_t CopyLen = MI->getOperand(2).getImm(); 4971d81e5cSYonghong Song uint64_t Alignment = MI->getOperand(3).getImm(); 5071d81e5cSYonghong Song unsigned ScratchReg = MI->getOperand(4).getReg(); 5171d81e5cSYonghong Song MachineBasicBlock *BB = MI->getParent(); 5271d81e5cSYonghong Song DebugLoc dl = MI->getDebugLoc(); 5371d81e5cSYonghong Song unsigned LdOpc, StOpc; 5471d81e5cSYonghong Song 5571d81e5cSYonghong Song switch (Alignment) { 5671d81e5cSYonghong Song case 1: 5771d81e5cSYonghong Song LdOpc = BPF::LDB; 5871d81e5cSYonghong Song StOpc = BPF::STB; 5971d81e5cSYonghong Song break; 6071d81e5cSYonghong Song case 2: 6171d81e5cSYonghong Song LdOpc = BPF::LDH; 6271d81e5cSYonghong Song StOpc = BPF::STH; 6371d81e5cSYonghong Song break; 6471d81e5cSYonghong Song case 4: 6571d81e5cSYonghong Song LdOpc = BPF::LDW; 6671d81e5cSYonghong Song StOpc = BPF::STW; 6771d81e5cSYonghong Song break; 6871d81e5cSYonghong Song case 8: 6971d81e5cSYonghong Song LdOpc = BPF::LDD; 7071d81e5cSYonghong Song StOpc = BPF::STD; 7171d81e5cSYonghong Song break; 7271d81e5cSYonghong Song default: 7371d81e5cSYonghong Song llvm_unreachable("unsupported memcpy alignment"); 7471d81e5cSYonghong Song } 7571d81e5cSYonghong Song 7671d81e5cSYonghong Song unsigned IterationNum = CopyLen >> Log2_64(Alignment); 7771d81e5cSYonghong Song for(unsigned I = 0; I < IterationNum; ++I) { 7871d81e5cSYonghong Song BuildMI(*BB, MI, dl, get(LdOpc)) 7904ccfda0SYonghong Song .addReg(ScratchReg, RegState::Define).addReg(SrcReg) 8004ccfda0SYonghong Song .addImm(I * Alignment); 8171d81e5cSYonghong Song BuildMI(*BB, MI, dl, get(StOpc)) 8204ccfda0SYonghong Song .addReg(ScratchReg, RegState::Kill).addReg(DstReg) 8304ccfda0SYonghong Song .addImm(I * Alignment); 8471d81e5cSYonghong Song } 8571d81e5cSYonghong Song 8671d81e5cSYonghong Song unsigned BytesLeft = CopyLen & (Alignment - 1); 8771d81e5cSYonghong Song unsigned Offset = IterationNum * Alignment; 8871d81e5cSYonghong Song bool Hanging4Byte = BytesLeft & 0x4; 8971d81e5cSYonghong Song bool Hanging2Byte = BytesLeft & 0x2; 9071d81e5cSYonghong Song bool Hanging1Byte = BytesLeft & 0x1; 9171d81e5cSYonghong Song if (Hanging4Byte) { 9271d81e5cSYonghong Song BuildMI(*BB, MI, dl, get(BPF::LDW)) 9304ccfda0SYonghong Song .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); 9471d81e5cSYonghong Song BuildMI(*BB, MI, dl, get(BPF::STW)) 9504ccfda0SYonghong Song .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); 9671d81e5cSYonghong Song Offset += 4; 9771d81e5cSYonghong Song } 9871d81e5cSYonghong Song if (Hanging2Byte) { 9971d81e5cSYonghong Song BuildMI(*BB, MI, dl, get(BPF::LDH)) 10004ccfda0SYonghong Song .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); 10171d81e5cSYonghong Song BuildMI(*BB, MI, dl, get(BPF::STH)) 10204ccfda0SYonghong Song .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); 10371d81e5cSYonghong Song Offset += 2; 10471d81e5cSYonghong Song } 10571d81e5cSYonghong Song if (Hanging1Byte) { 10671d81e5cSYonghong Song BuildMI(*BB, MI, dl, get(BPF::LDB)) 10704ccfda0SYonghong Song .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); 10871d81e5cSYonghong Song BuildMI(*BB, MI, dl, get(BPF::STB)) 10904ccfda0SYonghong Song .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); 11071d81e5cSYonghong Song } 11171d81e5cSYonghong Song 11271d81e5cSYonghong Song BB->erase(MI); 11371d81e5cSYonghong Song } 11471d81e5cSYonghong Song 11571d81e5cSYonghong Song bool BPFInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { 11671d81e5cSYonghong Song if (MI.getOpcode() == BPF::MEMCPY) { 11771d81e5cSYonghong Song expandMEMCPY(MI); 11871d81e5cSYonghong Song return true; 11971d81e5cSYonghong Song } 12071d81e5cSYonghong Song 12171d81e5cSYonghong Song return false; 12271d81e5cSYonghong Song } 12371d81e5cSYonghong Song 124e4c8c807SAlexei Starovoitov void BPFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, 125e4c8c807SAlexei Starovoitov MachineBasicBlock::iterator I, 126e4c8c807SAlexei Starovoitov unsigned SrcReg, bool IsKill, int FI, 127e4c8c807SAlexei Starovoitov const TargetRegisterClass *RC, 128e4c8c807SAlexei Starovoitov const TargetRegisterInfo *TRI) const { 129e4c8c807SAlexei Starovoitov DebugLoc DL; 130e4c8c807SAlexei Starovoitov if (I != MBB.end()) 131e4c8c807SAlexei Starovoitov DL = I->getDebugLoc(); 132e4c8c807SAlexei Starovoitov 133e4c8c807SAlexei Starovoitov if (RC == &BPF::GPRRegClass) 134e4c8c807SAlexei Starovoitov BuildMI(MBB, I, DL, get(BPF::STD)) 135e4c8c807SAlexei Starovoitov .addReg(SrcReg, getKillRegState(IsKill)) 136e4c8c807SAlexei Starovoitov .addFrameIndex(FI) 137e4c8c807SAlexei Starovoitov .addImm(0); 138fcd1e0f6SYonghong Song else if (RC == &BPF::GPR32RegClass) 139fcd1e0f6SYonghong Song BuildMI(MBB, I, DL, get(BPF::STW32)) 140fcd1e0f6SYonghong Song .addReg(SrcReg, getKillRegState(IsKill)) 141fcd1e0f6SYonghong Song .addFrameIndex(FI) 142fcd1e0f6SYonghong Song .addImm(0); 143e4c8c807SAlexei Starovoitov else 144e4c8c807SAlexei Starovoitov llvm_unreachable("Can't store this register to stack slot"); 145e4c8c807SAlexei Starovoitov } 146e4c8c807SAlexei Starovoitov 147e4c8c807SAlexei Starovoitov void BPFInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, 148e4c8c807SAlexei Starovoitov MachineBasicBlock::iterator I, 149e4c8c807SAlexei Starovoitov unsigned DestReg, int FI, 150e4c8c807SAlexei Starovoitov const TargetRegisterClass *RC, 151e4c8c807SAlexei Starovoitov const TargetRegisterInfo *TRI) const { 152e4c8c807SAlexei Starovoitov DebugLoc DL; 153e4c8c807SAlexei Starovoitov if (I != MBB.end()) 154e4c8c807SAlexei Starovoitov DL = I->getDebugLoc(); 155e4c8c807SAlexei Starovoitov 156e4c8c807SAlexei Starovoitov if (RC == &BPF::GPRRegClass) 157e4c8c807SAlexei Starovoitov BuildMI(MBB, I, DL, get(BPF::LDD), DestReg).addFrameIndex(FI).addImm(0); 158fcd1e0f6SYonghong Song else if (RC == &BPF::GPR32RegClass) 159fcd1e0f6SYonghong Song BuildMI(MBB, I, DL, get(BPF::LDW32), DestReg).addFrameIndex(FI).addImm(0); 160e4c8c807SAlexei Starovoitov else 161e4c8c807SAlexei Starovoitov llvm_unreachable("Can't load this register from stack slot"); 162e4c8c807SAlexei Starovoitov } 163e4c8c807SAlexei Starovoitov 16471c30a14SJacques Pienaar bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 165e4c8c807SAlexei Starovoitov MachineBasicBlock *&TBB, 166e4c8c807SAlexei Starovoitov MachineBasicBlock *&FBB, 167e4c8c807SAlexei Starovoitov SmallVectorImpl<MachineOperand> &Cond, 168e4c8c807SAlexei Starovoitov bool AllowModify) const { 169e4c8c807SAlexei Starovoitov // Start from the bottom of the block and work up, examining the 170e4c8c807SAlexei Starovoitov // terminator instructions. 171e4c8c807SAlexei Starovoitov MachineBasicBlock::iterator I = MBB.end(); 172e4c8c807SAlexei Starovoitov while (I != MBB.begin()) { 173e4c8c807SAlexei Starovoitov --I; 174801bf7ebSShiva Chen if (I->isDebugInstr()) 175e4c8c807SAlexei Starovoitov continue; 176e4c8c807SAlexei Starovoitov 177e4c8c807SAlexei Starovoitov // Working from the bottom, when we see a non-terminator 178e4c8c807SAlexei Starovoitov // instruction, we're done. 1796307eb55SDuncan P. N. Exon Smith if (!isUnpredicatedTerminator(*I)) 180e4c8c807SAlexei Starovoitov break; 181e4c8c807SAlexei Starovoitov 182e4c8c807SAlexei Starovoitov // A terminator that isn't a branch can't easily be handled 183e4c8c807SAlexei Starovoitov // by this analysis. 184e4c8c807SAlexei Starovoitov if (!I->isBranch()) 185e4c8c807SAlexei Starovoitov return true; 186e4c8c807SAlexei Starovoitov 187e4c8c807SAlexei Starovoitov // Handle unconditional branches. 188e4c8c807SAlexei Starovoitov if (I->getOpcode() == BPF::JMP) { 189e4c8c807SAlexei Starovoitov if (!AllowModify) { 190e4c8c807SAlexei Starovoitov TBB = I->getOperand(0).getMBB(); 191e4c8c807SAlexei Starovoitov continue; 192e4c8c807SAlexei Starovoitov } 193e4c8c807SAlexei Starovoitov 194e4c8c807SAlexei Starovoitov // If the block has any instructions after a J, delete them. 195e4c8c807SAlexei Starovoitov while (std::next(I) != MBB.end()) 196e4c8c807SAlexei Starovoitov std::next(I)->eraseFromParent(); 197e4c8c807SAlexei Starovoitov Cond.clear(); 1984282c404SEugene Zelenko FBB = nullptr; 199e4c8c807SAlexei Starovoitov 200e4c8c807SAlexei Starovoitov // Delete the J if it's equivalent to a fall-through. 201e4c8c807SAlexei Starovoitov if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { 2024282c404SEugene Zelenko TBB = nullptr; 203e4c8c807SAlexei Starovoitov I->eraseFromParent(); 204e4c8c807SAlexei Starovoitov I = MBB.end(); 205e4c8c807SAlexei Starovoitov continue; 206e4c8c807SAlexei Starovoitov } 207e4c8c807SAlexei Starovoitov 208e4c8c807SAlexei Starovoitov // TBB is used to indicate the unconditinal destination. 209e4c8c807SAlexei Starovoitov TBB = I->getOperand(0).getMBB(); 210e4c8c807SAlexei Starovoitov continue; 211e4c8c807SAlexei Starovoitov } 212e4c8c807SAlexei Starovoitov // Cannot handle conditional branches 213e4c8c807SAlexei Starovoitov return true; 214e4c8c807SAlexei Starovoitov } 215e4c8c807SAlexei Starovoitov 216e4c8c807SAlexei Starovoitov return false; 217e4c8c807SAlexei Starovoitov } 218e4c8c807SAlexei Starovoitov 219e8e0f5caSMatt Arsenault unsigned BPFInstrInfo::insertBranch(MachineBasicBlock &MBB, 220e4c8c807SAlexei Starovoitov MachineBasicBlock *TBB, 221e4c8c807SAlexei Starovoitov MachineBasicBlock *FBB, 222c88bf543SAhmed Bougacha ArrayRef<MachineOperand> Cond, 223a2b036e8SMatt Arsenault const DebugLoc &DL, 224a2b036e8SMatt Arsenault int *BytesAdded) const { 225a2b036e8SMatt Arsenault assert(!BytesAdded && "code size not handled"); 226a2b036e8SMatt Arsenault 227e4c8c807SAlexei Starovoitov // Shouldn't be a fall through. 228e8e0f5caSMatt Arsenault assert(TBB && "insertBranch must not be told to insert a fallthrough"); 229e4c8c807SAlexei Starovoitov 230e4c8c807SAlexei Starovoitov if (Cond.empty()) { 231e4c8c807SAlexei Starovoitov // Unconditional branch 232e4c8c807SAlexei Starovoitov assert(!FBB && "Unconditional branch with multiple successors!"); 233e4c8c807SAlexei Starovoitov BuildMI(&MBB, DL, get(BPF::JMP)).addMBB(TBB); 234e4c8c807SAlexei Starovoitov return 1; 235e4c8c807SAlexei Starovoitov } 236e4c8c807SAlexei Starovoitov 237e4c8c807SAlexei Starovoitov llvm_unreachable("Unexpected conditional branch"); 238e4c8c807SAlexei Starovoitov } 239e4c8c807SAlexei Starovoitov 2401b9fc8edSMatt Arsenault unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB, 241a2b036e8SMatt Arsenault int *BytesRemoved) const { 242a2b036e8SMatt Arsenault assert(!BytesRemoved && "code size not handled"); 243a2b036e8SMatt Arsenault 244e4c8c807SAlexei Starovoitov MachineBasicBlock::iterator I = MBB.end(); 245e4c8c807SAlexei Starovoitov unsigned Count = 0; 246e4c8c807SAlexei Starovoitov 247e4c8c807SAlexei Starovoitov while (I != MBB.begin()) { 248e4c8c807SAlexei Starovoitov --I; 249801bf7ebSShiva Chen if (I->isDebugInstr()) 250e4c8c807SAlexei Starovoitov continue; 251e4c8c807SAlexei Starovoitov if (I->getOpcode() != BPF::JMP) 252e4c8c807SAlexei Starovoitov break; 253e4c8c807SAlexei Starovoitov // Remove the branch. 254e4c8c807SAlexei Starovoitov I->eraseFromParent(); 255e4c8c807SAlexei Starovoitov I = MBB.end(); 256e4c8c807SAlexei Starovoitov ++Count; 257e4c8c807SAlexei Starovoitov } 258e4c8c807SAlexei Starovoitov 259e4c8c807SAlexei Starovoitov return Count; 260e4c8c807SAlexei Starovoitov } 261