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