1 //===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file defines the WebAssembly-specific support for the FastISel
11 /// class. Some of the target-specific code is generated by tablegen in the file
12 /// WebAssemblyGenFastISel.inc, which is #included here.
13 ///
14 /// TODO: kill flags
15 ///
16 //===----------------------------------------------------------------------===//
17
18 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19 #include "Utils/WebAssemblyUtilities.h"
20 #include "WebAssembly.h"
21 #include "WebAssemblyMachineFunctionInfo.h"
22 #include "WebAssemblySubtarget.h"
23 #include "WebAssemblyTargetMachine.h"
24 #include "llvm/Analysis/BranchProbabilityInfo.h"
25 #include "llvm/CodeGen/FastISel.h"
26 #include "llvm/CodeGen/FunctionLoweringInfo.h"
27 #include "llvm/CodeGen/MachineConstantPool.h"
28 #include "llvm/CodeGen/MachineFrameInfo.h"
29 #include "llvm/CodeGen/MachineInstrBuilder.h"
30 #include "llvm/CodeGen/MachineModuleInfo.h"
31 #include "llvm/CodeGen/MachineRegisterInfo.h"
32 #include "llvm/IR/DataLayout.h"
33 #include "llvm/IR/DerivedTypes.h"
34 #include "llvm/IR/Function.h"
35 #include "llvm/IR/GetElementPtrTypeIterator.h"
36 #include "llvm/IR/GlobalAlias.h"
37 #include "llvm/IR/GlobalVariable.h"
38 #include "llvm/IR/Instructions.h"
39 #include "llvm/IR/IntrinsicInst.h"
40 #include "llvm/IR/Operator.h"
41 #include "llvm/IR/PatternMatch.h"
42
43 using namespace llvm;
44 using namespace PatternMatch;
45
46 #define DEBUG_TYPE "wasm-fastisel"
47
48 namespace {
49
50 class WebAssemblyFastISel final : public FastISel {
51 // All possible address modes.
52 class Address {
53 public:
54 using BaseKind = enum { RegBase, FrameIndexBase };
55
56 private:
57 BaseKind Kind = RegBase;
58 union {
59 unsigned Reg;
60 int FI;
61 } Base;
62
63 // Whether the base has been determined yet
64 bool IsBaseSet = false;
65
66 int64_t Offset = 0;
67
68 const GlobalValue *GV = nullptr;
69
70 public:
71 // Innocuous defaults for our address.
Address()72 Address() { Base.Reg = 0; }
setKind(BaseKind K)73 void setKind(BaseKind K) {
74 assert(!isSet() && "Can't change kind with non-zero base");
75 Kind = K;
76 }
getKind() const77 BaseKind getKind() const { return Kind; }
isRegBase() const78 bool isRegBase() const { return Kind == RegBase; }
isFIBase() const79 bool isFIBase() const { return Kind == FrameIndexBase; }
setReg(unsigned Reg)80 void setReg(unsigned Reg) {
81 assert(isRegBase() && "Invalid base register access!");
82 assert(!IsBaseSet && "Base cannot be reset");
83 Base.Reg = Reg;
84 IsBaseSet = true;
85 }
getReg() const86 unsigned getReg() const {
87 assert(isRegBase() && "Invalid base register access!");
88 return Base.Reg;
89 }
setFI(unsigned FI)90 void setFI(unsigned FI) {
91 assert(isFIBase() && "Invalid base frame index access!");
92 assert(!IsBaseSet && "Base cannot be reset");
93 Base.FI = FI;
94 IsBaseSet = true;
95 }
getFI() const96 unsigned getFI() const {
97 assert(isFIBase() && "Invalid base frame index access!");
98 return Base.FI;
99 }
100
setOffset(int64_t NewOffset)101 void setOffset(int64_t NewOffset) {
102 assert(NewOffset >= 0 && "Offsets must be non-negative");
103 Offset = NewOffset;
104 }
getOffset() const105 int64_t getOffset() const { return Offset; }
setGlobalValue(const GlobalValue * G)106 void setGlobalValue(const GlobalValue *G) { GV = G; }
getGlobalValue() const107 const GlobalValue *getGlobalValue() const { return GV; }
isSet() const108 bool isSet() const { return IsBaseSet; }
109 };
110
111 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
112 /// right decision when generating code for different targets.
113 const WebAssemblySubtarget *Subtarget;
114 LLVMContext *Context;
115
116 private:
117 // Utility helper routines
getSimpleType(Type * Ty)118 MVT::SimpleValueType getSimpleType(Type *Ty) {
119 EVT VT = TLI.getValueType(DL, Ty, /*AllowUnknown=*/true);
120 return VT.isSimple() ? VT.getSimpleVT().SimpleTy
121 : MVT::INVALID_SIMPLE_VALUE_TYPE;
122 }
getLegalType(MVT::SimpleValueType VT)123 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
124 switch (VT) {
125 case MVT::i1:
126 case MVT::i8:
127 case MVT::i16:
128 return MVT::i32;
129 case MVT::i32:
130 case MVT::i64:
131 case MVT::f32:
132 case MVT::f64:
133 case MVT::funcref:
134 case MVT::externref:
135 return VT;
136 case MVT::f16:
137 return MVT::f32;
138 case MVT::v16i8:
139 case MVT::v8i16:
140 case MVT::v4i32:
141 case MVT::v4f32:
142 case MVT::v2i64:
143 case MVT::v2f64:
144 if (Subtarget->hasSIMD128())
145 return VT;
146 break;
147 default:
148 break;
149 }
150 return MVT::INVALID_SIMPLE_VALUE_TYPE;
151 }
152 bool computeAddress(const Value *Obj, Address &Addr);
153 void materializeLoadStoreOperands(Address &Addr);
154 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
155 MachineMemOperand *MMO);
156 unsigned maskI1Value(unsigned Reg, const Value *V);
157 unsigned getRegForI1Value(const Value *V, bool &Not);
158 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
159 MVT::SimpleValueType From);
160 unsigned signExtendToI32(unsigned Reg, const Value *V,
161 MVT::SimpleValueType From);
162 unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
163 MVT::SimpleValueType To);
164 unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
165 MVT::SimpleValueType To);
166 unsigned getRegForUnsignedValue(const Value *V);
167 unsigned getRegForSignedValue(const Value *V);
168 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
169 unsigned notValue(unsigned Reg);
170 unsigned copyValue(unsigned Reg);
171
172 // Backend specific FastISel code.
173 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
174 unsigned fastMaterializeConstant(const Constant *C) override;
175 bool fastLowerArguments() override;
176
177 // Selection routines.
178 bool selectCall(const Instruction *I);
179 bool selectSelect(const Instruction *I);
180 bool selectTrunc(const Instruction *I);
181 bool selectZExt(const Instruction *I);
182 bool selectSExt(const Instruction *I);
183 bool selectICmp(const Instruction *I);
184 bool selectFCmp(const Instruction *I);
185 bool selectBitCast(const Instruction *I);
186 bool selectLoad(const Instruction *I);
187 bool selectStore(const Instruction *I);
188 bool selectBr(const Instruction *I);
189 bool selectRet(const Instruction *I);
190 bool selectUnreachable(const Instruction *I);
191
192 public:
193 // Backend specific FastISel code.
WebAssemblyFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)194 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
195 const TargetLibraryInfo *LibInfo)
196 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
197 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
198 Context = &FuncInfo.Fn->getContext();
199 }
200
201 bool fastSelectInstruction(const Instruction *I) override;
202
203 #include "WebAssemblyGenFastISel.inc"
204 };
205
206 } // end anonymous namespace
207
computeAddress(const Value * Obj,Address & Addr)208 bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
209 const User *U = nullptr;
210 unsigned Opcode = Instruction::UserOp1;
211 if (const auto *I = dyn_cast<Instruction>(Obj)) {
212 // Don't walk into other basic blocks unless the object is an alloca from
213 // another block, otherwise it may not have a virtual register assigned.
214 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
215 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
216 Opcode = I->getOpcode();
217 U = I;
218 }
219 } else if (const auto *C = dyn_cast<ConstantExpr>(Obj)) {
220 Opcode = C->getOpcode();
221 U = C;
222 }
223
224 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
225 if (Ty->getAddressSpace() > 255)
226 // Fast instruction selection doesn't support the special
227 // address spaces.
228 return false;
229
230 if (const auto *GV = dyn_cast<GlobalValue>(Obj)) {
231 if (TLI.isPositionIndependent())
232 return false;
233 if (Addr.getGlobalValue())
234 return false;
235 if (GV->isThreadLocal())
236 return false;
237 Addr.setGlobalValue(GV);
238 return true;
239 }
240
241 switch (Opcode) {
242 default:
243 break;
244 case Instruction::BitCast: {
245 // Look through bitcasts.
246 return computeAddress(U->getOperand(0), Addr);
247 }
248 case Instruction::IntToPtr: {
249 // Look past no-op inttoptrs.
250 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
251 TLI.getPointerTy(DL))
252 return computeAddress(U->getOperand(0), Addr);
253 break;
254 }
255 case Instruction::PtrToInt: {
256 // Look past no-op ptrtoints.
257 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
258 return computeAddress(U->getOperand(0), Addr);
259 break;
260 }
261 case Instruction::GetElementPtr: {
262 Address SavedAddr = Addr;
263 uint64_t TmpOffset = Addr.getOffset();
264 // Non-inbounds geps can wrap; wasm's offsets can't.
265 if (!cast<GEPOperator>(U)->isInBounds())
266 goto unsupported_gep;
267 // Iterate through the GEP folding the constants into offsets where
268 // we can.
269 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
270 GTI != E; ++GTI) {
271 const Value *Op = GTI.getOperand();
272 if (StructType *STy = GTI.getStructTypeOrNull()) {
273 const StructLayout *SL = DL.getStructLayout(STy);
274 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
275 TmpOffset += SL->getElementOffset(Idx);
276 } else {
277 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
278 for (;;) {
279 if (const auto *CI = dyn_cast<ConstantInt>(Op)) {
280 // Constant-offset addressing.
281 TmpOffset += CI->getSExtValue() * S;
282 break;
283 }
284 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
285 // An unscaled add of a register. Set it as the new base.
286 unsigned Reg = getRegForValue(Op);
287 if (Reg == 0)
288 return false;
289 Addr.setReg(Reg);
290 break;
291 }
292 if (canFoldAddIntoGEP(U, Op)) {
293 // A compatible add with a constant operand. Fold the constant.
294 auto *CI = cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
295 TmpOffset += CI->getSExtValue() * S;
296 // Iterate on the other operand.
297 Op = cast<AddOperator>(Op)->getOperand(0);
298 continue;
299 }
300 // Unsupported
301 goto unsupported_gep;
302 }
303 }
304 }
305 // Don't fold in negative offsets.
306 if (int64_t(TmpOffset) >= 0) {
307 // Try to grab the base operand now.
308 Addr.setOffset(TmpOffset);
309 if (computeAddress(U->getOperand(0), Addr))
310 return true;
311 }
312 // We failed, restore everything and try the other options.
313 Addr = SavedAddr;
314 unsupported_gep:
315 break;
316 }
317 case Instruction::Alloca: {
318 const auto *AI = cast<AllocaInst>(Obj);
319 DenseMap<const AllocaInst *, int>::iterator SI =
320 FuncInfo.StaticAllocaMap.find(AI);
321 if (SI != FuncInfo.StaticAllocaMap.end()) {
322 if (Addr.isSet()) {
323 return false;
324 }
325 Addr.setKind(Address::FrameIndexBase);
326 Addr.setFI(SI->second);
327 return true;
328 }
329 break;
330 }
331 case Instruction::Add: {
332 // Adds of constants are common and easy enough.
333 const Value *LHS = U->getOperand(0);
334 const Value *RHS = U->getOperand(1);
335
336 if (isa<ConstantInt>(LHS))
337 std::swap(LHS, RHS);
338
339 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
340 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
341 if (int64_t(TmpOffset) >= 0) {
342 Addr.setOffset(TmpOffset);
343 return computeAddress(LHS, Addr);
344 }
345 }
346
347 Address Backup = Addr;
348 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
349 return true;
350 Addr = Backup;
351
352 break;
353 }
354 case Instruction::Sub: {
355 // Subs of constants are common and easy enough.
356 const Value *LHS = U->getOperand(0);
357 const Value *RHS = U->getOperand(1);
358
359 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
360 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
361 if (TmpOffset >= 0) {
362 Addr.setOffset(TmpOffset);
363 return computeAddress(LHS, Addr);
364 }
365 }
366 break;
367 }
368 }
369 if (Addr.isSet()) {
370 return false;
371 }
372 unsigned Reg = getRegForValue(Obj);
373 if (Reg == 0)
374 return false;
375 Addr.setReg(Reg);
376 return Addr.getReg() != 0;
377 }
378
materializeLoadStoreOperands(Address & Addr)379 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
380 if (Addr.isRegBase()) {
381 unsigned Reg = Addr.getReg();
382 if (Reg == 0) {
383 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
384 : &WebAssembly::I32RegClass);
385 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
386 : WebAssembly::CONST_I32;
387 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
388 .addImm(0);
389 Addr.setReg(Reg);
390 }
391 }
392 }
393
addLoadStoreOperands(const Address & Addr,const MachineInstrBuilder & MIB,MachineMemOperand * MMO)394 void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
395 const MachineInstrBuilder &MIB,
396 MachineMemOperand *MMO) {
397 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
398 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
399 MIB.addImm(0);
400
401 if (const GlobalValue *GV = Addr.getGlobalValue())
402 MIB.addGlobalAddress(GV, Addr.getOffset());
403 else
404 MIB.addImm(Addr.getOffset());
405
406 if (Addr.isRegBase())
407 MIB.addReg(Addr.getReg());
408 else
409 MIB.addFrameIndex(Addr.getFI());
410
411 MIB.addMemOperand(MMO);
412 }
413
maskI1Value(unsigned Reg,const Value * V)414 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
415 return zeroExtendToI32(Reg, V, MVT::i1);
416 }
417
getRegForI1Value(const Value * V,bool & Not)418 unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
419 if (const auto *ICmp = dyn_cast<ICmpInst>(V))
420 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
421 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
422 Not = ICmp->isTrueWhenEqual();
423 return getRegForValue(ICmp->getOperand(0));
424 }
425
426 Value *NotV;
427 if (match(V, m_Not(m_Value(NotV))) && V->getType()->isIntegerTy(32)) {
428 Not = true;
429 return getRegForValue(NotV);
430 }
431
432 Not = false;
433 unsigned Reg = getRegForValue(V);
434 if (Reg == 0)
435 return 0;
436 return maskI1Value(Reg, V);
437 }
438
zeroExtendToI32(unsigned Reg,const Value * V,MVT::SimpleValueType From)439 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
440 MVT::SimpleValueType From) {
441 if (Reg == 0)
442 return 0;
443
444 switch (From) {
445 case MVT::i1:
446 // If the value is naturally an i1, we don't need to mask it. We only know
447 // if a value is naturally an i1 if it is definitely lowered by FastISel,
448 // not a DAG ISel fallback.
449 if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
450 return copyValue(Reg);
451 break;
452 case MVT::i8:
453 case MVT::i16:
454 break;
455 case MVT::i32:
456 return copyValue(Reg);
457 default:
458 return 0;
459 }
460
461 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
462 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
463 TII.get(WebAssembly::CONST_I32), Imm)
464 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
465
466 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
467 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
468 TII.get(WebAssembly::AND_I32), Result)
469 .addReg(Reg)
470 .addReg(Imm);
471
472 return Result;
473 }
474
signExtendToI32(unsigned Reg,const Value * V,MVT::SimpleValueType From)475 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
476 MVT::SimpleValueType From) {
477 if (Reg == 0)
478 return 0;
479
480 switch (From) {
481 case MVT::i1:
482 case MVT::i8:
483 case MVT::i16:
484 break;
485 case MVT::i32:
486 return copyValue(Reg);
487 default:
488 return 0;
489 }
490
491 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
492 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
493 TII.get(WebAssembly::CONST_I32), Imm)
494 .addImm(32 - MVT(From).getSizeInBits());
495
496 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
497 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
498 TII.get(WebAssembly::SHL_I32), Left)
499 .addReg(Reg)
500 .addReg(Imm);
501
502 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
503 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
504 TII.get(WebAssembly::SHR_S_I32), Right)
505 .addReg(Left)
506 .addReg(Imm);
507
508 return Right;
509 }
510
zeroExtend(unsigned Reg,const Value * V,MVT::SimpleValueType From,MVT::SimpleValueType To)511 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
512 MVT::SimpleValueType From,
513 MVT::SimpleValueType To) {
514 if (To == MVT::i64) {
515 if (From == MVT::i64)
516 return copyValue(Reg);
517
518 Reg = zeroExtendToI32(Reg, V, From);
519
520 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
521 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
522 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
523 .addReg(Reg);
524 return Result;
525 }
526
527 if (To == MVT::i32)
528 return zeroExtendToI32(Reg, V, From);
529
530 return 0;
531 }
532
signExtend(unsigned Reg,const Value * V,MVT::SimpleValueType From,MVT::SimpleValueType To)533 unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
534 MVT::SimpleValueType From,
535 MVT::SimpleValueType To) {
536 if (To == MVT::i64) {
537 if (From == MVT::i64)
538 return copyValue(Reg);
539
540 Reg = signExtendToI32(Reg, V, From);
541
542 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
543 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
544 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
545 .addReg(Reg);
546 return Result;
547 }
548
549 if (To == MVT::i32)
550 return signExtendToI32(Reg, V, From);
551
552 return 0;
553 }
554
getRegForUnsignedValue(const Value * V)555 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
556 MVT::SimpleValueType From = getSimpleType(V->getType());
557 MVT::SimpleValueType To = getLegalType(From);
558 unsigned VReg = getRegForValue(V);
559 if (VReg == 0)
560 return 0;
561 return zeroExtend(VReg, V, From, To);
562 }
563
getRegForSignedValue(const Value * V)564 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
565 MVT::SimpleValueType From = getSimpleType(V->getType());
566 MVT::SimpleValueType To = getLegalType(From);
567 unsigned VReg = getRegForValue(V);
568 if (VReg == 0)
569 return 0;
570 return signExtend(VReg, V, From, To);
571 }
572
getRegForPromotedValue(const Value * V,bool IsSigned)573 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
574 bool IsSigned) {
575 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
576 }
577
notValue(unsigned Reg)578 unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
579 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
580
581 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
582 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
583 TII.get(WebAssembly::EQZ_I32), NotReg)
584 .addReg(Reg);
585 return NotReg;
586 }
587
copyValue(unsigned Reg)588 unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
589 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
590 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(WebAssembly::COPY),
591 ResultReg)
592 .addReg(Reg);
593 return ResultReg;
594 }
595
fastMaterializeAlloca(const AllocaInst * AI)596 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
597 DenseMap<const AllocaInst *, int>::iterator SI =
598 FuncInfo.StaticAllocaMap.find(AI);
599
600 if (SI != FuncInfo.StaticAllocaMap.end()) {
601 unsigned ResultReg =
602 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
603 : &WebAssembly::I32RegClass);
604 unsigned Opc =
605 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
606 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
607 .addFrameIndex(SI->second);
608 return ResultReg;
609 }
610
611 return 0;
612 }
613
fastMaterializeConstant(const Constant * C)614 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
615 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
616 if (TLI.isPositionIndependent())
617 return 0;
618 if (GV->isThreadLocal())
619 return 0;
620 unsigned ResultReg =
621 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
622 : &WebAssembly::I32RegClass);
623 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
624 : WebAssembly::CONST_I32;
625 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
626 .addGlobalAddress(GV);
627 return ResultReg;
628 }
629
630 // Let target-independent code handle it.
631 return 0;
632 }
633
fastLowerArguments()634 bool WebAssemblyFastISel::fastLowerArguments() {
635 if (!FuncInfo.CanLowerReturn)
636 return false;
637
638 const Function *F = FuncInfo.Fn;
639 if (F->isVarArg())
640 return false;
641
642 if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
643 return false;
644
645 unsigned I = 0;
646 for (auto const &Arg : F->args()) {
647 const AttributeList &Attrs = F->getAttributes();
648 if (Attrs.hasParamAttribute(I, Attribute::ByVal) ||
649 Attrs.hasParamAttribute(I, Attribute::SwiftSelf) ||
650 Attrs.hasParamAttribute(I, Attribute::SwiftError) ||
651 Attrs.hasParamAttribute(I, Attribute::InAlloca) ||
652 Attrs.hasParamAttribute(I, Attribute::Nest))
653 return false;
654
655 Type *ArgTy = Arg.getType();
656 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
657 return false;
658 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
659 return false;
660
661 unsigned Opc;
662 const TargetRegisterClass *RC;
663 switch (getSimpleType(ArgTy)) {
664 case MVT::i1:
665 case MVT::i8:
666 case MVT::i16:
667 case MVT::i32:
668 Opc = WebAssembly::ARGUMENT_i32;
669 RC = &WebAssembly::I32RegClass;
670 break;
671 case MVT::i64:
672 Opc = WebAssembly::ARGUMENT_i64;
673 RC = &WebAssembly::I64RegClass;
674 break;
675 case MVT::f32:
676 Opc = WebAssembly::ARGUMENT_f32;
677 RC = &WebAssembly::F32RegClass;
678 break;
679 case MVT::f64:
680 Opc = WebAssembly::ARGUMENT_f64;
681 RC = &WebAssembly::F64RegClass;
682 break;
683 case MVT::v16i8:
684 Opc = WebAssembly::ARGUMENT_v16i8;
685 RC = &WebAssembly::V128RegClass;
686 break;
687 case MVT::v8i16:
688 Opc = WebAssembly::ARGUMENT_v8i16;
689 RC = &WebAssembly::V128RegClass;
690 break;
691 case MVT::v4i32:
692 Opc = WebAssembly::ARGUMENT_v4i32;
693 RC = &WebAssembly::V128RegClass;
694 break;
695 case MVT::v2i64:
696 Opc = WebAssembly::ARGUMENT_v2i64;
697 RC = &WebAssembly::V128RegClass;
698 break;
699 case MVT::v4f32:
700 Opc = WebAssembly::ARGUMENT_v4f32;
701 RC = &WebAssembly::V128RegClass;
702 break;
703 case MVT::v2f64:
704 Opc = WebAssembly::ARGUMENT_v2f64;
705 RC = &WebAssembly::V128RegClass;
706 break;
707 case MVT::funcref:
708 Opc = WebAssembly::ARGUMENT_funcref;
709 RC = &WebAssembly::FUNCREFRegClass;
710 break;
711 case MVT::externref:
712 Opc = WebAssembly::ARGUMENT_externref;
713 RC = &WebAssembly::EXTERNREFRegClass;
714 break;
715 default:
716 return false;
717 }
718 unsigned ResultReg = createResultReg(RC);
719 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
720 .addImm(I);
721 updateValueMap(&Arg, ResultReg);
722
723 ++I;
724 }
725
726 MRI.addLiveIn(WebAssembly::ARGUMENTS);
727
728 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
729 for (auto const &Arg : F->args()) {
730 MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
731 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
732 MFI->clearParamsAndResults();
733 return false;
734 }
735 MFI->addParam(ArgTy);
736 }
737
738 if (!F->getReturnType()->isVoidTy()) {
739 MVT::SimpleValueType RetTy =
740 getLegalType(getSimpleType(F->getReturnType()));
741 if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
742 MFI->clearParamsAndResults();
743 return false;
744 }
745 MFI->addResult(RetTy);
746 }
747
748 return true;
749 }
750
selectCall(const Instruction * I)751 bool WebAssemblyFastISel::selectCall(const Instruction *I) {
752 const auto *Call = cast<CallInst>(I);
753
754 // TODO: Support tail calls in FastISel
755 if (Call->isMustTailCall() || Call->isInlineAsm() ||
756 Call->getFunctionType()->isVarArg())
757 return false;
758
759 Function *Func = Call->getCalledFunction();
760 if (Func && Func->isIntrinsic())
761 return false;
762
763 if (Call->getCallingConv() == CallingConv::Swift)
764 return false;
765
766 bool IsDirect = Func != nullptr;
767 if (!IsDirect && isa<ConstantExpr>(Call->getCalledOperand()))
768 return false;
769
770 FunctionType *FuncTy = Call->getFunctionType();
771 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
772 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
773 unsigned ResultReg;
774 if (!IsVoid) {
775 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
776 return false;
777
778 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
779 switch (RetTy) {
780 case MVT::i1:
781 case MVT::i8:
782 case MVT::i16:
783 case MVT::i32:
784 ResultReg = createResultReg(&WebAssembly::I32RegClass);
785 break;
786 case MVT::i64:
787 ResultReg = createResultReg(&WebAssembly::I64RegClass);
788 break;
789 case MVT::f32:
790 ResultReg = createResultReg(&WebAssembly::F32RegClass);
791 break;
792 case MVT::f64:
793 ResultReg = createResultReg(&WebAssembly::F64RegClass);
794 break;
795 case MVT::v16i8:
796 ResultReg = createResultReg(&WebAssembly::V128RegClass);
797 break;
798 case MVT::v8i16:
799 ResultReg = createResultReg(&WebAssembly::V128RegClass);
800 break;
801 case MVT::v4i32:
802 ResultReg = createResultReg(&WebAssembly::V128RegClass);
803 break;
804 case MVT::v2i64:
805 ResultReg = createResultReg(&WebAssembly::V128RegClass);
806 break;
807 case MVT::v4f32:
808 ResultReg = createResultReg(&WebAssembly::V128RegClass);
809 break;
810 case MVT::v2f64:
811 ResultReg = createResultReg(&WebAssembly::V128RegClass);
812 break;
813 case MVT::funcref:
814 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
815 break;
816 case MVT::externref:
817 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
818 break;
819 default:
820 return false;
821 }
822 }
823
824 SmallVector<unsigned, 8> Args;
825 for (unsigned I = 0, E = Call->getNumArgOperands(); I < E; ++I) {
826 Value *V = Call->getArgOperand(I);
827 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
828 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
829 return false;
830
831 const AttributeList &Attrs = Call->getAttributes();
832 if (Attrs.hasParamAttribute(I, Attribute::ByVal) ||
833 Attrs.hasParamAttribute(I, Attribute::SwiftSelf) ||
834 Attrs.hasParamAttribute(I, Attribute::SwiftError) ||
835 Attrs.hasParamAttribute(I, Attribute::InAlloca) ||
836 Attrs.hasParamAttribute(I, Attribute::Nest))
837 return false;
838
839 unsigned Reg;
840
841 if (Attrs.hasParamAttribute(I, Attribute::SExt))
842 Reg = getRegForSignedValue(V);
843 else if (Attrs.hasParamAttribute(I, Attribute::ZExt))
844 Reg = getRegForUnsignedValue(V);
845 else
846 Reg = getRegForValue(V);
847
848 if (Reg == 0)
849 return false;
850
851 Args.push_back(Reg);
852 }
853
854 unsigned CalleeReg = 0;
855 if (!IsDirect) {
856 CalleeReg = getRegForValue(Call->getCalledOperand());
857 if (!CalleeReg)
858 return false;
859 }
860
861 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
862
863 if (!IsVoid)
864 MIB.addReg(ResultReg, RegState::Define);
865
866 if (IsDirect) {
867 MIB.addGlobalAddress(Func);
868 } else {
869 // Placeholder for the type index.
870 MIB.addImm(0);
871 // The table into which this call_indirect indexes.
872 MCSymbolWasm *Table = WebAssembly::getOrCreateFunctionTableSymbol(
873 MF->getMMI().getContext(), Subtarget);
874 if (Subtarget->hasReferenceTypes()) {
875 MIB.addSym(Table);
876 } else {
877 // Otherwise for the MVP there is at most one table whose number is 0, but
878 // we can't write a table symbol or issue relocations. Instead we just
879 // ensure the table is live.
880 Table->setNoStrip();
881 MIB.addImm(0);
882 }
883 // See if we must truncate the function pointer.
884 // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers
885 // as 64-bit for uniformity with other pointer types.
886 // See also: WebAssemblyISelLowering.cpp: LowerCallResults
887 if (Subtarget->hasAddr64()) {
888 auto Wrap = BuildMI(*FuncInfo.MBB, std::prev(FuncInfo.InsertPt), DbgLoc,
889 TII.get(WebAssembly::I32_WRAP_I64));
890 unsigned Reg32 = createResultReg(&WebAssembly::I32RegClass);
891 Wrap.addReg(Reg32, RegState::Define);
892 Wrap.addReg(CalleeReg);
893 CalleeReg = Reg32;
894 }
895 }
896
897 for (unsigned ArgReg : Args)
898 MIB.addReg(ArgReg);
899
900 if (!IsDirect)
901 MIB.addReg(CalleeReg);
902
903 if (!IsVoid)
904 updateValueMap(Call, ResultReg);
905 return true;
906 }
907
selectSelect(const Instruction * I)908 bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
909 const auto *Select = cast<SelectInst>(I);
910
911 bool Not;
912 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
913 if (CondReg == 0)
914 return false;
915
916 unsigned TrueReg = getRegForValue(Select->getTrueValue());
917 if (TrueReg == 0)
918 return false;
919
920 unsigned FalseReg = getRegForValue(Select->getFalseValue());
921 if (FalseReg == 0)
922 return false;
923
924 if (Not)
925 std::swap(TrueReg, FalseReg);
926
927 unsigned Opc;
928 const TargetRegisterClass *RC;
929 switch (getSimpleType(Select->getType())) {
930 case MVT::i1:
931 case MVT::i8:
932 case MVT::i16:
933 case MVT::i32:
934 Opc = WebAssembly::SELECT_I32;
935 RC = &WebAssembly::I32RegClass;
936 break;
937 case MVT::i64:
938 Opc = WebAssembly::SELECT_I64;
939 RC = &WebAssembly::I64RegClass;
940 break;
941 case MVT::f32:
942 Opc = WebAssembly::SELECT_F32;
943 RC = &WebAssembly::F32RegClass;
944 break;
945 case MVT::f64:
946 Opc = WebAssembly::SELECT_F64;
947 RC = &WebAssembly::F64RegClass;
948 break;
949 case MVT::funcref:
950 Opc = WebAssembly::SELECT_FUNCREF;
951 RC = &WebAssembly::FUNCREFRegClass;
952 break;
953 case MVT::externref:
954 Opc = WebAssembly::SELECT_EXTERNREF;
955 RC = &WebAssembly::EXTERNREFRegClass;
956 break;
957 default:
958 return false;
959 }
960
961 unsigned ResultReg = createResultReg(RC);
962 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
963 .addReg(TrueReg)
964 .addReg(FalseReg)
965 .addReg(CondReg);
966
967 updateValueMap(Select, ResultReg);
968 return true;
969 }
970
selectTrunc(const Instruction * I)971 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
972 const auto *Trunc = cast<TruncInst>(I);
973
974 unsigned Reg = getRegForValue(Trunc->getOperand(0));
975 if (Reg == 0)
976 return false;
977
978 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
979 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
980 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
981 TII.get(WebAssembly::I32_WRAP_I64), Result)
982 .addReg(Reg);
983 Reg = Result;
984 }
985
986 updateValueMap(Trunc, Reg);
987 return true;
988 }
989
selectZExt(const Instruction * I)990 bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
991 const auto *ZExt = cast<ZExtInst>(I);
992
993 const Value *Op = ZExt->getOperand(0);
994 MVT::SimpleValueType From = getSimpleType(Op->getType());
995 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
996 unsigned In = getRegForValue(Op);
997 if (In == 0)
998 return false;
999 unsigned Reg = zeroExtend(In, Op, From, To);
1000 if (Reg == 0)
1001 return false;
1002
1003 updateValueMap(ZExt, Reg);
1004 return true;
1005 }
1006
selectSExt(const Instruction * I)1007 bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
1008 const auto *SExt = cast<SExtInst>(I);
1009
1010 const Value *Op = SExt->getOperand(0);
1011 MVT::SimpleValueType From = getSimpleType(Op->getType());
1012 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
1013 unsigned In = getRegForValue(Op);
1014 if (In == 0)
1015 return false;
1016 unsigned Reg = signExtend(In, Op, From, To);
1017 if (Reg == 0)
1018 return false;
1019
1020 updateValueMap(SExt, Reg);
1021 return true;
1022 }
1023
selectICmp(const Instruction * I)1024 bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
1025 const auto *ICmp = cast<ICmpInst>(I);
1026
1027 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1028 unsigned Opc;
1029 bool IsSigned = false;
1030 switch (ICmp->getPredicate()) {
1031 case ICmpInst::ICMP_EQ:
1032 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1033 break;
1034 case ICmpInst::ICMP_NE:
1035 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1036 break;
1037 case ICmpInst::ICMP_UGT:
1038 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1039 break;
1040 case ICmpInst::ICMP_UGE:
1041 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1042 break;
1043 case ICmpInst::ICMP_ULT:
1044 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1045 break;
1046 case ICmpInst::ICMP_ULE:
1047 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1048 break;
1049 case ICmpInst::ICMP_SGT:
1050 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1051 IsSigned = true;
1052 break;
1053 case ICmpInst::ICMP_SGE:
1054 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1055 IsSigned = true;
1056 break;
1057 case ICmpInst::ICMP_SLT:
1058 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1059 IsSigned = true;
1060 break;
1061 case ICmpInst::ICMP_SLE:
1062 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1063 IsSigned = true;
1064 break;
1065 default:
1066 return false;
1067 }
1068
1069 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1070 if (LHS == 0)
1071 return false;
1072
1073 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1074 if (RHS == 0)
1075 return false;
1076
1077 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1078 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1079 .addReg(LHS)
1080 .addReg(RHS);
1081 updateValueMap(ICmp, ResultReg);
1082 return true;
1083 }
1084
selectFCmp(const Instruction * I)1085 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1086 const auto *FCmp = cast<FCmpInst>(I);
1087
1088 unsigned LHS = getRegForValue(FCmp->getOperand(0));
1089 if (LHS == 0)
1090 return false;
1091
1092 unsigned RHS = getRegForValue(FCmp->getOperand(1));
1093 if (RHS == 0)
1094 return false;
1095
1096 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1097 unsigned Opc;
1098 bool Not = false;
1099 switch (FCmp->getPredicate()) {
1100 case FCmpInst::FCMP_OEQ:
1101 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1102 break;
1103 case FCmpInst::FCMP_UNE:
1104 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1105 break;
1106 case FCmpInst::FCMP_OGT:
1107 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1108 break;
1109 case FCmpInst::FCMP_OGE:
1110 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1111 break;
1112 case FCmpInst::FCMP_OLT:
1113 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1114 break;
1115 case FCmpInst::FCMP_OLE:
1116 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1117 break;
1118 case FCmpInst::FCMP_UGT:
1119 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1120 Not = true;
1121 break;
1122 case FCmpInst::FCMP_UGE:
1123 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1124 Not = true;
1125 break;
1126 case FCmpInst::FCMP_ULT:
1127 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1128 Not = true;
1129 break;
1130 case FCmpInst::FCMP_ULE:
1131 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1132 Not = true;
1133 break;
1134 default:
1135 return false;
1136 }
1137
1138 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1139 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1140 .addReg(LHS)
1141 .addReg(RHS);
1142
1143 if (Not)
1144 ResultReg = notValue(ResultReg);
1145
1146 updateValueMap(FCmp, ResultReg);
1147 return true;
1148 }
1149
selectBitCast(const Instruction * I)1150 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1151 // Target-independent code can handle this, except it doesn't set the dead
1152 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1153 // to satisfy code that expects this of isBitcast() instructions.
1154 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1155 EVT RetVT = TLI.getValueType(DL, I->getType());
1156 if (!VT.isSimple() || !RetVT.isSimple())
1157 return false;
1158
1159 unsigned In = getRegForValue(I->getOperand(0));
1160 if (In == 0)
1161 return false;
1162
1163 if (VT == RetVT) {
1164 // No-op bitcast.
1165 updateValueMap(I, In);
1166 return true;
1167 }
1168
1169 Register Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1170 In);
1171 if (!Reg)
1172 return false;
1173 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1174 --Iter;
1175 assert(Iter->isBitcast());
1176 Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI);
1177 updateValueMap(I, Reg);
1178 return true;
1179 }
1180
selectLoad(const Instruction * I)1181 bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1182 const auto *Load = cast<LoadInst>(I);
1183 if (Load->isAtomic())
1184 return false;
1185 if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace()))
1186 return false;
1187 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1188 return false;
1189
1190 Address Addr;
1191 if (!computeAddress(Load->getPointerOperand(), Addr))
1192 return false;
1193
1194 // TODO: Fold a following sign-/zero-extend into the load instruction.
1195
1196 unsigned Opc;
1197 const TargetRegisterClass *RC;
1198 bool A64 = Subtarget->hasAddr64();
1199 switch (getSimpleType(Load->getType())) {
1200 case MVT::i1:
1201 case MVT::i8:
1202 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1203 RC = &WebAssembly::I32RegClass;
1204 break;
1205 case MVT::i16:
1206 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1207 RC = &WebAssembly::I32RegClass;
1208 break;
1209 case MVT::i32:
1210 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1211 RC = &WebAssembly::I32RegClass;
1212 break;
1213 case MVT::i64:
1214 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1215 RC = &WebAssembly::I64RegClass;
1216 break;
1217 case MVT::f32:
1218 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1219 RC = &WebAssembly::F32RegClass;
1220 break;
1221 case MVT::f64:
1222 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1223 RC = &WebAssembly::F64RegClass;
1224 break;
1225 default:
1226 return false;
1227 }
1228
1229 materializeLoadStoreOperands(Addr);
1230
1231 unsigned ResultReg = createResultReg(RC);
1232 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1233 ResultReg);
1234
1235 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1236
1237 updateValueMap(Load, ResultReg);
1238 return true;
1239 }
1240
selectStore(const Instruction * I)1241 bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1242 const auto *Store = cast<StoreInst>(I);
1243 if (Store->isAtomic())
1244 return false;
1245 if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace()))
1246 return false;
1247 if (!Subtarget->hasSIMD128() &&
1248 Store->getValueOperand()->getType()->isVectorTy())
1249 return false;
1250
1251 Address Addr;
1252 if (!computeAddress(Store->getPointerOperand(), Addr))
1253 return false;
1254
1255 unsigned Opc;
1256 bool VTIsi1 = false;
1257 bool A64 = Subtarget->hasAddr64();
1258 switch (getSimpleType(Store->getValueOperand()->getType())) {
1259 case MVT::i1:
1260 VTIsi1 = true;
1261 LLVM_FALLTHROUGH;
1262 case MVT::i8:
1263 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1264 break;
1265 case MVT::i16:
1266 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1267 break;
1268 case MVT::i32:
1269 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1270 break;
1271 case MVT::i64:
1272 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1273 break;
1274 case MVT::f32:
1275 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1276 break;
1277 case MVT::f64:
1278 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1279 break;
1280 default:
1281 return false;
1282 }
1283
1284 materializeLoadStoreOperands(Addr);
1285
1286 unsigned ValueReg = getRegForValue(Store->getValueOperand());
1287 if (ValueReg == 0)
1288 return false;
1289 if (VTIsi1)
1290 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1291
1292 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
1293
1294 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1295
1296 MIB.addReg(ValueReg);
1297 return true;
1298 }
1299
selectBr(const Instruction * I)1300 bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1301 const auto *Br = cast<BranchInst>(I);
1302 if (Br->isUnconditional()) {
1303 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1304 fastEmitBranch(MSucc, Br->getDebugLoc());
1305 return true;
1306 }
1307
1308 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1309 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1310
1311 bool Not;
1312 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
1313 if (CondReg == 0)
1314 return false;
1315
1316 unsigned Opc = WebAssembly::BR_IF;
1317 if (Not)
1318 Opc = WebAssembly::BR_UNLESS;
1319
1320 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1321 .addMBB(TBB)
1322 .addReg(CondReg);
1323
1324 finishCondBranch(Br->getParent(), TBB, FBB);
1325 return true;
1326 }
1327
selectRet(const Instruction * I)1328 bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1329 if (!FuncInfo.CanLowerReturn)
1330 return false;
1331
1332 const auto *Ret = cast<ReturnInst>(I);
1333
1334 if (Ret->getNumOperands() == 0) {
1335 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1336 TII.get(WebAssembly::RETURN));
1337 return true;
1338 }
1339
1340 // TODO: support multiple return in FastISel
1341 if (Ret->getNumOperands() > 1)
1342 return false;
1343
1344 Value *RV = Ret->getOperand(0);
1345 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1346 return false;
1347
1348 switch (getSimpleType(RV->getType())) {
1349 case MVT::i1:
1350 case MVT::i8:
1351 case MVT::i16:
1352 case MVT::i32:
1353 case MVT::i64:
1354 case MVT::f32:
1355 case MVT::f64:
1356 case MVT::v16i8:
1357 case MVT::v8i16:
1358 case MVT::v4i32:
1359 case MVT::v2i64:
1360 case MVT::v4f32:
1361 case MVT::v2f64:
1362 case MVT::funcref:
1363 case MVT::externref:
1364 break;
1365 default:
1366 return false;
1367 }
1368
1369 unsigned Reg;
1370 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1371 Reg = getRegForSignedValue(RV);
1372 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1373 Reg = getRegForUnsignedValue(RV);
1374 else
1375 Reg = getRegForValue(RV);
1376
1377 if (Reg == 0)
1378 return false;
1379
1380 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1381 TII.get(WebAssembly::RETURN))
1382 .addReg(Reg);
1383 return true;
1384 }
1385
selectUnreachable(const Instruction * I)1386 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1387 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1388 TII.get(WebAssembly::UNREACHABLE));
1389 return true;
1390 }
1391
fastSelectInstruction(const Instruction * I)1392 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1393 switch (I->getOpcode()) {
1394 case Instruction::Call:
1395 if (selectCall(I))
1396 return true;
1397 break;
1398 case Instruction::Select:
1399 return selectSelect(I);
1400 case Instruction::Trunc:
1401 return selectTrunc(I);
1402 case Instruction::ZExt:
1403 return selectZExt(I);
1404 case Instruction::SExt:
1405 return selectSExt(I);
1406 case Instruction::ICmp:
1407 return selectICmp(I);
1408 case Instruction::FCmp:
1409 return selectFCmp(I);
1410 case Instruction::BitCast:
1411 return selectBitCast(I);
1412 case Instruction::Load:
1413 return selectLoad(I);
1414 case Instruction::Store:
1415 return selectStore(I);
1416 case Instruction::Br:
1417 return selectBr(I);
1418 case Instruction::Ret:
1419 return selectRet(I);
1420 case Instruction::Unreachable:
1421 return selectUnreachable(I);
1422 default:
1423 break;
1424 }
1425
1426 // Fall back to target-independent instruction selection.
1427 return selectOperator(I, I->getOpcode());
1428 }
1429
createFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)1430 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1431 const TargetLibraryInfo *LibInfo) {
1432 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1433 }
1434