LLVM 23.0.0git
BPFISelDAGToDAG.cpp
Go to the documentation of this file.
1//===-- BPFISelDAGToDAG.cpp - A dag to dag inst selector for BPF ----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines a DAG pattern matching instruction selector for BPF,
10// converting from a legalized dag to a BPF dag.
11//
12//===----------------------------------------------------------------------===//
13
14#include "BPF.h"
15#include "BPFSubtarget.h"
16#include "BPFTargetMachine.h"
22#include "llvm/IR/Constants.h"
24#include "llvm/IR/IntrinsicsBPF.h"
25#include "llvm/Support/Debug.h"
26#include "llvm/Support/Endian.h"
29
30using namespace llvm;
31
32#define DEBUG_TYPE "bpf-isel"
33#define PASS_NAME "BPF DAG->DAG Pattern Instruction Selection"
34
35// Instruction Selector Implementation
36namespace {
37
38class BPFDAGToDAGISel : public SelectionDAGISel {
39
40 /// Subtarget - Keep a pointer to the BPFSubtarget around so that we can
41 /// make the right decision when generating code for different subtargets.
42 const BPFSubtarget *Subtarget;
43
44public:
45 BPFDAGToDAGISel() = delete;
46
47 explicit BPFDAGToDAGISel(BPFTargetMachine &TM)
48 : SelectionDAGISel(TM), Subtarget(nullptr) {}
49
50 bool runOnMachineFunction(MachineFunction &MF) override {
51 // Reset the subtarget each time through.
52 Subtarget = &MF.getSubtarget<BPFSubtarget>();
54 }
55
56 void PreprocessISelDAG() override;
57
58 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
59 InlineAsm::ConstraintCode ConstraintCode,
60 std::vector<SDValue> &OutOps) override;
61
62private:
63// Include the pieces autogenerated from the target description.
64#include "BPFGenDAGISel.inc"
65
66 void Select(SDNode *N) override;
67
68 // Complex Pattern for address selection.
69 bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
70 bool SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
71
72 // Node preprocessing cases
73 void PreprocessLoad(SDNode *Node, SelectionDAG::allnodes_iterator &I);
74 void PreprocessTrunc(SDNode *Node, SelectionDAG::allnodes_iterator &I);
75
76 // Find constants from a constant structure
77 typedef std::vector<unsigned char> val_vec_type;
78 bool fillGenericConstant(const DataLayout &DL, const Constant *CV,
79 val_vec_type &Vals, uint64_t Offset);
80 bool fillConstantDataArray(const DataLayout &DL, const ConstantDataArray *CDA,
81 val_vec_type &Vals, int Offset);
82 bool fillConstantArray(const DataLayout &DL, const ConstantArray *CA,
83 val_vec_type &Vals, int Offset);
84 bool fillConstantStruct(const DataLayout &DL, const ConstantStruct *CS,
85 val_vec_type &Vals, int Offset);
86 bool getConstantFieldValue(const GlobalAddressSDNode *Node, uint64_t Offset,
87 uint64_t Size, unsigned char *ByteSeq);
88 // Mapping from ConstantStruct global value to corresponding byte-list values
89 std::map<const void *, val_vec_type> cs_vals_;
90};
91
92class BPFDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
93public:
94 static char ID;
95 BPFDAGToDAGISelLegacy(BPFTargetMachine &TM)
96 : SelectionDAGISelLegacy(ID, std::make_unique<BPFDAGToDAGISel>(TM)) {}
97};
98} // namespace
99
100char BPFDAGToDAGISelLegacy::ID = 0;
101
102INITIALIZE_PASS(BPFDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
103
104// ComplexPattern used on BPF Load/Store instructions
105bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) {
106 // if Address is FI, get the TargetFrameIndex.
107 SDLoc DL(Addr);
108 if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
109 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
110 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
111 return true;
112 }
113
114 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
115 Addr.getOpcode() == ISD::TargetGlobalAddress)
116 return false;
117
118 // Addresses of the form Addr+const or Addr|const
119 if (CurDAG->isBaseWithConstantOffset(Addr)) {
120 auto *CN = cast<ConstantSDNode>(Addr.getOperand(1));
121 if (isInt<16>(CN->getSExtValue())) {
122 // If the first operand is a FI, get the TargetFI Node
123 if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
124 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
125 else
126 Base = Addr.getOperand(0);
127
128 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64);
129 return true;
130 }
131 }
132
133 Base = Addr;
134 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
135 return true;
136}
137
138// ComplexPattern used on BPF FI instruction
139bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base,
140 SDValue &Offset) {
141 SDLoc DL(Addr);
142
143 if (!CurDAG->isBaseWithConstantOffset(Addr))
144 return false;
145
146 // Addresses of the form Addr+const or Addr|const
147 auto *CN = cast<ConstantSDNode>(Addr.getOperand(1));
148 if (isInt<16>(CN->getSExtValue())) {
149 // If the first operand is a FI, get the TargetFI Node
150 if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
151 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
152 else
153 return false;
154
155 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64);
156 return true;
157 }
158
159 return false;
160}
161
162bool BPFDAGToDAGISel::SelectInlineAsmMemoryOperand(
163 const SDValue &Op, InlineAsm::ConstraintCode ConstraintCode,
164 std::vector<SDValue> &OutOps) {
165 SDValue Op0, Op1;
166 switch (ConstraintCode) {
167 default:
168 return true;
169 case InlineAsm::ConstraintCode::m: // memory
170 if (!SelectAddr(Op, Op0, Op1))
171 return true;
172 break;
173 }
174
175 SDLoc DL(Op);
176 SDValue AluOp = CurDAG->getTargetConstant(ISD::ADD, DL, MVT::i32);
177 OutOps.push_back(Op0);
178 OutOps.push_back(Op1);
179 OutOps.push_back(AluOp);
180 return false;
181}
182
183void BPFDAGToDAGISel::Select(SDNode *Node) {
184 unsigned Opcode = Node->getOpcode();
185
186 // If we have a custom node, we already have selected!
187 if (Node->isMachineOpcode()) {
188 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
189 return;
190 }
191
192 // tablegen selection should be handled here.
193 switch (Opcode) {
194 default:
195 break;
196 case BPFISD::LOAD_STACK_ARG: {
197 SDValue Chain = Node->getOperand(0);
198 auto *CN = cast<ConstantSDNode>(Node->getOperand(1));
199 SDValue Off =
200 CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Node), MVT::i64);
201 EVT ValVT = Node->getValueType(0);
202 CurDAG->SelectNodeTo(Node, BPF::LOAD_STACK_ARG_PSEUDO, ValVT, MVT::Other,
203 Off, Chain);
204 return;
205 }
206
207 case BPFISD::STORE_STACK_ARG: {
208 SDValue Chain = Node->getOperand(0);
209 auto *CN = cast<ConstantSDNode>(Node->getOperand(1));
210 SDValue Off =
211 CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Node), MVT::i64);
212 SDValue Val = Node->getOperand(2);
213
214 // Use store-immediate when the value is a constant that fits in 32 bits.
215 if (auto *ValCN = dyn_cast<ConstantSDNode>(Val);
216 ValCN && Subtarget->hasStoreImm() && isInt<32>(ValCN->getSExtValue())) {
217 SDValue Imm = CurDAG->getTargetConstant(ValCN->getSExtValue(),
218 SDLoc(Node), MVT::i64);
219 CurDAG->SelectNodeTo(Node, BPF::STORE_STACK_ARG_IMM_PSEUDO, MVT::Other,
220 Off, Imm, Chain);
221 } else {
222 CurDAG->SelectNodeTo(Node, BPF::STORE_STACK_ARG_PSEUDO, MVT::Other, Off,
223 Val, Chain);
224 }
225 return;
226 }
227
228 case ISD::FrameIndex: {
229 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
230 EVT VT = Node->getValueType(0);
231 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
232 unsigned Opc = BPF::MOV_rr;
233 if (Node->hasOneUse()) {
234 CurDAG->SelectNodeTo(Node, Opc, VT, TFI);
235 return;
236 }
237 ReplaceNode(Node, CurDAG->getMachineNode(Opc, SDLoc(Node), VT, TFI));
238 return;
239 }
240 }
241
242 // Select the default instruction
243 SelectCode(Node);
244}
245
246void BPFDAGToDAGISel::PreprocessLoad(SDNode *Node,
248 union {
249 uint8_t c[8];
250 uint16_t s;
251 uint32_t i;
252 uint64_t d;
253 } new_val; // hold up the constant values replacing loads.
254 bool to_replace = false;
255 SDLoc DL(Node);
256 const LoadSDNode *LD = cast<LoadSDNode>(Node);
257 if (!LD->getMemOperand()->getSize().hasValue())
258 return;
259 uint64_t size = LD->getMemOperand()->getSize().getValue();
260
261 if (!size || size > 8 || (size & (size - 1)) || !LD->isSimple())
262 return;
263
264 SDNode *LDAddrNode = LD->getOperand(1).getNode();
265 // Match LDAddr against either global_addr or (global_addr + offset)
266 unsigned opcode = LDAddrNode->getOpcode();
267 if (opcode == ISD::ADD) {
268 SDValue OP1 = LDAddrNode->getOperand(0);
269 SDValue OP2 = LDAddrNode->getOperand(1);
270
271 // We want to find the pattern global_addr + offset
272 SDNode *OP1N = OP1.getNode();
273 if (OP1N->getOpcode() <= ISD::BUILTIN_OP_END || OP1N->getNumOperands() == 0)
274 return;
275
276 LLVM_DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n');
277
278 const GlobalAddressSDNode *GADN =
280 const ConstantSDNode *CDN = dyn_cast<ConstantSDNode>(OP2.getNode());
281 if (GADN && CDN)
282 to_replace =
283 getConstantFieldValue(GADN, CDN->getZExtValue(), size, new_val.c);
284 } else if (LDAddrNode->getOpcode() > ISD::BUILTIN_OP_END &&
285 LDAddrNode->getNumOperands() > 0) {
286 LLVM_DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n');
287
288 SDValue OP1 = LDAddrNode->getOperand(0);
289 if (const GlobalAddressSDNode *GADN =
291 to_replace = getConstantFieldValue(GADN, 0, size, new_val.c);
292 }
293
294 if (!to_replace)
295 return;
296
297 // replacing the old with a new value
298 uint64_t val;
299 if (size == 1)
300 val = new_val.c[0];
301 else if (size == 2)
302 val = new_val.s;
303 else if (size == 4)
304 val = new_val.i;
305 else {
306 val = new_val.d;
307 }
308
309 LLVM_DEBUG(dbgs() << "Replacing load of size " << size << " with constant "
310 << val << '\n');
311 SDValue NVal = CurDAG->getConstant(val, DL, LD->getValueType(0));
312
313 // After replacement, the current node is dead, we need to
314 // go backward one step to make iterator still work
315 I--;
316 SDValue From[] = {SDValue(Node, 0), SDValue(Node, 1)};
317 SDValue To[] = {NVal, NVal};
318 CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2);
319 I++;
320 // It is safe to delete node now
321 CurDAG->DeleteNode(Node);
322}
323
324void BPFDAGToDAGISel::PreprocessISelDAG() {
325 // Iterate through all nodes, interested in the following case:
326 //
327 // . loads from ConstantStruct or ConstantArray of constructs
328 // which can be turns into constant itself, with this we can
329 // avoid reading from read-only section at runtime.
330 //
331 // . Removing redundant AND for intrinsic narrow loads.
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::AND)
340 PreprocessTrunc(Node, I);
341 }
342}
343
344bool BPFDAGToDAGISel::getConstantFieldValue(const GlobalAddressSDNode *Node,
345 uint64_t Offset, uint64_t Size,
346 unsigned char *ByteSeq) {
347 const GlobalVariable *V = dyn_cast<GlobalVariable>(Node->getGlobal());
348
349 if (!V || !V->hasInitializer() || !V->isConstant())
350 return false;
351
352 const Constant *Init = V->getInitializer();
353 const DataLayout &DL = CurDAG->getDataLayout();
354 val_vec_type TmpVal;
355
356 auto it = cs_vals_.find(static_cast<const void *>(Init));
357 if (it != cs_vals_.end()) {
358 TmpVal = it->second;
359 } else {
360 uint64_t total_size = 0;
361 if (const ConstantStruct *CS = dyn_cast<ConstantStruct>(Init))
362 total_size =
363 DL.getStructLayout(cast<StructType>(CS->getType()))->getSizeInBytes();
364 else if (const ConstantArray *CA = dyn_cast<ConstantArray>(Init))
365 total_size = DL.getTypeAllocSize(CA->getType()->getElementType()) *
366 CA->getNumOperands();
367 else
368 return false;
369
370 val_vec_type Vals(total_size, 0);
371 if (fillGenericConstant(DL, Init, Vals, 0) == false)
372 return false;
373 cs_vals_[static_cast<const void *>(Init)] = Vals;
374 TmpVal = std::move(Vals);
375 }
376
377 // test whether host endianness matches target
378 union {
379 uint8_t c[2];
380 uint16_t s;
381 } test_buf;
382 uint16_t test_val = 0x2345;
383 if (DL.isLittleEndian())
384 support::endian::write16le(test_buf.c, test_val);
385 else
386 support::endian::write16be(test_buf.c, test_val);
387
388 bool endian_match = test_buf.s == test_val;
389 for (uint64_t i = Offset, j = 0; i < Offset + Size; i++, j++)
390 ByteSeq[j] = endian_match ? TmpVal[i] : TmpVal[Offset + Size - 1 - j];
391
392 return true;
393}
394
395bool BPFDAGToDAGISel::fillGenericConstant(const DataLayout &DL,
396 const Constant *CV,
397 val_vec_type &Vals, uint64_t Offset) {
398 uint64_t Size = DL.getTypeAllocSize(CV->getType());
399
401 return true; // already done
402
403 if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
404 uint64_t val = CI->getZExtValue();
405 LLVM_DEBUG(dbgs() << "Byte array at offset " << Offset << " with value "
406 << val << '\n');
407
408 if (Size > 8 || (Size & (Size - 1)))
409 return false;
410
411 // Store based on target endian
412 for (uint64_t i = 0; i < Size; ++i) {
413 Vals[Offset + i] = DL.isLittleEndian()
414 ? ((val >> (i * 8)) & 0xFF)
415 : ((val >> ((Size - i - 1) * 8)) & 0xFF);
416 }
417 return true;
418 }
419
420 if (const ConstantDataArray *CDA = dyn_cast<ConstantDataArray>(CV))
421 return fillConstantDataArray(DL, CDA, Vals, Offset);
422
423 if (const ConstantArray *CA = dyn_cast<ConstantArray>(CV))
424 return fillConstantArray(DL, CA, Vals, Offset);
425
426 if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV))
427 return fillConstantStruct(DL, CVS, Vals, Offset);
428
429 return false;
430}
431
432bool BPFDAGToDAGISel::fillConstantDataArray(const DataLayout &DL,
433 const ConstantDataArray *CDA,
434 val_vec_type &Vals, int Offset) {
435 for (unsigned i = 0, e = CDA->getNumElements(); i != e; ++i) {
436 if (fillGenericConstant(DL, CDA->getElementAsConstant(i), Vals, Offset) ==
437 false)
438 return false;
439 Offset += DL.getTypeAllocSize(CDA->getElementAsConstant(i)->getType());
440 }
441
442 return true;
443}
444
445bool BPFDAGToDAGISel::fillConstantArray(const DataLayout &DL,
446 const ConstantArray *CA,
447 val_vec_type &Vals, int Offset) {
448 for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
449 if (fillGenericConstant(DL, CA->getOperand(i), Vals, Offset) == false)
450 return false;
451 Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType());
452 }
453
454 return true;
455}
456
457bool BPFDAGToDAGISel::fillConstantStruct(const DataLayout &DL,
458 const ConstantStruct *CS,
459 val_vec_type &Vals, int Offset) {
460 const StructLayout *Layout = DL.getStructLayout(CS->getType());
461 for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) {
462 const Constant *Field = CS->getOperand(i);
463 uint64_t SizeSoFar = Layout->getElementOffset(i);
464 if (fillGenericConstant(DL, Field, Vals, Offset + SizeSoFar) == false)
465 return false;
466 }
467 return true;
468}
469
470void BPFDAGToDAGISel::PreprocessTrunc(SDNode *Node,
472 ConstantSDNode *MaskN = dyn_cast<ConstantSDNode>(Node->getOperand(1));
473 if (!MaskN)
474 return;
475
476 // The Reg operand should be a virtual register, which is defined
477 // outside the current basic block. DAG combiner has done a pretty
478 // good job in removing truncating inside a single basic block except
479 // when the Reg operand comes from bpf_load_[byte | half | word] for
480 // which the generic optimizer doesn't understand their results are
481 // zero extended.
482 SDValue BaseV = Node->getOperand(0);
483 if (BaseV.getOpcode() != ISD::INTRINSIC_W_CHAIN)
484 return;
485
486 unsigned IntNo = BaseV->getConstantOperandVal(1);
487 uint64_t MaskV = MaskN->getZExtValue();
488
489 if (!((IntNo == Intrinsic::bpf_load_byte && MaskV == 0xFF) ||
490 (IntNo == Intrinsic::bpf_load_half && MaskV == 0xFFFF) ||
491 (IntNo == Intrinsic::bpf_load_word && MaskV == 0xFFFFFFFF)))
492 return;
493
494 LLVM_DEBUG(dbgs() << "Remove the redundant AND operation in: ";
495 Node->dump(); dbgs() << '\n');
496
497 I--;
498 CurDAG->ReplaceAllUsesWith(SDValue(Node, 0), BaseV);
499 I++;
500 CurDAG->DeleteNode(Node);
501}
502
504 return new BPFDAGToDAGISelLegacy(TM);
505}
return SDValue()
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
#define DEBUG_TYPE
#define I(x, y, z)
Definition MD5.cpp:57
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
OptimizedStructLayoutField Field
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define LLVM_DEBUG(...)
Definition Debug.h:114
#define PASS_NAME
bool hasStoreImm() const
ConstantArray - Constant Array Declarations.
Definition Constants.h:579
An array constant whose element type is a simple 1/2/4/8-byte integer, bytes or float/double,...
Definition Constants.h:852
LLVM_ABI Constant * getElementAsConstant(uint64_t i) const
Return a Constant for a specified index's element.
LLVM_ABI uint64_t getNumElements() const
Return the number of elements in the array or vector.
uint64_t getZExtValue() const
StructType * getType() const
Specialization - reduce amount of casting.
Definition Constants.h:650
This is an important base class in LLVM.
Definition Constant.h:43
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
unsigned getNumOperands() const
Return the number of values used by this operation.
const SDValue & getOperand(unsigned Num) const
uint64_t getConstantOperandVal(unsigned Num) const
Helper method returns the integer value of a ConstantSDNode operand.
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
const SDValue & getOperand(unsigned i) const
unsigned getOpcode() const
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual bool runOnMachineFunction(MachineFunction &mf)
ilist< SDNode >::iterator allnodes_iterator
TypeSize getElementOffset(unsigned Idx) const
Definition DataLayout.h:774
Value * getOperand(unsigned i) const
Definition User.h:207
unsigned getNumOperands() const
Definition User.h:229
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:264
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
@ BUILTIN_OP_END
BUILTIN_OP_END - This must be the last enum value in this list.
@ TargetExternalSymbol
Definition ISDOpcodes.h:190
@ TargetGlobalAddress
TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...
Definition ISDOpcodes.h:185
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:739
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:213
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
void write16be(void *P, uint16_t V)
Definition Endian.h:481
void write16le(void *P, uint16_t V)
Definition Endian.h:472
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:557
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1668
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:165
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
FunctionPass * createBPFISelDag(BPFTargetMachine &TM)
#define N