blob: 7d5fb6ca17b98bfb160a3273e093a3c3a9bcb613 [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"
19#include "llvm/CodeGen/MachineConstantPool.h"
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000020#include "llvm/CodeGen/MachineFrameInfo.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000021#include "llvm/CodeGen/MachineFunction.h"
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000022#include "llvm/CodeGen/MachineInstrBuilder.h"
23#include "llvm/CodeGen/MachineRegisterInfo.h"
24#include "llvm/CodeGen/SelectionDAGISel.h"
Yonghong Songac2e2502017-06-16 15:41:16 +000025#include "llvm/IR/Constants.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000026#include "llvm/IR/IntrinsicInst.h"
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000027#include "llvm/Support/Debug.h"
Yonghong Songac2e2502017-06-16 15:41:16 +000028#include "llvm/Support/Endian.h"
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000029#include "llvm/Support/ErrorHandling.h"
30#include "llvm/Support/raw_ostream.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000031#include "llvm/Target/TargetMachine.h"
Yonghong Songac2e2502017-06-16 15:41:16 +000032
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000033using namespace llvm;
34
35#define DEBUG_TYPE "bpf-isel"
36
37// Instruction Selector Implementation
38namespace {
39
40class BPFDAGToDAGISel : public SelectionDAGISel {
41public:
42 explicit BPFDAGToDAGISel(BPFTargetMachine &TM) : SelectionDAGISel(TM) {}
43
Mehdi Amini117296c2016-10-01 02:56:57 +000044 StringRef getPassName() const override {
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000045 return "BPF DAG->DAG Pattern Instruction Selection";
46 }
47
Yonghong Songac2e2502017-06-16 15:41:16 +000048 void PreprocessISelDAG() override;
49
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000050private:
51// Include the pieces autogenerated from the target description.
52#include "BPFGenDAGISel.inc"
53
Justin Bognerf076e792016-05-12 21:14:47 +000054 void Select(SDNode *N) override;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000055
56 // Complex Pattern for address selection.
57 bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
Alexei Starovoitov4e01a382015-10-06 04:00:53 +000058 bool SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset);
Yonghong Songac2e2502017-06-16 15:41:16 +000059
60 // Find constants from a constant structure
61 typedef std::vector<unsigned char> val_vec_type;
62 bool fillGenericConstant(const DataLayout &DL, const Constant *CV,
63 val_vec_type &Vals, uint64_t Offset);
64 bool fillConstantDataArray(const DataLayout &DL, const ConstantDataArray *CDA,
65 val_vec_type &Vals, int Offset);
66 bool fillConstantArray(const DataLayout &DL, const ConstantArray *CA,
67 val_vec_type &Vals, int Offset);
68 bool fillConstantStruct(const DataLayout &DL, const ConstantStruct *CS,
69 val_vec_type &Vals, int Offset);
70 bool getConstantFieldValue(const GlobalAddressSDNode *Node, uint64_t Offset,
71 uint64_t Size, unsigned char *ByteSeq);
72
73 // Mapping from ConstantStruct global value to corresponding byte-list values
74 std::map<const void *, val_vec_type> cs_vals_;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000075};
Yonghong Songac2e2502017-06-16 15:41:16 +000076} // namespace
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000077
78// ComplexPattern used on BPF Load/Store instructions
79bool BPFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) {
80 // if Address is FI, get the TargetFrameIndex.
Alexei Starovoitov659ece92015-04-28 20:38:56 +000081 SDLoc DL(Addr);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000082 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Yonghong Songac2e2502017-06-16 15:41:16 +000083 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
Alexei Starovoitov659ece92015-04-28 20:38:56 +000084 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000085 return true;
86 }
87
88 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
89 Addr.getOpcode() == ISD::TargetGlobalAddress)
90 return false;
91
Alexei Starovoitov4e01a382015-10-06 04:00:53 +000092 // Addresses of the form Addr+const or Addr|const
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000093 if (CurDAG->isBaseWithConstantOffset(Addr)) {
94 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
Alexei Starovoitov56db1452017-04-13 22:24:13 +000095 if (isInt<16>(CN->getSExtValue())) {
Alexei Starovoitove4c8c802015-01-24 17:51:26 +000096
97 // If the first operand is a FI, get the TargetFI Node
98 if (FrameIndexSDNode *FIN =
99 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
100 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
101 else
102 Base = Addr.getOperand(0);
103
Alexei Starovoitov659ece92015-04-28 20:38:56 +0000104 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000105 return true;
106 }
107 }
108
Yonghong Songac2e2502017-06-16 15:41:16 +0000109 Base = Addr;
Alexei Starovoitov659ece92015-04-28 20:38:56 +0000110 Offset = CurDAG->getTargetConstant(0, DL, MVT::i64);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000111 return true;
112}
113
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000114// ComplexPattern used on BPF FI instruction
Yonghong Songac2e2502017-06-16 15:41:16 +0000115bool BPFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base,
116 SDValue &Offset) {
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000117 SDLoc DL(Addr);
118
119 if (!CurDAG->isBaseWithConstantOffset(Addr))
120 return false;
121
122 // Addresses of the form Addr+const or Addr|const
123 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
Alexei Starovoitov56db1452017-04-13 22:24:13 +0000124 if (isInt<16>(CN->getSExtValue())) {
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000125
126 // If the first operand is a FI, get the TargetFI Node
Yonghong Songac2e2502017-06-16 15:41:16 +0000127 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
Alexei Starovoitov4e01a382015-10-06 04:00:53 +0000128 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
129 else
130 return false;
131
132 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64);
133 return true;
134 }
135
136 return false;
137}
138
Justin Bognerf076e792016-05-12 21:14:47 +0000139void BPFDAGToDAGISel::Select(SDNode *Node) {
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000140 unsigned Opcode = Node->getOpcode();
141
142 // Dump information about the Node being selected
143 DEBUG(dbgs() << "Selecting: "; Node->dump(CurDAG); dbgs() << '\n');
144
145 // If we have a custom node, we already have selected!
146 if (Node->isMachineOpcode()) {
147 DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n');
Justin Bognerf076e792016-05-12 21:14:47 +0000148 return;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000149 }
150
151 // tablegen selection should be handled here.
152 switch (Opcode) {
Yonghong Songac2e2502017-06-16 15:41:16 +0000153 default:
154 break;
Alexei Starovoitov7e453bb2016-03-18 22:02:47 +0000155 case ISD::SDIV: {
156 DebugLoc Empty;
157 const DebugLoc &DL = Node->getDebugLoc();
158 if (DL != Empty)
159 errs() << "Error at line " << DL.getLine() << ": ";
160 else
161 errs() << "Error: ";
162 errs() << "Unsupport signed division for DAG: ";
Matthias Braun8c209aa2017-01-28 02:02:38 +0000163 Node->print(errs(), CurDAG);
Alexei Starovoitov7e453bb2016-03-18 22:02:47 +0000164 errs() << "Please convert to unsigned div/mod.\n";
165 break;
166 }
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000167 case ISD::INTRINSIC_W_CHAIN: {
168 unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue();
169 switch (IntNo) {
170 case Intrinsic::bpf_load_byte:
171 case Intrinsic::bpf_load_half:
172 case Intrinsic::bpf_load_word: {
173 SDLoc DL(Node);
174 SDValue Chain = Node->getOperand(0);
175 SDValue N1 = Node->getOperand(1);
176 SDValue Skb = Node->getOperand(2);
177 SDValue N3 = Node->getOperand(3);
178
179 SDValue R6Reg = CurDAG->getRegister(BPF::R6, MVT::i64);
180 Chain = CurDAG->getCopyToReg(Chain, DL, R6Reg, Skb, SDValue());
181 Node = CurDAG->UpdateNodeOperands(Node, Chain, N1, R6Reg, N3);
182 break;
183 }
184 }
185 break;
186 }
187
188 case ISD::FrameIndex: {
Benjamin Kramer619c4e52015-04-10 11:24:51 +0000189 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000190 EVT VT = Node->getValueType(0);
191 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
192 unsigned Opc = BPF::MOV_rr;
Justin Bognerf076e792016-05-12 21:14:47 +0000193 if (Node->hasOneUse()) {
194 CurDAG->SelectNodeTo(Node, Opc, VT, TFI);
195 return;
196 }
197 ReplaceNode(Node, CurDAG->getMachineNode(Opc, SDLoc(Node), VT, TFI));
198 return;
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000199 }
200 }
201
202 // Select the default instruction
Justin Bognerf076e792016-05-12 21:14:47 +0000203 SelectCode(Node);
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000204}
205
Yonghong Songac2e2502017-06-16 15:41:16 +0000206void BPFDAGToDAGISel::PreprocessISelDAG() {
207 // Iterate through all nodes, only interested in loads from ConstantStruct
208 // ConstantArray should have converted by IR->DAG processing
209 for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(),
210 E = CurDAG->allnodes_end();
211 I != E;) {
212 SDNode *Node = &*I++;
213 unsigned Opcode = Node->getOpcode();
214 if (Opcode != ISD::LOAD)
215 continue;
216
217 unsigned char new_val[8]; // hold up the constant values replacing loads.
218 bool to_replace = false;
219 SDLoc DL(Node);
220 const LoadSDNode *LD = cast<LoadSDNode>(Node);
221 uint64_t size = LD->getMemOperand()->getSize();
222 if (!size || size > 8 || (size & (size - 1)))
223 continue;
224
225 SDNode *LDAddrNode = LD->getOperand(1).getNode();
226 // Match LDAddr against either global_addr or (global_addr + offset)
227 unsigned opcode = LDAddrNode->getOpcode();
228 if (opcode == ISD::ADD) {
229 SDValue OP1 = LDAddrNode->getOperand(0);
230 SDValue OP2 = LDAddrNode->getOperand(1);
231
232 // We want to find the pattern global_addr + offset
233 SDNode *OP1N = OP1.getNode();
234 if (OP1N->getOpcode() <= ISD::BUILTIN_OP_END ||
235 OP1N->getNumOperands() == 0)
236 continue;
237
238 DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n');
239
240 const GlobalAddressSDNode *GADN =
241 dyn_cast<GlobalAddressSDNode>(OP1N->getOperand(0).getNode());
242 const ConstantSDNode *CDN = dyn_cast<ConstantSDNode>(OP2.getNode());
243 if (GADN && CDN)
244 to_replace =
245 getConstantFieldValue(GADN, CDN->getZExtValue(), size, new_val);
246 } else if (LDAddrNode->getOpcode() > ISD::BUILTIN_OP_END &&
247 LDAddrNode->getNumOperands() > 0) {
248 DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n');
249
250 SDValue OP1 = LDAddrNode->getOperand(0);
251 if (const GlobalAddressSDNode *GADN =
252 dyn_cast<GlobalAddressSDNode>(OP1.getNode()))
253 to_replace = getConstantFieldValue(GADN, 0, size, new_val);
254 }
255
256 if (!to_replace)
257 continue;
258
259 // replacing the old with a new value
260 uint64_t val;
261 if (size == 1)
262 val = *(uint8_t *)new_val;
263 else if (size == 2)
264 val = *(uint16_t *)new_val;
265 else if (size == 4)
266 val = *(uint32_t *)new_val;
267 else {
268 val = *(uint64_t *)new_val;
269 }
270
271 DEBUG(dbgs() << "Replacing load of size " << size << " with constant "
272 << val << '\n');
273 SDValue NVal = CurDAG->getConstant(val, DL, MVT::i64);
274
275 // After replacement, the current node is dead, we need to
276 // go backward one step to make iterator still work
277 I--;
278 SDValue From[] = {SDValue(Node, 0), SDValue(Node, 1)};
279 SDValue To[] = {NVal, NVal};
280 CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2);
281 I++;
282 // It is safe to delete node now
283 CurDAG->DeleteNode(Node);
284 }
285}
286
287bool BPFDAGToDAGISel::getConstantFieldValue(const GlobalAddressSDNode *Node,
288 uint64_t Offset, uint64_t Size,
289 unsigned char *ByteSeq) {
290 const GlobalVariable *V = dyn_cast<GlobalVariable>(Node->getGlobal());
291
292 if (!V || !V->hasInitializer())
293 return false;
294
295 const Constant *Init = V->getInitializer();
296 const DataLayout &DL = CurDAG->getDataLayout();
297 val_vec_type TmpVal;
298
299 auto it = cs_vals_.find(static_cast<const void *>(Init));
300 if (it != cs_vals_.end()) {
301 TmpVal = it->second;
302 } else {
303 uint64_t total_size = 0;
304 if (const ConstantStruct *CS = dyn_cast<ConstantStruct>(Init))
305 total_size =
306 DL.getStructLayout(cast<StructType>(CS->getType()))->getSizeInBytes();
307 else if (const ConstantArray *CA = dyn_cast<ConstantArray>(Init))
308 total_size = DL.getTypeAllocSize(CA->getType()->getElementType()) *
309 CA->getNumOperands();
310 else
311 return false;
312
313 val_vec_type Vals(total_size, 0);
314 if (fillGenericConstant(DL, Init, Vals, 0) == false)
315 return false;
316 cs_vals_[static_cast<const void *>(Init)] = Vals;
317 TmpVal = std::move(Vals);
318 }
319
320 // test whether host endianness matches target
321 uint8_t test_buf[2];
322 uint16_t test_val = 0x2345;
323 if (DL.isLittleEndian())
324 support::endian::write16le(test_buf, test_val);
325 else
326 support::endian::write16be(test_buf, test_val);
327
328 bool endian_match = *(uint16_t *)test_buf == test_val;
329 for (uint64_t i = Offset, j = 0; i < Offset + Size; i++, j++)
330 ByteSeq[j] = endian_match ? TmpVal[i] : TmpVal[Offset + Size - 1 - j];
331
332 return true;
333}
334
335bool BPFDAGToDAGISel::fillGenericConstant(const DataLayout &DL,
336 const Constant *CV,
337 val_vec_type &Vals, uint64_t Offset) {
338 uint64_t Size = DL.getTypeAllocSize(CV->getType());
339
340 if (isa<ConstantAggregateZero>(CV) || isa<UndefValue>(CV))
341 return true; // already done
342
343 if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
344 uint64_t val = CI->getZExtValue();
345 DEBUG(dbgs() << "Byte array at offset " << Offset << " with value " << val
346 << '\n');
347
348 if (Size > 8 || (Size & (Size - 1)))
349 return false;
350
351 // Store based on target endian
352 for (uint64_t i = 0; i < Size; ++i) {
353 Vals[Offset + i] = DL.isLittleEndian()
354 ? ((val >> (i * 8)) & 0xFF)
355 : ((val >> ((Size - i - 1) * 8)) & 0xFF);
356 }
357 return true;
358 }
359
360 if (const ConstantDataArray *CDA = dyn_cast<ConstantDataArray>(CV))
361 return fillConstantDataArray(DL, CDA, Vals, Offset);
362
363 if (const ConstantArray *CA = dyn_cast<ConstantArray>(CV))
364 return fillConstantArray(DL, CA, Vals, Offset);
365
366 if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV))
367 return fillConstantStruct(DL, CVS, Vals, Offset);
368
369 return false;
370}
371
372bool BPFDAGToDAGISel::fillConstantDataArray(const DataLayout &DL,
373 const ConstantDataArray *CDA,
374 val_vec_type &Vals, int Offset) {
375 for (unsigned i = 0, e = CDA->getNumElements(); i != e; ++i) {
376 if (fillGenericConstant(DL, CDA->getElementAsConstant(i), Vals, Offset) ==
377 false)
378 return false;
379 Offset += DL.getTypeAllocSize(CDA->getElementAsConstant(i)->getType());
380 }
381
382 return true;
383}
384
385bool BPFDAGToDAGISel::fillConstantArray(const DataLayout &DL,
386 const ConstantArray *CA,
387 val_vec_type &Vals, int Offset) {
388 for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
389 if (fillGenericConstant(DL, CA->getOperand(i), Vals, Offset) == false)
390 return false;
391 Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType());
392 }
393
394 return true;
395}
396
397bool BPFDAGToDAGISel::fillConstantStruct(const DataLayout &DL,
398 const ConstantStruct *CS,
399 val_vec_type &Vals, int Offset) {
400 const StructLayout *Layout = DL.getStructLayout(CS->getType());
401 for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) {
402 const Constant *Field = CS->getOperand(i);
403 uint64_t SizeSoFar = Layout->getElementOffset(i);
404 if (fillGenericConstant(DL, Field, Vals, Offset + SizeSoFar) == false)
405 return false;
406 }
407 return true;
408}
409
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000410FunctionPass *llvm::createBPFISelDag(BPFTargetMachine &TM) {
411 return new BPFDAGToDAGISel(TM);
412}