blob: 8b9bc08e144f54f2100cc47fd481869e03ec721c [file] [log] [blame]
Alexei Starovoitove4c8c802015-01-24 17:51:26 +00001//===-- 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"
Yonghong Song5fbe01b2017-06-29 15:18:54 +000019#include "llvm/CodeGen/FunctionLoweringInfo.h"
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000020#include "llvm/CodeGen/MachineConstantPool.h"
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000021#include "llvm/CodeGen/MachineFrameInfo.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000022#include "llvm/CodeGen/MachineFunction.h"
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000023#include "llvm/CodeGen/MachineInstrBuilder.h"
24#include "llvm/CodeGen/MachineRegisterInfo.h"
25#include "llvm/CodeGen/SelectionDAGISel.h"
Yonghong Songac2e2502017-06-16 15:41:16 +000026#include "llvm/IR/Constants.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000027#include "llvm/IR/IntrinsicInst.h"
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000028#include "llvm/Support/Debug.h"
Yonghong Songac2e2502017-06-16 15:41:16 +000029#include "llvm/Support/Endian.h"
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000030#include "llvm/Support/ErrorHandling.h"
31#include "llvm/Support/raw_ostream.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000032#include "llvm/Target/TargetMachine.h"
Yonghong Songac2e2502017-06-16 15:41:16 +000033
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000034using namespace llvm;
35
36#define DEBUG_TYPE "bpf-isel"
37
38// Instruction Selector Implementation
39namespace {
40
41class BPFDAGToDAGISel : public SelectionDAGISel {
Yonghong Songb1a52bd2018-02-23 23:49:28 +000042
43 /// Subtarget - Keep a pointer to the BPFSubtarget around so that we can
44 /// make the right decision when generating code for different subtargets.
45 const BPFSubtarget *Subtarget;
46
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000047public:
Yonghong Songb1a52bd2018-02-23 23:49:28 +000048 explicit BPFDAGToDAGISel(BPFTargetMachine &TM)
49 : SelectionDAGISel(TM), Subtarget(nullptr) {
Yonghong Song9af998e2017-10-24 21:36:33 +000050 curr_func_ = nullptr;
51 }
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000052
Mehdi Amini117296c2016-10-01 02:56:57 +000053 StringRef getPassName() const override {
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000054 return "BPF DAG->DAG Pattern Instruction Selection";
55 }
56
Yonghong Songb1a52bd2018-02-23 23:49:28 +000057 bool runOnMachineFunction(MachineFunction &MF) override {
58 // Reset the subtarget each time through.
59 Subtarget = &MF.getSubtarget<BPFSubtarget>();
60 return SelectionDAGISel::runOnMachineFunction(MF);
61 }
62
Yonghong Songac2e2502017-06-16 15:41:16 +000063 void PreprocessISelDAG() override;
64
Yonghong Song9ef85f02017-09-18 23:29:36 +000065 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
66 std::vector<SDValue> &OutOps) override;
67
68
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000069private:
70// Include the pieces autogenerated from the target description.
71#include "BPFGenDAGISel.inc"
72
Justin Bognerf076e792016-05-12 21:14:47 +000073 void Select(SDNode *N) override;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000074
75 // Complex Pattern for address selection.
76 bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
Alexei Starovoitov4e01a382015-10-06 04:00:53 +000077 bool SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
Yonghong Songac2e2502017-06-16 15:41:16 +000078
Yonghong Song5fbe01b2017-06-29 15:18:54 +000079 // Node preprocessing cases
Yonghong Song920df522018-02-15 17:06:45 +000080 void PreprocessLoad(SDNode *Node, SelectionDAG::allnodes_iterator &I);
Yonghong Song5fbe01b2017-06-29 15:18:54 +000081 void PreprocessCopyToReg(SDNode *Node);
Yonghong Song920df522018-02-15 17:06:45 +000082 void PreprocessTrunc(SDNode *Node, SelectionDAG::allnodes_iterator &I);
Yonghong Song5fbe01b2017-06-29 15:18:54 +000083
Yonghong Songac2e2502017-06-16 15:41:16 +000084 // Find constants from a constant structure
85 typedef std::vector<unsigned char> val_vec_type;
86 bool fillGenericConstant(const DataLayout &DL, const Constant *CV,
87 val_vec_type &Vals, uint64_t Offset);
88 bool fillConstantDataArray(const DataLayout &DL, const ConstantDataArray *CDA,
89 val_vec_type &Vals, int Offset);
90 bool fillConstantArray(const DataLayout &DL, const ConstantArray *CA,
91 val_vec_type &Vals, int Offset);
92 bool fillConstantStruct(const DataLayout &DL, const ConstantStruct *CS,
93 val_vec_type &Vals, int Offset);
94 bool getConstantFieldValue(const GlobalAddressSDNode *Node, uint64_t Offset,
95 uint64_t Size, unsigned char *ByteSeq);
Yonghong Song5fbe01b2017-06-29 15:18:54 +000096 bool checkLoadDef(unsigned DefReg, unsigned match_load_op);
Yonghong Songac2e2502017-06-16 15:41:16 +000097
98 // Mapping from ConstantStruct global value to corresponding byte-list values
99 std::map<const void *, val_vec_type> cs_vals_;
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000100 // Mapping from vreg to load memory opcode
101 std::map<unsigned, unsigned> load_to_vreg_;
Yonghong Songee68d8e2017-10-24 18:21:10 +0000102 // Current function
103 const Function *curr_func_;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000104};
Yonghong Songac2e2502017-06-16 15:41:16 +0000105} // namespace
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000106
107// ComplexPattern used on BPF Load/Store instructions
108bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) {
109 // if Address is FI, get the TargetFrameIndex.
Alexei Starovoitov659ece92015-04-28 20:38:56 +0000110 SDLoc DL(Addr);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000111 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Yonghong Songac2e2502017-06-16 15:41:16 +0000112 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
Alexei Starovoitov659ece92015-04-28 20:38:56 +0000113 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000114 return true;
115 }
116
117 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
118 Addr.getOpcode() == ISD::TargetGlobalAddress)
119 return false;
120
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000121 // Addresses of the form Addr+const or Addr|const
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000122 if (CurDAG->isBaseWithConstantOffset(Addr)) {
123 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
Alexei Starovoitov56db1452017-04-13 22:24:13 +0000124 if (isInt<16>(CN->getSExtValue())) {
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000125
126 // If the first operand is a FI, get the TargetFI Node
127 if (FrameIndexSDNode *FIN =
128 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
129 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
130 else
131 Base = Addr.getOperand(0);
132
Alexei Starovoitov659ece92015-04-28 20:38:56 +0000133 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000134 return true;
135 }
136 }
137
Yonghong Songac2e2502017-06-16 15:41:16 +0000138 Base = Addr;
Alexei Starovoitov659ece92015-04-28 20:38:56 +0000139 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000140 return true;
141}
142
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000143// ComplexPattern used on BPF FI instruction
Yonghong Songac2e2502017-06-16 15:41:16 +0000144bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base,
145 SDValue &Offset) {
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000146 SDLoc DL(Addr);
147
148 if (!CurDAG->isBaseWithConstantOffset(Addr))
149 return false;
150
151 // Addresses of the form Addr+const or Addr|const
152 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
Alexei Starovoitov56db1452017-04-13 22:24:13 +0000153 if (isInt<16>(CN->getSExtValue())) {
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000154
155 // If the first operand is a FI, get the TargetFI Node
Yonghong Songac2e2502017-06-16 15:41:16 +0000156 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000157 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
158 else
159 return false;
160
161 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64);
162 return true;
163 }
164
165 return false;
166}
167
Yonghong Song9ef85f02017-09-18 23:29:36 +0000168bool BPFDAGToDAGISel::SelectInlineAsmMemoryOperand(
169 const SDValue &Op, unsigned ConstraintCode, std::vector<SDValue> &OutOps) {
170 SDValue Op0, Op1;
171 switch (ConstraintCode) {
172 default:
173 return true;
174 case InlineAsm::Constraint_m: // memory
175 if (!SelectAddr(Op, Op0, Op1))
176 return true;
177 break;
178 }
179
180 SDLoc DL(Op);
181 SDValue AluOp = CurDAG->getTargetConstant(ISD::ADD, DL, MVT::i32);;
182 OutOps.push_back(Op0);
183 OutOps.push_back(Op1);
184 OutOps.push_back(AluOp);
185 return false;
186}
187
Justin Bognerf076e792016-05-12 21:14:47 +0000188void BPFDAGToDAGISel::Select(SDNode *Node) {
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000189 unsigned Opcode = Node->getOpcode();
190
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000191 // If we have a custom node, we already have selected!
192 if (Node->isMachineOpcode()) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000193 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
Justin Bognerf076e792016-05-12 21:14:47 +0000194 return;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000195 }
196
197 // tablegen selection should be handled here.
198 switch (Opcode) {
Yonghong Songac2e2502017-06-16 15:41:16 +0000199 default:
200 break;
Alexei Starovoitov7e453bb2016-03-18 22:02:47 +0000201 case ISD::SDIV: {
202 DebugLoc Empty;
203 const DebugLoc &DL = Node->getDebugLoc();
204 if (DL != Empty)
205 errs() << "Error at line " << DL.getLine() << ": ";
206 else
207 errs() << "Error: ";
208 errs() << "Unsupport signed division for DAG: ";
Matthias Braun8c209aa2017-01-28 02:02:38 +0000209 Node->print(errs(), CurDAG);
Alexei Starovoitov7e453bb2016-03-18 22:02:47 +0000210 errs() << "Please convert to unsigned div/mod.\n";
211 break;
212 }
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000213 case ISD::INTRINSIC_W_CHAIN: {
214 unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
215 switch (IntNo) {
216 case Intrinsic::bpf_load_byte:
217 case Intrinsic::bpf_load_half:
218 case Intrinsic::bpf_load_word: {
219 SDLoc DL(Node);
220 SDValue Chain = Node->getOperand(0);
221 SDValue N1 = Node->getOperand(1);
222 SDValue Skb = Node->getOperand(2);
223 SDValue N3 = Node->getOperand(3);
224
225 SDValue R6Reg = CurDAG->getRegister(BPF::R6, MVT::i64);
226 Chain = CurDAG->getCopyToReg(Chain, DL, R6Reg, Skb, SDValue());
227 Node = CurDAG->UpdateNodeOperands(Node, Chain, N1, R6Reg, N3);
228 break;
229 }
230 }
231 break;
232 }
233
234 case ISD::FrameIndex: {
Benjamin Kramer619c4e52015-04-10 11:24:51 +0000235 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000236 EVT VT = Node->getValueType(0);
237 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
238 unsigned Opc = BPF::MOV_rr;
Justin Bognerf076e792016-05-12 21:14:47 +0000239 if (Node->hasOneUse()) {
240 CurDAG->SelectNodeTo(Node, Opc, VT, TFI);
241 return;
242 }
243 ReplaceNode(Node, CurDAG->getMachineNode(Opc, SDLoc(Node), VT, TFI));
244 return;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000245 }
246 }
247
248 // Select the default instruction
Justin Bognerf076e792016-05-12 21:14:47 +0000249 SelectCode(Node);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000250}
251
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000252void BPFDAGToDAGISel::PreprocessLoad(SDNode *Node,
Yonghong Song920df522018-02-15 17:06:45 +0000253 SelectionDAG::allnodes_iterator &I) {
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000254 union {
255 uint8_t c[8];
256 uint16_t s;
257 uint32_t i;
258 uint64_t d;
259 } new_val; // hold up the constant values replacing loads.
260 bool to_replace = false;
261 SDLoc DL(Node);
262 const LoadSDNode *LD = cast<LoadSDNode>(Node);
263 uint64_t size = LD->getMemOperand()->getSize();
264
265 if (!size || size > 8 || (size & (size - 1)))
266 return;
267
268 SDNode *LDAddrNode = LD->getOperand(1).getNode();
269 // Match LDAddr against either global_addr or (global_addr + offset)
270 unsigned opcode = LDAddrNode->getOpcode();
271 if (opcode == ISD::ADD) {
272 SDValue OP1 = LDAddrNode->getOperand(0);
273 SDValue OP2 = LDAddrNode->getOperand(1);
274
275 // We want to find the pattern global_addr + offset
276 SDNode *OP1N = OP1.getNode();
277 if (OP1N->getOpcode() <= ISD::BUILTIN_OP_END || OP1N->getNumOperands() == 0)
278 return;
279
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000280 LLVM_DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n');
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000281
282 const GlobalAddressSDNode *GADN =
283 dyn_cast<GlobalAddressSDNode>(OP1N->getOperand(0).getNode());
284 const ConstantSDNode *CDN = dyn_cast<ConstantSDNode>(OP2.getNode());
285 if (GADN && CDN)
286 to_replace =
287 getConstantFieldValue(GADN, CDN->getZExtValue(), size, new_val.c);
288 } else if (LDAddrNode->getOpcode() > ISD::BUILTIN_OP_END &&
289 LDAddrNode->getNumOperands() > 0) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000290 LLVM_DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n');
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000291
292 SDValue OP1 = LDAddrNode->getOperand(0);
293 if (const GlobalAddressSDNode *GADN =
294 dyn_cast<GlobalAddressSDNode>(OP1.getNode()))
295 to_replace = getConstantFieldValue(GADN, 0, size, new_val.c);
296 }
297
298 if (!to_replace)
299 return;
300
301 // replacing the old with a new value
302 uint64_t val;
303 if (size == 1)
304 val = new_val.c[0];
305 else if (size == 2)
306 val = new_val.s;
307 else if (size == 4)
308 val = new_val.i;
309 else {
310 val = new_val.d;
311 }
312
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000313 LLVM_DEBUG(dbgs() << "Replacing load of size " << size << " with constant "
314 << val << '\n');
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000315 SDValue NVal = CurDAG->getConstant(val, DL, MVT::i64);
316
317 // After replacement, the current node is dead, we need to
318 // go backward one step to make iterator still work
319 I--;
320 SDValue From[] = {SDValue(Node, 0), SDValue(Node, 1)};
321 SDValue To[] = {NVal, NVal};
322 CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2);
323 I++;
324 // It is safe to delete node now
325 CurDAG->DeleteNode(Node);
326}
327
Yonghong Songac2e2502017-06-16 15:41:16 +0000328void BPFDAGToDAGISel::PreprocessISelDAG() {
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000329 // Iterate through all nodes, interested in the following cases:
330 //
331 // . loads from ConstantStruct or ConstantArray of constructs
332 // which can be turns into constant itself, with this we can
333 // avoid reading from read-only section at runtime.
334 //
335 // . reg truncating is often the result of 8/16/32bit->64bit or
336 // 8/16bit->32bit conversion. If the reg value is loaded with
337 // masked byte width, the AND operation can be removed since
338 // BPF LOAD already has zero extension.
339 //
340 // This also solved a correctness issue.
341 // In BPF socket-related program, e.g., __sk_buff->{data, data_end}
342 // are 32-bit registers, but later on, kernel verifier will rewrite
343 // it with 64-bit value. Therefore, truncating the value after the
344 // load will result in incorrect code.
Yonghong Song0f836d52017-10-24 17:29:03 +0000345
346 // clear the load_to_vreg_ map so that we have a clean start
347 // for this function.
Yonghong Songee68d8e2017-10-24 18:21:10 +0000348 if (!curr_func_) {
349 curr_func_ = FuncInfo->Fn;
350 } else if (curr_func_ != FuncInfo->Fn) {
351 load_to_vreg_.clear();
352 curr_func_ = FuncInfo->Fn;
353 }
Yonghong Song0f836d52017-10-24 17:29:03 +0000354
Yonghong Songac2e2502017-06-16 15:41:16 +0000355 for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(),
356 E = CurDAG->allnodes_end();
357 I != E;) {
358 SDNode *Node = &*I++;
359 unsigned Opcode = Node->getOpcode();
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000360 if (Opcode == ISD::LOAD)
361 PreprocessLoad(Node, I);
362 else if (Opcode == ISD::CopyToReg)
363 PreprocessCopyToReg(Node);
364 else if (Opcode == ISD::AND)
365 PreprocessTrunc(Node, I);
Yonghong Songac2e2502017-06-16 15:41:16 +0000366 }
367}
368
369bool BPFDAGToDAGISel::getConstantFieldValue(const GlobalAddressSDNode *Node,
370 uint64_t Offset, uint64_t Size,
371 unsigned char *ByteSeq) {
372 const GlobalVariable *V = dyn_cast<GlobalVariable>(Node->getGlobal());
373
374 if (!V || !V->hasInitializer())
375 return false;
376
377 const Constant *Init = V->getInitializer();
378 const DataLayout &DL = CurDAG->getDataLayout();
379 val_vec_type TmpVal;
380
381 auto it = cs_vals_.find(static_cast<const void *>(Init));
382 if (it != cs_vals_.end()) {
383 TmpVal = it->second;
384 } else {
385 uint64_t total_size = 0;
386 if (const ConstantStruct *CS = dyn_cast<ConstantStruct>(Init))
387 total_size =
388 DL.getStructLayout(cast<StructType>(CS->getType()))->getSizeInBytes();
389 else if (const ConstantArray *CA = dyn_cast<ConstantArray>(Init))
390 total_size = DL.getTypeAllocSize(CA->getType()->getElementType()) *
391 CA->getNumOperands();
392 else
393 return false;
394
395 val_vec_type Vals(total_size, 0);
396 if (fillGenericConstant(DL, Init, Vals, 0) == false)
397 return false;
398 cs_vals_[static_cast<const void *>(Init)] = Vals;
399 TmpVal = std::move(Vals);
400 }
401
402 // test whether host endianness matches target
Yonghong Songa63178f2017-06-16 23:28:04 +0000403 union {
404 uint8_t c[2];
405 uint16_t s;
406 } test_buf;
Yonghong Songac2e2502017-06-16 15:41:16 +0000407 uint16_t test_val = 0x2345;
408 if (DL.isLittleEndian())
Yonghong Songa63178f2017-06-16 23:28:04 +0000409 support::endian::write16le(test_buf.c, test_val);
Yonghong Songac2e2502017-06-16 15:41:16 +0000410 else
Yonghong Songa63178f2017-06-16 23:28:04 +0000411 support::endian::write16be(test_buf.c, test_val);
Yonghong Songac2e2502017-06-16 15:41:16 +0000412
Yonghong Songa63178f2017-06-16 23:28:04 +0000413 bool endian_match = test_buf.s == test_val;
Yonghong Songac2e2502017-06-16 15:41:16 +0000414 for (uint64_t i = Offset, j = 0; i < Offset + Size; i++, j++)
415 ByteSeq[j] = endian_match ? TmpVal[i] : TmpVal[Offset + Size - 1 - j];
416
417 return true;
418}
419
420bool BPFDAGToDAGISel::fillGenericConstant(const DataLayout &DL,
421 const Constant *CV,
422 val_vec_type &Vals, uint64_t Offset) {
423 uint64_t Size = DL.getTypeAllocSize(CV->getType());
424
425 if (isa<ConstantAggregateZero>(CV) || isa<UndefValue>(CV))
426 return true; // already done
427
428 if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
429 uint64_t val = CI->getZExtValue();
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000430 LLVM_DEBUG(dbgs() << "Byte array at offset " << Offset << " with value "
431 << val << '\n');
Yonghong Songac2e2502017-06-16 15:41:16 +0000432
433 if (Size > 8 || (Size & (Size - 1)))
434 return false;
435
436 // Store based on target endian
437 for (uint64_t i = 0; i < Size; ++i) {
438 Vals[Offset + i] = DL.isLittleEndian()
439 ? ((val >> (i * 8)) & 0xFF)
440 : ((val >> ((Size - i - 1) * 8)) & 0xFF);
441 }
442 return true;
443 }
444
445 if (const ConstantDataArray *CDA = dyn_cast<ConstantDataArray>(CV))
446 return fillConstantDataArray(DL, CDA, Vals, Offset);
447
448 if (const ConstantArray *CA = dyn_cast<ConstantArray>(CV))
449 return fillConstantArray(DL, CA, Vals, Offset);
450
451 if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV))
452 return fillConstantStruct(DL, CVS, Vals, Offset);
453
454 return false;
455}
456
457bool BPFDAGToDAGISel::fillConstantDataArray(const DataLayout &DL,
458 const ConstantDataArray *CDA,
459 val_vec_type &Vals, int Offset) {
460 for (unsigned i = 0, e = CDA->getNumElements(); i != e; ++i) {
461 if (fillGenericConstant(DL, CDA->getElementAsConstant(i), Vals, Offset) ==
462 false)
463 return false;
464 Offset += DL.getTypeAllocSize(CDA->getElementAsConstant(i)->getType());
465 }
466
467 return true;
468}
469
470bool BPFDAGToDAGISel::fillConstantArray(const DataLayout &DL,
471 const ConstantArray *CA,
472 val_vec_type &Vals, int Offset) {
473 for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
474 if (fillGenericConstant(DL, CA->getOperand(i), Vals, Offset) == false)
475 return false;
476 Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType());
477 }
478
479 return true;
480}
481
482bool BPFDAGToDAGISel::fillConstantStruct(const DataLayout &DL,
483 const ConstantStruct *CS,
484 val_vec_type &Vals, int Offset) {
485 const StructLayout *Layout = DL.getStructLayout(CS->getType());
486 for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) {
487 const Constant *Field = CS->getOperand(i);
488 uint64_t SizeSoFar = Layout->getElementOffset(i);
489 if (fillGenericConstant(DL, Field, Vals, Offset + SizeSoFar) == false)
490 return false;
491 }
492 return true;
493}
494
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000495void BPFDAGToDAGISel::PreprocessCopyToReg(SDNode *Node) {
496 const RegisterSDNode *RegN = dyn_cast<RegisterSDNode>(Node->getOperand(1));
497 if (!RegN || !TargetRegisterInfo::isVirtualRegister(RegN->getReg()))
498 return;
499
500 const LoadSDNode *LD = dyn_cast<LoadSDNode>(Node->getOperand(2));
501 if (!LD)
502 return;
503
504 // Assign a load value to a virtual register. record its load width
505 unsigned mem_load_op = 0;
506 switch (LD->getMemOperand()->getSize()) {
507 default:
508 return;
509 case 4:
510 mem_load_op = BPF::LDW;
511 break;
512 case 2:
513 mem_load_op = BPF::LDH;
514 break;
515 case 1:
516 mem_load_op = BPF::LDB;
517 break;
518 }
519
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000520 LLVM_DEBUG(dbgs() << "Find Load Value to VReg "
521 << TargetRegisterInfo::virtReg2Index(RegN->getReg())
522 << '\n');
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000523 load_to_vreg_[RegN->getReg()] = mem_load_op;
524}
525
526void BPFDAGToDAGISel::PreprocessTrunc(SDNode *Node,
Yonghong Song920df522018-02-15 17:06:45 +0000527 SelectionDAG::allnodes_iterator &I) {
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000528 ConstantSDNode *MaskN = dyn_cast<ConstantSDNode>(Node->getOperand(1));
529 if (!MaskN)
530 return;
531
Yonghong Songb42c7c72018-01-16 07:27:19 +0000532 // The Reg operand should be a virtual register, which is defined
533 // outside the current basic block. DAG combiner has done a pretty
534 // good job in removing truncating inside a single basic block except
535 // when the Reg operand comes from bpf_load_[byte | half | word] for
536 // which the generic optimizer doesn't understand their results are
537 // zero extended.
538 SDValue BaseV = Node->getOperand(0);
539 if (BaseV.getOpcode() == ISD::INTRINSIC_W_CHAIN) {
540 unsigned IntNo = cast<ConstantSDNode>(BaseV->getOperand(1))->getZExtValue();
541 uint64_t MaskV = MaskN->getZExtValue();
542
543 if (!((IntNo == Intrinsic::bpf_load_byte && MaskV == 0xFF) ||
544 (IntNo == Intrinsic::bpf_load_half && MaskV == 0xFFFF) ||
545 (IntNo == Intrinsic::bpf_load_word && MaskV == 0xFFFFFFFF)))
546 return;
547
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000548 LLVM_DEBUG(dbgs() << "Remove the redundant AND operation in: ";
549 Node->dump(); dbgs() << '\n');
Yonghong Songb42c7c72018-01-16 07:27:19 +0000550
551 I--;
552 CurDAG->ReplaceAllUsesWith(SDValue(Node, 0), BaseV);
553 I++;
554 CurDAG->DeleteNode(Node);
555
556 return;
557 }
558
559 // Multiple basic blocks case.
560 if (BaseV.getOpcode() != ISD::CopyFromReg)
561 return;
562
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000563 unsigned match_load_op = 0;
564 switch (MaskN->getZExtValue()) {
565 default:
566 return;
567 case 0xFFFFFFFF:
568 match_load_op = BPF::LDW;
569 break;
570 case 0xFFFF:
571 match_load_op = BPF::LDH;
572 break;
573 case 0xFF:
574 match_load_op = BPF::LDB;
575 break;
576 }
577
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000578 const RegisterSDNode *RegN =
579 dyn_cast<RegisterSDNode>(BaseV.getNode()->getOperand(1));
580 if (!RegN || !TargetRegisterInfo::isVirtualRegister(RegN->getReg()))
581 return;
582 unsigned AndOpReg = RegN->getReg();
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000583 LLVM_DEBUG(dbgs() << "Examine " << printReg(AndOpReg) << '\n');
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000584
585 // Examine the PHI insns in the MachineBasicBlock to found out the
586 // definitions of this virtual register. At this stage (DAG2DAG
587 // transformation), only PHI machine insns are available in the machine basic
588 // block.
589 MachineBasicBlock *MBB = FuncInfo->MBB;
590 MachineInstr *MII = nullptr;
591 for (auto &MI : *MBB) {
592 for (unsigned i = 0; i < MI.getNumOperands(); ++i) {
593 const MachineOperand &MOP = MI.getOperand(i);
594 if (!MOP.isReg() || !MOP.isDef())
595 continue;
596 unsigned Reg = MOP.getReg();
597 if (TargetRegisterInfo::isVirtualRegister(Reg) && Reg == AndOpReg) {
598 MII = &MI;
599 break;
600 }
601 }
602 }
603
604 if (MII == nullptr) {
605 // No phi definition in this block.
606 if (!checkLoadDef(AndOpReg, match_load_op))
607 return;
608 } else {
609 // The PHI node looks like:
Francis Visoiu Mistriha8a83d12017-12-07 10:40:31 +0000610 // %2 = PHI %0, <%bb.1>, %1, <%bb.3>
Francis Visoiu Mistrih25528d62017-12-04 17:18:51 +0000611 // Trace each incoming definition, e.g., (%0, %bb.1) and (%1, %bb.3)
612 // The AND operation can be removed if both %0 in %bb.1 and %1 in
Fangrui Song956ee792018-03-30 22:22:31 +0000613 // %bb.3 are defined with a load matching the MaskN.
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000614 LLVM_DEBUG(dbgs() << "Check PHI Insn: "; MII->dump(); dbgs() << '\n');
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000615 unsigned PrevReg = -1;
616 for (unsigned i = 0; i < MII->getNumOperands(); ++i) {
617 const MachineOperand &MOP = MII->getOperand(i);
618 if (MOP.isReg()) {
619 if (MOP.isDef())
620 continue;
621 PrevReg = MOP.getReg();
622 if (!TargetRegisterInfo::isVirtualRegister(PrevReg))
623 return;
624 if (!checkLoadDef(PrevReg, match_load_op))
625 return;
626 }
627 }
628 }
629
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000630 LLVM_DEBUG(dbgs() << "Remove the redundant AND operation in: "; Node->dump();
631 dbgs() << '\n');
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000632
633 I--;
634 CurDAG->ReplaceAllUsesWith(SDValue(Node, 0), BaseV);
635 I++;
636 CurDAG->DeleteNode(Node);
637}
638
639bool BPFDAGToDAGISel::checkLoadDef(unsigned DefReg, unsigned match_load_op) {
640 auto it = load_to_vreg_.find(DefReg);
641 if (it == load_to_vreg_.end())
642 return false; // The definition of register is not exported yet.
643
644 return it->second == match_load_op;
645}
646
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000647FunctionPass *llvm::createBPFISelDag(BPFTargetMachine &TM) {
648 return new BPFDAGToDAGISel(TM);
649}