diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.cpp | 260 | 
1 files changed, 260 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.cpp b/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.cpp new file mode 100644 index 000000000000..54360a89782b --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.cpp @@ -0,0 +1,260 @@ +//===-- 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, MCRegister DestReg, +                               MCRegister SrcReg, bool KillSrc) 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) 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) 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. +      while (std::next(I) != MBB.end()) +        std::next(I)->eraseFromParent(); +      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; +}  | 
