| //===-- 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; | 
 | } |