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