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