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 return VT;
134 case MVT::funcref:
135 case MVT::externref:
136 if (Subtarget->hasReferenceTypes())
137 return VT;
138 break;
139 case MVT::f16:
140 return MVT::f32;
141 case MVT::v16i8:
142 case MVT::v8i16:
143 case MVT::v4i32:
144 case MVT::v4f32:
145 case MVT::v2i64:
146 case MVT::v2f64:
147 if (Subtarget->hasSIMD128())
148 return VT;
149 break;
150 default:
151 break;
152 }
153 return MVT::INVALID_SIMPLE_VALUE_TYPE;
154 }
155 bool computeAddress(const Value *Obj, Address &Addr);
156 void materializeLoadStoreOperands(Address &Addr);
157 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
158 MachineMemOperand *MMO);
159 unsigned maskI1Value(unsigned Reg, const Value *V);
160 unsigned getRegForI1Value(const Value *V, const BasicBlock *BB, bool &Not);
161 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
162 MVT::SimpleValueType From);
163 unsigned signExtendToI32(unsigned Reg, const Value *V,
164 MVT::SimpleValueType From);
165 unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
166 MVT::SimpleValueType To);
167 unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
168 MVT::SimpleValueType To);
169 unsigned getRegForUnsignedValue(const Value *V);
170 unsigned getRegForSignedValue(const Value *V);
171 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
172 unsigned notValue(unsigned Reg);
173 unsigned copyValue(unsigned Reg);
174
175 // Backend specific FastISel code.
176 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
177 unsigned fastMaterializeConstant(const Constant *C) override;
178 bool fastLowerArguments() override;
179
180 // Selection routines.
181 bool selectCall(const Instruction *I);
182 bool selectSelect(const Instruction *I);
183 bool selectTrunc(const Instruction *I);
184 bool selectZExt(const Instruction *I);
185 bool selectSExt(const Instruction *I);
186 bool selectICmp(const Instruction *I);
187 bool selectFCmp(const Instruction *I);
188 bool selectBitCast(const Instruction *I);
189 bool selectLoad(const Instruction *I);
190 bool selectStore(const Instruction *I);
191 bool selectBr(const Instruction *I);
192 bool selectRet(const Instruction *I);
193 bool selectUnreachable(const Instruction *I);
194
195 public:
196 // Backend specific FastISel code.
WebAssemblyFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)197 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
198 const TargetLibraryInfo *LibInfo)
199 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
200 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
201 Context = &FuncInfo.Fn->getContext();
202 }
203
204 bool fastSelectInstruction(const Instruction *I) override;
205
206 #include "WebAssemblyGenFastISel.inc"
207 };
208
209 } // end anonymous namespace
210
computeAddress(const Value * Obj,Address & Addr)211 bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
212 const User *U = nullptr;
213 unsigned Opcode = Instruction::UserOp1;
214 if (const auto *I = dyn_cast<Instruction>(Obj)) {
215 // Don't walk into other basic blocks unless the object is an alloca from
216 // another block, otherwise it may not have a virtual register assigned.
217 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
218 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
219 Opcode = I->getOpcode();
220 U = I;
221 }
222 } else if (const auto *C = dyn_cast<ConstantExpr>(Obj)) {
223 Opcode = C->getOpcode();
224 U = C;
225 }
226
227 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
228 if (Ty->getAddressSpace() > 255)
229 // Fast instruction selection doesn't support the special
230 // address spaces.
231 return false;
232
233 if (const auto *GV = dyn_cast<GlobalValue>(Obj)) {
234 if (TLI.isPositionIndependent())
235 return false;
236 if (Addr.getGlobalValue())
237 return false;
238 if (GV->isThreadLocal())
239 return false;
240 Addr.setGlobalValue(GV);
241 return true;
242 }
243
244 switch (Opcode) {
245 default:
246 break;
247 case Instruction::BitCast: {
248 // Look through bitcasts.
249 return computeAddress(U->getOperand(0), Addr);
250 }
251 case Instruction::IntToPtr: {
252 // Look past no-op inttoptrs.
253 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
254 TLI.getPointerTy(DL))
255 return computeAddress(U->getOperand(0), Addr);
256 break;
257 }
258 case Instruction::PtrToInt: {
259 // Look past no-op ptrtoints.
260 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
261 return computeAddress(U->getOperand(0), Addr);
262 break;
263 }
264 case Instruction::GetElementPtr: {
265 Address SavedAddr = Addr;
266 uint64_t TmpOffset = Addr.getOffset();
267 // Non-inbounds geps can wrap; wasm's offsets can't.
268 if (!cast<GEPOperator>(U)->isInBounds())
269 goto unsupported_gep;
270 // Iterate through the GEP folding the constants into offsets where
271 // we can.
272 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
273 GTI != E; ++GTI) {
274 const Value *Op = GTI.getOperand();
275 if (StructType *STy = GTI.getStructTypeOrNull()) {
276 const StructLayout *SL = DL.getStructLayout(STy);
277 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
278 TmpOffset += SL->getElementOffset(Idx);
279 } else {
280 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
281 for (;;) {
282 if (const auto *CI = dyn_cast<ConstantInt>(Op)) {
283 // Constant-offset addressing.
284 TmpOffset += CI->getSExtValue() * S;
285 break;
286 }
287 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
288 // An unscaled add of a register. Set it as the new base.
289 unsigned Reg = getRegForValue(Op);
290 if (Reg == 0)
291 return false;
292 Addr.setReg(Reg);
293 break;
294 }
295 if (canFoldAddIntoGEP(U, Op)) {
296 // A compatible add with a constant operand. Fold the constant.
297 auto *CI = cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
298 TmpOffset += CI->getSExtValue() * S;
299 // Iterate on the other operand.
300 Op = cast<AddOperator>(Op)->getOperand(0);
301 continue;
302 }
303 // Unsupported
304 goto unsupported_gep;
305 }
306 }
307 }
308 // Don't fold in negative offsets.
309 if (int64_t(TmpOffset) >= 0) {
310 // Try to grab the base operand now.
311 Addr.setOffset(TmpOffset);
312 if (computeAddress(U->getOperand(0), Addr))
313 return true;
314 }
315 // We failed, restore everything and try the other options.
316 Addr = SavedAddr;
317 unsupported_gep:
318 break;
319 }
320 case Instruction::Alloca: {
321 const auto *AI = cast<AllocaInst>(Obj);
322 DenseMap<const AllocaInst *, int>::iterator SI =
323 FuncInfo.StaticAllocaMap.find(AI);
324 if (SI != FuncInfo.StaticAllocaMap.end()) {
325 if (Addr.isSet()) {
326 return false;
327 }
328 Addr.setKind(Address::FrameIndexBase);
329 Addr.setFI(SI->second);
330 return true;
331 }
332 break;
333 }
334 case Instruction::Add: {
335 // Adds of constants are common and easy enough.
336 const Value *LHS = U->getOperand(0);
337 const Value *RHS = U->getOperand(1);
338
339 if (isa<ConstantInt>(LHS))
340 std::swap(LHS, RHS);
341
342 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
343 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
344 if (int64_t(TmpOffset) >= 0) {
345 Addr.setOffset(TmpOffset);
346 return computeAddress(LHS, Addr);
347 }
348 }
349
350 Address Backup = Addr;
351 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
352 return true;
353 Addr = Backup;
354
355 break;
356 }
357 case Instruction::Sub: {
358 // Subs of constants are common and easy enough.
359 const Value *LHS = U->getOperand(0);
360 const Value *RHS = U->getOperand(1);
361
362 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
363 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
364 if (TmpOffset >= 0) {
365 Addr.setOffset(TmpOffset);
366 return computeAddress(LHS, Addr);
367 }
368 }
369 break;
370 }
371 }
372 if (Addr.isSet()) {
373 return false;
374 }
375 unsigned Reg = getRegForValue(Obj);
376 if (Reg == 0)
377 return false;
378 Addr.setReg(Reg);
379 return Addr.getReg() != 0;
380 }
381
materializeLoadStoreOperands(Address & Addr)382 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
383 if (Addr.isRegBase()) {
384 unsigned Reg = Addr.getReg();
385 if (Reg == 0) {
386 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
387 : &WebAssembly::I32RegClass);
388 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
389 : WebAssembly::CONST_I32;
390 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
391 .addImm(0);
392 Addr.setReg(Reg);
393 }
394 }
395 }
396
addLoadStoreOperands(const Address & Addr,const MachineInstrBuilder & MIB,MachineMemOperand * MMO)397 void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
398 const MachineInstrBuilder &MIB,
399 MachineMemOperand *MMO) {
400 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
401 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
402 MIB.addImm(0);
403
404 if (const GlobalValue *GV = Addr.getGlobalValue())
405 MIB.addGlobalAddress(GV, Addr.getOffset());
406 else
407 MIB.addImm(Addr.getOffset());
408
409 if (Addr.isRegBase())
410 MIB.addReg(Addr.getReg());
411 else
412 MIB.addFrameIndex(Addr.getFI());
413
414 MIB.addMemOperand(MMO);
415 }
416
maskI1Value(unsigned Reg,const Value * V)417 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
418 return zeroExtendToI32(Reg, V, MVT::i1);
419 }
420
getRegForI1Value(const Value * V,const BasicBlock * BB,bool & Not)421 unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V,
422 const BasicBlock *BB,
423 bool &Not) {
424 if (const auto *ICmp = dyn_cast<ICmpInst>(V))
425 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
426 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32) &&
427 ICmp->getParent() == BB) {
428 Not = ICmp->isTrueWhenEqual();
429 return getRegForValue(ICmp->getOperand(0));
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 =
913 getRegForI1Value(Select->getCondition(), I->getParent(), Not);
914 if (CondReg == 0)
915 return false;
916
917 unsigned TrueReg = getRegForValue(Select->getTrueValue());
918 if (TrueReg == 0)
919 return false;
920
921 unsigned FalseReg = getRegForValue(Select->getFalseValue());
922 if (FalseReg == 0)
923 return false;
924
925 if (Not)
926 std::swap(TrueReg, FalseReg);
927
928 unsigned Opc;
929 const TargetRegisterClass *RC;
930 switch (getSimpleType(Select->getType())) {
931 case MVT::i1:
932 case MVT::i8:
933 case MVT::i16:
934 case MVT::i32:
935 Opc = WebAssembly::SELECT_I32;
936 RC = &WebAssembly::I32RegClass;
937 break;
938 case MVT::i64:
939 Opc = WebAssembly::SELECT_I64;
940 RC = &WebAssembly::I64RegClass;
941 break;
942 case MVT::f32:
943 Opc = WebAssembly::SELECT_F32;
944 RC = &WebAssembly::F32RegClass;
945 break;
946 case MVT::f64:
947 Opc = WebAssembly::SELECT_F64;
948 RC = &WebAssembly::F64RegClass;
949 break;
950 case MVT::funcref:
951 Opc = WebAssembly::SELECT_FUNCREF;
952 RC = &WebAssembly::FUNCREFRegClass;
953 break;
954 case MVT::externref:
955 Opc = WebAssembly::SELECT_EXTERNREF;
956 RC = &WebAssembly::EXTERNREFRegClass;
957 break;
958 default:
959 return false;
960 }
961
962 unsigned ResultReg = createResultReg(RC);
963 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
964 .addReg(TrueReg)
965 .addReg(FalseReg)
966 .addReg(CondReg);
967
968 updateValueMap(Select, ResultReg);
969 return true;
970 }
971
selectTrunc(const Instruction * I)972 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
973 const auto *Trunc = cast<TruncInst>(I);
974
975 unsigned Reg = getRegForValue(Trunc->getOperand(0));
976 if (Reg == 0)
977 return false;
978
979 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
980 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
981 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
982 TII.get(WebAssembly::I32_WRAP_I64), Result)
983 .addReg(Reg);
984 Reg = Result;
985 }
986
987 updateValueMap(Trunc, Reg);
988 return true;
989 }
990
selectZExt(const Instruction * I)991 bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
992 const auto *ZExt = cast<ZExtInst>(I);
993
994 const Value *Op = ZExt->getOperand(0);
995 MVT::SimpleValueType From = getSimpleType(Op->getType());
996 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
997 unsigned In = getRegForValue(Op);
998 if (In == 0)
999 return false;
1000 unsigned Reg = zeroExtend(In, Op, From, To);
1001 if (Reg == 0)
1002 return false;
1003
1004 updateValueMap(ZExt, Reg);
1005 return true;
1006 }
1007
selectSExt(const Instruction * I)1008 bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
1009 const auto *SExt = cast<SExtInst>(I);
1010
1011 const Value *Op = SExt->getOperand(0);
1012 MVT::SimpleValueType From = getSimpleType(Op->getType());
1013 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
1014 unsigned In = getRegForValue(Op);
1015 if (In == 0)
1016 return false;
1017 unsigned Reg = signExtend(In, Op, From, To);
1018 if (Reg == 0)
1019 return false;
1020
1021 updateValueMap(SExt, Reg);
1022 return true;
1023 }
1024
selectICmp(const Instruction * I)1025 bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
1026 const auto *ICmp = cast<ICmpInst>(I);
1027
1028 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1029 unsigned Opc;
1030 bool IsSigned = false;
1031 switch (ICmp->getPredicate()) {
1032 case ICmpInst::ICMP_EQ:
1033 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1034 break;
1035 case ICmpInst::ICMP_NE:
1036 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1037 break;
1038 case ICmpInst::ICMP_UGT:
1039 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1040 break;
1041 case ICmpInst::ICMP_UGE:
1042 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1043 break;
1044 case ICmpInst::ICMP_ULT:
1045 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1046 break;
1047 case ICmpInst::ICMP_ULE:
1048 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1049 break;
1050 case ICmpInst::ICMP_SGT:
1051 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1052 IsSigned = true;
1053 break;
1054 case ICmpInst::ICMP_SGE:
1055 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1056 IsSigned = true;
1057 break;
1058 case ICmpInst::ICMP_SLT:
1059 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1060 IsSigned = true;
1061 break;
1062 case ICmpInst::ICMP_SLE:
1063 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1064 IsSigned = true;
1065 break;
1066 default:
1067 return false;
1068 }
1069
1070 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1071 if (LHS == 0)
1072 return false;
1073
1074 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1075 if (RHS == 0)
1076 return false;
1077
1078 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1079 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1080 .addReg(LHS)
1081 .addReg(RHS);
1082 updateValueMap(ICmp, ResultReg);
1083 return true;
1084 }
1085
selectFCmp(const Instruction * I)1086 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1087 const auto *FCmp = cast<FCmpInst>(I);
1088
1089 unsigned LHS = getRegForValue(FCmp->getOperand(0));
1090 if (LHS == 0)
1091 return false;
1092
1093 unsigned RHS = getRegForValue(FCmp->getOperand(1));
1094 if (RHS == 0)
1095 return false;
1096
1097 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1098 unsigned Opc;
1099 bool Not = false;
1100 switch (FCmp->getPredicate()) {
1101 case FCmpInst::FCMP_OEQ:
1102 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1103 break;
1104 case FCmpInst::FCMP_UNE:
1105 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1106 break;
1107 case FCmpInst::FCMP_OGT:
1108 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1109 break;
1110 case FCmpInst::FCMP_OGE:
1111 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1112 break;
1113 case FCmpInst::FCMP_OLT:
1114 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1115 break;
1116 case FCmpInst::FCMP_OLE:
1117 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1118 break;
1119 case FCmpInst::FCMP_UGT:
1120 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1121 Not = true;
1122 break;
1123 case FCmpInst::FCMP_UGE:
1124 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1125 Not = true;
1126 break;
1127 case FCmpInst::FCMP_ULT:
1128 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1129 Not = true;
1130 break;
1131 case FCmpInst::FCMP_ULE:
1132 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1133 Not = true;
1134 break;
1135 default:
1136 return false;
1137 }
1138
1139 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1140 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1141 .addReg(LHS)
1142 .addReg(RHS);
1143
1144 if (Not)
1145 ResultReg = notValue(ResultReg);
1146
1147 updateValueMap(FCmp, ResultReg);
1148 return true;
1149 }
1150
selectBitCast(const Instruction * I)1151 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1152 // Target-independent code can handle this, except it doesn't set the dead
1153 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1154 // to satisfy code that expects this of isBitcast() instructions.
1155 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1156 EVT RetVT = TLI.getValueType(DL, I->getType());
1157 if (!VT.isSimple() || !RetVT.isSimple())
1158 return false;
1159
1160 unsigned In = getRegForValue(I->getOperand(0));
1161 if (In == 0)
1162 return false;
1163
1164 if (VT == RetVT) {
1165 // No-op bitcast.
1166 updateValueMap(I, In);
1167 return true;
1168 }
1169
1170 Register Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1171 In);
1172 if (!Reg)
1173 return false;
1174 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1175 --Iter;
1176 assert(Iter->isBitcast());
1177 Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI);
1178 updateValueMap(I, Reg);
1179 return true;
1180 }
1181
selectLoad(const Instruction * I)1182 bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1183 const auto *Load = cast<LoadInst>(I);
1184 if (Load->isAtomic())
1185 return false;
1186 if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace()))
1187 return false;
1188 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1189 return false;
1190
1191 Address Addr;
1192 if (!computeAddress(Load->getPointerOperand(), Addr))
1193 return false;
1194
1195 // TODO: Fold a following sign-/zero-extend into the load instruction.
1196
1197 unsigned Opc;
1198 const TargetRegisterClass *RC;
1199 bool A64 = Subtarget->hasAddr64();
1200 switch (getSimpleType(Load->getType())) {
1201 case MVT::i1:
1202 case MVT::i8:
1203 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1204 RC = &WebAssembly::I32RegClass;
1205 break;
1206 case MVT::i16:
1207 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1208 RC = &WebAssembly::I32RegClass;
1209 break;
1210 case MVT::i32:
1211 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1212 RC = &WebAssembly::I32RegClass;
1213 break;
1214 case MVT::i64:
1215 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1216 RC = &WebAssembly::I64RegClass;
1217 break;
1218 case MVT::f32:
1219 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1220 RC = &WebAssembly::F32RegClass;
1221 break;
1222 case MVT::f64:
1223 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1224 RC = &WebAssembly::F64RegClass;
1225 break;
1226 default:
1227 return false;
1228 }
1229
1230 materializeLoadStoreOperands(Addr);
1231
1232 unsigned ResultReg = createResultReg(RC);
1233 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1234 ResultReg);
1235
1236 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1237
1238 updateValueMap(Load, ResultReg);
1239 return true;
1240 }
1241
selectStore(const Instruction * I)1242 bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1243 const auto *Store = cast<StoreInst>(I);
1244 if (Store->isAtomic())
1245 return false;
1246 if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace()))
1247 return false;
1248 if (!Subtarget->hasSIMD128() &&
1249 Store->getValueOperand()->getType()->isVectorTy())
1250 return false;
1251
1252 Address Addr;
1253 if (!computeAddress(Store->getPointerOperand(), Addr))
1254 return false;
1255
1256 unsigned Opc;
1257 bool VTIsi1 = false;
1258 bool A64 = Subtarget->hasAddr64();
1259 switch (getSimpleType(Store->getValueOperand()->getType())) {
1260 case MVT::i1:
1261 VTIsi1 = true;
1262 LLVM_FALLTHROUGH;
1263 case MVT::i8:
1264 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1265 break;
1266 case MVT::i16:
1267 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1268 break;
1269 case MVT::i32:
1270 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1271 break;
1272 case MVT::i64:
1273 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1274 break;
1275 case MVT::f32:
1276 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1277 break;
1278 case MVT::f64:
1279 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1280 break;
1281 default:
1282 return false;
1283 }
1284
1285 materializeLoadStoreOperands(Addr);
1286
1287 unsigned ValueReg = getRegForValue(Store->getValueOperand());
1288 if (ValueReg == 0)
1289 return false;
1290 if (VTIsi1)
1291 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1292
1293 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
1294
1295 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1296
1297 MIB.addReg(ValueReg);
1298 return true;
1299 }
1300
selectBr(const Instruction * I)1301 bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1302 const auto *Br = cast<BranchInst>(I);
1303 if (Br->isUnconditional()) {
1304 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1305 fastEmitBranch(MSucc, Br->getDebugLoc());
1306 return true;
1307 }
1308
1309 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1310 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1311
1312 bool Not;
1313 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1314 if (CondReg == 0)
1315 return false;
1316
1317 unsigned Opc = WebAssembly::BR_IF;
1318 if (Not)
1319 Opc = WebAssembly::BR_UNLESS;
1320
1321 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1322 .addMBB(TBB)
1323 .addReg(CondReg);
1324
1325 finishCondBranch(Br->getParent(), TBB, FBB);
1326 return true;
1327 }
1328
selectRet(const Instruction * I)1329 bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1330 if (!FuncInfo.CanLowerReturn)
1331 return false;
1332
1333 const auto *Ret = cast<ReturnInst>(I);
1334
1335 if (Ret->getNumOperands() == 0) {
1336 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1337 TII.get(WebAssembly::RETURN));
1338 return true;
1339 }
1340
1341 // TODO: support multiple return in FastISel
1342 if (Ret->getNumOperands() > 1)
1343 return false;
1344
1345 Value *RV = Ret->getOperand(0);
1346 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1347 return false;
1348
1349 switch (getSimpleType(RV->getType())) {
1350 case MVT::i1:
1351 case MVT::i8:
1352 case MVT::i16:
1353 case MVT::i32:
1354 case MVT::i64:
1355 case MVT::f32:
1356 case MVT::f64:
1357 case MVT::v16i8:
1358 case MVT::v8i16:
1359 case MVT::v4i32:
1360 case MVT::v2i64:
1361 case MVT::v4f32:
1362 case MVT::v2f64:
1363 case MVT::funcref:
1364 case MVT::externref:
1365 break;
1366 default:
1367 return false;
1368 }
1369
1370 unsigned Reg;
1371 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1372 Reg = getRegForSignedValue(RV);
1373 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1374 Reg = getRegForUnsignedValue(RV);
1375 else
1376 Reg = getRegForValue(RV);
1377
1378 if (Reg == 0)
1379 return false;
1380
1381 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1382 TII.get(WebAssembly::RETURN))
1383 .addReg(Reg);
1384 return true;
1385 }
1386
selectUnreachable(const Instruction * I)1387 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1388 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1389 TII.get(WebAssembly::UNREACHABLE));
1390 return true;
1391 }
1392
fastSelectInstruction(const Instruction * I)1393 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1394 switch (I->getOpcode()) {
1395 case Instruction::Call:
1396 if (selectCall(I))
1397 return true;
1398 break;
1399 case Instruction::Select:
1400 return selectSelect(I);
1401 case Instruction::Trunc:
1402 return selectTrunc(I);
1403 case Instruction::ZExt:
1404 return selectZExt(I);
1405 case Instruction::SExt:
1406 return selectSExt(I);
1407 case Instruction::ICmp:
1408 return selectICmp(I);
1409 case Instruction::FCmp:
1410 return selectFCmp(I);
1411 case Instruction::BitCast:
1412 return selectBitCast(I);
1413 case Instruction::Load:
1414 return selectLoad(I);
1415 case Instruction::Store:
1416 return selectStore(I);
1417 case Instruction::Br:
1418 return selectBr(I);
1419 case Instruction::Ret:
1420 return selectRet(I);
1421 case Instruction::Unreachable:
1422 return selectUnreachable(I);
1423 default:
1424 break;
1425 }
1426
1427 // Fall back to target-independent instruction selection.
1428 return selectOperator(I, I->getOpcode());
1429 }
1430
createFastISel(FunctionLoweringInfo & FuncInfo,const TargetLibraryInfo * LibInfo)1431 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1432 const TargetLibraryInfo *LibInfo) {
1433 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1434 }
1435