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