LLVM 23.0.0git
WebAssemblyFastISel.cpp
Go to the documentation of this file.
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
32#include "llvm/IR/DataLayout.h"
34#include "llvm/IR/Function.h"
38#include "llvm/IR/IntrinsicsWebAssembly.h"
39#include "llvm/IR/Operator.h"
40
41using namespace llvm;
42
43#define DEBUG_TYPE "wasm-fastisel"
44
45namespace {
46
47class WebAssemblyFastISel final : public FastISel {
48 // All possible address modes.
49 class Address {
50 public:
51 enum BaseKind { RegBase, FrameIndexBase };
52
53 private:
54 BaseKind Kind = RegBase;
55 union {
56 unsigned Reg;
57 int FI;
58 } Base;
59
60 // Whether the base has been determined yet
61 bool IsBaseSet = false;
62
63 int64_t Offset = 0;
64
65 const GlobalValue *GV = nullptr;
66
67 public:
68 // Innocuous defaults for our address.
69 Address() { Base.Reg = 0; }
70 void setKind(BaseKind K) {
71 assert(!isSet() && "Can't change kind with non-zero base");
72 Kind = K;
73 }
74 BaseKind getKind() const { return Kind; }
75 bool isRegBase() const { return Kind == RegBase; }
76 bool isFIBase() const { return Kind == FrameIndexBase; }
77 void setReg(unsigned Reg) {
78 assert(isRegBase() && "Invalid base register access!");
79 assert(!IsBaseSet && "Base cannot be reset");
80 Base.Reg = Reg;
81 IsBaseSet = true;
82 }
83 unsigned getReg() const {
84 assert(isRegBase() && "Invalid base register access!");
85 return Base.Reg;
86 }
87 void setFI(unsigned FI) {
88 assert(isFIBase() && "Invalid base frame index access!");
89 assert(!IsBaseSet && "Base cannot be reset");
90 Base.FI = FI;
91 IsBaseSet = true;
92 }
93 unsigned getFI() const {
94 assert(isFIBase() && "Invalid base frame index access!");
95 return Base.FI;
96 }
97
98 void setOffset(int64_t NewOffset) {
99 assert(NewOffset >= 0 && "Offsets must be non-negative");
100 Offset = NewOffset;
101 }
102 int64_t getOffset() const { return Offset; }
103 void setGlobalValue(const GlobalValue *G) { GV = G; }
104 const GlobalValue *getGlobalValue() const { return GV; }
105 bool isSet() const { return IsBaseSet; }
106 };
107
108 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
109 /// right decision when generating code for different targets.
110 const WebAssemblySubtarget *Subtarget;
111 LLVMContext *Context;
112
113private:
114 // Utility helper routines
115 MVT::SimpleValueType getSimpleType(Type *Ty) {
116 EVT VT = TLI.getValueType(DL, Ty, /*AllowUnknown=*/true);
117 return VT.isSimple() ? VT.getSimpleVT().SimpleTy
119 }
121 switch (VT) {
122 case MVT::i1:
123 case MVT::i8:
124 case MVT::i16:
125 return MVT::i32;
126 case MVT::i32:
127 case MVT::i64:
128 case MVT::f32:
129 case MVT::f64:
130 return VT;
131 case MVT::funcref:
132 case MVT::externref:
133 if (Subtarget->hasReferenceTypes())
134 return VT;
135 break;
136 case MVT::exnref:
137 if (Subtarget->hasReferenceTypes() && Subtarget->hasExceptionHandling())
138 return VT;
139 break;
140 case MVT::f16:
141 return MVT::f32;
142 case MVT::v16i8:
143 case MVT::v8i16:
144 case MVT::v4i32:
145 case MVT::v4f32:
146 case MVT::v2i64:
147 case MVT::v2f64:
148 if (Subtarget->hasSIMD128())
149 return VT;
150 break;
151 default:
152 break;
153 }
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 bool emitLoad(Register ResultReg, unsigned Opc, const LoadInst *LoadInst);
161 unsigned maskI1Value(unsigned Reg, const Value *V);
162 unsigned getRegForI1Value(const Value *V, const BasicBlock *BB, bool &Not);
163 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
165 unsigned signExtendToI32(unsigned Reg, const Value *V,
167 unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
169 unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
171 unsigned getRegForUnsignedValue(const Value *V);
172 unsigned getRegForSignedValue(const Value *V);
173 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
174 unsigned notValue(unsigned Reg);
175 unsigned copyValue(unsigned Reg);
176
177 // Backend specific FastISel code.
178 Register fastMaterializeAlloca(const AllocaInst *AI) override;
179 Register fastMaterializeConstant(const Constant *C) override;
180 bool fastLowerArguments() override;
181
182 // Selection routines.
183 bool selectCall(const Instruction *I);
184 bool selectSelect(const Instruction *I);
185 bool selectTrunc(const Instruction *I);
186 bool selectZExt(const Instruction *I);
187 bool selectSExt(const Instruction *I);
188 bool selectICmp(const Instruction *I);
189 bool selectFCmp(const Instruction *I);
190 bool selectBitCast(const Instruction *I);
191 bool selectLoad(const Instruction *I);
192 bool selectStore(const Instruction *I);
193 bool selectCondBr(const Instruction *I);
194 bool selectRet(const Instruction *I);
195 bool selectUnreachable(const Instruction *I);
196
197public:
198 // Backend specific FastISel code.
199 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
200 const TargetLibraryInfo *LibInfo,
201 const LibcallLoweringInfo *LibcallLowering)
202 : FastISel(FuncInfo, LibInfo, LibcallLowering,
203 /*SkipTargetIndependentISel=*/true) {
204 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
205 Context = &FuncInfo.Fn->getContext();
206 }
207
208 bool fastSelectInstruction(const Instruction *I) override;
209 bool tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
210 const LoadInst *LI) override;
211
212#include "WebAssemblyGenFastISel.inc"
213};
214
215} // end anonymous namespace
216
217bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
218 const User *U = nullptr;
219 unsigned Opcode = Instruction::UserOp1;
220 if (const auto *I = dyn_cast<Instruction>(Obj)) {
221 // Don't walk into other basic blocks unless the object is an alloca from
222 // another block, otherwise it may not have a virtual register assigned.
223 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
224 FuncInfo.getMBB(I->getParent()) == FuncInfo.MBB) {
225 Opcode = I->getOpcode();
226 U = I;
227 }
228 } else if (const auto *C = dyn_cast<ConstantExpr>(Obj)) {
229 Opcode = C->getOpcode();
230 U = C;
231 }
232
233 if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
234 if (Ty->getAddressSpace() > 255)
235 // Fast instruction selection doesn't support the special
236 // address spaces.
237 return false;
238
239 if (const auto *GV = dyn_cast<GlobalValue>(Obj)) {
240 if (TLI.isPositionIndependent())
241 return false;
242 if (Addr.getGlobalValue())
243 return false;
244 if (GV->isThreadLocal())
245 return false;
246 Addr.setGlobalValue(GV);
247 return true;
248 }
249
250 switch (Opcode) {
251 default:
252 break;
253 case Instruction::BitCast: {
254 // Look through bitcasts.
255 return computeAddress(U->getOperand(0), Addr);
256 }
257 case Instruction::IntToPtr: {
258 // Look past no-op inttoptrs.
259 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
260 TLI.getPointerTy(DL))
261 return computeAddress(U->getOperand(0), Addr);
262 break;
263 }
264 case Instruction::PtrToInt: {
265 // Look past no-op ptrtoints.
266 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
267 return computeAddress(U->getOperand(0), Addr);
268 break;
269 }
270 case Instruction::GetElementPtr: {
271 Address SavedAddr = Addr;
272 uint64_t TmpOffset = Addr.getOffset();
273 // Non-inbounds geps can wrap; wasm's offsets can't.
274 if (!cast<GEPOperator>(U)->isInBounds())
275 goto unsupported_gep;
276 // Iterate through the GEP folding the constants into offsets where
277 // we can.
279 GTI != E; ++GTI) {
280 const Value *Op = GTI.getOperand();
281 if (StructType *STy = GTI.getStructTypeOrNull()) {
282 const StructLayout *SL = DL.getStructLayout(STy);
283 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
284 TmpOffset += SL->getElementOffset(Idx);
285 } else {
286 uint64_t S = GTI.getSequentialElementStride(DL);
287 for (;;) {
288 if (const auto *CI = dyn_cast<ConstantInt>(Op)) {
289 // Constant-offset addressing.
290 TmpOffset += CI->getSExtValue() * S;
291 break;
292 }
293 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
294 // An unscaled add of a register. Set it as the new base.
295 Register Reg = getRegForValue(Op);
296 if (Reg == 0)
297 return false;
298 Addr.setReg(Reg);
299 break;
300 }
301 if (canFoldAddIntoGEP(U, Op)) {
302 // A compatible add with a constant operand. Fold the constant.
303 auto *CI = cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
304 TmpOffset += CI->getSExtValue() * S;
305 // Iterate on the other operand.
306 Op = cast<AddOperator>(Op)->getOperand(0);
307 continue;
308 }
309 // Unsupported
310 goto unsupported_gep;
311 }
312 }
313 }
314 // Don't fold in negative offsets.
315 if (int64_t(TmpOffset) >= 0) {
316 // Try to grab the base operand now.
317 Addr.setOffset(TmpOffset);
318 if (computeAddress(U->getOperand(0), Addr))
319 return true;
320 }
321 // We failed, restore everything and try the other options.
322 Addr = SavedAddr;
323 unsupported_gep:
324 break;
325 }
326 case Instruction::Alloca: {
327 const auto *AI = cast<AllocaInst>(Obj);
328 auto SI = FuncInfo.StaticAllocaMap.find(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 // We should not fold operands into an offset when 'nuw' (no unsigned wrap)
341 // is not present, because the address calculation does not wrap.
342 if (auto *OFBinOp = dyn_cast<OverflowingBinaryOperator>(U))
343 if (!OFBinOp->hasNoUnsignedWrap())
344 break;
345
346 // Adds of constants are common and easy enough.
347 const Value *LHS = U->getOperand(0);
348 const Value *RHS = U->getOperand(1);
349
351 std::swap(LHS, RHS);
352
353 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
354 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
355 if (int64_t(TmpOffset) >= 0) {
356 Addr.setOffset(TmpOffset);
357 return computeAddress(LHS, Addr);
358 }
359 }
360
361 Address Backup = Addr;
362 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
363 return true;
364 Addr = Backup;
365
366 break;
367 }
368 case Instruction::Sub: {
369 // We should not fold operands into an offset when 'nuw' (no unsigned wrap)
370 // is not present, because the address calculation does not wrap.
371 if (auto *OFBinOp = dyn_cast<OverflowingBinaryOperator>(U))
372 if (!OFBinOp->hasNoUnsignedWrap())
373 break;
374
375 // Subs of constants are common and easy enough.
376 const Value *LHS = U->getOperand(0);
377 const Value *RHS = U->getOperand(1);
378
379 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
380 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
381 if (TmpOffset >= 0) {
382 Addr.setOffset(TmpOffset);
383 return computeAddress(LHS, Addr);
384 }
385 }
386 break;
387 }
388 }
389 if (Addr.isSet()) {
390 return false;
391 }
392 Register Reg = getRegForValue(Obj);
393 if (Reg == 0)
394 return false;
395 Addr.setReg(Reg);
396 return Addr.getReg() != 0;
397}
398
399void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
400 if (Addr.isRegBase()) {
401 unsigned Reg = Addr.getReg();
402 if (Reg == 0) {
403 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
404 : &WebAssembly::I32RegClass);
405 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
406 : WebAssembly::CONST_I32;
407 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), Reg)
408 .addImm(0);
409 Addr.setReg(Reg);
410 }
411 }
412}
413
414void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
415 const MachineInstrBuilder &MIB,
416 MachineMemOperand *MMO) {
417 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
418 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
419 MIB.addImm(0);
420
421 if (const GlobalValue *GV = Addr.getGlobalValue())
422 MIB.addGlobalAddress(GV, Addr.getOffset());
423 else
424 MIB.addImm(Addr.getOffset());
425
426 if (Addr.isRegBase())
427 MIB.addReg(Addr.getReg());
428 else
429 MIB.addFrameIndex(Addr.getFI());
430
431 MIB.addMemOperand(MMO);
432}
433
434bool WebAssemblyFastISel::emitLoad(Register ResultReg, unsigned Opc,
435 const LoadInst *Load) {
436 Address Addr;
437 if (!computeAddress(Load->getPointerOperand(), Addr))
438 return false;
439
440 materializeLoadStoreOperands(Addr);
441 auto MIB =
442 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg);
443 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
444
445 return true;
446}
447
448unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
449 return zeroExtendToI32(Reg, V, MVT::i1);
450}
451
452unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V,
453 const BasicBlock *BB,
454 bool &Not) {
455 if (const auto *ICmp = dyn_cast<ICmpInst>(V))
456 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
457 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32) &&
458 ICmp->getParent() == BB) {
459 Not = ICmp->isTrueWhenEqual();
460 return getRegForValue(ICmp->getOperand(0));
461 }
462
463 Not = false;
464 Register Reg = getRegForValue(V);
465 if (Reg == 0)
466 return 0;
467 return maskI1Value(Reg, V);
468}
469
470unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
472 if (Reg == 0)
473 return 0;
474
475 switch (From) {
476 case MVT::i1:
477 // If the value is naturally an i1, we don't need to mask it. We only know
478 // if a value is naturally an i1 if it is definitely lowered by FastISel,
479 // not a DAG ISel fallback.
480 if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
481 return copyValue(Reg);
482 break;
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(&WebAssembly::I32RegClass);
493 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
494 TII.get(WebAssembly::CONST_I32), Imm)
495 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
496
497 Register Result = createResultReg(&WebAssembly::I32RegClass);
498 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::AND_I32),
499 Result)
500 .addReg(Reg)
501 .addReg(Imm);
502
503 return Result;
504}
505
506unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
508 if (Reg == 0)
509 return 0;
510
511 switch (From) {
512 case MVT::i1:
513 case MVT::i8:
514 case MVT::i16:
515 break;
516 case MVT::i32:
517 return copyValue(Reg);
518 default:
519 return 0;
520 }
521
522 if (Subtarget->hasSignExt()) {
523 if (From == MVT::i8 || From == MVT::i16) {
524 Register Result = createResultReg(&WebAssembly::I32RegClass);
525 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
526 TII.get(From == MVT::i16 ? WebAssembly::I32_EXTEND16_S_I32
527 : WebAssembly::I32_EXTEND8_S_I32),
528 Result)
529 .addReg(Reg);
530 return Result;
531 }
532 }
533
534 Register Imm = createResultReg(&WebAssembly::I32RegClass);
535 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
536 TII.get(WebAssembly::CONST_I32), Imm)
537 .addImm(32 - MVT(From).getSizeInBits());
538
539 Register Left = createResultReg(&WebAssembly::I32RegClass);
540 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::SHL_I32),
541 Left)
542 .addReg(Reg)
543 .addReg(Imm);
544
545 Register Right = createResultReg(&WebAssembly::I32RegClass);
546 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
547 TII.get(WebAssembly::SHR_S_I32), Right)
548 .addReg(Left)
549 .addReg(Imm);
550
551 return Right;
552}
553
554unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
557 if (To == MVT::i64) {
558 if (From == MVT::i64)
559 return copyValue(Reg);
560
561 Reg = zeroExtendToI32(Reg, V, From);
562
563 Register Result = createResultReg(&WebAssembly::I64RegClass);
564 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
565 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
566 .addReg(Reg);
567 return Result;
568 }
569
570 if (To == MVT::i32)
571 return zeroExtendToI32(Reg, V, From);
572
573 return 0;
574}
575
576unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
579 if (To == MVT::i64) {
580 if (From == MVT::i64)
581 return copyValue(Reg);
582
583 Register Result = createResultReg(&WebAssembly::I64RegClass);
584
585 if (Subtarget->hasSignExt()) {
586 if (From != MVT::i32) {
587 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
588 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
589 .addReg(Reg);
590
591 Reg = Result;
592 Result = createResultReg(&WebAssembly::I64RegClass);
593 }
594
595 switch (From) {
596 case MVT::i8:
597 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
598 TII.get(WebAssembly::I64_EXTEND8_S_I64), Result)
599 .addReg(Reg);
600 return Result;
601 case MVT::i16:
602 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
603 TII.get(WebAssembly::I64_EXTEND16_S_I64), Result)
604 .addReg(Reg);
605 return Result;
606 case MVT::i32:
607 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
608 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
609 .addReg(Reg);
610 return Result;
611 default:
612 break;
613 }
614 } else {
615 Reg = signExtendToI32(Reg, V, From);
616
617 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
618 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
619 .addReg(Reg);
620 }
621
622 return Result;
623 }
624
625 if (To == MVT::i32)
626 return signExtendToI32(Reg, V, From);
627
628 return 0;
629}
630
631unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
632 MVT::SimpleValueType From = getSimpleType(V->getType());
633 MVT::SimpleValueType To = getLegalType(From);
634 Register VReg = getRegForValue(V);
635 if (VReg == 0)
636 return 0;
637 if (From == To)
638 return VReg;
639 return zeroExtend(VReg, V, From, To);
640}
641
642unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
643 MVT::SimpleValueType From = getSimpleType(V->getType());
644 MVT::SimpleValueType To = getLegalType(From);
645 Register VReg = getRegForValue(V);
646 if (VReg == 0)
647 return 0;
648 if (From == To)
649 return VReg;
650 return signExtend(VReg, V, From, To);
651}
652
653unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
654 bool IsSigned) {
655 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
656}
657
658unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
659 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
660
661 Register NotReg = createResultReg(&WebAssembly::I32RegClass);
662 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::EQZ_I32),
663 NotReg)
664 .addReg(Reg);
665 return NotReg;
666}
667
668unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
669 Register ResultReg = createResultReg(MRI.getRegClass(Reg));
670 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::COPY),
671 ResultReg)
672 .addReg(Reg);
673 return ResultReg;
674}
675
676Register WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
677 auto SI = FuncInfo.StaticAllocaMap.find(AI);
678
679 if (SI != FuncInfo.StaticAllocaMap.end()) {
680 Register ResultReg =
681 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
682 : &WebAssembly::I32RegClass);
683 unsigned Opc =
684 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
685 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
686 .addFrameIndex(SI->second);
687 return ResultReg;
688 }
689
690 return Register();
691}
692
693Register WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
694 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
695 if (TLI.isPositionIndependent())
696 return Register();
697 if (GV->isThreadLocal())
698 return Register();
699 Register ResultReg =
700 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
701 : &WebAssembly::I32RegClass);
702 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
703 : WebAssembly::CONST_I32;
704 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
705 .addGlobalAddress(GV);
706 return ResultReg;
707 }
708
709 // Let target-independent code handle it.
710 return Register();
711}
712
713bool WebAssemblyFastISel::fastLowerArguments() {
714 if (!FuncInfo.CanLowerReturn)
715 return false;
716
717 const Function *F = FuncInfo.Fn;
718 if (F->isVarArg())
719 return false;
720
721 if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
722 return false;
723
724 unsigned I = 0;
725 for (auto const &Arg : F->args()) {
726 const AttributeList &Attrs = F->getAttributes();
727 if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
728 Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
729 Attrs.hasParamAttr(I, Attribute::SwiftError) ||
730 Attrs.hasParamAttr(I, Attribute::InAlloca) ||
731 Attrs.hasParamAttr(I, Attribute::Nest))
732 return false;
733
734 Type *ArgTy = Arg.getType();
735 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
736 return false;
737 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
738 return false;
739
740 unsigned Opc;
741 const TargetRegisterClass *RC;
742 switch (getSimpleType(ArgTy)) {
743 case MVT::i1:
744 case MVT::i8:
745 case MVT::i16:
746 case MVT::i32:
747 Opc = WebAssembly::ARGUMENT_i32;
748 RC = &WebAssembly::I32RegClass;
749 break;
750 case MVT::i64:
751 Opc = WebAssembly::ARGUMENT_i64;
752 RC = &WebAssembly::I64RegClass;
753 break;
754 case MVT::f32:
755 Opc = WebAssembly::ARGUMENT_f32;
756 RC = &WebAssembly::F32RegClass;
757 break;
758 case MVT::f64:
759 Opc = WebAssembly::ARGUMENT_f64;
760 RC = &WebAssembly::F64RegClass;
761 break;
762 case MVT::v16i8:
763 Opc = WebAssembly::ARGUMENT_v16i8;
764 RC = &WebAssembly::V128RegClass;
765 break;
766 case MVT::v8i16:
767 Opc = WebAssembly::ARGUMENT_v8i16;
768 RC = &WebAssembly::V128RegClass;
769 break;
770 case MVT::v4i32:
771 Opc = WebAssembly::ARGUMENT_v4i32;
772 RC = &WebAssembly::V128RegClass;
773 break;
774 case MVT::v2i64:
775 Opc = WebAssembly::ARGUMENT_v2i64;
776 RC = &WebAssembly::V128RegClass;
777 break;
778 case MVT::v4f32:
779 Opc = WebAssembly::ARGUMENT_v4f32;
780 RC = &WebAssembly::V128RegClass;
781 break;
782 case MVT::v2f64:
783 Opc = WebAssembly::ARGUMENT_v2f64;
784 RC = &WebAssembly::V128RegClass;
785 break;
786 case MVT::funcref:
787 Opc = WebAssembly::ARGUMENT_funcref;
788 RC = &WebAssembly::FUNCREFRegClass;
789 break;
790 case MVT::externref:
791 Opc = WebAssembly::ARGUMENT_externref;
792 RC = &WebAssembly::EXTERNREFRegClass;
793 break;
794 case MVT::exnref:
795 Opc = WebAssembly::ARGUMENT_exnref;
796 RC = &WebAssembly::EXNREFRegClass;
797 break;
798 default:
799 return false;
800 }
801 Register ResultReg = createResultReg(RC);
802 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
803 .addImm(I);
804 updateValueMap(&Arg, ResultReg);
805
806 ++I;
807 }
808
809 MRI.addLiveIn(WebAssembly::ARGUMENTS);
810
811 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
812 for (auto const &Arg : F->args()) {
813 MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
814 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
815 MFI->clearParamsAndResults();
816 return false;
817 }
818 MFI->addParam(ArgTy);
819 }
820
821 if (!F->getReturnType()->isVoidTy()) {
823 getLegalType(getSimpleType(F->getReturnType()));
824 if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
825 MFI->clearParamsAndResults();
826 return false;
827 }
828 MFI->addResult(RetTy);
829 }
830
831 return true;
832}
833
834bool WebAssemblyFastISel::selectCall(const Instruction *I) {
835 const auto *Call = cast<CallInst>(I);
836
837 // TODO: Support tail calls in FastISel
838 if (Call->isMustTailCall() || Call->isInlineAsm() ||
840 return false;
841
843 if (Func && Func->isIntrinsic())
844 return false;
845
846 if (Call->getCallingConv() == CallingConv::Swift)
847 return false;
848
849 bool IsDirect = Func != nullptr;
850 if (!IsDirect && isa<ConstantExpr>(Call->getCalledOperand()))
851 return false;
852
853 FunctionType *FuncTy = Call->getFunctionType();
854 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
855 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
856 unsigned ResultReg;
857 if (!IsVoid) {
858 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
859 return false;
860
861 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
862 switch (RetTy) {
863 case MVT::i1:
864 case MVT::i8:
865 case MVT::i16:
866 case MVT::i32:
867 ResultReg = createResultReg(&WebAssembly::I32RegClass);
868 break;
869 case MVT::i64:
870 ResultReg = createResultReg(&WebAssembly::I64RegClass);
871 break;
872 case MVT::f32:
873 ResultReg = createResultReg(&WebAssembly::F32RegClass);
874 break;
875 case MVT::f64:
876 ResultReg = createResultReg(&WebAssembly::F64RegClass);
877 break;
878 case MVT::v16i8:
879 ResultReg = createResultReg(&WebAssembly::V128RegClass);
880 break;
881 case MVT::v8i16:
882 ResultReg = createResultReg(&WebAssembly::V128RegClass);
883 break;
884 case MVT::v4i32:
885 ResultReg = createResultReg(&WebAssembly::V128RegClass);
886 break;
887 case MVT::v2i64:
888 ResultReg = createResultReg(&WebAssembly::V128RegClass);
889 break;
890 case MVT::v4f32:
891 ResultReg = createResultReg(&WebAssembly::V128RegClass);
892 break;
893 case MVT::v2f64:
894 ResultReg = createResultReg(&WebAssembly::V128RegClass);
895 break;
896 case MVT::funcref:
897 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
898 break;
899 case MVT::externref:
900 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
901 break;
902 case MVT::exnref:
903 ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
904 break;
905 default:
906 return false;
907 }
908 }
909
910 SmallVector<unsigned, 8> Args;
911 for (unsigned I = 0, E = Call->arg_size(); I < E; ++I) {
913 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
915 return false;
916
917 const AttributeList &Attrs = Call->getAttributes();
918 if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
919 Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
920 Attrs.hasParamAttr(I, Attribute::SwiftError) ||
921 Attrs.hasParamAttr(I, Attribute::InAlloca) ||
922 Attrs.hasParamAttr(I, Attribute::Nest))
923 return false;
924
925 unsigned Reg;
926
927 if (Call->paramHasAttr(I, Attribute::SExt))
928 Reg = getRegForSignedValue(V);
929 else if (Call->paramHasAttr(I, Attribute::ZExt))
930 Reg = getRegForUnsignedValue(V);
931 else
932 Reg = getRegForValue(V);
933
934 if (Reg == 0)
935 return false;
936
937 Args.push_back(Reg);
938 }
939
940 unsigned CalleeReg = 0;
941 // A call through a funcref is expressed as a call through the pointer
942 // produced by llvm.wasm.funcref.to_ptr. Recover the funcref operand, place it
943 // into __funcref_call_table, and call it.
944 //
945 // TODO: Use call_ref if wasm-gc feature is available, would lead to simpler
946 // code here.
947 const Value *FuncrefArg = nullptr;
948 if (const auto *Conv = dyn_cast<CallInst>(Call->getCalledOperand()))
949 if (Conv->getIntrinsicID() == Intrinsic::wasm_funcref_to_ptr)
950 FuncrefArg = Conv->getArgOperand(0);
951
952 const bool IsFuncrefCall = FuncrefArg != nullptr;
953 MCSymbolWasm *Table = nullptr;
954
955 if (!IsDirect) {
956 if (!IsFuncrefCall) {
957 // Table is ___indirect_function_table
958 Table = WebAssembly::getOrCreateFunctionTableSymbol(MF->getContext(),
959 Subtarget);
960 CalleeReg = getRegForValue(Call->getCalledOperand());
961 if (!CalleeReg)
962 return false;
963 } else {
964 // Table is __funcref_call_table
965 Table = WebAssembly::getOrCreateFuncrefCallTableSymbol(MF->getContext(),
966 Subtarget);
967 CalleeReg = getRegForValue(FuncrefArg);
968 // Put the funcref in slot 0 of __funcref_call_table
969 unsigned ZeroReg = createResultReg(&WebAssembly::I32RegClass);
970 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
971 TII.get(WebAssembly::CONST_I32), ZeroReg)
972 .addImm(0);
973 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
974 TII.get(WebAssembly::TABLE_SET_FUNCREF))
975 .addSym(Table)
976 .addReg(ZeroReg)
977 .addReg(CalleeReg);
978 // Set CalleeReg to an immediate 0
979 CalleeReg = createResultReg(&WebAssembly::I32RegClass);
980 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
981 TII.get(WebAssembly::CONST_I32), CalleeReg)
982 .addImm(0);
983 }
984 }
985
986 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
987
988 if (!IsVoid)
989 MIB.addReg(ResultReg, RegState::Define);
990
991 if (IsDirect) {
992 MIB.addGlobalAddress(Func);
993 } else {
994 // Placeholder for the type index.
995 MIB.addImm(0);
996 if (Subtarget->hasCallIndirectOverlong()) {
997 MIB.addSym(Table);
998 } else {
999 // Otherwise for the MVP there is at most one table whose number is 0, but
1000 // we can't write a table symbol or issue relocations. Instead we just
1001 // ensure the table is live.
1002 Table->setNoStrip();
1003 MIB.addImm(0);
1004 }
1005 }
1006
1007 for (unsigned ArgReg : Args)
1008 MIB.addReg(ArgReg);
1009
1010 if (!IsDirect)
1011 MIB.addReg(CalleeReg);
1012
1013 if (IsFuncrefCall) {
1014 // Clear slot 0 of the funcref call table after the call.
1015 unsigned ZeroReg = createResultReg(&WebAssembly::I32RegClass);
1016 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1017 TII.get(WebAssembly::CONST_I32), ZeroReg)
1018 .addImm(0);
1019 unsigned NullReg = createResultReg(&WebAssembly::FUNCREFRegClass);
1020 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1021 TII.get(WebAssembly::REF_NULL_FUNCREF), NullReg);
1022 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1023 TII.get(WebAssembly::TABLE_SET_FUNCREF))
1024 .addSym(Table)
1025 .addReg(ZeroReg)
1026 .addReg(NullReg);
1027 }
1028
1029 if (!IsVoid)
1030 updateValueMap(Call, ResultReg);
1031
1033 return true;
1034}
1035
1036bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
1037 const auto *Select = cast<SelectInst>(I);
1038
1039 bool Not;
1040 unsigned CondReg =
1041 getRegForI1Value(Select->getCondition(), I->getParent(), Not);
1042 if (CondReg == 0)
1043 return false;
1044
1045 Register TrueReg = getRegForValue(Select->getTrueValue());
1046 if (TrueReg == 0)
1047 return false;
1048
1049 Register FalseReg = getRegForValue(Select->getFalseValue());
1050 if (FalseReg == 0)
1051 return false;
1052
1053 if (Not)
1054 std::swap(TrueReg, FalseReg);
1055
1056 unsigned Opc;
1057 const TargetRegisterClass *RC;
1058 switch (getSimpleType(Select->getType())) {
1059 case MVT::i1:
1060 case MVT::i8:
1061 case MVT::i16:
1062 case MVT::i32:
1063 Opc = WebAssembly::SELECT_I32;
1064 RC = &WebAssembly::I32RegClass;
1065 break;
1066 case MVT::i64:
1067 Opc = WebAssembly::SELECT_I64;
1068 RC = &WebAssembly::I64RegClass;
1069 break;
1070 case MVT::f32:
1071 Opc = WebAssembly::SELECT_F32;
1072 RC = &WebAssembly::F32RegClass;
1073 break;
1074 case MVT::f64:
1075 Opc = WebAssembly::SELECT_F64;
1076 RC = &WebAssembly::F64RegClass;
1077 break;
1078 case MVT::funcref:
1079 Opc = WebAssembly::SELECT_FUNCREF;
1080 RC = &WebAssembly::FUNCREFRegClass;
1081 break;
1082 case MVT::externref:
1083 Opc = WebAssembly::SELECT_EXTERNREF;
1084 RC = &WebAssembly::EXTERNREFRegClass;
1085 break;
1086 case MVT::exnref:
1087 Opc = WebAssembly::SELECT_EXNREF;
1088 RC = &WebAssembly::EXNREFRegClass;
1089 break;
1090 default:
1091 return false;
1092 }
1093
1094 Register ResultReg = createResultReg(RC);
1095 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1096 .addReg(TrueReg)
1097 .addReg(FalseReg)
1098 .addReg(CondReg);
1099
1100 updateValueMap(Select, ResultReg);
1101 return true;
1102}
1103
1104bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
1105 const auto *Trunc = cast<TruncInst>(I);
1106
1107 const Value *Op = Trunc->getOperand(0);
1108 MVT::SimpleValueType From = getSimpleType(Op->getType());
1109 MVT::SimpleValueType To = getLegalType(getSimpleType(Trunc->getType()));
1110 Register In = getRegForValue(Op);
1111 if (In == 0)
1112 return false;
1113
1114 auto Truncate = [&](Register Reg) -> unsigned {
1115 if (From == MVT::i64) {
1116 if (To == MVT::i64)
1117 return copyValue(Reg);
1118
1119 if (To == MVT::i1 || To == MVT::i8 || To == MVT::i16 || To == MVT::i32) {
1120 Register Result = createResultReg(&WebAssembly::I32RegClass);
1121 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1122 TII.get(WebAssembly::I32_WRAP_I64), Result)
1123 .addReg(Reg);
1124 return Result;
1125 }
1126 }
1127
1128 if (From == MVT::i32)
1129 return copyValue(Reg);
1130
1131 return 0;
1132 };
1133
1134 unsigned Reg = Truncate(In);
1135 if (Reg == 0)
1136 return false;
1137
1138 updateValueMap(Trunc, Reg);
1139 return true;
1140}
1141
1142bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
1143 const auto *ZExt = cast<ZExtInst>(I);
1144
1145 const Value *Op = ZExt->getOperand(0);
1146 MVT::SimpleValueType From = getSimpleType(Op->getType());
1147 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
1148 Register In = getRegForValue(Op);
1149 if (In == 0)
1150 return false;
1151 unsigned Reg = zeroExtend(In, Op, From, To);
1152 if (Reg == 0)
1153 return false;
1154
1155 updateValueMap(ZExt, Reg);
1156 return true;
1157}
1158
1159bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
1160 const auto *SExt = cast<SExtInst>(I);
1161
1162 const Value *Op = SExt->getOperand(0);
1163 MVT::SimpleValueType From = getSimpleType(Op->getType());
1164 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
1165 Register In = getRegForValue(Op);
1166 if (In == 0)
1167 return false;
1168 unsigned Reg = signExtend(In, Op, From, To);
1169 if (Reg == 0)
1170 return false;
1171
1172 updateValueMap(SExt, Reg);
1173 return true;
1174}
1175
1176bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
1177 const auto *ICmp = cast<ICmpInst>(I);
1178
1179 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1180 unsigned Opc;
1181 bool IsSigned = false;
1182 switch (ICmp->getPredicate()) {
1183 case ICmpInst::ICMP_EQ:
1184 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1185 break;
1186 case ICmpInst::ICMP_NE:
1187 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1188 break;
1189 case ICmpInst::ICMP_UGT:
1190 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1191 break;
1192 case ICmpInst::ICMP_UGE:
1193 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1194 break;
1195 case ICmpInst::ICMP_ULT:
1196 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1197 break;
1198 case ICmpInst::ICMP_ULE:
1199 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1200 break;
1201 case ICmpInst::ICMP_SGT:
1202 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1203 IsSigned = true;
1204 break;
1205 case ICmpInst::ICMP_SGE:
1206 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1207 IsSigned = true;
1208 break;
1209 case ICmpInst::ICMP_SLT:
1210 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1211 IsSigned = true;
1212 break;
1213 case ICmpInst::ICMP_SLE:
1214 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1215 IsSigned = true;
1216 break;
1217 default:
1218 return false;
1219 }
1220
1221 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1222 if (LHS == 0)
1223 return false;
1224
1225 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1226 if (RHS == 0)
1227 return false;
1228
1229 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1230 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1231 .addReg(LHS)
1232 .addReg(RHS);
1233 updateValueMap(ICmp, ResultReg);
1234 return true;
1235}
1236
1237bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1238 const auto *FCmp = cast<FCmpInst>(I);
1239
1240 Register LHS = getRegForValue(FCmp->getOperand(0));
1241 if (LHS == 0)
1242 return false;
1243
1244 Register RHS = getRegForValue(FCmp->getOperand(1));
1245 if (RHS == 0)
1246 return false;
1247
1248 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1249 unsigned Opc;
1250 bool Not = false;
1251 switch (FCmp->getPredicate()) {
1252 case FCmpInst::FCMP_OEQ:
1253 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1254 break;
1255 case FCmpInst::FCMP_UNE:
1256 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1257 break;
1258 case FCmpInst::FCMP_OGT:
1259 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1260 break;
1261 case FCmpInst::FCMP_OGE:
1262 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1263 break;
1264 case FCmpInst::FCMP_OLT:
1265 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1266 break;
1267 case FCmpInst::FCMP_OLE:
1268 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1269 break;
1270 case FCmpInst::FCMP_UGT:
1271 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1272 Not = true;
1273 break;
1274 case FCmpInst::FCMP_UGE:
1275 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1276 Not = true;
1277 break;
1278 case FCmpInst::FCMP_ULT:
1279 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1280 Not = true;
1281 break;
1282 case FCmpInst::FCMP_ULE:
1283 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1284 Not = true;
1285 break;
1286 default:
1287 return false;
1288 }
1289
1290 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1291 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1292 .addReg(LHS)
1293 .addReg(RHS);
1294
1295 if (Not)
1296 ResultReg = notValue(ResultReg);
1297
1298 updateValueMap(FCmp, ResultReg);
1299 return true;
1300}
1301
1302bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1303 // Target-independent code can handle this, except it doesn't set the dead
1304 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1305 // to satisfy code that expects this of isBitcast() instructions.
1306 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1307 EVT RetVT = TLI.getValueType(DL, I->getType());
1308 if (!VT.isSimple() || !RetVT.isSimple())
1309 return false;
1310
1311 Register In = getRegForValue(I->getOperand(0));
1312 if (In == 0)
1313 return false;
1314
1315 if (VT == RetVT) {
1316 // No-op bitcast.
1317 updateValueMap(I, In);
1318 return true;
1319 }
1320
1321 Register Reg =
1322 fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(), In);
1323 if (!Reg)
1324 return false;
1325 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1326 --Iter;
1327 assert(Iter->isBitcast());
1328 Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI);
1329 updateValueMap(I, Reg);
1330 return true;
1331}
1332
1333static unsigned getSExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64) {
1334 if (I64Result) {
1335 switch (LoadSize) {
1336 default:
1337 return WebAssembly::INSTRUCTION_LIST_END;
1338 case 8:
1339 return A64 ? WebAssembly::LOAD8_S_I64_A64 : WebAssembly::LOAD8_S_I64_A32;
1340 case 16:
1341 return A64 ? WebAssembly::LOAD16_S_I64_A64
1342 : WebAssembly::LOAD16_S_I64_A32;
1343 case 32:
1344 return A64 ? WebAssembly::LOAD32_S_I64_A64
1345 : WebAssembly::LOAD32_S_I64_A32;
1346 }
1347 }
1348
1349 switch (LoadSize) {
1350 default:
1351 return WebAssembly::INSTRUCTION_LIST_END;
1352 case 8:
1353 return A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
1354 case 16:
1355 return A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;
1356 }
1357}
1358
1359static unsigned getZExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64) {
1360 if (I64Result) {
1361 switch (LoadSize) {
1362 default:
1363 return WebAssembly::INSTRUCTION_LIST_END;
1364 case 8:
1365 return A64 ? WebAssembly::LOAD8_U_I64_A64 : WebAssembly::LOAD8_U_I64_A32;
1366 case 16:
1367 return A64 ? WebAssembly::LOAD16_U_I64_A64
1368 : WebAssembly::LOAD16_U_I64_A32;
1369 case 32:
1370 return A64 ? WebAssembly::LOAD32_U_I64_A64
1371 : WebAssembly::LOAD32_U_I64_A32;
1372 }
1373 }
1374
1375 switch (LoadSize) {
1376 default:
1377 return WebAssembly::INSTRUCTION_LIST_END;
1378 case 8:
1379 return A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1380 case 16:
1381 return A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1382 }
1383}
1384
1385static bool isFoldableSExtOpcode(unsigned Opc) {
1386 switch (Opc) {
1387 default:
1388 return false;
1389 case WebAssembly::I32_EXTEND8_S_I32:
1390 case WebAssembly::I32_EXTEND16_S_I32:
1391 case WebAssembly::I64_EXTEND8_S_I64:
1392 case WebAssembly::I64_EXTEND16_S_I64:
1393 case WebAssembly::I64_EXTEND32_S_I64:
1394 case WebAssembly::I64_EXTEND_S_I32:
1395 return true;
1396 }
1397}
1398
1399static bool isI64SExtResult(unsigned Opc) {
1400 switch (Opc) {
1401 default:
1402 llvm_unreachable("unexpected opcode");
1403 case WebAssembly::I32_EXTEND8_S_I32:
1404 case WebAssembly::I32_EXTEND16_S_I32:
1405 return false;
1406 case WebAssembly::I64_EXTEND8_S_I64:
1407 case WebAssembly::I64_EXTEND16_S_I64:
1408 case WebAssembly::I64_EXTEND32_S_I64:
1409 case WebAssembly::I64_EXTEND_S_I32:
1410 return true;
1411 }
1412}
1413
1415 const LoadInst *LI, bool A64) {
1416 unsigned Opc = MI->getOpcode();
1417
1419 unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
1420 return getSExtLoadOpcode(LoadSize, isI64SExtResult(Opc), A64);
1421 }
1422
1423 return WebAssembly::INSTRUCTION_LIST_END;
1424}
1425
1426static unsigned getFoldedI64LoadOpcode(Register DestReg, const LoadInst *LI,
1427 MachineRegisterInfo &MRI, bool A64,
1428 MachineInstr *&OuterUserMI,
1429 unsigned NarrowOpc) {
1430 if (!MRI.hasOneNonDBGUse(DestReg))
1431 return NarrowOpc;
1432
1433 MachineInstr *UserMI = &*MRI.use_instr_nodbg_begin(DestReg);
1434 unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
1435 switch (UserMI->getOpcode()) {
1436 case WebAssembly::I64_EXTEND_U_I32:
1437 OuterUserMI = UserMI;
1438 return getZExtLoadOpcode(LoadSize, /*I64Result=*/true, A64);
1439 case WebAssembly::I64_EXTEND_S_I32:
1440 OuterUserMI = UserMI;
1441 return getSExtLoadOpcode(LoadSize, /*I64Result=*/true, A64);
1442 default:
1443 return NarrowOpc;
1444 }
1445}
1446
1447/// Matches a sign-extension pattern (shl + shr_s) to fold it into a signed
1448/// load. FastISel assumes that 'sext' from i8 or i16 will first be lowered to a
1449/// 32-bit zero-extending load (i32.load8_u / i32.load16_u) followed by 32-bit
1450/// shifts, even when extending to i64. Therefore, this function only matches
1451/// 32-bit shifts (SHL_I32 / SHR_S_I32) and specifically checks if both shift
1452/// amounts are identical, compile-time constants that match the exact extension
1453/// size (32 - LoadBitWidth).
1454static unsigned matchFoldableShift(MachineInstr *MI, const LoadInst *LI,
1455 MachineRegisterInfo &MRI, bool A64,
1456 MachineInstr *&UserMI,
1457 MachineInstr *&OuterUserMI) {
1458 unsigned Opc = MI->getOpcode();
1459 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1460 if (Opc != WebAssembly::SHL_I32)
1461 return NewOpc;
1462
1463 Register DestReg = MI->getOperand(0).getReg();
1464 if (!MRI.hasOneNonDBGUse(DestReg))
1465 return NewOpc;
1466
1467 UserMI = &*MRI.use_instr_nodbg_begin(DestReg);
1468 unsigned UserOpc = UserMI->getOpcode();
1469 if (UserOpc != WebAssembly::SHR_S_I32)
1470 return NewOpc;
1471
1472 Type *LoadTy = LI->getType();
1473 if (!LoadTy->isIntegerTy(8) && !LoadTy->isIntegerTy(16))
1474 return NewOpc;
1475
1476 int64_t ExpectedShiftAmt = 32 - LoadTy->getIntegerBitWidth();
1477 Register ShlAmtReg = MI->getOperand(2).getReg();
1478 Register ShrAmtReg = UserMI->getOperand(2).getReg();
1479 MachineInstr *ShlAmtDef = MRI.getUniqueVRegDef(ShlAmtReg);
1480 MachineInstr *ShrAmtDef = MRI.getUniqueVRegDef(ShrAmtReg);
1481 auto IsExpectedConst = [ExpectedShiftAmt](MachineInstr *MI) {
1482 return MI && MI->getOpcode() == WebAssembly::CONST_I32 &&
1483 MI->getOperand(1).getImm() == ExpectedShiftAmt;
1484 };
1485 if (!IsExpectedConst(ShlAmtDef) || !IsExpectedConst(ShrAmtDef))
1486 return NewOpc;
1487
1488 unsigned LoadSize = LoadTy->getIntegerBitWidth();
1489 unsigned NarrowOpc = getSExtLoadOpcode(LoadSize, /*I64Result=*/false, A64);
1490 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1491 return WebAssembly::INSTRUCTION_LIST_END;
1492
1493 return getFoldedI64LoadOpcode(UserMI->getOperand(0).getReg(), LI, MRI, A64,
1494 OuterUserMI, NarrowOpc);
1495}
1496
1498 const LoadInst *LI,
1500 bool A64,
1501 MachineInstr *&UserMI) {
1502 if (MI->getOpcode() != WebAssembly::I64_EXTEND_U_I32)
1503 return WebAssembly::INSTRUCTION_LIST_END;
1504
1505 unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
1506 Register DestReg = MI->getOperand(0).getReg();
1507 if (!MRI.hasOneNonDBGUse(DestReg))
1508 return WebAssembly::INSTRUCTION_LIST_END;
1509
1510 UserMI = &*MRI.use_instr_nodbg_begin(DestReg);
1511 switch (UserMI->getOpcode()) {
1512 default:
1513 return WebAssembly::INSTRUCTION_LIST_END;
1514 case WebAssembly::I64_EXTEND8_S_I64:
1515 if (LoadSize != 8)
1516 return WebAssembly::INSTRUCTION_LIST_END;
1517 return getSExtLoadOpcode(LoadSize, true, A64);
1518 case WebAssembly::I64_EXTEND16_S_I64:
1519 if (LoadSize != 16)
1520 return WebAssembly::INSTRUCTION_LIST_END;
1521 return getSExtLoadOpcode(LoadSize, true, A64);
1522 }
1523}
1524
1526 MachineRegisterInfo &MRI, bool A64,
1527 MachineInstr *&OuterUserMI) {
1528 if (MI->getOpcode() != WebAssembly::COPY)
1529 return WebAssembly::INSTRUCTION_LIST_END;
1530
1531 unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
1532 if (LoadSize != 32)
1533 return WebAssembly::INSTRUCTION_LIST_END;
1534
1535 Register CopyDst = MI->getOperand(0).getReg();
1536 if (!MRI.hasOneNonDBGUse(CopyDst))
1537 return WebAssembly::INSTRUCTION_LIST_END;
1538
1539 OuterUserMI = &*MRI.use_instr_nodbg_begin(CopyDst);
1540 switch (OuterUserMI->getOpcode()) {
1541 default:
1542 return WebAssembly::INSTRUCTION_LIST_END;
1543 case WebAssembly::I64_EXTEND_U_I32:
1544 return getZExtLoadOpcode(LoadSize, true, A64);
1545 case WebAssembly::I64_EXTEND_S_I32:
1546 return getSExtLoadOpcode(LoadSize, true, A64);
1547 }
1548}
1549
1550static unsigned matchFoldableAnd(MachineInstr *MI, const LoadInst *LI,
1551 MachineRegisterInfo &MRI, bool A64,
1552 MachineInstr *&OuterUserMI) {
1553 if (MI->getOpcode() != WebAssembly::AND_I32 &&
1554 MI->getOpcode() != WebAssembly::AND_I64)
1555 return WebAssembly::INSTRUCTION_LIST_END;
1556
1557 uint64_t Mask = 0;
1558 bool IsConstant = false;
1559 for (unsigned I = 1; I <= 2; ++I) {
1560 Register Reg = MI->getOperand(I).getReg();
1562 if (DefMI && (DefMI->getOpcode() == WebAssembly::CONST_I32 ||
1563 DefMI->getOpcode() == WebAssembly::CONST_I64)) {
1564 Mask = DefMI->getOperand(1).getImm();
1565 IsConstant = true;
1566 break;
1567 }
1568 }
1569
1570 if (!IsConstant)
1571 return WebAssembly::INSTRUCTION_LIST_END;
1572
1573 unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
1574 if (Mask != llvm::maskTrailingOnes<uint64_t>(LoadSize))
1575 return WebAssembly::INSTRUCTION_LIST_END;
1576
1577 if (MI->getOpcode() == WebAssembly::AND_I64)
1578 return getZExtLoadOpcode(LoadSize, /*I64Result=*/true, A64);
1579
1580 unsigned NarrowOpc = getZExtLoadOpcode(LoadSize, /*I64Result=*/false, A64);
1581 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1582 return WebAssembly::INSTRUCTION_LIST_END;
1583
1584 return getFoldedI64LoadOpcode(MI->getOperand(0).getReg(), LI, MRI, A64,
1585 OuterUserMI, NarrowOpc);
1586}
1587
1588bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
1589 const LoadInst *LI) {
1590 bool A64 = Subtarget->hasAddr64();
1591 MachineRegisterInfo &MRI = FuncInfo.MF->getRegInfo();
1592 Register ResultReg;
1593 MachineInstr *UserMI = nullptr;
1594 MachineInstr *OuterUserMI = nullptr;
1595 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1596 if ((NewOpc = matchFoldableSExtFromPromotedI32(MI, LI, MRI, A64, UserMI)) !=
1597 WebAssembly::INSTRUCTION_LIST_END) {
1598 ResultReg = UserMI->getOperand(0).getReg();
1599 } else if ((NewOpc =
1600 matchFoldableCopyToI64Ext(MI, LI, MRI, A64, OuterUserMI)) !=
1601 WebAssembly::INSTRUCTION_LIST_END) {
1602 ResultReg = OuterUserMI->getOperand(0).getReg();
1603 } else if ((NewOpc = matchFoldableAnd(MI, LI, MRI, A64, OuterUserMI)) !=
1604 WebAssembly::INSTRUCTION_LIST_END) {
1605 ResultReg = OuterUserMI ? OuterUserMI->getOperand(0).getReg()
1606 : MI->getOperand(0).getReg();
1607 } else if ((NewOpc = getFoldedLoadOpcode(MI, MRI, LI, A64)) !=
1608 WebAssembly::INSTRUCTION_LIST_END) {
1609 ResultReg = MI->getOperand(0).getReg();
1610 } else if ((NewOpc =
1611 matchFoldableShift(MI, LI, MRI, A64, UserMI, OuterUserMI)) !=
1612 WebAssembly::INSTRUCTION_LIST_END) {
1613 ResultReg = OuterUserMI ? OuterUserMI->getOperand(0).getReg()
1614 : UserMI->getOperand(0).getReg();
1615 } else {
1616 return false;
1617 }
1618
1619 if (!emitLoad(ResultReg, NewOpc, LI))
1620 return false;
1621
1622 if (OuterUserMI) {
1623 MachineBasicBlock::iterator OuterIter(OuterUserMI);
1624 removeDeadCode(OuterIter, std::next(OuterIter));
1625 }
1626
1627 if (UserMI) {
1628 MachineBasicBlock::iterator UserIter(UserMI);
1629 removeDeadCode(UserIter, std::next(UserIter));
1630 }
1631
1633 removeDeadCode(Iter, std::next(Iter));
1634 return true;
1635}
1636
1637bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1638 const auto *Load = cast<LoadInst>(I);
1639 if (Load->isAtomic())
1640 return false;
1641 if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace()))
1642 return false;
1643 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1644 return false;
1645
1646 // TODO: Fold a following sign-/zero-extend into the load instruction.
1647
1648 unsigned Opc;
1649 const TargetRegisterClass *RC;
1650 bool A64 = Subtarget->hasAddr64();
1651 switch (getSimpleType(Load->getType())) {
1652 case MVT::i1:
1653 case MVT::i8:
1654 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1655 RC = &WebAssembly::I32RegClass;
1656 break;
1657 case MVT::i16:
1658 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1659 RC = &WebAssembly::I32RegClass;
1660 break;
1661 case MVT::i32:
1662 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1663 RC = &WebAssembly::I32RegClass;
1664 break;
1665 case MVT::i64:
1666 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1667 RC = &WebAssembly::I64RegClass;
1668 break;
1669 case MVT::f32:
1670 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1671 RC = &WebAssembly::F32RegClass;
1672 break;
1673 case MVT::f64:
1674 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1675 RC = &WebAssembly::F64RegClass;
1676 break;
1677 default:
1678 return false;
1679 }
1680
1681 Register ResultReg = createResultReg(RC);
1682 if (!emitLoad(ResultReg, Opc, Load))
1683 return false;
1684
1685 updateValueMap(Load, ResultReg);
1686 return true;
1687}
1688
1689bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1690 const auto *Store = cast<StoreInst>(I);
1691 if (Store->isAtomic())
1692 return false;
1693 if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace()))
1694 return false;
1695 if (!Subtarget->hasSIMD128() &&
1696 Store->getValueOperand()->getType()->isVectorTy())
1697 return false;
1698
1699 Address Addr;
1700 if (!computeAddress(Store->getPointerOperand(), Addr))
1701 return false;
1702
1703 unsigned Opc;
1704 bool VTIsi1 = false;
1705 bool A64 = Subtarget->hasAddr64();
1706 switch (getSimpleType(Store->getValueOperand()->getType())) {
1707 case MVT::i1:
1708 VTIsi1 = true;
1709 [[fallthrough]];
1710 case MVT::i8:
1711 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1712 break;
1713 case MVT::i16:
1714 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1715 break;
1716 case MVT::i32:
1717 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1718 break;
1719 case MVT::i64:
1720 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1721 break;
1722 case MVT::f32:
1723 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1724 break;
1725 case MVT::f64:
1726 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1727 break;
1728 default:
1729 return false;
1730 }
1731
1732 materializeLoadStoreOperands(Addr);
1733
1734 Register ValueReg = getRegForValue(Store->getValueOperand());
1735 if (ValueReg == 0)
1736 return false;
1737 if (VTIsi1)
1738 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1739
1740 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
1741
1742 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1743
1744 MIB.addReg(ValueReg);
1745 return true;
1746}
1747
1748bool WebAssemblyFastISel::selectCondBr(const Instruction *I) {
1749 const auto *Br = cast<CondBrInst>(I);
1750
1751 MachineBasicBlock *TBB = FuncInfo.getMBB(Br->getSuccessor(0));
1752 MachineBasicBlock *FBB = FuncInfo.getMBB(Br->getSuccessor(1));
1753
1754 bool Not;
1755 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1756 if (CondReg == 0)
1757 return false;
1758
1759 unsigned Opc = WebAssembly::BR_IF;
1760 if (Not)
1761 Opc = WebAssembly::BR_UNLESS;
1762
1763 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc))
1764 .addMBB(TBB)
1765 .addReg(CondReg);
1766
1767 finishCondBranch(Br->getParent(), TBB, FBB);
1768 return true;
1769}
1770
1771bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1772 if (!FuncInfo.CanLowerReturn)
1773 return false;
1774
1775 const auto *Ret = cast<ReturnInst>(I);
1776
1777 if (Ret->getNumOperands() == 0) {
1778 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1779 TII.get(WebAssembly::RETURN));
1780 return true;
1781 }
1782
1783 // TODO: support multiple return in FastISel
1784 if (Ret->getNumOperands() > 1)
1785 return false;
1786
1787 Value *RV = Ret->getOperand(0);
1788 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1789 return false;
1790
1791 switch (getSimpleType(RV->getType())) {
1792 case MVT::i1:
1793 case MVT::i8:
1794 case MVT::i16:
1795 case MVT::i32:
1796 case MVT::i64:
1797 case MVT::f32:
1798 case MVT::f64:
1799 case MVT::v16i8:
1800 case MVT::v8i16:
1801 case MVT::v4i32:
1802 case MVT::v2i64:
1803 case MVT::v4f32:
1804 case MVT::v2f64:
1805 case MVT::funcref:
1806 case MVT::externref:
1807 case MVT::exnref:
1808 break;
1809 default:
1810 return false;
1811 }
1812
1813 unsigned Reg;
1814 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1815 Reg = getRegForSignedValue(RV);
1816 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1817 Reg = getRegForUnsignedValue(RV);
1818 else
1819 Reg = getRegForValue(RV);
1820
1821 if (Reg == 0)
1822 return false;
1823
1824 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::RETURN))
1825 .addReg(Reg);
1826 return true;
1827}
1828
1829bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1830 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1831 TII.get(WebAssembly::UNREACHABLE));
1832 return true;
1833}
1834
1835bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1836 switch (I->getOpcode()) {
1837 case Instruction::Call:
1838 if (selectCall(I))
1839 return true;
1840 break;
1841 case Instruction::Select:
1842 return selectSelect(I);
1843 case Instruction::Trunc:
1844 return selectTrunc(I);
1845 case Instruction::ZExt:
1846 return selectZExt(I);
1847 case Instruction::SExt:
1848 return selectSExt(I);
1849 case Instruction::ICmp:
1850 return selectICmp(I);
1851 case Instruction::FCmp:
1852 return selectFCmp(I);
1853 case Instruction::BitCast:
1854 return selectBitCast(I);
1855 case Instruction::Load:
1856 return selectLoad(I);
1857 case Instruction::Store:
1858 return selectStore(I);
1859 case Instruction::CondBr:
1860 return selectCondBr(I);
1861 case Instruction::Ret:
1862 return selectRet(I);
1863 case Instruction::Unreachable:
1864 return selectUnreachable(I);
1865 default:
1866 break;
1867 }
1868
1869 // Fall back to target-independent instruction selection.
1870 return selectOperator(I, I->getOpcode());
1871}
1872
1873FastISel *
1875 const TargetLibraryInfo *LibInfo,
1876 const LibcallLoweringInfo *LibcallLowering) {
1877 return new WebAssemblyFastISel(FuncInfo, LibInfo, LibcallLowering);
1878}
MachineInstrBuilder MachineInstrBuilder & DefMI
static void emitLoad(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator Pos, const TargetInstrInfo &TII, unsigned Reg1, unsigned Reg2, int Offset, bool IsPostDec)
Emit a load-pair instruction for frame-destroy.
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
constexpr LLT F32
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines the FastISel class.
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
static bool isFoldableSExtOpcode(unsigned Opc)
static unsigned getSExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64)
static bool isI64SExtResult(unsigned Opc)
static unsigned matchFoldableCopyToI64Ext(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&OuterUserMI)
static unsigned matchFoldableSExtFromPromotedI32(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&UserMI)
static unsigned getZExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64)
static unsigned matchFoldableShift(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&UserMI, MachineInstr *&OuterUserMI)
Matches a sign-extension pattern (shl + shr_s) to fold it into a signed load.
static unsigned getFoldedI64LoadOpcode(Register DestReg, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&OuterUserMI, unsigned NarrowOpc)
static unsigned getFoldedLoadOpcode(MachineInstr *MI, MachineRegisterInfo &MRI, const LoadInst *LI, bool A64)
static unsigned matchFoldableAnd(MachineInstr *MI, const LoadInst *LI, MachineRegisterInfo &MRI, bool A64, MachineInstr *&OuterUserMI)
This file provides WebAssembly-specific target descriptions.
This file declares WebAssembly-specific per-machine-function information.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file contains the declaration of the WebAssembly-specific utility functions.
Value * RHS
Value * LHS
an instruction to allocate memory on the stack
LLVM Basic Block Representation.
Definition BasicBlock.h:62
bool isInlineAsm() const
Check if this call is an inline asm statement.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
CallingConv::ID getCallingConv() const
LLVM_ABI bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const
Determine whether the argument or parameter has the given attribute.
Value * getCalledOperand() const
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
unsigned arg_size() const
AttributeList getAttributes() const
Return the attributes for this call.
bool isMustTailCall() const
This is an important base class in LLVM.
Definition Constant.h:43
This is a fast-path instruction selection class that generates poor code and doesn't support illegal ...
Definition FastISel.h:66
FunctionLoweringInfo - This contains information that is global to a function that is used when lower...
bool isVarArg() const
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:353
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
Tracks which library functions to use for a particular subtarget.
An instruction for reading from memory.
void setNoStrip() const
@ INVALID_SIMPLE_VALUE_TYPE
SimpleValueType SimpleTy
MachineInstrBundleIterator< MachineInstr > iterator
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addSym(MCSymbol *Sym, unsigned char TargetFlags=0) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMemOperand(MachineMemOperand *MMO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
A description of a memory reference used in the backend.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
LLVM_ABI MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
Wrapper class representing virtual and physical registers.
Definition Register.h:20
TypeSize getElementOffset(unsigned Idx) const
Definition DataLayout.h:774
Provides information about what library functions are available for the current target.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM_ABI unsigned getIntegerBitWidth() const
bool isVectorTy() const
True if this is an instance of VectorType.
Definition Type.h:288
bool isArrayTy() const
True if this is an instance of ArrayType.
Definition Type.h:279
bool isStructTy() const
True if this is an instance of StructType.
Definition Type.h:276
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:197
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:257
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
CallInst * Call
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
Not(const Pred &P) -> Not< Pred >
bool isDefaultAddressSpace(unsigned AS)
MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.
MCSymbolWasm * getOrCreateFuncrefCallTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)
Returns the __funcref_call_table, for use in funcref calls when lowered to table.set + call_indirect.
FastISel * createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo, const LibcallLoweringInfo *libcallLowering)
@ User
could "use" a pointer
NodeAddr< FuncNode * > Func
Definition RDFGraph.h:393
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:558
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI void diagnoseDontCall(const CallInst &CI)
gep_type_iterator gep_type_end(const User *GEP)
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
generic_gep_type_iterator<> gep_type_iterator
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
gep_type_iterator gep_type_begin(const User *GEP)
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
Definition MathExtras.h:77
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:862
Extended Value Type.
Definition ValueTypes.h:35
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition ValueTypes.h:145
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:339