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