1 //===-- BPFISelDAGToDAG.cpp - A dag to dag inst selector for BPF ----------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines a DAG pattern matching instruction selector for BPF,
10 // converting from a legalized dag to a BPF dag.
12 //===----------------------------------------------------------------------===//
15 #include "BPFRegisterInfo.h"
16 #include "BPFSubtarget.h"
17 #include "BPFTargetMachine.h"
18 #include "llvm/CodeGen/FunctionLoweringInfo.h"
19 #include "llvm/CodeGen/MachineConstantPool.h"
20 #include "llvm/CodeGen/MachineFrameInfo.h"
21 #include "llvm/CodeGen/MachineFunction.h"
22 #include "llvm/CodeGen/MachineInstrBuilder.h"
23 #include "llvm/CodeGen/MachineRegisterInfo.h"
24 #include "llvm/CodeGen/SelectionDAGISel.h"
25 #include "llvm/IR/Constants.h"
26 #include "llvm/IR/IntrinsicInst.h"
27 #include "llvm/Support/Debug.h"
28 #include "llvm/Support/Endian.h"
29 #include "llvm/Support/ErrorHandling.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include "llvm/Target/TargetMachine.h"
35 #define DEBUG_TYPE "bpf-isel"
37 // Instruction Selector Implementation
40 class BPFDAGToDAGISel
: public SelectionDAGISel
{
42 /// Subtarget - Keep a pointer to the BPFSubtarget around so that we can
43 /// make the right decision when generating code for different subtargets.
44 const BPFSubtarget
*Subtarget
;
47 explicit BPFDAGToDAGISel(BPFTargetMachine
&TM
)
48 : SelectionDAGISel(TM
), Subtarget(nullptr) {}
50 StringRef
getPassName() const override
{
51 return "BPF DAG->DAG Pattern Instruction Selection";
54 bool runOnMachineFunction(MachineFunction
&MF
) override
{
55 // Reset the subtarget each time through.
56 Subtarget
= &MF
.getSubtarget
<BPFSubtarget
>();
57 return SelectionDAGISel::runOnMachineFunction(MF
);
60 void PreprocessISelDAG() override
;
62 bool SelectInlineAsmMemoryOperand(const SDValue
&Op
, unsigned ConstraintCode
,
63 std::vector
<SDValue
> &OutOps
) override
;
67 // Include the pieces autogenerated from the target description.
68 #include "BPFGenDAGISel.inc"
70 void Select(SDNode
*N
) override
;
72 // Complex Pattern for address selection.
73 bool SelectAddr(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
);
74 bool SelectFIAddr(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
);
76 // Node preprocessing cases
77 void PreprocessLoad(SDNode
*Node
, SelectionDAG::allnodes_iterator
&I
);
78 void PreprocessCopyToReg(SDNode
*Node
);
79 void PreprocessTrunc(SDNode
*Node
, SelectionDAG::allnodes_iterator
&I
);
81 // Find constants from a constant structure
82 typedef std::vector
<unsigned char> val_vec_type
;
83 bool fillGenericConstant(const DataLayout
&DL
, const Constant
*CV
,
84 val_vec_type
&Vals
, uint64_t Offset
);
85 bool fillConstantDataArray(const DataLayout
&DL
, const ConstantDataArray
*CDA
,
86 val_vec_type
&Vals
, int Offset
);
87 bool fillConstantArray(const DataLayout
&DL
, const ConstantArray
*CA
,
88 val_vec_type
&Vals
, int Offset
);
89 bool fillConstantStruct(const DataLayout
&DL
, const ConstantStruct
*CS
,
90 val_vec_type
&Vals
, int Offset
);
91 bool getConstantFieldValue(const GlobalAddressSDNode
*Node
, uint64_t Offset
,
92 uint64_t Size
, unsigned char *ByteSeq
);
93 // Mapping from ConstantStruct global value to corresponding byte-list values
94 std::map
<const void *, val_vec_type
> cs_vals_
;
98 // ComplexPattern used on BPF Load/Store instructions
99 bool BPFDAGToDAGISel::SelectAddr(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
) {
100 // if Address is FI, get the TargetFrameIndex.
102 if (FrameIndexSDNode
*FIN
= dyn_cast
<FrameIndexSDNode
>(Addr
)) {
103 Base
= CurDAG
->getTargetFrameIndex(FIN
->getIndex(), MVT::i64
);
104 Offset
= CurDAG
->getTargetConstant(0, DL
, MVT::i64
);
108 if (Addr
.getOpcode() == ISD::TargetExternalSymbol
||
109 Addr
.getOpcode() == ISD::TargetGlobalAddress
)
112 // Addresses of the form Addr+const or Addr|const
113 if (CurDAG
->isBaseWithConstantOffset(Addr
)) {
114 ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Addr
.getOperand(1));
115 if (isInt
<16>(CN
->getSExtValue())) {
117 // If the first operand is a FI, get the TargetFI Node
118 if (FrameIndexSDNode
*FIN
=
119 dyn_cast
<FrameIndexSDNode
>(Addr
.getOperand(0)))
120 Base
= CurDAG
->getTargetFrameIndex(FIN
->getIndex(), MVT::i64
);
122 Base
= Addr
.getOperand(0);
124 Offset
= CurDAG
->getTargetConstant(CN
->getSExtValue(), DL
, MVT::i64
);
130 Offset
= CurDAG
->getTargetConstant(0, DL
, MVT::i64
);
134 // ComplexPattern used on BPF FI instruction
135 bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr
, SDValue
&Base
,
139 if (!CurDAG
->isBaseWithConstantOffset(Addr
))
142 // Addresses of the form Addr+const or Addr|const
143 ConstantSDNode
*CN
= dyn_cast
<ConstantSDNode
>(Addr
.getOperand(1));
144 if (isInt
<16>(CN
->getSExtValue())) {
146 // If the first operand is a FI, get the TargetFI Node
147 if (FrameIndexSDNode
*FIN
= dyn_cast
<FrameIndexSDNode
>(Addr
.getOperand(0)))
148 Base
= CurDAG
->getTargetFrameIndex(FIN
->getIndex(), MVT::i64
);
152 Offset
= CurDAG
->getTargetConstant(CN
->getSExtValue(), DL
, MVT::i64
);
159 bool BPFDAGToDAGISel::SelectInlineAsmMemoryOperand(
160 const SDValue
&Op
, unsigned ConstraintCode
, std::vector
<SDValue
> &OutOps
) {
162 switch (ConstraintCode
) {
165 case InlineAsm::Constraint_m
: // memory
166 if (!SelectAddr(Op
, Op0
, Op1
))
172 SDValue AluOp
= CurDAG
->getTargetConstant(ISD::ADD
, DL
, MVT::i32
);;
173 OutOps
.push_back(Op0
);
174 OutOps
.push_back(Op1
);
175 OutOps
.push_back(AluOp
);
179 void BPFDAGToDAGISel::Select(SDNode
*Node
) {
180 unsigned Opcode
= Node
->getOpcode();
182 // If we have a custom node, we already have selected!
183 if (Node
->isMachineOpcode()) {
184 LLVM_DEBUG(dbgs() << "== "; Node
->dump(CurDAG
); dbgs() << '\n');
188 // tablegen selection should be handled here.
194 const DebugLoc
&DL
= Node
->getDebugLoc();
196 errs() << "Error at line " << DL
.getLine() << ": ";
199 errs() << "Unsupport signed division for DAG: ";
200 Node
->print(errs(), CurDAG
);
201 errs() << "Please convert to unsigned div/mod.\n";
204 case ISD::INTRINSIC_W_CHAIN
: {
205 unsigned IntNo
= cast
<ConstantSDNode
>(Node
->getOperand(1))->getZExtValue();
207 case Intrinsic::bpf_load_byte
:
208 case Intrinsic::bpf_load_half
:
209 case Intrinsic::bpf_load_word
: {
211 SDValue Chain
= Node
->getOperand(0);
212 SDValue N1
= Node
->getOperand(1);
213 SDValue Skb
= Node
->getOperand(2);
214 SDValue N3
= Node
->getOperand(3);
216 SDValue R6Reg
= CurDAG
->getRegister(BPF::R6
, MVT::i64
);
217 Chain
= CurDAG
->getCopyToReg(Chain
, DL
, R6Reg
, Skb
, SDValue());
218 Node
= CurDAG
->UpdateNodeOperands(Node
, Chain
, N1
, R6Reg
, N3
);
225 case ISD::FrameIndex
: {
226 int FI
= cast
<FrameIndexSDNode
>(Node
)->getIndex();
227 EVT VT
= Node
->getValueType(0);
228 SDValue TFI
= CurDAG
->getTargetFrameIndex(FI
, VT
);
229 unsigned Opc
= BPF::MOV_rr
;
230 if (Node
->hasOneUse()) {
231 CurDAG
->SelectNodeTo(Node
, Opc
, VT
, TFI
);
234 ReplaceNode(Node
, CurDAG
->getMachineNode(Opc
, SDLoc(Node
), VT
, TFI
));
239 // Select the default instruction
243 void BPFDAGToDAGISel::PreprocessLoad(SDNode
*Node
,
244 SelectionDAG::allnodes_iterator
&I
) {
250 } new_val
; // hold up the constant values replacing loads.
251 bool to_replace
= false;
253 const LoadSDNode
*LD
= cast
<LoadSDNode
>(Node
);
254 uint64_t size
= LD
->getMemOperand()->getSize();
256 if (!size
|| size
> 8 || (size
& (size
- 1)))
259 SDNode
*LDAddrNode
= LD
->getOperand(1).getNode();
260 // Match LDAddr against either global_addr or (global_addr + offset)
261 unsigned opcode
= LDAddrNode
->getOpcode();
262 if (opcode
== ISD::ADD
) {
263 SDValue OP1
= LDAddrNode
->getOperand(0);
264 SDValue OP2
= LDAddrNode
->getOperand(1);
266 // We want to find the pattern global_addr + offset
267 SDNode
*OP1N
= OP1
.getNode();
268 if (OP1N
->getOpcode() <= ISD::BUILTIN_OP_END
|| OP1N
->getNumOperands() == 0)
271 LLVM_DEBUG(dbgs() << "Check candidate load: "; LD
->dump(); dbgs() << '\n');
273 const GlobalAddressSDNode
*GADN
=
274 dyn_cast
<GlobalAddressSDNode
>(OP1N
->getOperand(0).getNode());
275 const ConstantSDNode
*CDN
= dyn_cast
<ConstantSDNode
>(OP2
.getNode());
278 getConstantFieldValue(GADN
, CDN
->getZExtValue(), size
, new_val
.c
);
279 } else if (LDAddrNode
->getOpcode() > ISD::BUILTIN_OP_END
&&
280 LDAddrNode
->getNumOperands() > 0) {
281 LLVM_DEBUG(dbgs() << "Check candidate load: "; LD
->dump(); dbgs() << '\n');
283 SDValue OP1
= LDAddrNode
->getOperand(0);
284 if (const GlobalAddressSDNode
*GADN
=
285 dyn_cast
<GlobalAddressSDNode
>(OP1
.getNode()))
286 to_replace
= getConstantFieldValue(GADN
, 0, size
, new_val
.c
);
292 // replacing the old with a new value
304 LLVM_DEBUG(dbgs() << "Replacing load of size " << size
<< " with constant "
306 SDValue NVal
= CurDAG
->getConstant(val
, DL
, MVT::i64
);
308 // After replacement, the current node is dead, we need to
309 // go backward one step to make iterator still work
311 SDValue From
[] = {SDValue(Node
, 0), SDValue(Node
, 1)};
312 SDValue To
[] = {NVal
, NVal
};
313 CurDAG
->ReplaceAllUsesOfValuesWith(From
, To
, 2);
315 // It is safe to delete node now
316 CurDAG
->DeleteNode(Node
);
319 void BPFDAGToDAGISel::PreprocessISelDAG() {
320 // Iterate through all nodes, interested in the following case:
322 // . loads from ConstantStruct or ConstantArray of constructs
323 // which can be turns into constant itself, with this we can
324 // avoid reading from read-only section at runtime.
326 // . Removing redundant AND for intrinsic narrow loads.
327 for (SelectionDAG::allnodes_iterator I
= CurDAG
->allnodes_begin(),
328 E
= CurDAG
->allnodes_end();
330 SDNode
*Node
= &*I
++;
331 unsigned Opcode
= Node
->getOpcode();
332 if (Opcode
== ISD::LOAD
)
333 PreprocessLoad(Node
, I
);
334 else if (Opcode
== ISD::AND
)
335 PreprocessTrunc(Node
, I
);
339 bool BPFDAGToDAGISel::getConstantFieldValue(const GlobalAddressSDNode
*Node
,
340 uint64_t Offset
, uint64_t Size
,
341 unsigned char *ByteSeq
) {
342 const GlobalVariable
*V
= dyn_cast
<GlobalVariable
>(Node
->getGlobal());
344 if (!V
|| !V
->hasInitializer())
347 const Constant
*Init
= V
->getInitializer();
348 const DataLayout
&DL
= CurDAG
->getDataLayout();
351 auto it
= cs_vals_
.find(static_cast<const void *>(Init
));
352 if (it
!= cs_vals_
.end()) {
355 uint64_t total_size
= 0;
356 if (const ConstantStruct
*CS
= dyn_cast
<ConstantStruct
>(Init
))
358 DL
.getStructLayout(cast
<StructType
>(CS
->getType()))->getSizeInBytes();
359 else if (const ConstantArray
*CA
= dyn_cast
<ConstantArray
>(Init
))
360 total_size
= DL
.getTypeAllocSize(CA
->getType()->getElementType()) *
361 CA
->getNumOperands();
365 val_vec_type
Vals(total_size
, 0);
366 if (fillGenericConstant(DL
, Init
, Vals
, 0) == false)
368 cs_vals_
[static_cast<const void *>(Init
)] = Vals
;
369 TmpVal
= std::move(Vals
);
372 // test whether host endianness matches target
377 uint16_t test_val
= 0x2345;
378 if (DL
.isLittleEndian())
379 support::endian::write16le(test_buf
.c
, test_val
);
381 support::endian::write16be(test_buf
.c
, test_val
);
383 bool endian_match
= test_buf
.s
== test_val
;
384 for (uint64_t i
= Offset
, j
= 0; i
< Offset
+ Size
; i
++, j
++)
385 ByteSeq
[j
] = endian_match
? TmpVal
[i
] : TmpVal
[Offset
+ Size
- 1 - j
];
390 bool BPFDAGToDAGISel::fillGenericConstant(const DataLayout
&DL
,
392 val_vec_type
&Vals
, uint64_t Offset
) {
393 uint64_t Size
= DL
.getTypeAllocSize(CV
->getType());
395 if (isa
<ConstantAggregateZero
>(CV
) || isa
<UndefValue
>(CV
))
396 return true; // already done
398 if (const ConstantInt
*CI
= dyn_cast
<ConstantInt
>(CV
)) {
399 uint64_t val
= CI
->getZExtValue();
400 LLVM_DEBUG(dbgs() << "Byte array at offset " << Offset
<< " with value "
403 if (Size
> 8 || (Size
& (Size
- 1)))
406 // Store based on target endian
407 for (uint64_t i
= 0; i
< Size
; ++i
) {
408 Vals
[Offset
+ i
] = DL
.isLittleEndian()
409 ? ((val
>> (i
* 8)) & 0xFF)
410 : ((val
>> ((Size
- i
- 1) * 8)) & 0xFF);
415 if (const ConstantDataArray
*CDA
= dyn_cast
<ConstantDataArray
>(CV
))
416 return fillConstantDataArray(DL
, CDA
, Vals
, Offset
);
418 if (const ConstantArray
*CA
= dyn_cast
<ConstantArray
>(CV
))
419 return fillConstantArray(DL
, CA
, Vals
, Offset
);
421 if (const ConstantStruct
*CVS
= dyn_cast
<ConstantStruct
>(CV
))
422 return fillConstantStruct(DL
, CVS
, Vals
, Offset
);
427 bool BPFDAGToDAGISel::fillConstantDataArray(const DataLayout
&DL
,
428 const ConstantDataArray
*CDA
,
429 val_vec_type
&Vals
, int Offset
) {
430 for (unsigned i
= 0, e
= CDA
->getNumElements(); i
!= e
; ++i
) {
431 if (fillGenericConstant(DL
, CDA
->getElementAsConstant(i
), Vals
, Offset
) ==
434 Offset
+= DL
.getTypeAllocSize(CDA
->getElementAsConstant(i
)->getType());
440 bool BPFDAGToDAGISel::fillConstantArray(const DataLayout
&DL
,
441 const ConstantArray
*CA
,
442 val_vec_type
&Vals
, int Offset
) {
443 for (unsigned i
= 0, e
= CA
->getNumOperands(); i
!= e
; ++i
) {
444 if (fillGenericConstant(DL
, CA
->getOperand(i
), Vals
, Offset
) == false)
446 Offset
+= DL
.getTypeAllocSize(CA
->getOperand(i
)->getType());
452 bool BPFDAGToDAGISel::fillConstantStruct(const DataLayout
&DL
,
453 const ConstantStruct
*CS
,
454 val_vec_type
&Vals
, int Offset
) {
455 const StructLayout
*Layout
= DL
.getStructLayout(CS
->getType());
456 for (unsigned i
= 0, e
= CS
->getNumOperands(); i
!= e
; ++i
) {
457 const Constant
*Field
= CS
->getOperand(i
);
458 uint64_t SizeSoFar
= Layout
->getElementOffset(i
);
459 if (fillGenericConstant(DL
, Field
, Vals
, Offset
+ SizeSoFar
) == false)
465 void BPFDAGToDAGISel::PreprocessTrunc(SDNode
*Node
,
466 SelectionDAG::allnodes_iterator
&I
) {
467 ConstantSDNode
*MaskN
= dyn_cast
<ConstantSDNode
>(Node
->getOperand(1));
471 // The Reg operand should be a virtual register, which is defined
472 // outside the current basic block. DAG combiner has done a pretty
473 // good job in removing truncating inside a single basic block except
474 // when the Reg operand comes from bpf_load_[byte | half | word] for
475 // which the generic optimizer doesn't understand their results are
477 SDValue BaseV
= Node
->getOperand(0);
478 if (BaseV
.getOpcode() != ISD::INTRINSIC_W_CHAIN
)
481 unsigned IntNo
= cast
<ConstantSDNode
>(BaseV
->getOperand(1))->getZExtValue();
482 uint64_t MaskV
= MaskN
->getZExtValue();
484 if (!((IntNo
== Intrinsic::bpf_load_byte
&& MaskV
== 0xFF) ||
485 (IntNo
== Intrinsic::bpf_load_half
&& MaskV
== 0xFFFF) ||
486 (IntNo
== Intrinsic::bpf_load_word
&& MaskV
== 0xFFFFFFFF)))
489 LLVM_DEBUG(dbgs() << "Remove the redundant AND operation in: ";
490 Node
->dump(); dbgs() << '\n');
493 CurDAG
->ReplaceAllUsesWith(SDValue(Node
, 0), BaseV
);
495 CurDAG
->DeleteNode(Node
);
500 FunctionPass
*llvm::createBPFISelDag(BPFTargetMachine
&TM
) {
501 return new BPFDAGToDAGISel(TM
);