xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/BPFInstrInfo.cpp (revision 8bcb0991864975618c09697b1aca10683346d9f0)
10b57cec5SDimitry Andric //===-- BPFInstrInfo.cpp - BPF Instruction Information ----------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains the BPF implementation of the TargetInstrInfo class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "BPFInstrInfo.h"
140b57cec5SDimitry Andric #include "BPF.h"
150b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
180b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
190b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
200b57cec5SDimitry Andric #include <cassert>
210b57cec5SDimitry Andric #include <iterator>
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR
240b57cec5SDimitry Andric #include "BPFGenInstrInfo.inc"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric using namespace llvm;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric BPFInstrInfo::BPFInstrInfo()
290b57cec5SDimitry Andric     : BPFGenInstrInfo(BPF::ADJCALLSTACKDOWN, BPF::ADJCALLSTACKUP) {}
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric void BPFInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
320b57cec5SDimitry Andric                                MachineBasicBlock::iterator I,
330b57cec5SDimitry Andric                                const DebugLoc &DL, unsigned DestReg,
340b57cec5SDimitry Andric                                unsigned SrcReg, bool KillSrc) const {
350b57cec5SDimitry Andric   if (BPF::GPRRegClass.contains(DestReg, SrcReg))
360b57cec5SDimitry Andric     BuildMI(MBB, I, DL, get(BPF::MOV_rr), DestReg)
370b57cec5SDimitry Andric         .addReg(SrcReg, getKillRegState(KillSrc));
380b57cec5SDimitry Andric   else if (BPF::GPR32RegClass.contains(DestReg, SrcReg))
390b57cec5SDimitry Andric     BuildMI(MBB, I, DL, get(BPF::MOV_rr_32), DestReg)
400b57cec5SDimitry Andric         .addReg(SrcReg, getKillRegState(KillSrc));
410b57cec5SDimitry Andric   else
420b57cec5SDimitry Andric     llvm_unreachable("Impossible reg-to-reg copy");
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric void BPFInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const {
46*8bcb0991SDimitry Andric   Register DstReg = MI->getOperand(0).getReg();
47*8bcb0991SDimitry Andric   Register SrcReg = MI->getOperand(1).getReg();
480b57cec5SDimitry Andric   uint64_t CopyLen = MI->getOperand(2).getImm();
490b57cec5SDimitry Andric   uint64_t Alignment = MI->getOperand(3).getImm();
50*8bcb0991SDimitry Andric   Register ScratchReg = MI->getOperand(4).getReg();
510b57cec5SDimitry Andric   MachineBasicBlock *BB = MI->getParent();
520b57cec5SDimitry Andric   DebugLoc dl = MI->getDebugLoc();
530b57cec5SDimitry Andric   unsigned LdOpc, StOpc;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   switch (Alignment) {
560b57cec5SDimitry Andric   case 1:
570b57cec5SDimitry Andric     LdOpc = BPF::LDB;
580b57cec5SDimitry Andric     StOpc = BPF::STB;
590b57cec5SDimitry Andric     break;
600b57cec5SDimitry Andric   case 2:
610b57cec5SDimitry Andric     LdOpc = BPF::LDH;
620b57cec5SDimitry Andric     StOpc = BPF::STH;
630b57cec5SDimitry Andric     break;
640b57cec5SDimitry Andric   case 4:
650b57cec5SDimitry Andric     LdOpc = BPF::LDW;
660b57cec5SDimitry Andric     StOpc = BPF::STW;
670b57cec5SDimitry Andric     break;
680b57cec5SDimitry Andric   case 8:
690b57cec5SDimitry Andric     LdOpc = BPF::LDD;
700b57cec5SDimitry Andric     StOpc = BPF::STD;
710b57cec5SDimitry Andric     break;
720b57cec5SDimitry Andric   default:
730b57cec5SDimitry Andric     llvm_unreachable("unsupported memcpy alignment");
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   unsigned IterationNum = CopyLen >> Log2_64(Alignment);
770b57cec5SDimitry Andric   for(unsigned I = 0; I < IterationNum; ++I) {
780b57cec5SDimitry Andric     BuildMI(*BB, MI, dl, get(LdOpc))
790b57cec5SDimitry Andric             .addReg(ScratchReg, RegState::Define).addReg(SrcReg)
800b57cec5SDimitry Andric             .addImm(I * Alignment);
810b57cec5SDimitry Andric     BuildMI(*BB, MI, dl, get(StOpc))
820b57cec5SDimitry Andric             .addReg(ScratchReg, RegState::Kill).addReg(DstReg)
830b57cec5SDimitry Andric             .addImm(I * Alignment);
840b57cec5SDimitry Andric   }
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   unsigned BytesLeft = CopyLen & (Alignment - 1);
870b57cec5SDimitry Andric   unsigned Offset = IterationNum * Alignment;
880b57cec5SDimitry Andric   bool Hanging4Byte = BytesLeft & 0x4;
890b57cec5SDimitry Andric   bool Hanging2Byte = BytesLeft & 0x2;
900b57cec5SDimitry Andric   bool Hanging1Byte = BytesLeft & 0x1;
910b57cec5SDimitry Andric   if (Hanging4Byte) {
920b57cec5SDimitry Andric     BuildMI(*BB, MI, dl, get(BPF::LDW))
930b57cec5SDimitry Andric             .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);
940b57cec5SDimitry Andric     BuildMI(*BB, MI, dl, get(BPF::STW))
950b57cec5SDimitry Andric             .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);
960b57cec5SDimitry Andric     Offset += 4;
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric   if (Hanging2Byte) {
990b57cec5SDimitry Andric     BuildMI(*BB, MI, dl, get(BPF::LDH))
1000b57cec5SDimitry Andric             .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);
1010b57cec5SDimitry Andric     BuildMI(*BB, MI, dl, get(BPF::STH))
1020b57cec5SDimitry Andric             .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);
1030b57cec5SDimitry Andric     Offset += 2;
1040b57cec5SDimitry Andric   }
1050b57cec5SDimitry Andric   if (Hanging1Byte) {
1060b57cec5SDimitry Andric     BuildMI(*BB, MI, dl, get(BPF::LDB))
1070b57cec5SDimitry Andric             .addReg(ScratchReg, RegState::Define).addReg(SrcReg).addImm(Offset);
1080b57cec5SDimitry Andric     BuildMI(*BB, MI, dl, get(BPF::STB))
1090b57cec5SDimitry Andric             .addReg(ScratchReg, RegState::Kill).addReg(DstReg).addImm(Offset);
1100b57cec5SDimitry Andric   }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   BB->erase(MI);
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric bool BPFInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
1160b57cec5SDimitry Andric   if (MI.getOpcode() == BPF::MEMCPY) {
1170b57cec5SDimitry Andric     expandMEMCPY(MI);
1180b57cec5SDimitry Andric     return true;
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   return false;
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric void BPFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
1250b57cec5SDimitry Andric                                        MachineBasicBlock::iterator I,
1260b57cec5SDimitry Andric                                        unsigned SrcReg, bool IsKill, int FI,
1270b57cec5SDimitry Andric                                        const TargetRegisterClass *RC,
1280b57cec5SDimitry Andric                                        const TargetRegisterInfo *TRI) const {
1290b57cec5SDimitry Andric   DebugLoc DL;
1300b57cec5SDimitry Andric   if (I != MBB.end())
1310b57cec5SDimitry Andric     DL = I->getDebugLoc();
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric   if (RC == &BPF::GPRRegClass)
1340b57cec5SDimitry Andric     BuildMI(MBB, I, DL, get(BPF::STD))
1350b57cec5SDimitry Andric         .addReg(SrcReg, getKillRegState(IsKill))
1360b57cec5SDimitry Andric         .addFrameIndex(FI)
1370b57cec5SDimitry Andric         .addImm(0);
1380b57cec5SDimitry Andric   else if (RC == &BPF::GPR32RegClass)
1390b57cec5SDimitry Andric     BuildMI(MBB, I, DL, get(BPF::STW32))
1400b57cec5SDimitry Andric         .addReg(SrcReg, getKillRegState(IsKill))
1410b57cec5SDimitry Andric         .addFrameIndex(FI)
1420b57cec5SDimitry Andric         .addImm(0);
1430b57cec5SDimitry Andric   else
1440b57cec5SDimitry Andric     llvm_unreachable("Can't store this register to stack slot");
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric void BPFInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
1480b57cec5SDimitry Andric                                         MachineBasicBlock::iterator I,
1490b57cec5SDimitry Andric                                         unsigned DestReg, int FI,
1500b57cec5SDimitry Andric                                         const TargetRegisterClass *RC,
1510b57cec5SDimitry Andric                                         const TargetRegisterInfo *TRI) const {
1520b57cec5SDimitry Andric   DebugLoc DL;
1530b57cec5SDimitry Andric   if (I != MBB.end())
1540b57cec5SDimitry Andric     DL = I->getDebugLoc();
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   if (RC == &BPF::GPRRegClass)
1570b57cec5SDimitry Andric     BuildMI(MBB, I, DL, get(BPF::LDD), DestReg).addFrameIndex(FI).addImm(0);
1580b57cec5SDimitry Andric   else if (RC == &BPF::GPR32RegClass)
1590b57cec5SDimitry Andric     BuildMI(MBB, I, DL, get(BPF::LDW32), DestReg).addFrameIndex(FI).addImm(0);
1600b57cec5SDimitry Andric   else
1610b57cec5SDimitry Andric     llvm_unreachable("Can't load this register from stack slot");
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric bool BPFInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
1650b57cec5SDimitry Andric                                  MachineBasicBlock *&TBB,
1660b57cec5SDimitry Andric                                  MachineBasicBlock *&FBB,
1670b57cec5SDimitry Andric                                  SmallVectorImpl<MachineOperand> &Cond,
1680b57cec5SDimitry Andric                                  bool AllowModify) const {
1690b57cec5SDimitry Andric   // Start from the bottom of the block and work up, examining the
1700b57cec5SDimitry Andric   // terminator instructions.
1710b57cec5SDimitry Andric   MachineBasicBlock::iterator I = MBB.end();
1720b57cec5SDimitry Andric   while (I != MBB.begin()) {
1730b57cec5SDimitry Andric     --I;
1740b57cec5SDimitry Andric     if (I->isDebugInstr())
1750b57cec5SDimitry Andric       continue;
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric     // Working from the bottom, when we see a non-terminator
1780b57cec5SDimitry Andric     // instruction, we're done.
1790b57cec5SDimitry Andric     if (!isUnpredicatedTerminator(*I))
1800b57cec5SDimitry Andric       break;
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric     // A terminator that isn't a branch can't easily be handled
1830b57cec5SDimitry Andric     // by this analysis.
1840b57cec5SDimitry Andric     if (!I->isBranch())
1850b57cec5SDimitry Andric       return true;
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric     // Handle unconditional branches.
1880b57cec5SDimitry Andric     if (I->getOpcode() == BPF::JMP) {
1890b57cec5SDimitry Andric       if (!AllowModify) {
1900b57cec5SDimitry Andric         TBB = I->getOperand(0).getMBB();
1910b57cec5SDimitry Andric         continue;
1920b57cec5SDimitry Andric       }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric       // If the block has any instructions after a J, delete them.
1950b57cec5SDimitry Andric       while (std::next(I) != MBB.end())
1960b57cec5SDimitry Andric         std::next(I)->eraseFromParent();
1970b57cec5SDimitry Andric       Cond.clear();
1980b57cec5SDimitry Andric       FBB = nullptr;
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric       // Delete the J if it's equivalent to a fall-through.
2010b57cec5SDimitry Andric       if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) {
2020b57cec5SDimitry Andric         TBB = nullptr;
2030b57cec5SDimitry Andric         I->eraseFromParent();
2040b57cec5SDimitry Andric         I = MBB.end();
2050b57cec5SDimitry Andric         continue;
2060b57cec5SDimitry Andric       }
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric       // TBB is used to indicate the unconditinal destination.
2090b57cec5SDimitry Andric       TBB = I->getOperand(0).getMBB();
2100b57cec5SDimitry Andric       continue;
2110b57cec5SDimitry Andric     }
2120b57cec5SDimitry Andric     // Cannot handle conditional branches
2130b57cec5SDimitry Andric     return true;
2140b57cec5SDimitry Andric   }
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric   return false;
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric unsigned BPFInstrInfo::insertBranch(MachineBasicBlock &MBB,
2200b57cec5SDimitry Andric                                     MachineBasicBlock *TBB,
2210b57cec5SDimitry Andric                                     MachineBasicBlock *FBB,
2220b57cec5SDimitry Andric                                     ArrayRef<MachineOperand> Cond,
2230b57cec5SDimitry Andric                                     const DebugLoc &DL,
2240b57cec5SDimitry Andric                                     int *BytesAdded) const {
2250b57cec5SDimitry Andric   assert(!BytesAdded && "code size not handled");
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric   // Shouldn't be a fall through.
2280b57cec5SDimitry Andric   assert(TBB && "insertBranch must not be told to insert a fallthrough");
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   if (Cond.empty()) {
2310b57cec5SDimitry Andric     // Unconditional branch
2320b57cec5SDimitry Andric     assert(!FBB && "Unconditional branch with multiple successors!");
2330b57cec5SDimitry Andric     BuildMI(&MBB, DL, get(BPF::JMP)).addMBB(TBB);
2340b57cec5SDimitry Andric     return 1;
2350b57cec5SDimitry Andric   }
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   llvm_unreachable("Unexpected conditional branch");
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric unsigned BPFInstrInfo::removeBranch(MachineBasicBlock &MBB,
2410b57cec5SDimitry Andric                                     int *BytesRemoved) const {
2420b57cec5SDimitry Andric   assert(!BytesRemoved && "code size not handled");
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   MachineBasicBlock::iterator I = MBB.end();
2450b57cec5SDimitry Andric   unsigned Count = 0;
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric   while (I != MBB.begin()) {
2480b57cec5SDimitry Andric     --I;
2490b57cec5SDimitry Andric     if (I->isDebugInstr())
2500b57cec5SDimitry Andric       continue;
2510b57cec5SDimitry Andric     if (I->getOpcode() != BPF::JMP)
2520b57cec5SDimitry Andric       break;
2530b57cec5SDimitry Andric     // Remove the branch.
2540b57cec5SDimitry Andric     I->eraseFromParent();
2550b57cec5SDimitry Andric     I = MBB.end();
2560b57cec5SDimitry Andric     ++Count;
2570b57cec5SDimitry Andric   }
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric   return Count;
2600b57cec5SDimitry Andric }
261