Path: blob/main/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.cpp
35268 views
//===-- BPFInstrInfo.cpp - BPF Instruction Information ----------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains the BPF implementation of the TargetInstrInfo class.9//10//===----------------------------------------------------------------------===//1112#include "BPFInstrInfo.h"13#include "BPF.h"14#include "llvm/ADT/SmallVector.h"15#include "llvm/CodeGen/MachineBasicBlock.h"16#include "llvm/CodeGen/MachineInstrBuilder.h"17#include "llvm/IR/DebugLoc.h"18#include "llvm/Support/ErrorHandling.h"19#include <cassert>20#include <iterator>2122#define GET_INSTRINFO_CTOR_DTOR23#include "BPFGenInstrInfo.inc"2425using namespace llvm;2627BPFInstrInfo::BPFInstrInfo()28: BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {}2930void BPFInstrInfo::copyPhysReg(MachineBasicBlock &MBB,31MachineBasicBlock::iterator I,32const DebugLoc &DL, MCRegister DestReg,33MCRegister SrcReg, bool KillSrc) const {34if (BPF::GPRRegClass.contains(DestReg, SrcReg))35BuildMI(MBB, I, DL, get(BPF::MOV_rr), DestReg)36.addReg(SrcReg, getKillRegState(KillSrc));37else if (BPF::GPR32RegClass.contains(DestReg, SrcReg))38BuildMI(MBB, I, DL, get(BPF::MOV_rr_32), DestReg)39.addReg(SrcReg, getKillRegState(KillSrc));40else41llvm_unreachable("Impossible reg-to-reg copy");42}4344void BPFInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const {45Register DstReg = MI->getOperand(0).getReg();46Register SrcReg = MI->getOperand(1).getReg();47uint64_t CopyLen = MI->getOperand(2).getImm();48uint64_t Alignment = MI->getOperand(3).getImm();49Register ScratchReg = MI->getOperand(4).getReg();50MachineBasicBlock *BB = MI->getParent();51DebugLoc dl = MI->getDebugLoc();52unsigned LdOpc, StOpc;5354switch (Alignment) {55case 1:56LdOpc = BPF::LDB;57StOpc = BPF::STB;58break;59case 2:60LdOpc = BPF::LDH;61StOpc = BPF::STH;62break;63case 4:64LdOpc = BPF::LDW;65StOpc = BPF::STW;66break;67case 8:68LdOpc = BPF::LDD;69StOpc = BPF::STD;70break;71default:72llvm_unreachable("unsupported memcpy alignment");73}7475unsigned IterationNum = CopyLen >> Log2_64(Alignment);76for(unsigned I = 0; I < IterationNum; ++I) {77BuildMI(*BB, MI, dl, get(LdOpc))78.addReg(ScratchReg, RegState::Define).addReg(SrcReg)79.addImm(I * Alignment);80BuildMI(*BB, MI, dl, get(StOpc))81.addReg(ScratchReg, RegState::Kill).addReg(DstReg)82.addImm(I * Alignment);83}8485unsigned BytesLeft = CopyLen & (Alignment - 1);86unsigned Offset = IterationNum * Alignment;87bool Hanging4Byte = BytesLeft & 0x4;88bool Hanging2Byte = BytesLeft & 0x2;89bool Hanging1Byte = BytesLeft & 0x1;90if (Hanging4Byte) {91BuildMI(*BB, MI, dl, get(BPF::LDW))92.addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);93BuildMI(*BB, MI, dl, get(BPF::STW))94.addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);95Offset += 4;96}97if (Hanging2Byte) {98BuildMI(*BB, MI, dl, get(BPF::LDH))99.addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);100BuildMI(*BB, MI, dl, get(BPF::STH))101.addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);102Offset += 2;103}104if (Hanging1Byte) {105BuildMI(*BB, MI, dl, get(BPF::LDB))106.addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);107BuildMI(*BB, MI, dl, get(BPF::STB))108.addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);109}110111BB->erase(MI);112}113114bool BPFInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {115if (MI.getOpcode() == BPF::MEMCPY) {116expandMEMCPY(MI);117return true;118}119120return false;121}122123void BPFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,124MachineBasicBlock::iterator I,125Register SrcReg, bool IsKill, int FI,126const TargetRegisterClass *RC,127const TargetRegisterInfo *TRI,128Register VReg) const {129DebugLoc DL;130if (I != MBB.end())131DL = I->getDebugLoc();132133if (RC == &BPF::GPRRegClass)134BuildMI(MBB, I, DL, get(BPF::STD))135.addReg(SrcReg, getKillRegState(IsKill))136.addFrameIndex(FI)137.addImm(0);138else if (RC == &BPF::GPR32RegClass)139BuildMI(MBB, I, DL, get(BPF::STW32))140.addReg(SrcReg, getKillRegState(IsKill))141.addFrameIndex(FI)142.addImm(0);143else144llvm_unreachable("Can't store this register to stack slot");145}146147void BPFInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,148MachineBasicBlock::iterator I,149Register DestReg, int FI,150const TargetRegisterClass *RC,151const TargetRegisterInfo *TRI,152Register VReg) const {153DebugLoc DL;154if (I != MBB.end())155DL = I->getDebugLoc();156157if (RC == &BPF::GPRRegClass)158BuildMI(MBB, I, DL, get(BPF::LDD), DestReg).addFrameIndex(FI).addImm(0);159else if (RC == &BPF::GPR32RegClass)160BuildMI(MBB, I, DL, get(BPF::LDW32), DestReg).addFrameIndex(FI).addImm(0);161else162llvm_unreachable("Can't load this register from stack slot");163}164165bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB,166MachineBasicBlock *&TBB,167MachineBasicBlock *&FBB,168SmallVectorImpl<MachineOperand> &Cond,169bool AllowModify) const {170// Start from the bottom of the block and work up, examining the171// terminator instructions.172MachineBasicBlock::iterator I = MBB.end();173while (I != MBB.begin()) {174--I;175if (I->isDebugInstr())176continue;177178// Working from the bottom, when we see a non-terminator179// instruction, we're done.180if (!isUnpredicatedTerminator(*I))181break;182183// A terminator that isn't a branch can't easily be handled184// by this analysis.185if (!I->isBranch())186return true;187188// Handle unconditional branches.189if (I->getOpcode() == BPF::JMP) {190if (!AllowModify) {191TBB = I->getOperand(0).getMBB();192continue;193}194195// If the block has any instructions after a J, delete them.196MBB.erase(std::next(I), MBB.end());197Cond.clear();198FBB = nullptr;199200// Delete the J if it's equivalent to a fall-through.201if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) {202TBB = nullptr;203I->eraseFromParent();204I = MBB.end();205continue;206}207208// TBB is used to indicate the unconditinal destination.209TBB = I->getOperand(0).getMBB();210continue;211}212// Cannot handle conditional branches213return true;214}215216return false;217}218219unsigned BPFInstrInfo::insertBranch(MachineBasicBlock &MBB,220MachineBasicBlock *TBB,221MachineBasicBlock *FBB,222ArrayRef<MachineOperand> Cond,223const DebugLoc &DL,224int *BytesAdded) const {225assert(!BytesAdded && "code size not handled");226227// Shouldn't be a fall through.228assert(TBB && "insertBranch must not be told to insert a fallthrough");229230if (Cond.empty()) {231// Unconditional branch232assert(!FBB && "Unconditional branch with multiple successors!");233BuildMI(&MBB, DL, get(BPF::JMP)).addMBB(TBB);234return 1;235}236237llvm_unreachable("Unexpected conditional branch");238}239240unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB,241int *BytesRemoved) const {242assert(!BytesRemoved && "code size not handled");243244MachineBasicBlock::iterator I = MBB.end();245unsigned Count = 0;246247while (I != MBB.begin()) {248--I;249if (I->isDebugInstr())250continue;251if (I->getOpcode() != BPF::JMP)252break;253// Remove the branch.254I->eraseFromParent();255I = MBB.end();256++Count;257}258259return Count;260}261262263