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
BPFInstrInfo()280b57cec5SDimitry Andric BPFInstrInfo::BPFInstrInfo()
290b57cec5SDimitry Andric : BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {}
300b57cec5SDimitry Andric
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,const DebugLoc & DL,MCRegister DestReg,MCRegister SrcReg,bool KillSrc) const310b57cec5SDimitry 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
expandMEMCPY(MachineBasicBlock::iterator MI) const450b57cec5SDimitry 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
expandPostRAPseudo(MachineInstr & MI) const1150b57cec5SDimitry 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
storeRegToStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register SrcReg,bool IsKill,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const1240b57cec5SDimitry Andric void BPFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
1250b57cec5SDimitry Andric MachineBasicBlock::iterator I,
1265ffd83dbSDimitry Andric Register SrcReg, bool IsKill, int FI,
1270b57cec5SDimitry Andric const TargetRegisterClass *RC,
128*bdd1243dSDimitry Andric const TargetRegisterInfo *TRI,
129*bdd1243dSDimitry Andric Register VReg) const {
1300b57cec5SDimitry Andric DebugLoc DL;
1310b57cec5SDimitry Andric if (I != MBB.end())
1320b57cec5SDimitry Andric DL = I->getDebugLoc();
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric if (RC == &BPF::GPRRegClass)
1350b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(BPF::STD))
1360b57cec5SDimitry Andric .addReg(SrcReg, getKillRegState(IsKill))
1370b57cec5SDimitry Andric .addFrameIndex(FI)
1380b57cec5SDimitry Andric .addImm(0);
1390b57cec5SDimitry Andric else if (RC == &BPF::GPR32RegClass)
1400b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(BPF::STW32))
1410b57cec5SDimitry Andric .addReg(SrcReg, getKillRegState(IsKill))
1420b57cec5SDimitry Andric .addFrameIndex(FI)
1430b57cec5SDimitry Andric .addImm(0);
1440b57cec5SDimitry Andric else
1450b57cec5SDimitry Andric llvm_unreachable("Can't store this register to stack slot");
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric
loadRegFromStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register DestReg,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const1480b57cec5SDimitry Andric void BPFInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
1490b57cec5SDimitry Andric MachineBasicBlock::iterator I,
1505ffd83dbSDimitry Andric Register DestReg, int FI,
1510b57cec5SDimitry Andric const TargetRegisterClass *RC,
152*bdd1243dSDimitry Andric const TargetRegisterInfo *TRI,
153*bdd1243dSDimitry Andric Register VReg) const {
1540b57cec5SDimitry Andric DebugLoc DL;
1550b57cec5SDimitry Andric if (I != MBB.end())
1560b57cec5SDimitry Andric DL = I->getDebugLoc();
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric if (RC == &BPF::GPRRegClass)
1590b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(BPF::LDD), DestReg).addFrameIndex(FI).addImm(0);
1600b57cec5SDimitry Andric else if (RC == &BPF::GPR32RegClass)
1610b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(BPF::LDW32), DestReg).addFrameIndex(FI).addImm(0);
1620b57cec5SDimitry Andric else
1630b57cec5SDimitry Andric llvm_unreachable("Can't load this register from stack slot");
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric
analyzeBranch(MachineBasicBlock & MBB,MachineBasicBlock * & TBB,MachineBasicBlock * & FBB,SmallVectorImpl<MachineOperand> & Cond,bool AllowModify) const1660b57cec5SDimitry Andric bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
1670b57cec5SDimitry Andric MachineBasicBlock *&TBB,
1680b57cec5SDimitry Andric MachineBasicBlock *&FBB,
1690b57cec5SDimitry Andric SmallVectorImpl<MachineOperand> &Cond,
1700b57cec5SDimitry Andric bool AllowModify) const {
1710b57cec5SDimitry Andric // Start from the bottom of the block and work up, examining the
1720b57cec5SDimitry Andric // terminator instructions.
1730b57cec5SDimitry Andric MachineBasicBlock::iterator I = MBB.end();
1740b57cec5SDimitry Andric while (I != MBB.begin()) {
1750b57cec5SDimitry Andric --I;
1760b57cec5SDimitry Andric if (I->isDebugInstr())
1770b57cec5SDimitry Andric continue;
1780b57cec5SDimitry Andric
1790b57cec5SDimitry Andric // Working from the bottom, when we see a non-terminator
1800b57cec5SDimitry Andric // instruction, we're done.
1810b57cec5SDimitry Andric if (!isUnpredicatedTerminator(*I))
1820b57cec5SDimitry Andric break;
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric // A terminator that isn't a branch can't easily be handled
1850b57cec5SDimitry Andric // by this analysis.
1860b57cec5SDimitry Andric if (!I->isBranch())
1870b57cec5SDimitry Andric return true;
1880b57cec5SDimitry Andric
1890b57cec5SDimitry Andric // Handle unconditional branches.
1900b57cec5SDimitry Andric if (I->getOpcode() == BPF::JMP) {
1910b57cec5SDimitry Andric if (!AllowModify) {
1920b57cec5SDimitry Andric TBB = I->getOperand(0).getMBB();
1930b57cec5SDimitry Andric continue;
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric
1960b57cec5SDimitry Andric // If the block has any instructions after a J, delete them.
19781ad6265SDimitry Andric MBB.erase(std::next(I), MBB.end());
1980b57cec5SDimitry Andric Cond.clear();
1990b57cec5SDimitry Andric FBB = nullptr;
2000b57cec5SDimitry Andric
2010b57cec5SDimitry Andric // Delete the J if it's equivalent to a fall-through.
2020b57cec5SDimitry Andric if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) {
2030b57cec5SDimitry Andric TBB = nullptr;
2040b57cec5SDimitry Andric I->eraseFromParent();
2050b57cec5SDimitry Andric I = MBB.end();
2060b57cec5SDimitry Andric continue;
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric // TBB is used to indicate the unconditinal destination.
2100b57cec5SDimitry Andric TBB = I->getOperand(0).getMBB();
2110b57cec5SDimitry Andric continue;
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric // Cannot handle conditional branches
2140b57cec5SDimitry Andric return true;
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric return false;
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric
insertBranch(MachineBasicBlock & MBB,MachineBasicBlock * TBB,MachineBasicBlock * FBB,ArrayRef<MachineOperand> Cond,const DebugLoc & DL,int * BytesAdded) const2200b57cec5SDimitry Andric unsigned BPFInstrInfo::insertBranch(MachineBasicBlock &MBB,
2210b57cec5SDimitry Andric MachineBasicBlock *TBB,
2220b57cec5SDimitry Andric MachineBasicBlock *FBB,
2230b57cec5SDimitry Andric ArrayRef<MachineOperand> Cond,
2240b57cec5SDimitry Andric const DebugLoc &DL,
2250b57cec5SDimitry Andric int *BytesAdded) const {
2260b57cec5SDimitry Andric assert(!BytesAdded && "code size not handled");
2270b57cec5SDimitry Andric
2280b57cec5SDimitry Andric // Shouldn't be a fall through.
2290b57cec5SDimitry Andric assert(TBB && "insertBranch must not be told to insert a fallthrough");
2300b57cec5SDimitry Andric
2310b57cec5SDimitry Andric if (Cond.empty()) {
2320b57cec5SDimitry Andric // Unconditional branch
2330b57cec5SDimitry Andric assert(!FBB && "Unconditional branch with multiple successors!");
2340b57cec5SDimitry Andric BuildMI(&MBB, DL, get(BPF::JMP)).addMBB(TBB);
2350b57cec5SDimitry Andric return 1;
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric llvm_unreachable("Unexpected conditional branch");
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric
removeBranch(MachineBasicBlock & MBB,int * BytesRemoved) const2410b57cec5SDimitry Andric unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB,
2420b57cec5SDimitry Andric int *BytesRemoved) const {
2430b57cec5SDimitry Andric assert(!BytesRemoved && "code size not handled");
2440b57cec5SDimitry Andric
2450b57cec5SDimitry Andric MachineBasicBlock::iterator I = MBB.end();
2460b57cec5SDimitry Andric unsigned Count = 0;
2470b57cec5SDimitry Andric
2480b57cec5SDimitry Andric while (I != MBB.begin()) {
2490b57cec5SDimitry Andric --I;
2500b57cec5SDimitry Andric if (I->isDebugInstr())
2510b57cec5SDimitry Andric continue;
2520b57cec5SDimitry Andric if (I->getOpcode() != BPF::JMP)
2530b57cec5SDimitry Andric break;
2540b57cec5SDimitry Andric // Remove the branch.
2550b57cec5SDimitry Andric I->eraseFromParent();
2560b57cec5SDimitry Andric I = MBB.end();
2570b57cec5SDimitry Andric ++Count;
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric
2600b57cec5SDimitry Andric return Count;
2610b57cec5SDimitry Andric }
262