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

source code of llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp