xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- BPFISelDAGToDAG.cpp - A dag to dag inst selector for BPF ----------===//
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 defines a DAG pattern matching instruction selector for BPF,
100b57cec5SDimitry Andric // converting from a legalized dag to a BPF dag.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "BPF.h"
150b57cec5SDimitry Andric #include "BPFRegisterInfo.h"
160b57cec5SDimitry Andric #include "BPFSubtarget.h"
170b57cec5SDimitry Andric #include "BPFTargetMachine.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/FunctionLoweringInfo.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h"
250b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
260b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
27480093f4SDimitry Andric #include "llvm/IR/IntrinsicsBPF.h"
280b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
290b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
300b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
310b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
320b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric using namespace llvm;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric #define DEBUG_TYPE "bpf-isel"
37bdd1243dSDimitry Andric #define PASS_NAME "BPF DAG->DAG Pattern Instruction Selection"
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric // Instruction Selector Implementation
400b57cec5SDimitry Andric namespace {
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric class BPFDAGToDAGISel : public SelectionDAGISel {
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   /// Subtarget - Keep a pointer to the BPFSubtarget around so that we can
450b57cec5SDimitry Andric   /// make the right decision when generating code for different subtargets.
460b57cec5SDimitry Andric   const BPFSubtarget *Subtarget;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric public:
49bdd1243dSDimitry Andric   BPFDAGToDAGISel() = delete;
50bdd1243dSDimitry Andric 
BPFDAGToDAGISel(BPFTargetMachine & TM)51bdd1243dSDimitry Andric   explicit BPFDAGToDAGISel(BPFTargetMachine &TM)
52*0fca6ea1SDimitry Andric       : SelectionDAGISel(TM), Subtarget(nullptr) {}
530b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)540b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override {
550b57cec5SDimitry Andric     // Reset the subtarget each time through.
560b57cec5SDimitry Andric     Subtarget = &MF.getSubtarget<BPFSubtarget>();
570b57cec5SDimitry Andric     return SelectionDAGISel::runOnMachineFunction(MF);
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   void PreprocessISelDAG() override;
610b57cec5SDimitry Andric 
625f757f3fSDimitry Andric   bool SelectInlineAsmMemoryOperand(const SDValue &Op,
635f757f3fSDimitry Andric                                     InlineAsm::ConstraintCode ConstraintCode,
640b57cec5SDimitry Andric                                     std::vector<SDValue> &OutOps) override;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric private:
670b57cec5SDimitry Andric // Include the pieces autogenerated from the target description.
680b57cec5SDimitry Andric #include "BPFGenDAGISel.inc"
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   void Select(SDNode *N) override;
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   // Complex Pattern for address selection.
730b57cec5SDimitry Andric   bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
740b57cec5SDimitry Andric   bool SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   // Node preprocessing cases
770b57cec5SDimitry Andric   void PreprocessLoad(SDNode *Node, SelectionDAG::allnodes_iterator &I);
780b57cec5SDimitry Andric   void PreprocessTrunc(SDNode *Node, SelectionDAG::allnodes_iterator &I);
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   // Find constants from a constant structure
810b57cec5SDimitry Andric   typedef std::vector<unsigned char> val_vec_type;
820b57cec5SDimitry Andric   bool fillGenericConstant(const DataLayout &DL, const Constant *CV,
830b57cec5SDimitry Andric                            val_vec_type &Vals, uint64_t Offset);
840b57cec5SDimitry Andric   bool fillConstantDataArray(const DataLayout &DL, const ConstantDataArray *CDA,
850b57cec5SDimitry Andric                              val_vec_type &Vals, int Offset);
860b57cec5SDimitry Andric   bool fillConstantArray(const DataLayout &DL, const ConstantArray *CA,
870b57cec5SDimitry Andric                          val_vec_type &Vals, int Offset);
880b57cec5SDimitry Andric   bool fillConstantStruct(const DataLayout &DL, const ConstantStruct *CS,
890b57cec5SDimitry Andric                           val_vec_type &Vals, int Offset);
900b57cec5SDimitry Andric   bool getConstantFieldValue(const GlobalAddressSDNode *Node, uint64_t Offset,
910b57cec5SDimitry Andric                              uint64_t Size, unsigned char *ByteSeq);
920b57cec5SDimitry Andric   // Mapping from ConstantStruct global value to corresponding byte-list values
930b57cec5SDimitry Andric   std::map<const void *, val_vec_type> cs_vals_;
940b57cec5SDimitry Andric };
95*0fca6ea1SDimitry Andric 
96*0fca6ea1SDimitry Andric class BPFDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
97*0fca6ea1SDimitry Andric public:
98*0fca6ea1SDimitry Andric   static char ID;
BPFDAGToDAGISelLegacy(BPFTargetMachine & TM)99*0fca6ea1SDimitry Andric   BPFDAGToDAGISelLegacy(BPFTargetMachine &TM)
100*0fca6ea1SDimitry Andric       : SelectionDAGISelLegacy(ID, std::make_unique<BPFDAGToDAGISel>(TM)) {}
101*0fca6ea1SDimitry Andric };
1020b57cec5SDimitry Andric } // namespace
1030b57cec5SDimitry Andric 
104*0fca6ea1SDimitry Andric char BPFDAGToDAGISelLegacy::ID = 0;
105bdd1243dSDimitry Andric 
INITIALIZE_PASS(BPFDAGToDAGISelLegacy,DEBUG_TYPE,PASS_NAME,false,false)106*0fca6ea1SDimitry Andric INITIALIZE_PASS(BPFDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
107bdd1243dSDimitry Andric 
1080b57cec5SDimitry Andric // ComplexPattern used on BPF Load/Store instructions
1090b57cec5SDimitry Andric bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) {
1100b57cec5SDimitry Andric   // if Address is FI, get the TargetFrameIndex.
1110b57cec5SDimitry Andric   SDLoc DL(Addr);
112fe6060f1SDimitry Andric   if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
1130b57cec5SDimitry Andric     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
1140b57cec5SDimitry Andric     Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
1150b57cec5SDimitry Andric     return true;
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
1190b57cec5SDimitry Andric       Addr.getOpcode() == ISD::TargetGlobalAddress)
1200b57cec5SDimitry Andric     return false;
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   // Addresses of the form Addr+const or Addr|const
1230b57cec5SDimitry Andric   if (CurDAG->isBaseWithConstantOffset(Addr)) {
124fe6060f1SDimitry Andric     auto *CN = cast<ConstantSDNode>(Addr.getOperand(1));
1250b57cec5SDimitry Andric     if (isInt<16>(CN->getSExtValue())) {
1260b57cec5SDimitry Andric       // If the first operand is a FI, get the TargetFI Node
127fe6060f1SDimitry Andric       if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
1280b57cec5SDimitry Andric         Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
1290b57cec5SDimitry Andric       else
1300b57cec5SDimitry Andric         Base = Addr.getOperand(0);
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric       Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64);
1330b57cec5SDimitry Andric       return true;
1340b57cec5SDimitry Andric     }
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   Base = Addr;
1380b57cec5SDimitry Andric   Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
1390b57cec5SDimitry Andric   return true;
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric // ComplexPattern used on BPF FI instruction
SelectFIAddr(SDValue Addr,SDValue & Base,SDValue & Offset)1430b57cec5SDimitry Andric bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base,
1440b57cec5SDimitry Andric                                    SDValue &Offset) {
1450b57cec5SDimitry Andric   SDLoc DL(Addr);
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   if (!CurDAG->isBaseWithConstantOffset(Addr))
1480b57cec5SDimitry Andric     return false;
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   // Addresses of the form Addr+const or Addr|const
151fe6060f1SDimitry Andric   auto *CN = cast<ConstantSDNode>(Addr.getOperand(1));
1520b57cec5SDimitry Andric   if (isInt<16>(CN->getSExtValue())) {
1530b57cec5SDimitry Andric     // If the first operand is a FI, get the TargetFI Node
154fe6060f1SDimitry Andric     if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
1550b57cec5SDimitry Andric       Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
1560b57cec5SDimitry Andric     else
1570b57cec5SDimitry Andric       return false;
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric     Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64);
1600b57cec5SDimitry Andric     return true;
1610b57cec5SDimitry Andric   }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   return false;
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
SelectInlineAsmMemoryOperand(const SDValue & Op,InlineAsm::ConstraintCode ConstraintCode,std::vector<SDValue> & OutOps)1660b57cec5SDimitry Andric bool BPFDAGToDAGISel::SelectInlineAsmMemoryOperand(
1675f757f3fSDimitry Andric     const SDValue &Op, InlineAsm::ConstraintCode ConstraintCode,
1685f757f3fSDimitry Andric     std::vector<SDValue> &OutOps) {
1690b57cec5SDimitry Andric   SDValue Op0, Op1;
1700b57cec5SDimitry Andric   switch (ConstraintCode) {
1710b57cec5SDimitry Andric   default:
1720b57cec5SDimitry Andric     return true;
1735f757f3fSDimitry Andric   case InlineAsm::ConstraintCode::m: // memory
1740b57cec5SDimitry Andric     if (!SelectAddr(Op, Op0, Op1))
1750b57cec5SDimitry Andric       return true;
1760b57cec5SDimitry Andric     break;
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric   SDLoc DL(Op);
18006c3fb27SDimitry Andric   SDValue AluOp = CurDAG->getTargetConstant(ISD::ADD, DL, MVT::i32);
1810b57cec5SDimitry Andric   OutOps.push_back(Op0);
1820b57cec5SDimitry Andric   OutOps.push_back(Op1);
1830b57cec5SDimitry Andric   OutOps.push_back(AluOp);
1840b57cec5SDimitry Andric   return false;
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric 
Select(SDNode * Node)1870b57cec5SDimitry Andric void BPFDAGToDAGISel::Select(SDNode *Node) {
1880b57cec5SDimitry Andric   unsigned Opcode = Node->getOpcode();
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   // If we have a custom node, we already have selected!
1910b57cec5SDimitry Andric   if (Node->isMachineOpcode()) {
1920b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
1930b57cec5SDimitry Andric     return;
1940b57cec5SDimitry Andric   }
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   // tablegen selection should be handled here.
1970b57cec5SDimitry Andric   switch (Opcode) {
1980b57cec5SDimitry Andric   default:
1990b57cec5SDimitry Andric     break;
2000b57cec5SDimitry Andric   case ISD::INTRINSIC_W_CHAIN: {
201647cbc5dSDimitry Andric     unsigned IntNo = Node->getConstantOperandVal(1);
2020b57cec5SDimitry Andric     switch (IntNo) {
2030b57cec5SDimitry Andric     case Intrinsic::bpf_load_byte:
2040b57cec5SDimitry Andric     case Intrinsic::bpf_load_half:
2050b57cec5SDimitry Andric     case Intrinsic::bpf_load_word: {
2060b57cec5SDimitry Andric       SDLoc DL(Node);
2070b57cec5SDimitry Andric       SDValue Chain = Node->getOperand(0);
2080b57cec5SDimitry Andric       SDValue N1 = Node->getOperand(1);
2090b57cec5SDimitry Andric       SDValue Skb = Node->getOperand(2);
2100b57cec5SDimitry Andric       SDValue N3 = Node->getOperand(3);
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric       SDValue R6Reg = CurDAG->getRegister(BPF::R6, MVT::i64);
2130b57cec5SDimitry Andric       Chain = CurDAG->getCopyToReg(Chain, DL, R6Reg, Skb, SDValue());
2140b57cec5SDimitry Andric       Node = CurDAG->UpdateNodeOperands(Node, Chain, N1, R6Reg, N3);
2150b57cec5SDimitry Andric       break;
2160b57cec5SDimitry Andric     }
2170b57cec5SDimitry Andric     }
2180b57cec5SDimitry Andric     break;
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   case ISD::FrameIndex: {
2220b57cec5SDimitry Andric     int FI = cast<FrameIndexSDNode>(Node)->getIndex();
2230b57cec5SDimitry Andric     EVT VT = Node->getValueType(0);
2240b57cec5SDimitry Andric     SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
2250b57cec5SDimitry Andric     unsigned Opc = BPF::MOV_rr;
2260b57cec5SDimitry Andric     if (Node->hasOneUse()) {
2270b57cec5SDimitry Andric       CurDAG->SelectNodeTo(Node, Opc, VT, TFI);
2280b57cec5SDimitry Andric       return;
2290b57cec5SDimitry Andric     }
2300b57cec5SDimitry Andric     ReplaceNode(Node, CurDAG->getMachineNode(Opc, SDLoc(Node), VT, TFI));
2310b57cec5SDimitry Andric     return;
2320b57cec5SDimitry Andric   }
2330b57cec5SDimitry Andric   }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   // Select the default instruction
2360b57cec5SDimitry Andric   SelectCode(Node);
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric 
PreprocessLoad(SDNode * Node,SelectionDAG::allnodes_iterator & I)2390b57cec5SDimitry Andric void BPFDAGToDAGISel::PreprocessLoad(SDNode *Node,
2400b57cec5SDimitry Andric                                      SelectionDAG::allnodes_iterator &I) {
2410b57cec5SDimitry Andric   union {
2420b57cec5SDimitry Andric     uint8_t c[8];
2430b57cec5SDimitry Andric     uint16_t s;
2440b57cec5SDimitry Andric     uint32_t i;
2450b57cec5SDimitry Andric     uint64_t d;
2460b57cec5SDimitry Andric   } new_val; // hold up the constant values replacing loads.
2470b57cec5SDimitry Andric   bool to_replace = false;
2480b57cec5SDimitry Andric   SDLoc DL(Node);
2490b57cec5SDimitry Andric   const LoadSDNode *LD = cast<LoadSDNode>(Node);
250*0fca6ea1SDimitry Andric   if (!LD->getMemOperand()->getSize().hasValue())
251*0fca6ea1SDimitry Andric     return;
252*0fca6ea1SDimitry Andric   uint64_t size = LD->getMemOperand()->getSize().getValue();
2530b57cec5SDimitry Andric 
254eaeb601bSDimitry Andric   if (!size || size > 8 || (size & (size - 1)) || !LD->isSimple())
2550b57cec5SDimitry Andric     return;
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   SDNode *LDAddrNode = LD->getOperand(1).getNode();
2580b57cec5SDimitry Andric   // Match LDAddr against either global_addr or (global_addr + offset)
2590b57cec5SDimitry Andric   unsigned opcode = LDAddrNode->getOpcode();
2600b57cec5SDimitry Andric   if (opcode == ISD::ADD) {
2610b57cec5SDimitry Andric     SDValue OP1 = LDAddrNode->getOperand(0);
2620b57cec5SDimitry Andric     SDValue OP2 = LDAddrNode->getOperand(1);
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric     // We want to find the pattern global_addr + offset
2650b57cec5SDimitry Andric     SDNode *OP1N = OP1.getNode();
2660b57cec5SDimitry Andric     if (OP1N->getOpcode() <= ISD::BUILTIN_OP_END || OP1N->getNumOperands() == 0)
2670b57cec5SDimitry Andric       return;
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n');
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric     const GlobalAddressSDNode *GADN =
2720b57cec5SDimitry Andric         dyn_cast<GlobalAddressSDNode>(OP1N->getOperand(0).getNode());
2730b57cec5SDimitry Andric     const ConstantSDNode *CDN = dyn_cast<ConstantSDNode>(OP2.getNode());
2740b57cec5SDimitry Andric     if (GADN && CDN)
2750b57cec5SDimitry Andric       to_replace =
2760b57cec5SDimitry Andric           getConstantFieldValue(GADN, CDN->getZExtValue(), size, new_val.c);
2770b57cec5SDimitry Andric   } else if (LDAddrNode->getOpcode() > ISD::BUILTIN_OP_END &&
2780b57cec5SDimitry Andric              LDAddrNode->getNumOperands() > 0) {
2790b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n');
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric     SDValue OP1 = LDAddrNode->getOperand(0);
2820b57cec5SDimitry Andric     if (const GlobalAddressSDNode *GADN =
2830b57cec5SDimitry Andric             dyn_cast<GlobalAddressSDNode>(OP1.getNode()))
2840b57cec5SDimitry Andric       to_replace = getConstantFieldValue(GADN, 0, size, new_val.c);
2850b57cec5SDimitry Andric   }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric   if (!to_replace)
2880b57cec5SDimitry Andric     return;
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric   // replacing the old with a new value
2910b57cec5SDimitry Andric   uint64_t val;
2920b57cec5SDimitry Andric   if (size == 1)
2930b57cec5SDimitry Andric     val = new_val.c[0];
2940b57cec5SDimitry Andric   else if (size == 2)
2950b57cec5SDimitry Andric     val = new_val.s;
2960b57cec5SDimitry Andric   else if (size == 4)
2970b57cec5SDimitry Andric     val = new_val.i;
2980b57cec5SDimitry Andric   else {
2990b57cec5SDimitry Andric     val = new_val.d;
3000b57cec5SDimitry Andric   }
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Replacing load of size " << size << " with constant "
3030b57cec5SDimitry Andric                     << val << '\n');
3040946e70aSDimitry Andric   SDValue NVal = CurDAG->getConstant(val, DL, LD->getValueType(0));
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric   // After replacement, the current node is dead, we need to
3070b57cec5SDimitry Andric   // go backward one step to make iterator still work
3080b57cec5SDimitry Andric   I--;
3090b57cec5SDimitry Andric   SDValue From[] = {SDValue(Node, 0), SDValue(Node, 1)};
3100b57cec5SDimitry Andric   SDValue To[] = {NVal, NVal};
3110b57cec5SDimitry Andric   CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2);
3120b57cec5SDimitry Andric   I++;
3130b57cec5SDimitry Andric   // It is safe to delete node now
3140b57cec5SDimitry Andric   CurDAG->DeleteNode(Node);
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric 
PreprocessISelDAG()3170b57cec5SDimitry Andric void BPFDAGToDAGISel::PreprocessISelDAG() {
3188bcb0991SDimitry Andric   // Iterate through all nodes, interested in the following case:
3190b57cec5SDimitry Andric   //
3200b57cec5SDimitry Andric   //  . loads from ConstantStruct or ConstantArray of constructs
3210b57cec5SDimitry Andric   //    which can be turns into constant itself, with this we can
3220b57cec5SDimitry Andric   //    avoid reading from read-only section at runtime.
3230b57cec5SDimitry Andric   //
3248bcb0991SDimitry Andric   //  . Removing redundant AND for intrinsic narrow loads.
3250b57cec5SDimitry Andric   for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(),
3260b57cec5SDimitry Andric                                        E = CurDAG->allnodes_end();
3270b57cec5SDimitry Andric        I != E;) {
3280b57cec5SDimitry Andric     SDNode *Node = &*I++;
3290b57cec5SDimitry Andric     unsigned Opcode = Node->getOpcode();
3300b57cec5SDimitry Andric     if (Opcode == ISD::LOAD)
3310b57cec5SDimitry Andric       PreprocessLoad(Node, I);
3320b57cec5SDimitry Andric     else if (Opcode == ISD::AND)
3330b57cec5SDimitry Andric       PreprocessTrunc(Node, I);
3340b57cec5SDimitry Andric   }
3350b57cec5SDimitry Andric }
3360b57cec5SDimitry Andric 
getConstantFieldValue(const GlobalAddressSDNode * Node,uint64_t Offset,uint64_t Size,unsigned char * ByteSeq)3370b57cec5SDimitry Andric bool BPFDAGToDAGISel::getConstantFieldValue(const GlobalAddressSDNode *Node,
3380b57cec5SDimitry Andric                                             uint64_t Offset, uint64_t Size,
3390b57cec5SDimitry Andric                                             unsigned char *ByteSeq) {
3400b57cec5SDimitry Andric   const GlobalVariable *V = dyn_cast<GlobalVariable>(Node->getGlobal());
3410b57cec5SDimitry Andric 
342eaeb601bSDimitry Andric   if (!V || !V->hasInitializer() || !V->isConstant())
3430b57cec5SDimitry Andric     return false;
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   const Constant *Init = V->getInitializer();
3460b57cec5SDimitry Andric   const DataLayout &DL = CurDAG->getDataLayout();
3470b57cec5SDimitry Andric   val_vec_type TmpVal;
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric   auto it = cs_vals_.find(static_cast<const void *>(Init));
3500b57cec5SDimitry Andric   if (it != cs_vals_.end()) {
3510b57cec5SDimitry Andric     TmpVal = it->second;
3520b57cec5SDimitry Andric   } else {
3530b57cec5SDimitry Andric     uint64_t total_size = 0;
3540b57cec5SDimitry Andric     if (const ConstantStruct *CS = dyn_cast<ConstantStruct>(Init))
3550b57cec5SDimitry Andric       total_size =
3560b57cec5SDimitry Andric           DL.getStructLayout(cast<StructType>(CS->getType()))->getSizeInBytes();
3570b57cec5SDimitry Andric     else if (const ConstantArray *CA = dyn_cast<ConstantArray>(Init))
3580b57cec5SDimitry Andric       total_size = DL.getTypeAllocSize(CA->getType()->getElementType()) *
3590b57cec5SDimitry Andric                    CA->getNumOperands();
3600b57cec5SDimitry Andric     else
3610b57cec5SDimitry Andric       return false;
3620b57cec5SDimitry Andric 
3630b57cec5SDimitry Andric     val_vec_type Vals(total_size, 0);
3640b57cec5SDimitry Andric     if (fillGenericConstant(DL, Init, Vals, 0) == false)
3650b57cec5SDimitry Andric       return false;
3660b57cec5SDimitry Andric     cs_vals_[static_cast<const void *>(Init)] = Vals;
3670b57cec5SDimitry Andric     TmpVal = std::move(Vals);
3680b57cec5SDimitry Andric   }
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric   // test whether host endianness matches target
3710b57cec5SDimitry Andric   union {
3720b57cec5SDimitry Andric     uint8_t c[2];
3730b57cec5SDimitry Andric     uint16_t s;
3740b57cec5SDimitry Andric   } test_buf;
3750b57cec5SDimitry Andric   uint16_t test_val = 0x2345;
3760b57cec5SDimitry Andric   if (DL.isLittleEndian())
3770b57cec5SDimitry Andric     support::endian::write16le(test_buf.c, test_val);
3780b57cec5SDimitry Andric   else
3790b57cec5SDimitry Andric     support::endian::write16be(test_buf.c, test_val);
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric   bool endian_match = test_buf.s == test_val;
3820b57cec5SDimitry Andric   for (uint64_t i = Offset, j = 0; i < Offset + Size; i++, j++)
3830b57cec5SDimitry Andric     ByteSeq[j] = endian_match ? TmpVal[i] : TmpVal[Offset + Size - 1 - j];
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric   return true;
3860b57cec5SDimitry Andric }
3870b57cec5SDimitry Andric 
fillGenericConstant(const DataLayout & DL,const Constant * CV,val_vec_type & Vals,uint64_t Offset)3880b57cec5SDimitry Andric bool BPFDAGToDAGISel::fillGenericConstant(const DataLayout &DL,
3890b57cec5SDimitry Andric                                           const Constant *CV,
3900b57cec5SDimitry Andric                                           val_vec_type &Vals, uint64_t Offset) {
3910b57cec5SDimitry Andric   uint64_t Size = DL.getTypeAllocSize(CV->getType());
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric   if (isa<ConstantAggregateZero>(CV) || isa<UndefValue>(CV))
3940b57cec5SDimitry Andric     return true; // already done
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
3970b57cec5SDimitry Andric     uint64_t val = CI->getZExtValue();
3980b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Byte array at offset " << Offset << " with value "
3990b57cec5SDimitry Andric                       << val << '\n');
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric     if (Size > 8 || (Size & (Size - 1)))
4020b57cec5SDimitry Andric       return false;
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric     // Store based on target endian
4050b57cec5SDimitry Andric     for (uint64_t i = 0; i < Size; ++i) {
4060b57cec5SDimitry Andric       Vals[Offset + i] = DL.isLittleEndian()
4070b57cec5SDimitry Andric                              ? ((val >> (i * 8)) & 0xFF)
4080b57cec5SDimitry Andric                              : ((val >> ((Size - i - 1) * 8)) & 0xFF);
4090b57cec5SDimitry Andric     }
4100b57cec5SDimitry Andric     return true;
4110b57cec5SDimitry Andric   }
4120b57cec5SDimitry Andric 
4130b57cec5SDimitry Andric   if (const ConstantDataArray *CDA = dyn_cast<ConstantDataArray>(CV))
4140b57cec5SDimitry Andric     return fillConstantDataArray(DL, CDA, Vals, Offset);
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   if (const ConstantArray *CA = dyn_cast<ConstantArray>(CV))
4170b57cec5SDimitry Andric     return fillConstantArray(DL, CA, Vals, Offset);
4180b57cec5SDimitry Andric 
4190b57cec5SDimitry Andric   if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV))
4200b57cec5SDimitry Andric     return fillConstantStruct(DL, CVS, Vals, Offset);
4210b57cec5SDimitry Andric 
4220b57cec5SDimitry Andric   return false;
4230b57cec5SDimitry Andric }
4240b57cec5SDimitry Andric 
fillConstantDataArray(const DataLayout & DL,const ConstantDataArray * CDA,val_vec_type & Vals,int Offset)4250b57cec5SDimitry Andric bool BPFDAGToDAGISel::fillConstantDataArray(const DataLayout &DL,
4260b57cec5SDimitry Andric                                             const ConstantDataArray *CDA,
4270b57cec5SDimitry Andric                                             val_vec_type &Vals, int Offset) {
4280b57cec5SDimitry Andric   for (unsigned i = 0, e = CDA->getNumElements(); i != e; ++i) {
4290b57cec5SDimitry Andric     if (fillGenericConstant(DL, CDA->getElementAsConstant(i), Vals, Offset) ==
4300b57cec5SDimitry Andric         false)
4310b57cec5SDimitry Andric       return false;
4320b57cec5SDimitry Andric     Offset += DL.getTypeAllocSize(CDA->getElementAsConstant(i)->getType());
4330b57cec5SDimitry Andric   }
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric   return true;
4360b57cec5SDimitry Andric }
4370b57cec5SDimitry Andric 
fillConstantArray(const DataLayout & DL,const ConstantArray * CA,val_vec_type & Vals,int Offset)4380b57cec5SDimitry Andric bool BPFDAGToDAGISel::fillConstantArray(const DataLayout &DL,
4390b57cec5SDimitry Andric                                         const ConstantArray *CA,
4400b57cec5SDimitry Andric                                         val_vec_type &Vals, int Offset) {
4410b57cec5SDimitry Andric   for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
4420b57cec5SDimitry Andric     if (fillGenericConstant(DL, CA->getOperand(i), Vals, Offset) == false)
4430b57cec5SDimitry Andric       return false;
4440b57cec5SDimitry Andric     Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType());
4450b57cec5SDimitry Andric   }
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric   return true;
4480b57cec5SDimitry Andric }
4490b57cec5SDimitry Andric 
fillConstantStruct(const DataLayout & DL,const ConstantStruct * CS,val_vec_type & Vals,int Offset)4500b57cec5SDimitry Andric bool BPFDAGToDAGISel::fillConstantStruct(const DataLayout &DL,
4510b57cec5SDimitry Andric                                          const ConstantStruct *CS,
4520b57cec5SDimitry Andric                                          val_vec_type &Vals, int Offset) {
4530b57cec5SDimitry Andric   const StructLayout *Layout = DL.getStructLayout(CS->getType());
4540b57cec5SDimitry Andric   for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) {
4550b57cec5SDimitry Andric     const Constant *Field = CS->getOperand(i);
4560b57cec5SDimitry Andric     uint64_t SizeSoFar = Layout->getElementOffset(i);
4570b57cec5SDimitry Andric     if (fillGenericConstant(DL, Field, Vals, Offset + SizeSoFar) == false)
4580b57cec5SDimitry Andric       return false;
4590b57cec5SDimitry Andric   }
4600b57cec5SDimitry Andric   return true;
4610b57cec5SDimitry Andric }
4620b57cec5SDimitry Andric 
PreprocessTrunc(SDNode * Node,SelectionDAG::allnodes_iterator & I)4630b57cec5SDimitry Andric void BPFDAGToDAGISel::PreprocessTrunc(SDNode *Node,
4640b57cec5SDimitry Andric                                       SelectionDAG::allnodes_iterator &I) {
4650b57cec5SDimitry Andric   ConstantSDNode *MaskN = dyn_cast<ConstantSDNode>(Node->getOperand(1));
4660b57cec5SDimitry Andric   if (!MaskN)
4670b57cec5SDimitry Andric     return;
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric   // The Reg operand should be a virtual register, which is defined
4700b57cec5SDimitry Andric   // outside the current basic block. DAG combiner has done a pretty
4710b57cec5SDimitry Andric   // good job in removing truncating inside a single basic block except
4720b57cec5SDimitry Andric   // when the Reg operand comes from bpf_load_[byte | half | word] for
4730b57cec5SDimitry Andric   // which the generic optimizer doesn't understand their results are
4740b57cec5SDimitry Andric   // zero extended.
4750b57cec5SDimitry Andric   SDValue BaseV = Node->getOperand(0);
4768bcb0991SDimitry Andric   if (BaseV.getOpcode() != ISD::INTRINSIC_W_CHAIN)
4778bcb0991SDimitry Andric     return;
4788bcb0991SDimitry Andric 
479647cbc5dSDimitry Andric   unsigned IntNo = BaseV->getConstantOperandVal(1);
4800b57cec5SDimitry Andric   uint64_t MaskV = MaskN->getZExtValue();
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric   if (!((IntNo == Intrinsic::bpf_load_byte && MaskV == 0xFF) ||
4830b57cec5SDimitry Andric         (IntNo == Intrinsic::bpf_load_half && MaskV == 0xFFFF) ||
4840b57cec5SDimitry Andric         (IntNo == Intrinsic::bpf_load_word && MaskV == 0xFFFFFFFF)))
4850b57cec5SDimitry Andric     return;
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Remove the redundant AND operation in: ";
4880b57cec5SDimitry Andric              Node->dump(); dbgs() << '\n');
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric   I--;
4910b57cec5SDimitry Andric   CurDAG->ReplaceAllUsesWith(SDValue(Node, 0), BaseV);
4920b57cec5SDimitry Andric   I++;
4930b57cec5SDimitry Andric   CurDAG->DeleteNode(Node);
4940b57cec5SDimitry Andric }
4950b57cec5SDimitry Andric 
createBPFISelDag(BPFTargetMachine & TM)4960b57cec5SDimitry Andric FunctionPass *llvm::createBPFISelDag(BPFTargetMachine &TM) {
497*0fca6ea1SDimitry Andric   return new BPFDAGToDAGISelLegacy(TM);
4980b57cec5SDimitry Andric }
499