|  | //===-- BPFInstrInfo.cpp - BPF Instruction Information ----------*- C++ -*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file contains the BPF implementation of the TargetInstrInfo class. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "BPFInstrInfo.h" | 
|  | #include "BPF.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  | #include "llvm/CodeGen/MachineBasicBlock.h" | 
|  | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | #include "llvm/IR/DebugLoc.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  | #include <cassert> | 
|  | #include <iterator> | 
|  |  | 
|  | #define GET_INSTRINFO_CTOR_DTOR | 
|  | #include "BPFGenInstrInfo.inc" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | BPFInstrInfo::BPFInstrInfo() | 
|  | : BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {} | 
|  |  | 
|  | void BPFInstrInfo::copyPhysReg(MachineBasicBlock &MBB, | 
|  | MachineBasicBlock::iterator I, | 
|  | const DebugLoc &DL, Register DestReg, | 
|  | Register SrcReg, bool KillSrc, | 
|  | bool RenamableDest, bool RenamableSrc) const { | 
|  | if (BPF::GPRRegClass.contains(DestReg, SrcReg)) | 
|  | BuildMI(MBB, I, DL, get(BPF::MOV_rr), DestReg) | 
|  | .addReg(SrcReg, getKillRegState(KillSrc)); | 
|  | else if (BPF::GPR32RegClass.contains(DestReg, SrcReg)) | 
|  | BuildMI(MBB, I, DL, get(BPF::MOV_rr_32), DestReg) | 
|  | .addReg(SrcReg, getKillRegState(KillSrc)); | 
|  | else | 
|  | llvm_unreachable("Impossible reg-to-reg copy"); | 
|  | } | 
|  |  | 
|  | void BPFInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const { | 
|  | Register DstReg = MI->getOperand(0).getReg(); | 
|  | Register SrcReg = MI->getOperand(1).getReg(); | 
|  | uint64_t CopyLen = MI->getOperand(2).getImm(); | 
|  | uint64_t Alignment = MI->getOperand(3).getImm(); | 
|  | Register ScratchReg = MI->getOperand(4).getReg(); | 
|  | MachineBasicBlock *BB = MI->getParent(); | 
|  | DebugLoc dl = MI->getDebugLoc(); | 
|  | unsigned LdOpc, StOpc; | 
|  |  | 
|  | switch (Alignment) { | 
|  | case 1: | 
|  | LdOpc = BPF::LDB; | 
|  | StOpc = BPF::STB; | 
|  | break; | 
|  | case 2: | 
|  | LdOpc = BPF::LDH; | 
|  | StOpc = BPF::STH; | 
|  | break; | 
|  | case 4: | 
|  | LdOpc = BPF::LDW; | 
|  | StOpc = BPF::STW; | 
|  | break; | 
|  | case 8: | 
|  | LdOpc = BPF::LDD; | 
|  | StOpc = BPF::STD; | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("unsupported memcpy alignment"); | 
|  | } | 
|  |  | 
|  | unsigned IterationNum = CopyLen >> Log2_64(Alignment); | 
|  | for(unsigned I = 0; I < IterationNum; ++I) { | 
|  | BuildMI(*BB, MI, dl, get(LdOpc)) | 
|  | .addReg(ScratchReg, RegState::Define).addReg(SrcReg) | 
|  | .addImm(I * Alignment); | 
|  | BuildMI(*BB, MI, dl, get(StOpc)) | 
|  | .addReg(ScratchReg, RegState::Kill).addReg(DstReg) | 
|  | .addImm(I * Alignment); | 
|  | } | 
|  |  | 
|  | unsigned BytesLeft = CopyLen & (Alignment - 1); | 
|  | unsigned Offset = IterationNum * Alignment; | 
|  | bool Hanging4Byte = BytesLeft & 0x4; | 
|  | bool Hanging2Byte = BytesLeft & 0x2; | 
|  | bool Hanging1Byte = BytesLeft & 0x1; | 
|  | if (Hanging4Byte) { | 
|  | BuildMI(*BB, MI, dl, get(BPF::LDW)) | 
|  | .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); | 
|  | BuildMI(*BB, MI, dl, get(BPF::STW)) | 
|  | .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); | 
|  | Offset += 4; | 
|  | } | 
|  | if (Hanging2Byte) { | 
|  | BuildMI(*BB, MI, dl, get(BPF::LDH)) | 
|  | .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); | 
|  | BuildMI(*BB, MI, dl, get(BPF::STH)) | 
|  | .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); | 
|  | Offset += 2; | 
|  | } | 
|  | if (Hanging1Byte) { | 
|  | BuildMI(*BB, MI, dl, get(BPF::LDB)) | 
|  | .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset); | 
|  | BuildMI(*BB, MI, dl, get(BPF::STB)) | 
|  | .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset); | 
|  | } | 
|  |  | 
|  | BB->erase(MI); | 
|  | } | 
|  |  | 
|  | bool BPFInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { | 
|  | if (MI.getOpcode() == BPF::MEMCPY) { | 
|  | expandMEMCPY(MI); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void BPFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, | 
|  | MachineBasicBlock::iterator I, | 
|  | Register SrcReg, bool IsKill, int FI, | 
|  | const TargetRegisterClass *RC, | 
|  | const TargetRegisterInfo *TRI, | 
|  | Register VReg, | 
|  | MachineInstr::MIFlag Flags) const { | 
|  | DebugLoc DL; | 
|  | if (I != MBB.end()) | 
|  | DL = I->getDebugLoc(); | 
|  |  | 
|  | if (RC == &BPF::GPRRegClass) | 
|  | BuildMI(MBB, I, DL, get(BPF::STD)) | 
|  | .addReg(SrcReg, getKillRegState(IsKill)) | 
|  | .addFrameIndex(FI) | 
|  | .addImm(0); | 
|  | else if (RC == &BPF::GPR32RegClass) | 
|  | BuildMI(MBB, I, DL, get(BPF::STW32)) | 
|  | .addReg(SrcReg, getKillRegState(IsKill)) | 
|  | .addFrameIndex(FI) | 
|  | .addImm(0); | 
|  | else | 
|  | llvm_unreachable("Can't store this register to stack slot"); | 
|  | } | 
|  |  | 
|  | void BPFInstrInfo::loadRegFromStackSlot( | 
|  | MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Register DestReg, | 
|  | int FI, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI, | 
|  | Register VReg, MachineInstr::MIFlag Flags) const { | 
|  | DebugLoc DL; | 
|  | if (I != MBB.end()) | 
|  | DL = I->getDebugLoc(); | 
|  |  | 
|  | if (RC == &BPF::GPRRegClass) | 
|  | BuildMI(MBB, I, DL, get(BPF::LDD), DestReg).addFrameIndex(FI).addImm(0); | 
|  | else if (RC == &BPF::GPR32RegClass) | 
|  | BuildMI(MBB, I, DL, get(BPF::LDW32), DestReg).addFrameIndex(FI).addImm(0); | 
|  | else | 
|  | llvm_unreachable("Can't load this register from stack slot"); | 
|  | } | 
|  |  | 
|  | bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB, | 
|  | MachineBasicBlock *&TBB, | 
|  | MachineBasicBlock *&FBB, | 
|  | SmallVectorImpl<MachineOperand> &Cond, | 
|  | bool AllowModify) const { | 
|  | // Start from the bottom of the block and work up, examining the | 
|  | // terminator instructions. | 
|  | MachineBasicBlock::iterator I = MBB.end(); | 
|  | while (I != MBB.begin()) { | 
|  | --I; | 
|  | if (I->isDebugInstr()) | 
|  | continue; | 
|  |  | 
|  | // Working from the bottom, when we see a non-terminator | 
|  | // instruction, we're done. | 
|  | if (!isUnpredicatedTerminator(*I)) | 
|  | break; | 
|  |  | 
|  | // A terminator that isn't a branch can't easily be handled | 
|  | // by this analysis. | 
|  | if (!I->isBranch()) | 
|  | return true; | 
|  |  | 
|  | // Handle unconditional branches. | 
|  | if (I->getOpcode() == BPF::JMP) { | 
|  | if (!AllowModify) { | 
|  | TBB = I->getOperand(0).getMBB(); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // If the block has any instructions after a J, delete them. | 
|  | MBB.erase(std::next(I), MBB.end()); | 
|  | Cond.clear(); | 
|  | FBB = nullptr; | 
|  |  | 
|  | // Delete the J if it's equivalent to a fall-through. | 
|  | if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { | 
|  | TBB = nullptr; | 
|  | I->eraseFromParent(); | 
|  | I = MBB.end(); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // TBB is used to indicate the unconditinal destination. | 
|  | TBB = I->getOperand(0).getMBB(); | 
|  | continue; | 
|  | } | 
|  | // Cannot handle conditional branches | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | unsigned BPFInstrInfo::insertBranch(MachineBasicBlock &MBB, | 
|  | MachineBasicBlock *TBB, | 
|  | MachineBasicBlock *FBB, | 
|  | ArrayRef<MachineOperand> Cond, | 
|  | const DebugLoc &DL, | 
|  | int *BytesAdded) const { | 
|  | assert(!BytesAdded && "code size not handled"); | 
|  |  | 
|  | // Shouldn't be a fall through. | 
|  | assert(TBB && "insertBranch must not be told to insert a fallthrough"); | 
|  |  | 
|  | if (Cond.empty()) { | 
|  | // Unconditional branch | 
|  | assert(!FBB && "Unconditional branch with multiple successors!"); | 
|  | BuildMI(&MBB, DL, get(BPF::JMP)).addMBB(TBB); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | llvm_unreachable("Unexpected conditional branch"); | 
|  | } | 
|  |  | 
|  | unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB, | 
|  | int *BytesRemoved) const { | 
|  | assert(!BytesRemoved && "code size not handled"); | 
|  |  | 
|  | MachineBasicBlock::iterator I = MBB.end(); | 
|  | unsigned Count = 0; | 
|  |  | 
|  | while (I != MBB.begin()) { | 
|  | --I; | 
|  | if (I->isDebugInstr()) | 
|  | continue; | 
|  | if (I->getOpcode() != BPF::JMP) | 
|  | break; | 
|  | // Remove the branch. | 
|  | I->eraseFromParent(); | 
|  | I = MBB.end(); | 
|  | ++Count; | 
|  | } | 
|  |  | 
|  | return Count; | 
|  | } |