1 //===-- BPFISelDAGToDAG.cpp - A dag to dag inst selector for BPF ----------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines a DAG pattern matching instruction selector for BPF, 11 // converting from a legalized dag to a BPF dag. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "BPF.h" 16 #include "BPFRegisterInfo.h" 17 #include "BPFSubtarget.h" 18 #include "BPFTargetMachine.h" 19 #include "llvm/CodeGen/FunctionLoweringInfo.h" 20 #include "llvm/CodeGen/MachineConstantPool.h" 21 #include "llvm/CodeGen/MachineFrameInfo.h" 22 #include "llvm/CodeGen/MachineFunction.h" 23 #include "llvm/CodeGen/MachineInstrBuilder.h" 24 #include "llvm/CodeGen/MachineRegisterInfo.h" 25 #include "llvm/CodeGen/SelectionDAGISel.h" 26 #include "llvm/IR/Constants.h" 27 #include "llvm/IR/IntrinsicInst.h" 28 #include "llvm/Support/Debug.h" 29 #include "llvm/Support/Endian.h" 30 #include "llvm/Support/ErrorHandling.h" 31 #include "llvm/Support/raw_ostream.h" 32 #include "llvm/Target/TargetMachine.h" 33 34 using namespace llvm; 35 36 #define DEBUG_TYPE "bpf-isel" 37 38 // Instruction Selector Implementation 39 namespace { 40 41 class BPFDAGToDAGISel : public SelectionDAGISel { 42 public: 43 explicit BPFDAGToDAGISel(BPFTargetMachine &TM) : SelectionDAGISel(TM) {} 44 45 StringRef getPassName() const override { 46 return "BPF DAG->DAG Pattern Instruction Selection"; 47 } 48 49 void PreprocessISelDAG() override; 50 51 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode, 52 std::vector<SDValue> &OutOps) override; 53 54 55 private: 56 // Include the pieces autogenerated from the target description. 57 #include "BPFGenDAGISel.inc" 58 59 void Select(SDNode *N) override; 60 61 // Complex Pattern for address selection. 62 bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset); 63 bool SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset); 64 65 // Node preprocessing cases 66 void PreprocessLoad(SDNode *Node, SelectionDAG::allnodes_iterator I); 67 void PreprocessCopyToReg(SDNode *Node); 68 void PreprocessTrunc(SDNode *Node, SelectionDAG::allnodes_iterator I); 69 70 // Find constants from a constant structure 71 typedef std::vector<unsigned char> val_vec_type; 72 bool fillGenericConstant(const DataLayout &DL, const Constant *CV, 73 val_vec_type &Vals, uint64_t Offset); 74 bool fillConstantDataArray(const DataLayout &DL, const ConstantDataArray *CDA, 75 val_vec_type &Vals, int Offset); 76 bool fillConstantArray(const DataLayout &DL, const ConstantArray *CA, 77 val_vec_type &Vals, int Offset); 78 bool fillConstantStruct(const DataLayout &DL, const ConstantStruct *CS, 79 val_vec_type &Vals, int Offset); 80 bool getConstantFieldValue(const GlobalAddressSDNode *Node, uint64_t Offset, 81 uint64_t Size, unsigned char *ByteSeq); 82 bool checkLoadDef(unsigned DefReg, unsigned match_load_op); 83 84 // Mapping from ConstantStruct global value to corresponding byte-list values 85 std::map<const void *, val_vec_type> cs_vals_; 86 // Mapping from vreg to load memory opcode 87 std::map<unsigned, unsigned> load_to_vreg_; 88 }; 89 } // namespace 90 91 // ComplexPattern used on BPF Load/Store instructions 92 bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { 93 // if Address is FI, get the TargetFrameIndex. 94 SDLoc DL(Addr); 95 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 96 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64); 97 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64); 98 return true; 99 } 100 101 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 102 Addr.getOpcode() == ISD::TargetGlobalAddress) 103 return false; 104 105 // Addresses of the form Addr+const or Addr|const 106 if (CurDAG->isBaseWithConstantOffset(Addr)) { 107 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)); 108 if (isInt<16>(CN->getSExtValue())) { 109 110 // If the first operand is a FI, get the TargetFI Node 111 if (FrameIndexSDNode *FIN = 112 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) 113 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64); 114 else 115 Base = Addr.getOperand(0); 116 117 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64); 118 return true; 119 } 120 } 121 122 Base = Addr; 123 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64); 124 return true; 125 } 126 127 // ComplexPattern used on BPF FI instruction 128 bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base, 129 SDValue &Offset) { 130 SDLoc DL(Addr); 131 132 if (!CurDAG->isBaseWithConstantOffset(Addr)) 133 return false; 134 135 // Addresses of the form Addr+const or Addr|const 136 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)); 137 if (isInt<16>(CN->getSExtValue())) { 138 139 // If the first operand is a FI, get the TargetFI Node 140 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) 141 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64); 142 else 143 return false; 144 145 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64); 146 return true; 147 } 148 149 return false; 150 } 151 152 bool BPFDAGToDAGISel::SelectInlineAsmMemoryOperand( 153 const SDValue &Op, unsigned ConstraintCode, std::vector<SDValue> &OutOps) { 154 SDValue Op0, Op1; 155 switch (ConstraintCode) { 156 default: 157 return true; 158 case InlineAsm::Constraint_m: // memory 159 if (!SelectAddr(Op, Op0, Op1)) 160 return true; 161 break; 162 } 163 164 SDLoc DL(Op); 165 SDValue AluOp = CurDAG->getTargetConstant(ISD::ADD, DL, MVT::i32);; 166 OutOps.push_back(Op0); 167 OutOps.push_back(Op1); 168 OutOps.push_back(AluOp); 169 return false; 170 } 171 172 void BPFDAGToDAGISel::Select(SDNode *Node) { 173 unsigned Opcode = Node->getOpcode(); 174 175 // Dump information about the Node being selected 176 DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n'); 177 178 // If we have a custom node, we already have selected! 179 if (Node->isMachineOpcode()) { 180 DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n'); 181 return; 182 } 183 184 // tablegen selection should be handled here. 185 switch (Opcode) { 186 default: 187 break; 188 case ISD::SDIV: { 189 DebugLoc Empty; 190 const DebugLoc &DL = Node->getDebugLoc(); 191 if (DL != Empty) 192 errs() << "Error at line " << DL.getLine() << ": "; 193 else 194 errs() << "Error: "; 195 errs() << "Unsupport signed division for DAG: "; 196 Node->print(errs(), CurDAG); 197 errs() << "Please convert to unsigned div/mod.\n"; 198 break; 199 } 200 case ISD::INTRINSIC_W_CHAIN: { 201 unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 202 switch (IntNo) { 203 case Intrinsic::bpf_load_byte: 204 case Intrinsic::bpf_load_half: 205 case Intrinsic::bpf_load_word: { 206 SDLoc DL(Node); 207 SDValue Chain = Node->getOperand(0); 208 SDValue N1 = Node->getOperand(1); 209 SDValue Skb = Node->getOperand(2); 210 SDValue N3 = Node->getOperand(3); 211 212 SDValue R6Reg = CurDAG->getRegister(BPF::R6, MVT::i64); 213 Chain = CurDAG->getCopyToReg(Chain, DL, R6Reg, Skb, SDValue()); 214 Node = CurDAG->UpdateNodeOperands(Node, Chain, N1, R6Reg, N3); 215 break; 216 } 217 } 218 break; 219 } 220 221 case ISD::FrameIndex: { 222 int FI = cast<FrameIndexSDNode>(Node)->getIndex(); 223 EVT VT = Node->getValueType(0); 224 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); 225 unsigned Opc = BPF::MOV_rr; 226 if (Node->hasOneUse()) { 227 CurDAG->SelectNodeTo(Node, Opc, VT, TFI); 228 return; 229 } 230 ReplaceNode(Node, CurDAG->getMachineNode(Opc, SDLoc(Node), VT, TFI)); 231 return; 232 } 233 } 234 235 // Select the default instruction 236 SelectCode(Node); 237 } 238 239 void BPFDAGToDAGISel::PreprocessLoad(SDNode *Node, 240 SelectionDAG::allnodes_iterator I) { 241 union { 242 uint8_t c[8]; 243 uint16_t s; 244 uint32_t i; 245 uint64_t d; 246 } new_val; // hold up the constant values replacing loads. 247 bool to_replace = false; 248 SDLoc DL(Node); 249 const LoadSDNode *LD = cast<LoadSDNode>(Node); 250 uint64_t size = LD->getMemOperand()->getSize(); 251 252 if (!size || size > 8 || (size & (size - 1))) 253 return; 254 255 SDNode *LDAddrNode = LD->getOperand(1).getNode(); 256 // Match LDAddr against either global_addr or (global_addr + offset) 257 unsigned opcode = LDAddrNode->getOpcode(); 258 if (opcode == ISD::ADD) { 259 SDValue OP1 = LDAddrNode->getOperand(0); 260 SDValue OP2 = LDAddrNode->getOperand(1); 261 262 // We want to find the pattern global_addr + offset 263 SDNode *OP1N = OP1.getNode(); 264 if (OP1N->getOpcode() <= ISD::BUILTIN_OP_END || OP1N->getNumOperands() == 0) 265 return; 266 267 DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n'); 268 269 const GlobalAddressSDNode *GADN = 270 dyn_cast<GlobalAddressSDNode>(OP1N->getOperand(0).getNode()); 271 const ConstantSDNode *CDN = dyn_cast<ConstantSDNode>(OP2.getNode()); 272 if (GADN && CDN) 273 to_replace = 274 getConstantFieldValue(GADN, CDN->getZExtValue(), size, new_val.c); 275 } else if (LDAddrNode->getOpcode() > ISD::BUILTIN_OP_END && 276 LDAddrNode->getNumOperands() > 0) { 277 DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n'); 278 279 SDValue OP1 = LDAddrNode->getOperand(0); 280 if (const GlobalAddressSDNode *GADN = 281 dyn_cast<GlobalAddressSDNode>(OP1.getNode())) 282 to_replace = getConstantFieldValue(GADN, 0, size, new_val.c); 283 } 284 285 if (!to_replace) 286 return; 287 288 // replacing the old with a new value 289 uint64_t val; 290 if (size == 1) 291 val = new_val.c[0]; 292 else if (size == 2) 293 val = new_val.s; 294 else if (size == 4) 295 val = new_val.i; 296 else { 297 val = new_val.d; 298 } 299 300 DEBUG(dbgs() << "Replacing load of size " << size << " with constant " << val 301 << '\n'); 302 SDValue NVal = CurDAG->getConstant(val, DL, MVT::i64); 303 304 // After replacement, the current node is dead, we need to 305 // go backward one step to make iterator still work 306 I--; 307 SDValue From[] = {SDValue(Node, 0), SDValue(Node, 1)}; 308 SDValue To[] = {NVal, NVal}; 309 CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2); 310 I++; 311 // It is safe to delete node now 312 CurDAG->DeleteNode(Node); 313 } 314 315 void BPFDAGToDAGISel::PreprocessISelDAG() { 316 // Iterate through all nodes, interested in the following cases: 317 // 318 // . loads from ConstantStruct or ConstantArray of constructs 319 // which can be turns into constant itself, with this we can 320 // avoid reading from read-only section at runtime. 321 // 322 // . reg truncating is often the result of 8/16/32bit->64bit or 323 // 8/16bit->32bit conversion. If the reg value is loaded with 324 // masked byte width, the AND operation can be removed since 325 // BPF LOAD already has zero extension. 326 // 327 // This also solved a correctness issue. 328 // In BPF socket-related program, e.g., __sk_buff->{data, data_end} 329 // are 32-bit registers, but later on, kernel verifier will rewrite 330 // it with 64-bit value. Therefore, truncating the value after the 331 // load will result in incorrect code. 332 for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(), 333 E = CurDAG->allnodes_end(); 334 I != E;) { 335 SDNode *Node = &*I++; 336 unsigned Opcode = Node->getOpcode(); 337 if (Opcode == ISD::LOAD) 338 PreprocessLoad(Node, I); 339 else if (Opcode == ISD::CopyToReg) 340 PreprocessCopyToReg(Node); 341 else if (Opcode == ISD::AND) 342 PreprocessTrunc(Node, I); 343 } 344 } 345 346 bool BPFDAGToDAGISel::getConstantFieldValue(const GlobalAddressSDNode *Node, 347 uint64_t Offset, uint64_t Size, 348 unsigned char *ByteSeq) { 349 const GlobalVariable *V = dyn_cast<GlobalVariable>(Node->getGlobal()); 350 351 if (!V || !V->hasInitializer()) 352 return false; 353 354 const Constant *Init = V->getInitializer(); 355 const DataLayout &DL = CurDAG->getDataLayout(); 356 val_vec_type TmpVal; 357 358 auto it = cs_vals_.find(static_cast<const void *>(Init)); 359 if (it != cs_vals_.end()) { 360 TmpVal = it->second; 361 } else { 362 uint64_t total_size = 0; 363 if (const ConstantStruct *CS = dyn_cast<ConstantStruct>(Init)) 364 total_size = 365 DL.getStructLayout(cast<StructType>(CS->getType()))->getSizeInBytes(); 366 else if (const ConstantArray *CA = dyn_cast<ConstantArray>(Init)) 367 total_size = DL.getTypeAllocSize(CA->getType()->getElementType()) * 368 CA->getNumOperands(); 369 else 370 return false; 371 372 val_vec_type Vals(total_size, 0); 373 if (fillGenericConstant(DL, Init, Vals, 0) == false) 374 return false; 375 cs_vals_[static_cast<const void *>(Init)] = Vals; 376 TmpVal = std::move(Vals); 377 } 378 379 // test whether host endianness matches target 380 union { 381 uint8_t c[2]; 382 uint16_t s; 383 } test_buf; 384 uint16_t test_val = 0x2345; 385 if (DL.isLittleEndian()) 386 support::endian::write16le(test_buf.c, test_val); 387 else 388 support::endian::write16be(test_buf.c, test_val); 389 390 bool endian_match = test_buf.s == test_val; 391 for (uint64_t i = Offset, j = 0; i < Offset + Size; i++, j++) 392 ByteSeq[j] = endian_match ? TmpVal[i] : TmpVal[Offset + Size - 1 - j]; 393 394 return true; 395 } 396 397 bool BPFDAGToDAGISel::fillGenericConstant(const DataLayout &DL, 398 const Constant *CV, 399 val_vec_type &Vals, uint64_t Offset) { 400 uint64_t Size = DL.getTypeAllocSize(CV->getType()); 401 402 if (isa<ConstantAggregateZero>(CV) || isa<UndefValue>(CV)) 403 return true; // already done 404 405 if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) { 406 uint64_t val = CI->getZExtValue(); 407 DEBUG(dbgs() << "Byte array at offset " << Offset << " with value " << val 408 << '\n'); 409 410 if (Size > 8 || (Size & (Size - 1))) 411 return false; 412 413 // Store based on target endian 414 for (uint64_t i = 0; i < Size; ++i) { 415 Vals[Offset + i] = DL.isLittleEndian() 416 ? ((val >> (i * 8)) & 0xFF) 417 : ((val >> ((Size - i - 1) * 8)) & 0xFF); 418 } 419 return true; 420 } 421 422 if (const ConstantDataArray *CDA = dyn_cast<ConstantDataArray>(CV)) 423 return fillConstantDataArray(DL, CDA, Vals, Offset); 424 425 if (const ConstantArray *CA = dyn_cast<ConstantArray>(CV)) 426 return fillConstantArray(DL, CA, Vals, Offset); 427 428 if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV)) 429 return fillConstantStruct(DL, CVS, Vals, Offset); 430 431 return false; 432 } 433 434 bool BPFDAGToDAGISel::fillConstantDataArray(const DataLayout &DL, 435 const ConstantDataArray *CDA, 436 val_vec_type &Vals, int Offset) { 437 for (unsigned i = 0, e = CDA->getNumElements(); i != e; ++i) { 438 if (fillGenericConstant(DL, CDA->getElementAsConstant(i), Vals, Offset) == 439 false) 440 return false; 441 Offset += DL.getTypeAllocSize(CDA->getElementAsConstant(i)->getType()); 442 } 443 444 return true; 445 } 446 447 bool BPFDAGToDAGISel::fillConstantArray(const DataLayout &DL, 448 const ConstantArray *CA, 449 val_vec_type &Vals, int Offset) { 450 for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) { 451 if (fillGenericConstant(DL, CA->getOperand(i), Vals, Offset) == false) 452 return false; 453 Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType()); 454 } 455 456 return true; 457 } 458 459 bool BPFDAGToDAGISel::fillConstantStruct(const DataLayout &DL, 460 const ConstantStruct *CS, 461 val_vec_type &Vals, int Offset) { 462 const StructLayout *Layout = DL.getStructLayout(CS->getType()); 463 for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) { 464 const Constant *Field = CS->getOperand(i); 465 uint64_t SizeSoFar = Layout->getElementOffset(i); 466 if (fillGenericConstant(DL, Field, Vals, Offset + SizeSoFar) == false) 467 return false; 468 } 469 return true; 470 } 471 472 void BPFDAGToDAGISel::PreprocessCopyToReg(SDNode *Node) { 473 const RegisterSDNode *RegN = dyn_cast<RegisterSDNode>(Node->getOperand(1)); 474 if (!RegN || !TargetRegisterInfo::isVirtualRegister(RegN->getReg())) 475 return; 476 477 const LoadSDNode *LD = dyn_cast<LoadSDNode>(Node->getOperand(2)); 478 if (!LD) 479 return; 480 481 // Assign a load value to a virtual register. record its load width 482 unsigned mem_load_op = 0; 483 switch (LD->getMemOperand()->getSize()) { 484 default: 485 return; 486 case 4: 487 mem_load_op = BPF::LDW; 488 break; 489 case 2: 490 mem_load_op = BPF::LDH; 491 break; 492 case 1: 493 mem_load_op = BPF::LDB; 494 break; 495 } 496 497 DEBUG(dbgs() << "Find Load Value to VReg " 498 << TargetRegisterInfo::virtReg2Index(RegN->getReg()) << '\n'); 499 load_to_vreg_[RegN->getReg()] = mem_load_op; 500 } 501 502 void BPFDAGToDAGISel::PreprocessTrunc(SDNode *Node, 503 SelectionDAG::allnodes_iterator I) { 504 ConstantSDNode *MaskN = dyn_cast<ConstantSDNode>(Node->getOperand(1)); 505 if (!MaskN) 506 return; 507 508 unsigned match_load_op = 0; 509 switch (MaskN->getZExtValue()) { 510 default: 511 return; 512 case 0xFFFFFFFF: 513 match_load_op = BPF::LDW; 514 break; 515 case 0xFFFF: 516 match_load_op = BPF::LDH; 517 break; 518 case 0xFF: 519 match_load_op = BPF::LDB; 520 break; 521 } 522 523 // The Reg operand should be a virtual register, which is defined 524 // outside the current basic block. DAG combiner has done a pretty 525 // good job in removing truncating inside a single basic block. 526 SDValue BaseV = Node->getOperand(0); 527 if (BaseV.getOpcode() != ISD::CopyFromReg) 528 return; 529 530 const RegisterSDNode *RegN = 531 dyn_cast<RegisterSDNode>(BaseV.getNode()->getOperand(1)); 532 if (!RegN || !TargetRegisterInfo::isVirtualRegister(RegN->getReg())) 533 return; 534 unsigned AndOpReg = RegN->getReg(); 535 DEBUG(dbgs() << "Examine %vreg" << TargetRegisterInfo::virtReg2Index(AndOpReg) 536 << '\n'); 537 538 // Examine the PHI insns in the MachineBasicBlock to found out the 539 // definitions of this virtual register. At this stage (DAG2DAG 540 // transformation), only PHI machine insns are available in the machine basic 541 // block. 542 MachineBasicBlock *MBB = FuncInfo->MBB; 543 MachineInstr *MII = nullptr; 544 for (auto &MI : *MBB) { 545 for (unsigned i = 0; i < MI.getNumOperands(); ++i) { 546 const MachineOperand &MOP = MI.getOperand(i); 547 if (!MOP.isReg() || !MOP.isDef()) 548 continue; 549 unsigned Reg = MOP.getReg(); 550 if (TargetRegisterInfo::isVirtualRegister(Reg) && Reg == AndOpReg) { 551 MII = &MI; 552 break; 553 } 554 } 555 } 556 557 if (MII == nullptr) { 558 // No phi definition in this block. 559 if (!checkLoadDef(AndOpReg, match_load_op)) 560 return; 561 } else { 562 // The PHI node looks like: 563 // %vreg2<def> = PHI %vreg0, <BB#1>, %vreg1, <BB#3> 564 // Trace each incoming definition, e.g., (%vreg0, BB#1) and (%vreg1, BB#3) 565 // The AND operation can be removed if both %vreg0 in BB#1 and %vreg1 in 566 // BB#3 are defined with with a load matching the MaskN. 567 DEBUG(dbgs() << "Check PHI Insn: "; MII->dump(); dbgs() << '\n'); 568 unsigned PrevReg = -1; 569 for (unsigned i = 0; i < MII->getNumOperands(); ++i) { 570 const MachineOperand &MOP = MII->getOperand(i); 571 if (MOP.isReg()) { 572 if (MOP.isDef()) 573 continue; 574 PrevReg = MOP.getReg(); 575 if (!TargetRegisterInfo::isVirtualRegister(PrevReg)) 576 return; 577 if (!checkLoadDef(PrevReg, match_load_op)) 578 return; 579 } 580 } 581 } 582 583 DEBUG(dbgs() << "Remove the redundant AND operation in: "; Node->dump(); 584 dbgs() << '\n'); 585 586 I--; 587 CurDAG->ReplaceAllUsesWith(SDValue(Node, 0), BaseV); 588 I++; 589 CurDAG->DeleteNode(Node); 590 } 591 592 bool BPFDAGToDAGISel::checkLoadDef(unsigned DefReg, unsigned match_load_op) { 593 auto it = load_to_vreg_.find(DefReg); 594 if (it == load_to_vreg_.end()) 595 return false; // The definition of register is not exported yet. 596 597 return it->second == match_load_op; 598 } 599 600 FunctionPass *llvm::createBPFISelDag(BPFTargetMachine &TM) { 601 return new BPFDAGToDAGISel(TM); 602 } 603