10b57cec5SDimitry Andric //===-- BPFInstrInfo.cpp - BPF Instruction Information ----------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains the BPF implementation of the TargetInstrInfo class. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "BPFInstrInfo.h" 140b57cec5SDimitry Andric #include "BPF.h" 150b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 180b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h" 190b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 200b57cec5SDimitry Andric #include <cassert> 210b57cec5SDimitry Andric #include <iterator> 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR 240b57cec5SDimitry Andric #include "BPFGenInstrInfo.inc" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric BPFInstrInfo::BPFInstrInfo() 290b57cec5SDimitry Andric : BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {} 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric void BPFInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 320b57cec5SDimitry Andric MachineBasicBlock::iterator I, 33480093f4SDimitry Andric const DebugLoc &DL, MCRegister DestReg, 34480093f4SDimitry Andric MCRegister SrcReg, bool KillSrc) const { 350b57cec5SDimitry Andric if (BPF::GPRRegClass.contains(DestReg, SrcReg)) 360b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(BPF::MOV_rr), DestReg) 370b57cec5SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)); 380b57cec5SDimitry Andric else if (BPF::GPR32RegClass.contains(DestReg, SrcReg)) 390b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(BPF::MOV_rr_32), DestReg) 400b57cec5SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)); 410b57cec5SDimitry Andric else 420b57cec5SDimitry Andric llvm_unreachable("Impossible reg-to-reg copy"); 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric void BPFInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const { 468bcb0991SDimitry Andric Register DstReg = MI->getOperand(0).getReg(); 478bcb0991SDimitry Andric Register SrcReg = MI->getOperand(1).getReg(); 480b57cec5SDimitry Andric uint64_t CopyLen = MI->getOperand(2).getImm(); 490b57cec5SDimitry Andric uint64_t Alignment = MI->getOperand(3).getImm(); 508bcb0991SDimitry Andric Register ScratchReg = MI->getOperand(4).getReg(); 510b57cec5SDimitry Andric MachineBasicBlock *BB = MI->getParent(); 520b57cec5SDimitry Andric DebugLoc dl = MI->getDebugLoc(); 530b57cec5SDimitry Andric unsigned LdOpc, StOpc; 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric switch (Alignment) { 560b57cec5SDimitry Andric case 1: 570b57cec5SDimitry Andric LdOpc = BPF::LDB; 580b57cec5SDimitry Andric StOpc = BPF::STB; 590b57cec5SDimitry Andric break; 600b57cec5SDimitry Andric case 2: 610b57cec5SDimitry Andric LdOpc = BPF::LDH; 620b57cec5SDimitry Andric StOpc = BPF::STH; 630b57cec5SDimitry Andric break; 640b57cec5SDimitry Andric case 4: 650b57cec5SDimitry Andric LdOpc = BPF::LDW; 660b57cec5SDimitry Andric StOpc = BPF::STW; 670b57cec5SDimitry Andric break; 680b57cec5SDimitry Andric case 8: 690b57cec5SDimitry Andric LdOpc = BPF::LDD; 700b57cec5SDimitry Andric StOpc = BPF::STD; 710b57cec5SDimitry Andric break; 720b57cec5SDimitry Andric default: 730b57cec5SDimitry Andric llvm_unreachable("unsupported memcpy alignment"); 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric unsigned IterationNum = CopyLen >> Log2_64(Alignment); 770b57cec5SDimitry Andric for(unsigned I = 0; I < IterationNum; ++I) { 780b57cec5SDimitry Andric BuildMI(*BB, MI, dl, get(LdOpc)) 790b57cec5SDimitry Andric .addReg(ScratchReg, RegState::Define).addReg(SrcReg) 800b57cec5SDimitry Andric .addImm(I * Alignment); 810b57cec5SDimitry Andric BuildMI(*BB, MI, dl, get(StOpc)) 820b57cec5SDimitry Andric .addReg(ScratchReg, RegState::Kill).addReg(DstReg) 830b57cec5SDimitry Andric .addImm(I * Alignment); 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric unsigned BytesLeft = CopyLen & (Alignment - 1); 870b57cec5SDimitry Andric unsigned Offset = IterationNum * Alignment; 880b57cec5SDimitry Andric bool Hanging4Byte = BytesLeft & 0x4; 890b57cec5SDimitry Andric bool Hanging2Byte = BytesLeft & 0x2; 900b57cec5SDimitry Andric bool Hanging1Byte = BytesLeft & 0x1; 910b57cec5SDimitry Andric if (Hanging4Byte) { 920b57cec5SDimitry Andric BuildMI(*BB, MI, dl, get(BPF::LDW)) 930b57cec5SDimitry Andric .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); 940b57cec5SDimitry Andric BuildMI(*BB, MI, dl, get(BPF::STW)) 950b57cec5SDimitry Andric .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); 960b57cec5SDimitry Andric Offset += 4; 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric if (Hanging2Byte) { 990b57cec5SDimitry Andric BuildMI(*BB, MI, dl, get(BPF::LDH)) 1000b57cec5SDimitry Andric .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); 1010b57cec5SDimitry Andric BuildMI(*BB, MI, dl, get(BPF::STH)) 1020b57cec5SDimitry Andric .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); 1030b57cec5SDimitry Andric Offset += 2; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric if (Hanging1Byte) { 1060b57cec5SDimitry Andric BuildMI(*BB, MI, dl, get(BPF::LDB)) 1070b57cec5SDimitry Andric .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); 1080b57cec5SDimitry Andric BuildMI(*BB, MI, dl, get(BPF::STB)) 1090b57cec5SDimitry Andric .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric BB->erase(MI); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric bool BPFInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { 1160b57cec5SDimitry Andric if (MI.getOpcode() == BPF::MEMCPY) { 1170b57cec5SDimitry Andric expandMEMCPY(MI); 1180b57cec5SDimitry Andric return true; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric return false; 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric void BPFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, 1250b57cec5SDimitry Andric MachineBasicBlock::iterator I, 1265ffd83dbSDimitry Andric Register SrcReg, bool IsKill, int FI, 1270b57cec5SDimitry Andric const TargetRegisterClass *RC, 1280b57cec5SDimitry Andric const TargetRegisterInfo *TRI) const { 1290b57cec5SDimitry Andric DebugLoc DL; 1300b57cec5SDimitry Andric if (I != MBB.end()) 1310b57cec5SDimitry Andric DL = I->getDebugLoc(); 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric if (RC == &BPF::GPRRegClass) 1340b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(BPF::STD)) 1350b57cec5SDimitry Andric .addReg(SrcReg, getKillRegState(IsKill)) 1360b57cec5SDimitry Andric .addFrameIndex(FI) 1370b57cec5SDimitry Andric .addImm(0); 1380b57cec5SDimitry Andric else if (RC == &BPF::GPR32RegClass) 1390b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(BPF::STW32)) 1400b57cec5SDimitry Andric .addReg(SrcReg, getKillRegState(IsKill)) 1410b57cec5SDimitry Andric .addFrameIndex(FI) 1420b57cec5SDimitry Andric .addImm(0); 1430b57cec5SDimitry Andric else 1440b57cec5SDimitry Andric llvm_unreachable("Can't store this register to stack slot"); 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric void BPFInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, 1480b57cec5SDimitry Andric MachineBasicBlock::iterator I, 1495ffd83dbSDimitry Andric Register DestReg, int FI, 1500b57cec5SDimitry Andric const TargetRegisterClass *RC, 1510b57cec5SDimitry Andric const TargetRegisterInfo *TRI) const { 1520b57cec5SDimitry Andric DebugLoc DL; 1530b57cec5SDimitry Andric if (I != MBB.end()) 1540b57cec5SDimitry Andric DL = I->getDebugLoc(); 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric if (RC == &BPF::GPRRegClass) 1570b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(BPF::LDD), DestReg).addFrameIndex(FI).addImm(0); 1580b57cec5SDimitry Andric else if (RC == &BPF::GPR32RegClass) 1590b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(BPF::LDW32), DestReg).addFrameIndex(FI).addImm(0); 1600b57cec5SDimitry Andric else 1610b57cec5SDimitry Andric llvm_unreachable("Can't load this register from stack slot"); 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB, 1650b57cec5SDimitry Andric MachineBasicBlock *&TBB, 1660b57cec5SDimitry Andric MachineBasicBlock *&FBB, 1670b57cec5SDimitry Andric SmallVectorImpl<MachineOperand> &Cond, 1680b57cec5SDimitry Andric bool AllowModify) const { 1690b57cec5SDimitry Andric // Start from the bottom of the block and work up, examining the 1700b57cec5SDimitry Andric // terminator instructions. 1710b57cec5SDimitry Andric MachineBasicBlock::iterator I = MBB.end(); 1720b57cec5SDimitry Andric while (I != MBB.begin()) { 1730b57cec5SDimitry Andric --I; 1740b57cec5SDimitry Andric if (I->isDebugInstr()) 1750b57cec5SDimitry Andric continue; 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric // Working from the bottom, when we see a non-terminator 1780b57cec5SDimitry Andric // instruction, we're done. 1790b57cec5SDimitry Andric if (!isUnpredicatedTerminator(*I)) 1800b57cec5SDimitry Andric break; 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric // A terminator that isn't a branch can't easily be handled 1830b57cec5SDimitry Andric // by this analysis. 1840b57cec5SDimitry Andric if (!I->isBranch()) 1850b57cec5SDimitry Andric return true; 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric // Handle unconditional branches. 1880b57cec5SDimitry Andric if (I->getOpcode() == BPF::JMP) { 1890b57cec5SDimitry Andric if (!AllowModify) { 1900b57cec5SDimitry Andric TBB = I->getOperand(0).getMBB(); 1910b57cec5SDimitry Andric continue; 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric // If the block has any instructions after a J, delete them. 195*81ad6265SDimitry Andric MBB.erase(std::next(I), MBB.end()); 1960b57cec5SDimitry Andric Cond.clear(); 1970b57cec5SDimitry Andric FBB = nullptr; 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric // Delete the J if it's equivalent to a fall-through. 2000b57cec5SDimitry Andric if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { 2010b57cec5SDimitry Andric TBB = nullptr; 2020b57cec5SDimitry Andric I->eraseFromParent(); 2030b57cec5SDimitry Andric I = MBB.end(); 2040b57cec5SDimitry Andric continue; 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric // TBB is used to indicate the unconditinal destination. 2080b57cec5SDimitry Andric TBB = I->getOperand(0).getMBB(); 2090b57cec5SDimitry Andric continue; 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric // Cannot handle conditional branches 2120b57cec5SDimitry Andric return true; 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric return false; 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric unsigned BPFInstrInfo::insertBranch(MachineBasicBlock &MBB, 2190b57cec5SDimitry Andric MachineBasicBlock *TBB, 2200b57cec5SDimitry Andric MachineBasicBlock *FBB, 2210b57cec5SDimitry Andric ArrayRef<MachineOperand> Cond, 2220b57cec5SDimitry Andric const DebugLoc &DL, 2230b57cec5SDimitry Andric int *BytesAdded) const { 2240b57cec5SDimitry Andric assert(!BytesAdded && "code size not handled"); 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric // Shouldn't be a fall through. 2270b57cec5SDimitry Andric assert(TBB && "insertBranch must not be told to insert a fallthrough"); 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric if (Cond.empty()) { 2300b57cec5SDimitry Andric // Unconditional branch 2310b57cec5SDimitry Andric assert(!FBB && "Unconditional branch with multiple successors!"); 2320b57cec5SDimitry Andric BuildMI(&MBB, DL, get(BPF::JMP)).addMBB(TBB); 2330b57cec5SDimitry Andric return 1; 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric llvm_unreachable("Unexpected conditional branch"); 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB, 2400b57cec5SDimitry Andric int *BytesRemoved) const { 2410b57cec5SDimitry Andric assert(!BytesRemoved && "code size not handled"); 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric MachineBasicBlock::iterator I = MBB.end(); 2440b57cec5SDimitry Andric unsigned Count = 0; 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric while (I != MBB.begin()) { 2470b57cec5SDimitry Andric --I; 2480b57cec5SDimitry Andric if (I->isDebugInstr()) 2490b57cec5SDimitry Andric continue; 2500b57cec5SDimitry Andric if (I->getOpcode() != BPF::JMP) 2510b57cec5SDimitry Andric break; 2520b57cec5SDimitry Andric // Remove the branch. 2530b57cec5SDimitry Andric I->eraseFromParent(); 2540b57cec5SDimitry Andric I = MBB.end(); 2550b57cec5SDimitry Andric ++Count; 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric return Count; 2590b57cec5SDimitry Andric } 260