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, MCID: TII.get(Opcode: WebAssembly::AND_I32),
482 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 if (Subtarget->hasSignExt()) {
506 if (From == MVT::i8 || From == MVT::i16) {
507 Register Result = createResultReg(RC: &WebAssembly::I32RegClass);
508 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
509 MCID: TII.get(Opcode: From == MVT::i16 ? WebAssembly::I32_EXTEND16_S_I32
510 : WebAssembly::I32_EXTEND8_S_I32),
511 DestReg: Result)
512 .addReg(RegNo: Reg);
513 return Result;
514 }
515 }
516
517 Register Imm = createResultReg(RC: &WebAssembly::I32RegClass);
518 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
519 MCID: TII.get(Opcode: WebAssembly::CONST_I32), DestReg: Imm)
520 .addImm(Val: 32 - MVT(From).getSizeInBits());
521
522 Register Left = createResultReg(RC: &WebAssembly::I32RegClass);
523 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: WebAssembly::SHL_I32),
524 DestReg: Left)
525 .addReg(RegNo: Reg)
526 .addReg(RegNo: Imm);
527
528 Register Right = createResultReg(RC: &WebAssembly::I32RegClass);
529 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
530 MCID: TII.get(Opcode: WebAssembly::SHR_S_I32), DestReg: Right)
531 .addReg(RegNo: Left)
532 .addReg(RegNo: Imm);
533
534 return Right;
535}
536
537unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
538 MVT::SimpleValueType From,
539 MVT::SimpleValueType To) {
540 if (To == MVT::i64) {
541 if (From == MVT::i64)
542 return copyValue(Reg);
543
544 Reg = zeroExtendToI32(Reg, V, From);
545
546 Register Result = createResultReg(RC: &WebAssembly::I64RegClass);
547 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
548 MCID: TII.get(Opcode: WebAssembly::I64_EXTEND_U_I32), DestReg: Result)
549 .addReg(RegNo: Reg);
550 return Result;
551 }
552
553 if (To == MVT::i32)
554 return zeroExtendToI32(Reg, V, From);
555
556 return 0;
557}
558
559unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
560 MVT::SimpleValueType From,
561 MVT::SimpleValueType To) {
562 if (To == MVT::i64) {
563 if (From == MVT::i64)
564 return copyValue(Reg);
565
566 Register Result = createResultReg(RC: &WebAssembly::I64RegClass);
567
568 if (Subtarget->hasSignExt()) {
569 if (From != MVT::i32) {
570 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
571 MCID: TII.get(Opcode: WebAssembly::I64_EXTEND_U_I32), DestReg: Result)
572 .addReg(RegNo: Reg);
573
574 Reg = Result;
575 Result = createResultReg(RC: &WebAssembly::I64RegClass);
576 }
577
578 switch (From) {
579 case MVT::i8:
580 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
581 MCID: TII.get(Opcode: WebAssembly::I64_EXTEND8_S_I64), DestReg: Result)
582 .addReg(RegNo: Reg);
583 return Result;
584 case MVT::i16:
585 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
586 MCID: TII.get(Opcode: WebAssembly::I64_EXTEND16_S_I64), DestReg: Result)
587 .addReg(RegNo: Reg);
588 return Result;
589 case MVT::i32:
590 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
591 MCID: TII.get(Opcode: WebAssembly::I64_EXTEND_S_I32), DestReg: Result)
592 .addReg(RegNo: Reg);
593 return Result;
594 default:
595 break;
596 }
597 } else {
598 Reg = signExtendToI32(Reg, V, From);
599
600 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
601 MCID: TII.get(Opcode: WebAssembly::I64_EXTEND_S_I32), DestReg: Result)
602 .addReg(RegNo: Reg);
603 }
604
605 return Result;
606 }
607
608 if (To == MVT::i32)
609 return signExtendToI32(Reg, V, From);
610
611 return 0;
612}
613
614unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
615 MVT::SimpleValueType From = getSimpleType(Ty: V->getType());
616 MVT::SimpleValueType To = getLegalType(VT: From);
617 Register VReg = getRegForValue(V);
618 if (VReg == 0)
619 return 0;
620 if (From == To)
621 return VReg;
622 return zeroExtend(Reg: VReg, V, From, To);
623}
624
625unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
626 MVT::SimpleValueType From = getSimpleType(Ty: V->getType());
627 MVT::SimpleValueType To = getLegalType(VT: From);
628 Register VReg = getRegForValue(V);
629 if (VReg == 0)
630 return 0;
631 if (From == To)
632 return VReg;
633 return signExtend(Reg: VReg, V, From, To);
634}
635
636unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
637 bool IsSigned) {
638 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
639}
640
641unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
642 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
643
644 Register NotReg = createResultReg(RC: &WebAssembly::I32RegClass);
645 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: WebAssembly::EQZ_I32),
646 DestReg: NotReg)
647 .addReg(RegNo: Reg);
648 return NotReg;
649}
650
651unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
652 Register ResultReg = createResultReg(RC: MRI.getRegClass(Reg));
653 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: WebAssembly::COPY),
654 DestReg: ResultReg)
655 .addReg(RegNo: Reg);
656 return ResultReg;
657}
658
659Register WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
660 DenseMap<const AllocaInst *, int>::iterator SI =
661 FuncInfo.StaticAllocaMap.find(Val: AI);
662
663 if (SI != FuncInfo.StaticAllocaMap.end()) {
664 Register ResultReg =
665 createResultReg(RC: Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
666 : &WebAssembly::I32RegClass);
667 unsigned Opc =
668 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
669 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: Opc), DestReg: ResultReg)
670 .addFrameIndex(Idx: SI->second);
671 return ResultReg;
672 }
673
674 return Register();
675}
676
677Register WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
678 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Val: C)) {
679 if (TLI.isPositionIndependent())
680 return Register();
681 if (GV->isThreadLocal())
682 return Register();
683 Register ResultReg =
684 createResultReg(RC: Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
685 : &WebAssembly::I32RegClass);
686 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
687 : WebAssembly::CONST_I32;
688 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: Opc), DestReg: ResultReg)
689 .addGlobalAddress(GV);
690 return ResultReg;
691 }
692
693 // Let target-independent code handle it.
694 return Register();
695}
696
697bool WebAssemblyFastISel::fastLowerArguments() {
698 if (!FuncInfo.CanLowerReturn)
699 return false;
700
701 const Function *F = FuncInfo.Fn;
702 if (F->isVarArg())
703 return false;
704
705 if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
706 return false;
707
708 unsigned I = 0;
709 for (auto const &Arg : F->args()) {
710 const AttributeList &Attrs = F->getAttributes();
711 if (Attrs.hasParamAttr(ArgNo: I, Kind: Attribute::ByVal) ||
712 Attrs.hasParamAttr(ArgNo: I, Kind: Attribute::SwiftSelf) ||
713 Attrs.hasParamAttr(ArgNo: I, Kind: Attribute::SwiftError) ||
714 Attrs.hasParamAttr(ArgNo: I, Kind: Attribute::InAlloca) ||
715 Attrs.hasParamAttr(ArgNo: I, Kind: Attribute::Nest))
716 return false;
717
718 Type *ArgTy = Arg.getType();
719 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
720 return false;
721 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
722 return false;
723
724 unsigned Opc;
725 const TargetRegisterClass *RC;
726 switch (getSimpleType(Ty: ArgTy)) {
727 case MVT::i1:
728 case MVT::i8:
729 case MVT::i16:
730 case MVT::i32:
731 Opc = WebAssembly::ARGUMENT_i32;
732 RC = &WebAssembly::I32RegClass;
733 break;
734 case MVT::i64:
735 Opc = WebAssembly::ARGUMENT_i64;
736 RC = &WebAssembly::I64RegClass;
737 break;
738 case MVT::f32:
739 Opc = WebAssembly::ARGUMENT_f32;
740 RC = &WebAssembly::F32RegClass;
741 break;
742 case MVT::f64:
743 Opc = WebAssembly::ARGUMENT_f64;
744 RC = &WebAssembly::F64RegClass;
745 break;
746 case MVT::v16i8:
747 Opc = WebAssembly::ARGUMENT_v16i8;
748 RC = &WebAssembly::V128RegClass;
749 break;
750 case MVT::v8i16:
751 Opc = WebAssembly::ARGUMENT_v8i16;
752 RC = &WebAssembly::V128RegClass;
753 break;
754 case MVT::v4i32:
755 Opc = WebAssembly::ARGUMENT_v4i32;
756 RC = &WebAssembly::V128RegClass;
757 break;
758 case MVT::v2i64:
759 Opc = WebAssembly::ARGUMENT_v2i64;
760 RC = &WebAssembly::V128RegClass;
761 break;
762 case MVT::v4f32:
763 Opc = WebAssembly::ARGUMENT_v4f32;
764 RC = &WebAssembly::V128RegClass;
765 break;
766 case MVT::v2f64:
767 Opc = WebAssembly::ARGUMENT_v2f64;
768 RC = &WebAssembly::V128RegClass;
769 break;
770 case MVT::funcref:
771 Opc = WebAssembly::ARGUMENT_funcref;
772 RC = &WebAssembly::FUNCREFRegClass;
773 break;
774 case MVT::externref:
775 Opc = WebAssembly::ARGUMENT_externref;
776 RC = &WebAssembly::EXTERNREFRegClass;
777 break;
778 case MVT::exnref:
779 Opc = WebAssembly::ARGUMENT_exnref;
780 RC = &WebAssembly::EXNREFRegClass;
781 break;
782 default:
783 return false;
784 }
785 Register ResultReg = createResultReg(RC);
786 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: Opc), DestReg: ResultReg)
787 .addImm(Val: I);
788 updateValueMap(I: &Arg, Reg: ResultReg);
789
790 ++I;
791 }
792
793 MRI.addLiveIn(Reg: WebAssembly::ARGUMENTS);
794
795 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
796 for (auto const &Arg : F->args()) {
797 MVT::SimpleValueType ArgTy = getLegalType(VT: getSimpleType(Ty: Arg.getType()));
798 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
799 MFI->clearParamsAndResults();
800 return false;
801 }
802 MFI->addParam(VT: ArgTy);
803 }
804
805 if (!F->getReturnType()->isVoidTy()) {
806 MVT::SimpleValueType RetTy =
807 getLegalType(VT: getSimpleType(Ty: F->getReturnType()));
808 if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
809 MFI->clearParamsAndResults();
810 return false;
811 }
812 MFI->addResult(VT: RetTy);
813 }
814
815 return true;
816}
817
818bool WebAssemblyFastISel::selectCall(const Instruction *I) {
819 const auto *Call = cast<CallInst>(Val: I);
820
821 // FastISel does not support calls through funcref
822 if (Call->getCalledOperand()->getType()->getPointerAddressSpace() !=
823 WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_DEFAULT)
824 return false;
825
826 // TODO: Support tail calls in FastISel
827 if (Call->isMustTailCall() || Call->isInlineAsm() ||
828 Call->getFunctionType()->isVarArg())
829 return false;
830
831 Function *Func = Call->getCalledFunction();
832 if (Func && Func->isIntrinsic())
833 return false;
834
835 if (Call->getCallingConv() == CallingConv::Swift)
836 return false;
837
838 bool IsDirect = Func != nullptr;
839 if (!IsDirect && isa<ConstantExpr>(Val: Call->getCalledOperand()))
840 return false;
841
842 FunctionType *FuncTy = Call->getFunctionType();
843 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
844 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
845 unsigned ResultReg;
846 if (!IsVoid) {
847 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
848 return false;
849
850 MVT::SimpleValueType RetTy = getSimpleType(Ty: Call->getType());
851 switch (RetTy) {
852 case MVT::i1:
853 case MVT::i8:
854 case MVT::i16:
855 case MVT::i32:
856 ResultReg = createResultReg(RC: &WebAssembly::I32RegClass);
857 break;
858 case MVT::i64:
859 ResultReg = createResultReg(RC: &WebAssembly::I64RegClass);
860 break;
861 case MVT::f32:
862 ResultReg = createResultReg(RC: &WebAssembly::F32RegClass);
863 break;
864 case MVT::f64:
865 ResultReg = createResultReg(RC: &WebAssembly::F64RegClass);
866 break;
867 case MVT::v16i8:
868 ResultReg = createResultReg(RC: &WebAssembly::V128RegClass);
869 break;
870 case MVT::v8i16:
871 ResultReg = createResultReg(RC: &WebAssembly::V128RegClass);
872 break;
873 case MVT::v4i32:
874 ResultReg = createResultReg(RC: &WebAssembly::V128RegClass);
875 break;
876 case MVT::v2i64:
877 ResultReg = createResultReg(RC: &WebAssembly::V128RegClass);
878 break;
879 case MVT::v4f32:
880 ResultReg = createResultReg(RC: &WebAssembly::V128RegClass);
881 break;
882 case MVT::v2f64:
883 ResultReg = createResultReg(RC: &WebAssembly::V128RegClass);
884 break;
885 case MVT::funcref:
886 ResultReg = createResultReg(RC: &WebAssembly::FUNCREFRegClass);
887 break;
888 case MVT::externref:
889 ResultReg = createResultReg(RC: &WebAssembly::EXTERNREFRegClass);
890 break;
891 case MVT::exnref:
892 ResultReg = createResultReg(RC: &WebAssembly::EXNREFRegClass);
893 break;
894 default:
895 return false;
896 }
897 }
898
899 SmallVector<unsigned, 8> Args;
900 for (unsigned I = 0, E = Call->arg_size(); I < E; ++I) {
901 Value *V = Call->getArgOperand(i: I);
902 MVT::SimpleValueType ArgTy = getSimpleType(Ty: V->getType());
903 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
904 return false;
905
906 const AttributeList &Attrs = Call->getAttributes();
907 if (Attrs.hasParamAttr(ArgNo: I, Kind: Attribute::ByVal) ||
908 Attrs.hasParamAttr(ArgNo: I, Kind: Attribute::SwiftSelf) ||
909 Attrs.hasParamAttr(ArgNo: I, Kind: Attribute::SwiftError) ||
910 Attrs.hasParamAttr(ArgNo: I, Kind: Attribute::InAlloca) ||
911 Attrs.hasParamAttr(ArgNo: I, Kind: Attribute::Nest))
912 return false;
913
914 unsigned Reg;
915
916 if (Call->paramHasAttr(ArgNo: I, Kind: Attribute::SExt))
917 Reg = getRegForSignedValue(V);
918 else if (Call->paramHasAttr(ArgNo: I, Kind: Attribute::ZExt))
919 Reg = getRegForUnsignedValue(V);
920 else
921 Reg = getRegForValue(V);
922
923 if (Reg == 0)
924 return false;
925
926 Args.push_back(Elt: Reg);
927 }
928
929 unsigned CalleeReg = 0;
930 if (!IsDirect) {
931 CalleeReg = getRegForValue(V: Call->getCalledOperand());
932 if (!CalleeReg)
933 return false;
934 }
935
936 auto MIB = BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: Opc));
937
938 if (!IsVoid)
939 MIB.addReg(RegNo: ResultReg, Flags: RegState::Define);
940
941 if (IsDirect) {
942 MIB.addGlobalAddress(GV: Func);
943 } else {
944 // Placeholder for the type index.
945 MIB.addImm(Val: 0);
946 // The table into which this call_indirect indexes.
947 MCSymbolWasm *Table = WebAssembly::getOrCreateFunctionTableSymbol(
948 Ctx&: MF->getContext(), Subtarget);
949 if (Subtarget->hasCallIndirectOverlong()) {
950 MIB.addSym(Sym: Table);
951 } else {
952 // Otherwise for the MVP there is at most one table whose number is 0, but
953 // we can't write a table symbol or issue relocations. Instead we just
954 // ensure the table is live.
955 Table->setNoStrip();
956 MIB.addImm(Val: 0);
957 }
958 }
959
960 for (unsigned ArgReg : Args)
961 MIB.addReg(RegNo: ArgReg);
962
963 if (!IsDirect)
964 MIB.addReg(RegNo: CalleeReg);
965
966 if (!IsVoid)
967 updateValueMap(I: Call, Reg: ResultReg);
968
969 diagnoseDontCall(CI: *Call);
970 return true;
971}
972
973bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
974 const auto *Select = cast<SelectInst>(Val: I);
975
976 bool Not;
977 unsigned CondReg =
978 getRegForI1Value(V: Select->getCondition(), BB: I->getParent(), Not);
979 if (CondReg == 0)
980 return false;
981
982 Register TrueReg = getRegForValue(V: Select->getTrueValue());
983 if (TrueReg == 0)
984 return false;
985
986 Register FalseReg = getRegForValue(V: Select->getFalseValue());
987 if (FalseReg == 0)
988 return false;
989
990 if (Not)
991 std::swap(a&: TrueReg, b&: FalseReg);
992
993 unsigned Opc;
994 const TargetRegisterClass *RC;
995 switch (getSimpleType(Ty: Select->getType())) {
996 case MVT::i1:
997 case MVT::i8:
998 case MVT::i16:
999 case MVT::i32:
1000 Opc = WebAssembly::SELECT_I32;
1001 RC = &WebAssembly::I32RegClass;
1002 break;
1003 case MVT::i64:
1004 Opc = WebAssembly::SELECT_I64;
1005 RC = &WebAssembly::I64RegClass;
1006 break;
1007 case MVT::f32:
1008 Opc = WebAssembly::SELECT_F32;
1009 RC = &WebAssembly::F32RegClass;
1010 break;
1011 case MVT::f64:
1012 Opc = WebAssembly::SELECT_F64;
1013 RC = &WebAssembly::F64RegClass;
1014 break;
1015 case MVT::funcref:
1016 Opc = WebAssembly::SELECT_FUNCREF;
1017 RC = &WebAssembly::FUNCREFRegClass;
1018 break;
1019 case MVT::externref:
1020 Opc = WebAssembly::SELECT_EXTERNREF;
1021 RC = &WebAssembly::EXTERNREFRegClass;
1022 break;
1023 case MVT::exnref:
1024 Opc = WebAssembly::SELECT_EXNREF;
1025 RC = &WebAssembly::EXNREFRegClass;
1026 break;
1027 default:
1028 return false;
1029 }
1030
1031 Register ResultReg = createResultReg(RC);
1032 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: Opc), DestReg: ResultReg)
1033 .addReg(RegNo: TrueReg)
1034 .addReg(RegNo: FalseReg)
1035 .addReg(RegNo: CondReg);
1036
1037 updateValueMap(I: Select, Reg: ResultReg);
1038 return true;
1039}
1040
1041bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
1042 const auto *Trunc = cast<TruncInst>(Val: I);
1043
1044 const Value *Op = Trunc->getOperand(i_nocapture: 0);
1045 MVT::SimpleValueType From = getSimpleType(Ty: Op->getType());
1046 MVT::SimpleValueType To = getLegalType(VT: getSimpleType(Ty: Trunc->getType()));
1047 Register In = getRegForValue(V: Op);
1048 if (In == 0)
1049 return false;
1050
1051 auto Truncate = [&](Register Reg) -> unsigned {
1052 if (From == MVT::i64) {
1053 if (To == MVT::i64)
1054 return copyValue(Reg);
1055
1056 if (To == MVT::i1 || To == MVT::i8 || To == MVT::i16 || To == MVT::i32) {
1057 Register Result = createResultReg(RC: &WebAssembly::I32RegClass);
1058 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
1059 MCID: TII.get(Opcode: WebAssembly::I32_WRAP_I64), DestReg: Result)
1060 .addReg(RegNo: Reg);
1061 return Result;
1062 }
1063 }
1064
1065 if (From == MVT::i32)
1066 return copyValue(Reg);
1067
1068 return 0;
1069 };
1070
1071 unsigned Reg = Truncate(In);
1072 if (Reg == 0)
1073 return false;
1074
1075 updateValueMap(I: Trunc, Reg);
1076 return true;
1077}
1078
1079bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
1080 const auto *ZExt = cast<ZExtInst>(Val: I);
1081
1082 const Value *Op = ZExt->getOperand(i_nocapture: 0);
1083 MVT::SimpleValueType From = getSimpleType(Ty: Op->getType());
1084 MVT::SimpleValueType To = getLegalType(VT: getSimpleType(Ty: ZExt->getType()));
1085 Register In = getRegForValue(V: Op);
1086 if (In == 0)
1087 return false;
1088 unsigned Reg = zeroExtend(Reg: In, V: Op, From, To);
1089 if (Reg == 0)
1090 return false;
1091
1092 updateValueMap(I: ZExt, Reg);
1093 return true;
1094}
1095
1096bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
1097 const auto *SExt = cast<SExtInst>(Val: I);
1098
1099 const Value *Op = SExt->getOperand(i_nocapture: 0);
1100 MVT::SimpleValueType From = getSimpleType(Ty: Op->getType());
1101 MVT::SimpleValueType To = getLegalType(VT: getSimpleType(Ty: SExt->getType()));
1102 Register In = getRegForValue(V: Op);
1103 if (In == 0)
1104 return false;
1105 unsigned Reg = signExtend(Reg: In, V: Op, From, To);
1106 if (Reg == 0)
1107 return false;
1108
1109 updateValueMap(I: SExt, Reg);
1110 return true;
1111}
1112
1113bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
1114 const auto *ICmp = cast<ICmpInst>(Val: I);
1115
1116 bool I32 = getSimpleType(Ty: ICmp->getOperand(i_nocapture: 0)->getType()) != MVT::i64;
1117 unsigned Opc;
1118 bool IsSigned = false;
1119 switch (ICmp->getPredicate()) {
1120 case ICmpInst::ICMP_EQ:
1121 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1122 break;
1123 case ICmpInst::ICMP_NE:
1124 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1125 break;
1126 case ICmpInst::ICMP_UGT:
1127 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1128 break;
1129 case ICmpInst::ICMP_UGE:
1130 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1131 break;
1132 case ICmpInst::ICMP_ULT:
1133 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1134 break;
1135 case ICmpInst::ICMP_ULE:
1136 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1137 break;
1138 case ICmpInst::ICMP_SGT:
1139 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1140 IsSigned = true;
1141 break;
1142 case ICmpInst::ICMP_SGE:
1143 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1144 IsSigned = true;
1145 break;
1146 case ICmpInst::ICMP_SLT:
1147 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1148 IsSigned = true;
1149 break;
1150 case ICmpInst::ICMP_SLE:
1151 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1152 IsSigned = true;
1153 break;
1154 default:
1155 return false;
1156 }
1157
1158 unsigned LHS = getRegForPromotedValue(V: ICmp->getOperand(i_nocapture: 0), IsSigned);
1159 if (LHS == 0)
1160 return false;
1161
1162 unsigned RHS = getRegForPromotedValue(V: ICmp->getOperand(i_nocapture: 1), IsSigned);
1163 if (RHS == 0)
1164 return false;
1165
1166 Register ResultReg = createResultReg(RC: &WebAssembly::I32RegClass);
1167 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: Opc), DestReg: ResultReg)
1168 .addReg(RegNo: LHS)
1169 .addReg(RegNo: RHS);
1170 updateValueMap(I: ICmp, Reg: ResultReg);
1171 return true;
1172}
1173
1174bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1175 const auto *FCmp = cast<FCmpInst>(Val: I);
1176
1177 Register LHS = getRegForValue(V: FCmp->getOperand(i_nocapture: 0));
1178 if (LHS == 0)
1179 return false;
1180
1181 Register RHS = getRegForValue(V: FCmp->getOperand(i_nocapture: 1));
1182 if (RHS == 0)
1183 return false;
1184
1185 bool F32 = getSimpleType(Ty: FCmp->getOperand(i_nocapture: 0)->getType()) != MVT::f64;
1186 unsigned Opc;
1187 bool Not = false;
1188 switch (FCmp->getPredicate()) {
1189 case FCmpInst::FCMP_OEQ:
1190 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1191 break;
1192 case FCmpInst::FCMP_UNE:
1193 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1194 break;
1195 case FCmpInst::FCMP_OGT:
1196 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1197 break;
1198 case FCmpInst::FCMP_OGE:
1199 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1200 break;
1201 case FCmpInst::FCMP_OLT:
1202 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1203 break;
1204 case FCmpInst::FCMP_OLE:
1205 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1206 break;
1207 case FCmpInst::FCMP_UGT:
1208 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1209 Not = true;
1210 break;
1211 case FCmpInst::FCMP_UGE:
1212 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1213 Not = true;
1214 break;
1215 case FCmpInst::FCMP_ULT:
1216 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1217 Not = true;
1218 break;
1219 case FCmpInst::FCMP_ULE:
1220 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1221 Not = true;
1222 break;
1223 default:
1224 return false;
1225 }
1226
1227 Register ResultReg = createResultReg(RC: &WebAssembly::I32RegClass);
1228 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: Opc), DestReg: ResultReg)
1229 .addReg(RegNo: LHS)
1230 .addReg(RegNo: RHS);
1231
1232 if (Not)
1233 ResultReg = notValue(Reg: ResultReg);
1234
1235 updateValueMap(I: FCmp, Reg: ResultReg);
1236 return true;
1237}
1238
1239bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1240 // Target-independent code can handle this, except it doesn't set the dead
1241 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1242 // to satisfy code that expects this of isBitcast() instructions.
1243 EVT VT = TLI.getValueType(DL, Ty: I->getOperand(i: 0)->getType());
1244 EVT RetVT = TLI.getValueType(DL, Ty: I->getType());
1245 if (!VT.isSimple() || !RetVT.isSimple())
1246 return false;
1247
1248 Register In = getRegForValue(V: I->getOperand(i: 0));
1249 if (In == 0)
1250 return false;
1251
1252 if (VT == RetVT) {
1253 // No-op bitcast.
1254 updateValueMap(I, Reg: In);
1255 return true;
1256 }
1257
1258 Register Reg =
1259 fastEmit_ISD_BITCAST_r(VT: VT.getSimpleVT(), RetVT: RetVT.getSimpleVT(), Op0: In);
1260 if (!Reg)
1261 return false;
1262 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1263 --Iter;
1264 assert(Iter->isBitcast());
1265 Iter->setPhysRegsDeadExcept(UsedRegs: ArrayRef<Register>(), TRI);
1266 updateValueMap(I, Reg);
1267 return true;
1268}
1269
1270bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1271 const auto *Load = cast<LoadInst>(Val: I);
1272 if (Load->isAtomic())
1273 return false;
1274 if (!WebAssembly::isDefaultAddressSpace(AS: Load->getPointerAddressSpace()))
1275 return false;
1276 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1277 return false;
1278
1279 Address Addr;
1280 if (!computeAddress(Obj: Load->getPointerOperand(), Addr))
1281 return false;
1282
1283 // TODO: Fold a following sign-/zero-extend into the load instruction.
1284
1285 unsigned Opc;
1286 const TargetRegisterClass *RC;
1287 bool A64 = Subtarget->hasAddr64();
1288 switch (getSimpleType(Ty: Load->getType())) {
1289 case MVT::i1:
1290 case MVT::i8:
1291 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1292 RC = &WebAssembly::I32RegClass;
1293 break;
1294 case MVT::i16:
1295 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1296 RC = &WebAssembly::I32RegClass;
1297 break;
1298 case MVT::i32:
1299 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1300 RC = &WebAssembly::I32RegClass;
1301 break;
1302 case MVT::i64:
1303 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1304 RC = &WebAssembly::I64RegClass;
1305 break;
1306 case MVT::f32:
1307 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1308 RC = &WebAssembly::F32RegClass;
1309 break;
1310 case MVT::f64:
1311 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1312 RC = &WebAssembly::F64RegClass;
1313 break;
1314 default:
1315 return false;
1316 }
1317
1318 materializeLoadStoreOperands(Addr);
1319
1320 Register ResultReg = createResultReg(RC);
1321 auto MIB =
1322 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: Opc), DestReg: ResultReg);
1323
1324 addLoadStoreOperands(Addr, MIB, MMO: createMachineMemOperandFor(I: Load));
1325
1326 updateValueMap(I: Load, Reg: ResultReg);
1327 return true;
1328}
1329
1330bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1331 const auto *Store = cast<StoreInst>(Val: I);
1332 if (Store->isAtomic())
1333 return false;
1334 if (!WebAssembly::isDefaultAddressSpace(AS: Store->getPointerAddressSpace()))
1335 return false;
1336 if (!Subtarget->hasSIMD128() &&
1337 Store->getValueOperand()->getType()->isVectorTy())
1338 return false;
1339
1340 Address Addr;
1341 if (!computeAddress(Obj: Store->getPointerOperand(), Addr))
1342 return false;
1343
1344 unsigned Opc;
1345 bool VTIsi1 = false;
1346 bool A64 = Subtarget->hasAddr64();
1347 switch (getSimpleType(Ty: Store->getValueOperand()->getType())) {
1348 case MVT::i1:
1349 VTIsi1 = true;
1350 [[fallthrough]];
1351 case MVT::i8:
1352 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1353 break;
1354 case MVT::i16:
1355 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1356 break;
1357 case MVT::i32:
1358 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1359 break;
1360 case MVT::i64:
1361 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1362 break;
1363 case MVT::f32:
1364 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1365 break;
1366 case MVT::f64:
1367 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1368 break;
1369 default:
1370 return false;
1371 }
1372
1373 materializeLoadStoreOperands(Addr);
1374
1375 Register ValueReg = getRegForValue(V: Store->getValueOperand());
1376 if (ValueReg == 0)
1377 return false;
1378 if (VTIsi1)
1379 ValueReg = maskI1Value(Reg: ValueReg, V: Store->getValueOperand());
1380
1381 auto MIB = BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: Opc));
1382
1383 addLoadStoreOperands(Addr, MIB, MMO: createMachineMemOperandFor(I: Store));
1384
1385 MIB.addReg(RegNo: ValueReg);
1386 return true;
1387}
1388
1389bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1390 const auto *Br = cast<BranchInst>(Val: I);
1391 if (Br->isUnconditional()) {
1392 MachineBasicBlock *MSucc = FuncInfo.getMBB(BB: Br->getSuccessor(i: 0));
1393 fastEmitBranch(MSucc, DbgLoc: Br->getDebugLoc());
1394 return true;
1395 }
1396
1397 MachineBasicBlock *TBB = FuncInfo.getMBB(BB: Br->getSuccessor(i: 0));
1398 MachineBasicBlock *FBB = FuncInfo.getMBB(BB: Br->getSuccessor(i: 1));
1399
1400 bool Not;
1401 unsigned CondReg = getRegForI1Value(V: Br->getCondition(), BB: Br->getParent(), Not);
1402 if (CondReg == 0)
1403 return false;
1404
1405 unsigned Opc = WebAssembly::BR_IF;
1406 if (Not)
1407 Opc = WebAssembly::BR_UNLESS;
1408
1409 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: Opc))
1410 .addMBB(MBB: TBB)
1411 .addReg(RegNo: CondReg);
1412
1413 finishCondBranch(BranchBB: Br->getParent(), TrueMBB: TBB, FalseMBB: FBB);
1414 return true;
1415}
1416
1417bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1418 if (!FuncInfo.CanLowerReturn)
1419 return false;
1420
1421 const auto *Ret = cast<ReturnInst>(Val: I);
1422
1423 if (Ret->getNumOperands() == 0) {
1424 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
1425 MCID: TII.get(Opcode: WebAssembly::RETURN));
1426 return true;
1427 }
1428
1429 // TODO: support multiple return in FastISel
1430 if (Ret->getNumOperands() > 1)
1431 return false;
1432
1433 Value *RV = Ret->getOperand(i_nocapture: 0);
1434 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1435 return false;
1436
1437 switch (getSimpleType(Ty: RV->getType())) {
1438 case MVT::i1:
1439 case MVT::i8:
1440 case MVT::i16:
1441 case MVT::i32:
1442 case MVT::i64:
1443 case MVT::f32:
1444 case MVT::f64:
1445 case MVT::v16i8:
1446 case MVT::v8i16:
1447 case MVT::v4i32:
1448 case MVT::v2i64:
1449 case MVT::v4f32:
1450 case MVT::v2f64:
1451 case MVT::funcref:
1452 case MVT::externref:
1453 case MVT::exnref:
1454 break;
1455 default:
1456 return false;
1457 }
1458
1459 unsigned Reg;
1460 if (FuncInfo.Fn->getAttributes().hasRetAttr(Kind: Attribute::SExt))
1461 Reg = getRegForSignedValue(V: RV);
1462 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Kind: Attribute::ZExt))
1463 Reg = getRegForUnsignedValue(V: RV);
1464 else
1465 Reg = getRegForValue(V: RV);
1466
1467 if (Reg == 0)
1468 return false;
1469
1470 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD, MCID: TII.get(Opcode: WebAssembly::RETURN))
1471 .addReg(RegNo: Reg);
1472 return true;
1473}
1474
1475bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1476 BuildMI(BB&: *FuncInfo.MBB, I: FuncInfo.InsertPt, MIMD,
1477 MCID: TII.get(Opcode: WebAssembly::UNREACHABLE));
1478 return true;
1479}
1480
1481bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1482 switch (I->getOpcode()) {
1483 case Instruction::Call:
1484 if (selectCall(I))
1485 return true;
1486 break;
1487 case Instruction::Select:
1488 return selectSelect(I);
1489 case Instruction::Trunc:
1490 return selectTrunc(I);
1491 case Instruction::ZExt:
1492 return selectZExt(I);
1493 case Instruction::SExt:
1494 return selectSExt(I);
1495 case Instruction::ICmp:
1496 return selectICmp(I);
1497 case Instruction::FCmp:
1498 return selectFCmp(I);
1499 case Instruction::BitCast:
1500 return selectBitCast(I);
1501 case Instruction::Load:
1502 return selectLoad(I);
1503 case Instruction::Store:
1504 return selectStore(I);
1505 case Instruction::Br:
1506 return selectBr(I);
1507 case Instruction::Ret:
1508 return selectRet(I);
1509 case Instruction::Unreachable:
1510 return selectUnreachable(I);
1511 default:
1512 break;
1513 }
1514
1515 // Fall back to target-independent instruction selection.
1516 return selectOperator(I, Opcode: I->getOpcode());
1517}
1518
1519FastISel *
1520WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1521 const TargetLibraryInfo *LibInfo,
1522 const LibcallLoweringInfo *LibcallLowering) {
1523 return new WebAssemblyFastISel(FuncInfo, LibInfo, LibcallLowering);
1524}
1525