blob: 1f382f3e73f50d6d6e068ee5034b8db570283716 [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 {
42public:
43 explicit BPFDAGToDAGISel(BPFTargetMachine &TM) : SelectionDAGISel(TM) {}
44
Mehdi Amini117296c2016-10-01 02:56:57 +000045 StringRef getPassName() const override {
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000046 return "BPF DAG->DAG Pattern Instruction Selection";
47 }
48
Yonghong Songac2e2502017-06-16 15:41:16 +000049 void PreprocessISelDAG() override;
50
Yonghong Song9ef85f02017-09-18 23:29:36 +000051 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
52 std::vector<SDValue> &OutOps) override;
53
54
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000055private:
56// Include the pieces autogenerated from the target description.
57#include "BPFGenDAGISel.inc"
58
Justin Bognerf076e792016-05-12 21:14:47 +000059 void Select(SDNode *N) override;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000060
61 // Complex Pattern for address selection.
62 bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
Alexei Starovoitov4e01a382015-10-06 04:00:53 +000063 bool SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
Yonghong Songac2e2502017-06-16 15:41:16 +000064
Yonghong Song5fbe01b2017-06-29 15:18:54 +000065 // 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
Yonghong Songac2e2502017-06-16 15:41:16 +000070 // 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);
Yonghong Song5fbe01b2017-06-29 15:18:54 +000082 bool checkLoadDef(unsigned DefReg, unsigned match_load_op);
Yonghong Songac2e2502017-06-16 15:41:16 +000083
84 // Mapping from ConstantStruct global value to corresponding byte-list values
85 std::map<const void *, val_vec_type> cs_vals_;
Yonghong Song5fbe01b2017-06-29 15:18:54 +000086 // Mapping from vreg to load memory opcode
87 std::map<unsigned, unsigned> load_to_vreg_;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000088};
Yonghong Songac2e2502017-06-16 15:41:16 +000089} // namespace
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000090
91// ComplexPattern used on BPF Load/Store instructions
92bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) {
93 // if Address is FI, get the TargetFrameIndex.
Alexei Starovoitov659ece92015-04-28 20:38:56 +000094 SDLoc DL(Addr);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000095 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Yonghong Songac2e2502017-06-16 15:41:16 +000096 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
Alexei Starovoitov659ece92015-04-28 20:38:56 +000097 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000098 return true;
99 }
100
101 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
102 Addr.getOpcode() == ISD::TargetGlobalAddress)
103 return false;
104
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000105 // Addresses of the form Addr+const or Addr|const
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000106 if (CurDAG->isBaseWithConstantOffset(Addr)) {
107 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
Alexei Starovoitov56db1452017-04-13 22:24:13 +0000108 if (isInt<16>(CN->getSExtValue())) {
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000109
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
Alexei Starovoitov659ece92015-04-28 20:38:56 +0000117 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000118 return true;
119 }
120 }
121
Yonghong Songac2e2502017-06-16 15:41:16 +0000122 Base = Addr;
Alexei Starovoitov659ece92015-04-28 20:38:56 +0000123 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000124 return true;
125}
126
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000127// ComplexPattern used on BPF FI instruction
Yonghong Songac2e2502017-06-16 15:41:16 +0000128bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base,
129 SDValue &Offset) {
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000130 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));
Alexei Starovoitov56db1452017-04-13 22:24:13 +0000137 if (isInt<16>(CN->getSExtValue())) {
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000138
139 // If the first operand is a FI, get the TargetFI Node
Yonghong Songac2e2502017-06-16 15:41:16 +0000140 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000141 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
Yonghong Song9ef85f02017-09-18 23:29:36 +0000152bool 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
Justin Bognerf076e792016-05-12 21:14:47 +0000172void BPFDAGToDAGISel::Select(SDNode *Node) {
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000173 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');
Justin Bognerf076e792016-05-12 21:14:47 +0000181 return;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000182 }
183
184 // tablegen selection should be handled here.
185 switch (Opcode) {
Yonghong Songac2e2502017-06-16 15:41:16 +0000186 default:
187 break;
Alexei Starovoitov7e453bb2016-03-18 22:02:47 +0000188 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: ";
Matthias Braun8c209aa2017-01-28 02:02:38 +0000196 Node->print(errs(), CurDAG);
Alexei Starovoitov7e453bb2016-03-18 22:02:47 +0000197 errs() << "Please convert to unsigned div/mod.\n";
198 break;
199 }
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000200 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: {
Benjamin Kramer619c4e52015-04-10 11:24:51 +0000222 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000223 EVT VT = Node->getValueType(0);
224 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
225 unsigned Opc = BPF::MOV_rr;
Justin Bognerf076e792016-05-12 21:14:47 +0000226 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;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000232 }
233 }
234
235 // Select the default instruction
Justin Bognerf076e792016-05-12 21:14:47 +0000236 SelectCode(Node);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000237}
238
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000239void 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
Yonghong Songac2e2502017-06-16 15:41:16 +0000315void BPFDAGToDAGISel::PreprocessISelDAG() {
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000316 // 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.
Yonghong Songac2e2502017-06-16 15:41:16 +0000332 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();
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000337 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);
Yonghong Songac2e2502017-06-16 15:41:16 +0000343 }
344}
345
346bool 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
Yonghong Songa63178f2017-06-16 23:28:04 +0000380 union {
381 uint8_t c[2];
382 uint16_t s;
383 } test_buf;
Yonghong Songac2e2502017-06-16 15:41:16 +0000384 uint16_t test_val = 0x2345;
385 if (DL.isLittleEndian())
Yonghong Songa63178f2017-06-16 23:28:04 +0000386 support::endian::write16le(test_buf.c, test_val);
Yonghong Songac2e2502017-06-16 15:41:16 +0000387 else
Yonghong Songa63178f2017-06-16 23:28:04 +0000388 support::endian::write16be(test_buf.c, test_val);
Yonghong Songac2e2502017-06-16 15:41:16 +0000389
Yonghong Songa63178f2017-06-16 23:28:04 +0000390 bool endian_match = test_buf.s == test_val;
Yonghong Songac2e2502017-06-16 15:41:16 +0000391 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
397bool 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
434bool 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
447bool 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
459bool 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
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000472void 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
502void 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
592bool 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
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000600FunctionPass *llvm::createBPFISelDag(BPFTargetMachine &TM) {
601 return new BPFDAGToDAGISel(TM);
602}