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/IR/IntrinsicsBPF.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"
36 #define DEBUG_TYPE "bpf-isel"
37 #define PASS_NAME "BPF DAG->DAG Pattern Instruction Selection"
39 // Instruction Selector Implementation
42 class BPFDAGToDAGISel
: public SelectionDAGISel
{
44 /// Subtarget - Keep a pointer to the BPFSubtarget around so that we can
45 /// make the right decision when generating code for different subtargets.
46 const BPFSubtarget
*Subtarget
;
51 BPFDAGToDAGISel() = delete;
53 explicit BPFDAGToDAGISel(BPFTargetMachine
&TM
)
54 : SelectionDAGISel(ID
, TM
), Subtarget(nullptr) {}
56 bool runOnMachineFunction(MachineFunction
&MF
) override
{
57 // Reset the subtarget each time through.
58 Subtarget
= &MF
.getSubtarget
<BPFSubtarget
>();
59 return SelectionDAGISel::runOnMachineFunction(MF
);
62 void PreprocessISelDAG() override
;
64 bool SelectInlineAsmMemoryOperand(const SDValue
&Op
,
65 InlineAsm::ConstraintCode ConstraintCode
,
66 std::vector
<SDValue
> &OutOps
) override
;
69 // Include the pieces autogenerated from the target description.
70 #include "BPFGenDAGISel.inc"
72 void Select(SDNode
*N
) override
;
74 // Complex Pattern for address selection.
75 bool SelectAddr(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
);
76 bool SelectFIAddr(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
);
78 // Node preprocessing cases
79 void PreprocessLoad(SDNode
*Node
, SelectionDAG::allnodes_iterator
&I
);
80 void PreprocessTrunc(SDNode
*Node
, SelectionDAG::allnodes_iterator
&I
);
82 // Find constants from a constant structure
83 typedef std::vector
<unsigned char> val_vec_type
;
84 bool fillGenericConstant(const DataLayout
&DL
, const Constant
*CV
,
85 val_vec_type
&Vals
, uint64_t Offset
);
86 bool fillConstantDataArray(const DataLayout
&DL
, const ConstantDataArray
*CDA
,
87 val_vec_type
&Vals
, int Offset
);
88 bool fillConstantArray(const DataLayout
&DL
, const ConstantArray
*CA
,
89 val_vec_type
&Vals
, int Offset
);
90 bool fillConstantStruct(const DataLayout
&DL
, const ConstantStruct
*CS
,
91 val_vec_type
&Vals
, int Offset
);
92 bool getConstantFieldValue(const GlobalAddressSDNode
*Node
, uint64_t Offset
,
93 uint64_t Size
, unsigned char *ByteSeq
);
94 // Mapping from ConstantStruct global value to corresponding byte-list values
95 std::map
<const void *, val_vec_type
> cs_vals_
;
99 char BPFDAGToDAGISel::ID
= 0;
101 INITIALIZE_PASS(BPFDAGToDAGISel
, DEBUG_TYPE
, PASS_NAME
, false, false)
103 // ComplexPattern used on BPF Load/Store instructions
104 bool BPFDAGToDAGISel::SelectAddr(SDValue Addr
, SDValue
&Base
, SDValue
&Offset
) {
105 // if Address is FI, get the TargetFrameIndex.
107 if (auto *FIN
= dyn_cast
<FrameIndexSDNode
>(Addr
)) {
108 Base
= CurDAG
->getTargetFrameIndex(FIN
->getIndex(), MVT::i64
);
109 Offset
= CurDAG
->getTargetConstant(0, DL
, MVT::i64
);
113 if (Addr
.getOpcode() == ISD::TargetExternalSymbol
||
114 Addr
.getOpcode() == ISD::TargetGlobalAddress
)
117 // Addresses of the form Addr+const or Addr|const
118 if (CurDAG
->isBaseWithConstantOffset(Addr
)) {
119 auto *CN
= cast
<ConstantSDNode
>(Addr
.getOperand(1));
120 if (isInt
<16>(CN
->getSExtValue())) {
121 // If the first operand is a FI, get the TargetFI Node
122 if (auto *FIN
= dyn_cast
<FrameIndexSDNode
>(Addr
.getOperand(0)))
123 Base
= CurDAG
->getTargetFrameIndex(FIN
->getIndex(), MVT::i64
);
125 Base
= Addr
.getOperand(0);
127 Offset
= CurDAG
->getTargetConstant(CN
->getSExtValue(), DL
, MVT::i64
);
133 Offset
= CurDAG
->getTargetConstant(0, DL
, MVT::i64
);
137 // ComplexPattern used on BPF FI instruction
138 bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr
, SDValue
&Base
,
142 if (!CurDAG
->isBaseWithConstantOffset(Addr
))
145 // Addresses of the form Addr+const or Addr|const
146 auto *CN
= cast
<ConstantSDNode
>(Addr
.getOperand(1));
147 if (isInt
<16>(CN
->getSExtValue())) {
148 // If the first operand is a FI, get the TargetFI Node
149 if (auto *FIN
= dyn_cast
<FrameIndexSDNode
>(Addr
.getOperand(0)))
150 Base
= CurDAG
->getTargetFrameIndex(FIN
->getIndex(), MVT::i64
);
154 Offset
= CurDAG
->getTargetConstant(CN
->getSExtValue(), DL
, MVT::i64
);
161 bool BPFDAGToDAGISel::SelectInlineAsmMemoryOperand(
162 const SDValue
&Op
, InlineAsm::ConstraintCode ConstraintCode
,
163 std::vector
<SDValue
> &OutOps
) {
165 switch (ConstraintCode
) {
168 case InlineAsm::ConstraintCode::m
: // memory
169 if (!SelectAddr(Op
, Op0
, Op1
))
175 SDValue AluOp
= CurDAG
->getTargetConstant(ISD::ADD
, DL
, MVT::i32
);
176 OutOps
.push_back(Op0
);
177 OutOps
.push_back(Op1
);
178 OutOps
.push_back(AluOp
);
182 void BPFDAGToDAGISel::Select(SDNode
*Node
) {
183 unsigned Opcode
= Node
->getOpcode();
185 // If we have a custom node, we already have selected!
186 if (Node
->isMachineOpcode()) {
187 LLVM_DEBUG(dbgs() << "== "; Node
->dump(CurDAG
); dbgs() << '\n');
191 // tablegen selection should be handled here.
196 if (!Subtarget
->hasSdivSmod()) {
198 const DebugLoc
&DL
= Node
->getDebugLoc();
200 errs() << "Error at line " << DL
.getLine() << ": ";
203 errs() << "Unsupport signed division for DAG: ";
204 Node
->print(errs(), CurDAG
);
205 errs() << "Please convert to unsigned div/mod.\n";
209 case ISD::INTRINSIC_W_CHAIN
: {
210 unsigned IntNo
= cast
<ConstantSDNode
>(Node
->getOperand(1))->getZExtValue();
212 case Intrinsic::bpf_load_byte
:
213 case Intrinsic::bpf_load_half
:
214 case Intrinsic::bpf_load_word
: {
216 SDValue Chain
= Node
->getOperand(0);
217 SDValue N1
= Node
->getOperand(1);
218 SDValue Skb
= Node
->getOperand(2);
219 SDValue N3
= Node
->getOperand(3);
221 SDValue R6Reg
= CurDAG
->getRegister(BPF::R6
, MVT::i64
);
222 Chain
= CurDAG
->getCopyToReg(Chain
, DL
, R6Reg
, Skb
, SDValue());
223 Node
= CurDAG
->UpdateNodeOperands(Node
, Chain
, N1
, R6Reg
, N3
);
230 case ISD::FrameIndex
: {
231 int FI
= cast
<FrameIndexSDNode
>(Node
)->getIndex();
232 EVT VT
= Node
->getValueType(0);
233 SDValue TFI
= CurDAG
->getTargetFrameIndex(FI
, VT
);
234 unsigned Opc
= BPF::MOV_rr
;
235 if (Node
->hasOneUse()) {
236 CurDAG
->SelectNodeTo(Node
, Opc
, VT
, TFI
);
239 ReplaceNode(Node
, CurDAG
->getMachineNode(Opc
, SDLoc(Node
), VT
, TFI
));
244 // Select the default instruction
248 void BPFDAGToDAGISel::PreprocessLoad(SDNode
*Node
,
249 SelectionDAG::allnodes_iterator
&I
) {
255 } new_val
; // hold up the constant values replacing loads.
256 bool to_replace
= false;
258 const LoadSDNode
*LD
= cast
<LoadSDNode
>(Node
);
259 uint64_t size
= LD
->getMemOperand()->getSize();
261 if (!size
|| size
> 8 || (size
& (size
- 1)) || !LD
->isSimple())
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);
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)
276 LLVM_DEBUG(dbgs() << "Check candidate load: "; LD
->dump(); dbgs() << '\n');
278 const GlobalAddressSDNode
*GADN
=
279 dyn_cast
<GlobalAddressSDNode
>(OP1N
->getOperand(0).getNode());
280 const ConstantSDNode
*CDN
= dyn_cast
<ConstantSDNode
>(OP2
.getNode());
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');
288 SDValue OP1
= LDAddrNode
->getOperand(0);
289 if (const GlobalAddressSDNode
*GADN
=
290 dyn_cast
<GlobalAddressSDNode
>(OP1
.getNode()))
291 to_replace
= getConstantFieldValue(GADN
, 0, size
, new_val
.c
);
297 // replacing the old with a new value
309 LLVM_DEBUG(dbgs() << "Replacing load of size " << size
<< " with constant "
311 SDValue NVal
= CurDAG
->getConstant(val
, DL
, LD
->getValueType(0));
313 // After replacement, the current node is dead, we need to
314 // go backward one step to make iterator still work
316 SDValue From
[] = {SDValue(Node
, 0), SDValue(Node
, 1)};
317 SDValue To
[] = {NVal
, NVal
};
318 CurDAG
->ReplaceAllUsesOfValuesWith(From
, To
, 2);
320 // It is safe to delete node now
321 CurDAG
->DeleteNode(Node
);
324 void BPFDAGToDAGISel::PreprocessISelDAG() {
325 // Iterate through all nodes, interested in the following case:
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.
331 // . Removing redundant AND for intrinsic narrow loads.
332 for (SelectionDAG::allnodes_iterator I
= CurDAG
->allnodes_begin(),
333 E
= CurDAG
->allnodes_end();
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
);
344 bool 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());
349 if (!V
|| !V
->hasInitializer() || !V
->isConstant())
352 const Constant
*Init
= V
->getInitializer();
353 const DataLayout
&DL
= CurDAG
->getDataLayout();
356 auto it
= cs_vals_
.find(static_cast<const void *>(Init
));
357 if (it
!= cs_vals_
.end()) {
360 uint64_t total_size
= 0;
361 if (const ConstantStruct
*CS
= dyn_cast
<ConstantStruct
>(Init
))
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();
370 val_vec_type
Vals(total_size
, 0);
371 if (fillGenericConstant(DL
, Init
, Vals
, 0) == false)
373 cs_vals_
[static_cast<const void *>(Init
)] = Vals
;
374 TmpVal
= std::move(Vals
);
377 // test whether host endianness matches target
382 uint16_t test_val
= 0x2345;
383 if (DL
.isLittleEndian())
384 support::endian::write16le(test_buf
.c
, test_val
);
386 support::endian::write16be(test_buf
.c
, test_val
);
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
];
395 bool BPFDAGToDAGISel::fillGenericConstant(const DataLayout
&DL
,
397 val_vec_type
&Vals
, uint64_t Offset
) {
398 uint64_t Size
= DL
.getTypeAllocSize(CV
->getType());
400 if (isa
<ConstantAggregateZero
>(CV
) || isa
<UndefValue
>(CV
))
401 return true; // already done
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 "
408 if (Size
> 8 || (Size
& (Size
- 1)))
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);
420 if (const ConstantDataArray
*CDA
= dyn_cast
<ConstantDataArray
>(CV
))
421 return fillConstantDataArray(DL
, CDA
, Vals
, Offset
);
423 if (const ConstantArray
*CA
= dyn_cast
<ConstantArray
>(CV
))
424 return fillConstantArray(DL
, CA
, Vals
, Offset
);
426 if (const ConstantStruct
*CVS
= dyn_cast
<ConstantStruct
>(CV
))
427 return fillConstantStruct(DL
, CVS
, Vals
, Offset
);
432 bool 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
) ==
439 Offset
+= DL
.getTypeAllocSize(CDA
->getElementAsConstant(i
)->getType());
445 bool 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)
451 Offset
+= DL
.getTypeAllocSize(CA
->getOperand(i
)->getType());
457 bool 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)
470 void BPFDAGToDAGISel::PreprocessTrunc(SDNode
*Node
,
471 SelectionDAG::allnodes_iterator
&I
) {
472 ConstantSDNode
*MaskN
= dyn_cast
<ConstantSDNode
>(Node
->getOperand(1));
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
482 SDValue BaseV
= Node
->getOperand(0);
483 if (BaseV
.getOpcode() != ISD::INTRINSIC_W_CHAIN
)
486 unsigned IntNo
= cast
<ConstantSDNode
>(BaseV
->getOperand(1))->getZExtValue();
487 uint64_t MaskV
= MaskN
->getZExtValue();
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)))
494 LLVM_DEBUG(dbgs() << "Remove the redundant AND operation in: ";
495 Node
->dump(); dbgs() << '\n');
498 CurDAG
->ReplaceAllUsesWith(SDValue(Node
, 0), BaseV
);
500 CurDAG
->DeleteNode(Node
);
503 FunctionPass
*llvm::createBPFISelDag(BPFTargetMachine
&TM
) {
504 return new BPFDAGToDAGISel(TM
);