blob: f48429ee57b0ad937280b92c95a9a2c3c52b2716 [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
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000051private:
52// Include the pieces autogenerated from the target description.
53#include "BPFGenDAGISel.inc"
54
Justin Bognerf076e792016-05-12 21:14:47 +000055 void Select(SDNode *N) override;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000056
57 // Complex Pattern for address selection.
58 bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
Alexei Starovoitov4e01a382015-10-06 04:00:53 +000059 bool SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
Yonghong Songac2e2502017-06-16 15:41:16 +000060
Yonghong Song5fbe01b2017-06-29 15:18:54 +000061 // Node preprocessing cases
62 void PreprocessLoad(SDNode *Node, SelectionDAG::allnodes_iterator I);
63 void PreprocessCopyToReg(SDNode *Node);
64 void PreprocessTrunc(SDNode *Node, SelectionDAG::allnodes_iterator I);
65
Yonghong Songac2e2502017-06-16 15:41:16 +000066 // Find constants from a constant structure
67 typedef std::vector<unsigned char> val_vec_type;
68 bool fillGenericConstant(const DataLayout &DL, const Constant *CV,
69 val_vec_type &Vals, uint64_t Offset);
70 bool fillConstantDataArray(const DataLayout &DL, const ConstantDataArray *CDA,
71 val_vec_type &Vals, int Offset);
72 bool fillConstantArray(const DataLayout &DL, const ConstantArray *CA,
73 val_vec_type &Vals, int Offset);
74 bool fillConstantStruct(const DataLayout &DL, const ConstantStruct *CS,
75 val_vec_type &Vals, int Offset);
76 bool getConstantFieldValue(const GlobalAddressSDNode *Node, uint64_t Offset,
77 uint64_t Size, unsigned char *ByteSeq);
Yonghong Song5fbe01b2017-06-29 15:18:54 +000078 bool checkLoadDef(unsigned DefReg, unsigned match_load_op);
Yonghong Songac2e2502017-06-16 15:41:16 +000079
80 // Mapping from ConstantStruct global value to corresponding byte-list values
81 std::map<const void *, val_vec_type> cs_vals_;
Yonghong Song5fbe01b2017-06-29 15:18:54 +000082 // Mapping from vreg to load memory opcode
83 std::map<unsigned, unsigned> load_to_vreg_;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000084};
Yonghong Songac2e2502017-06-16 15:41:16 +000085} // namespace
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000086
87// ComplexPattern used on BPF Load/Store instructions
88bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) {
89 // if Address is FI, get the TargetFrameIndex.
Alexei Starovoitov659ece92015-04-28 20:38:56 +000090 SDLoc DL(Addr);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000091 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Yonghong Songac2e2502017-06-16 15:41:16 +000092 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
Alexei Starovoitov659ece92015-04-28 20:38:56 +000093 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000094 return true;
95 }
96
97 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
98 Addr.getOpcode() == ISD::TargetGlobalAddress)
99 return false;
100
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000101 // Addresses of the form Addr+const or Addr|const
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000102 if (CurDAG->isBaseWithConstantOffset(Addr)) {
103 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
Alexei Starovoitov56db1452017-04-13 22:24:13 +0000104 if (isInt<16>(CN->getSExtValue())) {
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000105
106 // If the first operand is a FI, get the TargetFI Node
107 if (FrameIndexSDNode *FIN =
108 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
109 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
110 else
111 Base = Addr.getOperand(0);
112
Alexei Starovoitov659ece92015-04-28 20:38:56 +0000113 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000114 return true;
115 }
116 }
117
Yonghong Songac2e2502017-06-16 15:41:16 +0000118 Base = Addr;
Alexei Starovoitov659ece92015-04-28 20:38:56 +0000119 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000120 return true;
121}
122
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000123// ComplexPattern used on BPF FI instruction
Yonghong Songac2e2502017-06-16 15:41:16 +0000124bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base,
125 SDValue &Offset) {
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000126 SDLoc DL(Addr);
127
128 if (!CurDAG->isBaseWithConstantOffset(Addr))
129 return false;
130
131 // Addresses of the form Addr+const or Addr|const
132 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
Alexei Starovoitov56db1452017-04-13 22:24:13 +0000133 if (isInt<16>(CN->getSExtValue())) {
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000134
135 // If the first operand is a FI, get the TargetFI Node
Yonghong Songac2e2502017-06-16 15:41:16 +0000136 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000137 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
138 else
139 return false;
140
141 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64);
142 return true;
143 }
144
145 return false;
146}
147
Justin Bognerf076e792016-05-12 21:14:47 +0000148void BPFDAGToDAGISel::Select(SDNode *Node) {
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000149 unsigned Opcode = Node->getOpcode();
150
151 // Dump information about the Node being selected
152 DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n');
153
154 // If we have a custom node, we already have selected!
155 if (Node->isMachineOpcode()) {
156 DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
Justin Bognerf076e792016-05-12 21:14:47 +0000157 return;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000158 }
159
160 // tablegen selection should be handled here.
161 switch (Opcode) {
Yonghong Songac2e2502017-06-16 15:41:16 +0000162 default:
163 break;
Alexei Starovoitov7e453bb2016-03-18 22:02:47 +0000164 case ISD::SDIV: {
165 DebugLoc Empty;
166 const DebugLoc &DL = Node->getDebugLoc();
167 if (DL != Empty)
168 errs() << "Error at line " << DL.getLine() << ": ";
169 else
170 errs() << "Error: ";
171 errs() << "Unsupport signed division for DAG: ";
Matthias Braun8c209aa2017-01-28 02:02:38 +0000172 Node->print(errs(), CurDAG);
Alexei Starovoitov7e453bb2016-03-18 22:02:47 +0000173 errs() << "Please convert to unsigned div/mod.\n";
174 break;
175 }
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000176 case ISD::INTRINSIC_W_CHAIN: {
177 unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
178 switch (IntNo) {
179 case Intrinsic::bpf_load_byte:
180 case Intrinsic::bpf_load_half:
181 case Intrinsic::bpf_load_word: {
182 SDLoc DL(Node);
183 SDValue Chain = Node->getOperand(0);
184 SDValue N1 = Node->getOperand(1);
185 SDValue Skb = Node->getOperand(2);
186 SDValue N3 = Node->getOperand(3);
187
188 SDValue R6Reg = CurDAG->getRegister(BPF::R6, MVT::i64);
189 Chain = CurDAG->getCopyToReg(Chain, DL, R6Reg, Skb, SDValue());
190 Node = CurDAG->UpdateNodeOperands(Node, Chain, N1, R6Reg, N3);
191 break;
192 }
193 }
194 break;
195 }
196
197 case ISD::FrameIndex: {
Benjamin Kramer619c4e52015-04-10 11:24:51 +0000198 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000199 EVT VT = Node->getValueType(0);
200 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
201 unsigned Opc = BPF::MOV_rr;
Justin Bognerf076e792016-05-12 21:14:47 +0000202 if (Node->hasOneUse()) {
203 CurDAG->SelectNodeTo(Node, Opc, VT, TFI);
204 return;
205 }
206 ReplaceNode(Node, CurDAG->getMachineNode(Opc, SDLoc(Node), VT, TFI));
207 return;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000208 }
209 }
210
211 // Select the default instruction
Justin Bognerf076e792016-05-12 21:14:47 +0000212 SelectCode(Node);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000213}
214
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000215void BPFDAGToDAGISel::PreprocessLoad(SDNode *Node,
216 SelectionDAG::allnodes_iterator I) {
217 union {
218 uint8_t c[8];
219 uint16_t s;
220 uint32_t i;
221 uint64_t d;
222 } new_val; // hold up the constant values replacing loads.
223 bool to_replace = false;
224 SDLoc DL(Node);
225 const LoadSDNode *LD = cast<LoadSDNode>(Node);
226 uint64_t size = LD->getMemOperand()->getSize();
227
228 if (!size || size > 8 || (size & (size - 1)))
229 return;
230
231 SDNode *LDAddrNode = LD->getOperand(1).getNode();
232 // Match LDAddr against either global_addr or (global_addr + offset)
233 unsigned opcode = LDAddrNode->getOpcode();
234 if (opcode == ISD::ADD) {
235 SDValue OP1 = LDAddrNode->getOperand(0);
236 SDValue OP2 = LDAddrNode->getOperand(1);
237
238 // We want to find the pattern global_addr + offset
239 SDNode *OP1N = OP1.getNode();
240 if (OP1N->getOpcode() <= ISD::BUILTIN_OP_END || OP1N->getNumOperands() == 0)
241 return;
242
243 DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n');
244
245 const GlobalAddressSDNode *GADN =
246 dyn_cast<GlobalAddressSDNode>(OP1N->getOperand(0).getNode());
247 const ConstantSDNode *CDN = dyn_cast<ConstantSDNode>(OP2.getNode());
248 if (GADN && CDN)
249 to_replace =
250 getConstantFieldValue(GADN, CDN->getZExtValue(), size, new_val.c);
251 } else if (LDAddrNode->getOpcode() > ISD::BUILTIN_OP_END &&
252 LDAddrNode->getNumOperands() > 0) {
253 DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n');
254
255 SDValue OP1 = LDAddrNode->getOperand(0);
256 if (const GlobalAddressSDNode *GADN =
257 dyn_cast<GlobalAddressSDNode>(OP1.getNode()))
258 to_replace = getConstantFieldValue(GADN, 0, size, new_val.c);
259 }
260
261 if (!to_replace)
262 return;
263
264 // replacing the old with a new value
265 uint64_t val;
266 if (size == 1)
267 val = new_val.c[0];
268 else if (size == 2)
269 val = new_val.s;
270 else if (size == 4)
271 val = new_val.i;
272 else {
273 val = new_val.d;
274 }
275
276 DEBUG(dbgs() << "Replacing load of size " << size << " with constant " << val
277 << '\n');
278 SDValue NVal = CurDAG->getConstant(val, DL, MVT::i64);
279
280 // After replacement, the current node is dead, we need to
281 // go backward one step to make iterator still work
282 I--;
283 SDValue From[] = {SDValue(Node, 0), SDValue(Node, 1)};
284 SDValue To[] = {NVal, NVal};
285 CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2);
286 I++;
287 // It is safe to delete node now
288 CurDAG->DeleteNode(Node);
289}
290
Yonghong Songac2e2502017-06-16 15:41:16 +0000291void BPFDAGToDAGISel::PreprocessISelDAG() {
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000292 // Iterate through all nodes, interested in the following cases:
293 //
294 // . loads from ConstantStruct or ConstantArray of constructs
295 // which can be turns into constant itself, with this we can
296 // avoid reading from read-only section at runtime.
297 //
298 // . reg truncating is often the result of 8/16/32bit->64bit or
299 // 8/16bit->32bit conversion. If the reg value is loaded with
300 // masked byte width, the AND operation can be removed since
301 // BPF LOAD already has zero extension.
302 //
303 // This also solved a correctness issue.
304 // In BPF socket-related program, e.g., __sk_buff->{data, data_end}
305 // are 32-bit registers, but later on, kernel verifier will rewrite
306 // it with 64-bit value. Therefore, truncating the value after the
307 // load will result in incorrect code.
Yonghong Songac2e2502017-06-16 15:41:16 +0000308 for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(),
309 E = CurDAG->allnodes_end();
310 I != E;) {
311 SDNode *Node = &*I++;
312 unsigned Opcode = Node->getOpcode();
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000313 if (Opcode == ISD::LOAD)
314 PreprocessLoad(Node, I);
315 else if (Opcode == ISD::CopyToReg)
316 PreprocessCopyToReg(Node);
317 else if (Opcode == ISD::AND)
318 PreprocessTrunc(Node, I);
Yonghong Songac2e2502017-06-16 15:41:16 +0000319 }
320}
321
322bool BPFDAGToDAGISel::getConstantFieldValue(const GlobalAddressSDNode *Node,
323 uint64_t Offset, uint64_t Size,
324 unsigned char *ByteSeq) {
325 const GlobalVariable *V = dyn_cast<GlobalVariable>(Node->getGlobal());
326
327 if (!V || !V->hasInitializer())
328 return false;
329
330 const Constant *Init = V->getInitializer();
331 const DataLayout &DL = CurDAG->getDataLayout();
332 val_vec_type TmpVal;
333
334 auto it = cs_vals_.find(static_cast<const void *>(Init));
335 if (it != cs_vals_.end()) {
336 TmpVal = it->second;
337 } else {
338 uint64_t total_size = 0;
339 if (const ConstantStruct *CS = dyn_cast<ConstantStruct>(Init))
340 total_size =
341 DL.getStructLayout(cast<StructType>(CS->getType()))->getSizeInBytes();
342 else if (const ConstantArray *CA = dyn_cast<ConstantArray>(Init))
343 total_size = DL.getTypeAllocSize(CA->getType()->getElementType()) *
344 CA->getNumOperands();
345 else
346 return false;
347
348 val_vec_type Vals(total_size, 0);
349 if (fillGenericConstant(DL, Init, Vals, 0) == false)
350 return false;
351 cs_vals_[static_cast<const void *>(Init)] = Vals;
352 TmpVal = std::move(Vals);
353 }
354
355 // test whether host endianness matches target
Yonghong Songa63178f2017-06-16 23:28:04 +0000356 union {
357 uint8_t c[2];
358 uint16_t s;
359 } test_buf;
Yonghong Songac2e2502017-06-16 15:41:16 +0000360 uint16_t test_val = 0x2345;
361 if (DL.isLittleEndian())
Yonghong Songa63178f2017-06-16 23:28:04 +0000362 support::endian::write16le(test_buf.c, test_val);
Yonghong Songac2e2502017-06-16 15:41:16 +0000363 else
Yonghong Songa63178f2017-06-16 23:28:04 +0000364 support::endian::write16be(test_buf.c, test_val);
Yonghong Songac2e2502017-06-16 15:41:16 +0000365
Yonghong Songa63178f2017-06-16 23:28:04 +0000366 bool endian_match = test_buf.s == test_val;
Yonghong Songac2e2502017-06-16 15:41:16 +0000367 for (uint64_t i = Offset, j = 0; i < Offset + Size; i++, j++)
368 ByteSeq[j] = endian_match ? TmpVal[i] : TmpVal[Offset + Size - 1 - j];
369
370 return true;
371}
372
373bool BPFDAGToDAGISel::fillGenericConstant(const DataLayout &DL,
374 const Constant *CV,
375 val_vec_type &Vals, uint64_t Offset) {
376 uint64_t Size = DL.getTypeAllocSize(CV->getType());
377
378 if (isa<ConstantAggregateZero>(CV) || isa<UndefValue>(CV))
379 return true; // already done
380
381 if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
382 uint64_t val = CI->getZExtValue();
383 DEBUG(dbgs() << "Byte array at offset " << Offset << " with value " << val
384 << '\n');
385
386 if (Size > 8 || (Size & (Size - 1)))
387 return false;
388
389 // Store based on target endian
390 for (uint64_t i = 0; i < Size; ++i) {
391 Vals[Offset + i] = DL.isLittleEndian()
392 ? ((val >> (i * 8)) & 0xFF)
393 : ((val >> ((Size - i - 1) * 8)) & 0xFF);
394 }
395 return true;
396 }
397
398 if (const ConstantDataArray *CDA = dyn_cast<ConstantDataArray>(CV))
399 return fillConstantDataArray(DL, CDA, Vals, Offset);
400
401 if (const ConstantArray *CA = dyn_cast<ConstantArray>(CV))
402 return fillConstantArray(DL, CA, Vals, Offset);
403
404 if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV))
405 return fillConstantStruct(DL, CVS, Vals, Offset);
406
407 return false;
408}
409
410bool BPFDAGToDAGISel::fillConstantDataArray(const DataLayout &DL,
411 const ConstantDataArray *CDA,
412 val_vec_type &Vals, int Offset) {
413 for (unsigned i = 0, e = CDA->getNumElements(); i != e; ++i) {
414 if (fillGenericConstant(DL, CDA->getElementAsConstant(i), Vals, Offset) ==
415 false)
416 return false;
417 Offset += DL.getTypeAllocSize(CDA->getElementAsConstant(i)->getType());
418 }
419
420 return true;
421}
422
423bool BPFDAGToDAGISel::fillConstantArray(const DataLayout &DL,
424 const ConstantArray *CA,
425 val_vec_type &Vals, int Offset) {
426 for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
427 if (fillGenericConstant(DL, CA->getOperand(i), Vals, Offset) == false)
428 return false;
429 Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType());
430 }
431
432 return true;
433}
434
435bool BPFDAGToDAGISel::fillConstantStruct(const DataLayout &DL,
436 const ConstantStruct *CS,
437 val_vec_type &Vals, int Offset) {
438 const StructLayout *Layout = DL.getStructLayout(CS->getType());
439 for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) {
440 const Constant *Field = CS->getOperand(i);
441 uint64_t SizeSoFar = Layout->getElementOffset(i);
442 if (fillGenericConstant(DL, Field, Vals, Offset + SizeSoFar) == false)
443 return false;
444 }
445 return true;
446}
447
Yonghong Song5fbe01b2017-06-29 15:18:54 +0000448void BPFDAGToDAGISel::PreprocessCopyToReg(SDNode *Node) {
449 const RegisterSDNode *RegN = dyn_cast<RegisterSDNode>(Node->getOperand(1));
450 if (!RegN || !TargetRegisterInfo::isVirtualRegister(RegN->getReg()))
451 return;
452
453 const LoadSDNode *LD = dyn_cast<LoadSDNode>(Node->getOperand(2));
454 if (!LD)
455 return;
456
457 // Assign a load value to a virtual register. record its load width
458 unsigned mem_load_op = 0;
459 switch (LD->getMemOperand()->getSize()) {
460 default:
461 return;
462 case 4:
463 mem_load_op = BPF::LDW;
464 break;
465 case 2:
466 mem_load_op = BPF::LDH;
467 break;
468 case 1:
469 mem_load_op = BPF::LDB;
470 break;
471 }
472
473 DEBUG(dbgs() << "Find Load Value to VReg "
474 << TargetRegisterInfo::virtReg2Index(RegN->getReg()) << '\n');
475 load_to_vreg_[RegN->getReg()] = mem_load_op;
476}
477
478void BPFDAGToDAGISel::PreprocessTrunc(SDNode *Node,
479 SelectionDAG::allnodes_iterator I) {
480 ConstantSDNode *MaskN = dyn_cast<ConstantSDNode>(Node->getOperand(1));
481 if (!MaskN)
482 return;
483
484 unsigned match_load_op = 0;
485 switch (MaskN->getZExtValue()) {
486 default:
487 return;
488 case 0xFFFFFFFF:
489 match_load_op = BPF::LDW;
490 break;
491 case 0xFFFF:
492 match_load_op = BPF::LDH;
493 break;
494 case 0xFF:
495 match_load_op = BPF::LDB;
496 break;
497 }
498
499 // The Reg operand should be a virtual register, which is defined
500 // outside the current basic block. DAG combiner has done a pretty
501 // good job in removing truncating inside a single basic block.
502 SDValue BaseV = Node->getOperand(0);
503 if (BaseV.getOpcode() != ISD::CopyFromReg)
504 return;
505
506 const RegisterSDNode *RegN =
507 dyn_cast<RegisterSDNode>(BaseV.getNode()->getOperand(1));
508 if (!RegN || !TargetRegisterInfo::isVirtualRegister(RegN->getReg()))
509 return;
510 unsigned AndOpReg = RegN->getReg();
511 DEBUG(dbgs() << "Examine %vreg" << TargetRegisterInfo::virtReg2Index(AndOpReg)
512 << '\n');
513
514 // Examine the PHI insns in the MachineBasicBlock to found out the
515 // definitions of this virtual register. At this stage (DAG2DAG
516 // transformation), only PHI machine insns are available in the machine basic
517 // block.
518 MachineBasicBlock *MBB = FuncInfo->MBB;
519 MachineInstr *MII = nullptr;
520 for (auto &MI : *MBB) {
521 for (unsigned i = 0; i < MI.getNumOperands(); ++i) {
522 const MachineOperand &MOP = MI.getOperand(i);
523 if (!MOP.isReg() || !MOP.isDef())
524 continue;
525 unsigned Reg = MOP.getReg();
526 if (TargetRegisterInfo::isVirtualRegister(Reg) && Reg == AndOpReg) {
527 MII = &MI;
528 break;
529 }
530 }
531 }
532
533 if (MII == nullptr) {
534 // No phi definition in this block.
535 if (!checkLoadDef(AndOpReg, match_load_op))
536 return;
537 } else {
538 // The PHI node looks like:
539 // %vreg2<def> = PHI %vreg0, <BB#1>, %vreg1, <BB#3>
540 // Trace each incoming definition, e.g., (%vreg0, BB#1) and (%vreg1, BB#3)
541 // The AND operation can be removed if both %vreg0 in BB#1 and %vreg1 in
542 // BB#3 are defined with with a load matching the MaskN.
543 DEBUG(dbgs() << "Check PHI Insn: "; MII->dump(); dbgs() << '\n');
544 unsigned PrevReg = -1;
545 for (unsigned i = 0; i < MII->getNumOperands(); ++i) {
546 const MachineOperand &MOP = MII->getOperand(i);
547 if (MOP.isReg()) {
548 if (MOP.isDef())
549 continue;
550 PrevReg = MOP.getReg();
551 if (!TargetRegisterInfo::isVirtualRegister(PrevReg))
552 return;
553 if (!checkLoadDef(PrevReg, match_load_op))
554 return;
555 }
556 }
557 }
558
559 DEBUG(dbgs() << "Remove the redundant AND operation in: "; Node->dump();
560 dbgs() << '\n');
561
562 I--;
563 CurDAG->ReplaceAllUsesWith(SDValue(Node, 0), BaseV);
564 I++;
565 CurDAG->DeleteNode(Node);
566}
567
568bool BPFDAGToDAGISel::checkLoadDef(unsigned DefReg, unsigned match_load_op) {
569 auto it = load_to_vreg_.find(DefReg);
570 if (it == load_to_vreg_.end())
571 return false; // The definition of register is not exported yet.
572
573 return it->second == match_load_op;
574}
575
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000576FunctionPass *llvm::createBPFISelDag(BPFTargetMachine &TM) {
577 return new BPFDAGToDAGISel(TM);
578}