aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.cpp260
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;
+}