blob: c6ddd6bdad5e639fb70ab372be4443d8410593a6 [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
Yonghong Songa63178f2017-06-16 23:28:04 +0000217 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.
Yonghong Songac2e2502017-06-16 15:41:16 +0000223 bool to_replace = false;
224 SDLoc DL(Node);
225 const LoadSDNode *LD = cast<LoadSDNode>(Node);
226 uint64_t size = LD->getMemOperand()->getSize();
227 if (!size || size > 8 || (size & (size - 1)))
228 continue;
229
230 SDNode *LDAddrNode = LD->getOperand(1).getNode();
231 // Match LDAddr against either global_addr or (global_addr + offset)
232 unsigned opcode = LDAddrNode->getOpcode();
233 if (opcode == ISD::ADD) {
234 SDValue OP1 = LDAddrNode->getOperand(0);
235 SDValue OP2 = LDAddrNode->getOperand(1);
236
237 // We want to find the pattern global_addr + offset
238 SDNode *OP1N = OP1.getNode();
239 if (OP1N->getOpcode() <= ISD::BUILTIN_OP_END ||
240 OP1N->getNumOperands() == 0)
241 continue;
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 =
Yonghong Songa63178f2017-06-16 23:28:04 +0000250 getConstantFieldValue(GADN, CDN->getZExtValue(), size, new_val.c);
Yonghong Songac2e2502017-06-16 15:41:16 +0000251 } 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()))
Yonghong Songa63178f2017-06-16 23:28:04 +0000258 to_replace = getConstantFieldValue(GADN, 0, size, new_val.c);
Yonghong Songac2e2502017-06-16 15:41:16 +0000259 }
260
261 if (!to_replace)
262 continue;
263
264 // replacing the old with a new value
265 uint64_t val;
266 if (size == 1)
Yonghong Songa63178f2017-06-16 23:28:04 +0000267 val = new_val.c[0];
Yonghong Songac2e2502017-06-16 15:41:16 +0000268 else if (size == 2)
Yonghong Songa63178f2017-06-16 23:28:04 +0000269 val = new_val.s;
Yonghong Songac2e2502017-06-16 15:41:16 +0000270 else if (size == 4)
Yonghong Songa63178f2017-06-16 23:28:04 +0000271 val = new_val.i;
Yonghong Songac2e2502017-06-16 15:41:16 +0000272 else {
Yonghong Songa63178f2017-06-16 23:28:04 +0000273 val = new_val.d;
Yonghong Songac2e2502017-06-16 15:41:16 +0000274 }
275
276 DEBUG(dbgs() << "Replacing load of size " << size << " with constant "
277 << val << '\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}
291
292bool BPFDAGToDAGISel::getConstantFieldValue(const GlobalAddressSDNode *Node,
293 uint64_t Offset, uint64_t Size,
294 unsigned char *ByteSeq) {
295 const GlobalVariable *V = dyn_cast<GlobalVariable>(Node->getGlobal());
296
297 if (!V || !V->hasInitializer())
298 return false;
299
300 const Constant *Init = V->getInitializer();
301 const DataLayout &DL = CurDAG->getDataLayout();
302 val_vec_type TmpVal;
303
304 auto it = cs_vals_.find(static_cast<const void *>(Init));
305 if (it != cs_vals_.end()) {
306 TmpVal = it->second;
307 } else {
308 uint64_t total_size = 0;
309 if (const ConstantStruct *CS = dyn_cast<ConstantStruct>(Init))
310 total_size =
311 DL.getStructLayout(cast<StructType>(CS->getType()))->getSizeInBytes();
312 else if (const ConstantArray *CA = dyn_cast<ConstantArray>(Init))
313 total_size = DL.getTypeAllocSize(CA->getType()->getElementType()) *
314 CA->getNumOperands();
315 else
316 return false;
317
318 val_vec_type Vals(total_size, 0);
319 if (fillGenericConstant(DL, Init, Vals, 0) == false)
320 return false;
321 cs_vals_[static_cast<const void *>(Init)] = Vals;
322 TmpVal = std::move(Vals);
323 }
324
325 // test whether host endianness matches target
Yonghong Songa63178f2017-06-16 23:28:04 +0000326 union {
327 uint8_t c[2];
328 uint16_t s;
329 } test_buf;
Yonghong Songac2e2502017-06-16 15:41:16 +0000330 uint16_t test_val = 0x2345;
331 if (DL.isLittleEndian())
Yonghong Songa63178f2017-06-16 23:28:04 +0000332 support::endian::write16le(test_buf.c, test_val);
Yonghong Songac2e2502017-06-16 15:41:16 +0000333 else
Yonghong Songa63178f2017-06-16 23:28:04 +0000334 support::endian::write16be(test_buf.c, test_val);
Yonghong Songac2e2502017-06-16 15:41:16 +0000335
Yonghong Songa63178f2017-06-16 23:28:04 +0000336 bool endian_match = test_buf.s == test_val;
Yonghong Songac2e2502017-06-16 15:41:16 +0000337 for (uint64_t i = Offset, j = 0; i < Offset + Size; i++, j++)
338 ByteSeq[j] = endian_match ? TmpVal[i] : TmpVal[Offset + Size - 1 - j];
339
340 return true;
341}
342
343bool BPFDAGToDAGISel::fillGenericConstant(const DataLayout &DL,
344 const Constant *CV,
345 val_vec_type &Vals, uint64_t Offset) {
346 uint64_t Size = DL.getTypeAllocSize(CV->getType());
347
348 if (isa<ConstantAggregateZero>(CV) || isa<UndefValue>(CV))
349 return true; // already done
350
351 if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
352 uint64_t val = CI->getZExtValue();
353 DEBUG(dbgs() << "Byte array at offset " << Offset << " with value " << val
354 << '\n');
355
356 if (Size > 8 || (Size & (Size - 1)))
357 return false;
358
359 // Store based on target endian
360 for (uint64_t i = 0; i < Size; ++i) {
361 Vals[Offset + i] = DL.isLittleEndian()
362 ? ((val >> (i * 8)) & 0xFF)
363 : ((val >> ((Size - i - 1) * 8)) & 0xFF);
364 }
365 return true;
366 }
367
368 if (const ConstantDataArray *CDA = dyn_cast<ConstantDataArray>(CV))
369 return fillConstantDataArray(DL, CDA, Vals, Offset);
370
371 if (const ConstantArray *CA = dyn_cast<ConstantArray>(CV))
372 return fillConstantArray(DL, CA, Vals, Offset);
373
374 if (const ConstantStruct *CVS = dyn_cast<ConstantStruct>(CV))
375 return fillConstantStruct(DL, CVS, Vals, Offset);
376
377 return false;
378}
379
380bool BPFDAGToDAGISel::fillConstantDataArray(const DataLayout &DL,
381 const ConstantDataArray *CDA,
382 val_vec_type &Vals, int Offset) {
383 for (unsigned i = 0, e = CDA->getNumElements(); i != e; ++i) {
384 if (fillGenericConstant(DL, CDA->getElementAsConstant(i), Vals, Offset) ==
385 false)
386 return false;
387 Offset += DL.getTypeAllocSize(CDA->getElementAsConstant(i)->getType());
388 }
389
390 return true;
391}
392
393bool BPFDAGToDAGISel::fillConstantArray(const DataLayout &DL,
394 const ConstantArray *CA,
395 val_vec_type &Vals, int Offset) {
396 for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
397 if (fillGenericConstant(DL, CA->getOperand(i), Vals, Offset) == false)
398 return false;
399 Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType());
400 }
401
402 return true;
403}
404
405bool BPFDAGToDAGISel::fillConstantStruct(const DataLayout &DL,
406 const ConstantStruct *CS,
407 val_vec_type &Vals, int Offset) {
408 const StructLayout *Layout = DL.getStructLayout(CS->getType());
409 for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) {
410 const Constant *Field = CS->getOperand(i);
411 uint64_t SizeSoFar = Layout->getElementOffset(i);
412 if (fillGenericConstant(DL, Field, Vals, Offset + SizeSoFar) == false)
413 return false;
414 }
415 return true;
416}
417
Alexei Starovoitove4c8c802015-01-24 17:51:26 +0000418FunctionPass *llvm::createBPFISelDag(BPFTargetMachine &TM) {
419 return new BPFDAGToDAGISel(TM);
420}