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.
109 const WebAssemblySubtarget *Subtarget;
110 LLVMContext *Context;
111
112private:
113 // Utility helper routines
114 MVT::SimpleValueType getSimpleType(Type *Ty) {
115 EVT VT = TLI.getValueType(DL, Ty, /*AllowUnknown=*/true);
116 return VT.isSimple() ? VT.getSimpleVT().SimpleTy
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) {
203 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
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)) {
239 if (TLI.isPositionIndependent())
240 return false;
241 if (Addr.getGlobalValue())
242 return false;
243 if (GV->isThreadLocal())
244 return false;
245 Addr.setGlobalValue(GV);
246 return true;
247 }
248
249 switch (Opcode) {
250 default:
251 break;
252 case Instruction::BitCast: {
253 // Look through bitcasts.
254 return computeAddress(U->getOperand(0), Addr);
255 }
256 case Instruction::IntToPtr: {
257 // Look past no-op inttoptrs.
258 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
259 TLI.getPointerTy(DL))
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)) {
692 if (TLI.isPositionIndependent())
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 return false;
720
721 unsigned I = 0;
722 for (auto const &Arg : F->args()) {
723 const AttributeList &Attrs = F->getAttributes();
724 if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
725 Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
726 Attrs.hasParamAttr(I, Attribute::SwiftError) ||
727 Attrs.hasParamAttr(I, Attribute::InAlloca) ||
728 Attrs.hasParamAttr(I, Attribute::Nest))
729 return false;
730
731 Type *ArgTy = Arg.getType();
732 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
733 return false;
734 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
735 return false;
736
737 unsigned Opc;
738 const TargetRegisterClass *RC;
739 switch (getSimpleType(ArgTy)) {
740 case MVT::i1:
741 case MVT::i8:
742 case MVT::i16:
743 case MVT::i32:
744 Opc = WebAssembly::ARGUMENT_i32;
745 RC = &WebAssembly::I32RegClass;
746 break;
747 case MVT::i64:
748 Opc = WebAssembly::ARGUMENT_i64;
749 RC = &WebAssembly::I64RegClass;
750 break;
751 case MVT::f32:
752 Opc = WebAssembly::ARGUMENT_f32;
753 RC = &WebAssembly::F32RegClass;
754 break;
755 case MVT::f64:
756 Opc = WebAssembly::ARGUMENT_f64;
757 RC = &WebAssembly::F64RegClass;
758 break;
759 case MVT::v16i8:
760 Opc = WebAssembly::ARGUMENT_v16i8;
761 RC = &WebAssembly::V128RegClass;
762 break;
763 case MVT::v8i16:
764 Opc = WebAssembly::ARGUMENT_v8i16;
765 RC = &WebAssembly::V128RegClass;
766 break;
767 case MVT::v4i32:
768 Opc = WebAssembly::ARGUMENT_v4i32;
769 RC = &WebAssembly::V128RegClass;
770 break;
771 case MVT::v2i64:
772 Opc = WebAssembly::ARGUMENT_v2i64;
773 RC = &WebAssembly::V128RegClass;
774 break;
775 case MVT::v4f32:
776 Opc = WebAssembly::ARGUMENT_v4f32;
777 RC = &WebAssembly::V128RegClass;
778 break;
779 case MVT::v2f64:
780 Opc = WebAssembly::ARGUMENT_v2f64;
781 RC = &WebAssembly::V128RegClass;
782 break;
783 case MVT::funcref:
784 Opc = WebAssembly::ARGUMENT_funcref;
785 RC = &WebAssembly::FUNCREFRegClass;
786 break;
787 case MVT::externref:
788 Opc = WebAssembly::ARGUMENT_externref;
789 RC = &WebAssembly::EXTERNREFRegClass;
790 break;
791 case MVT::exnref:
792 Opc = WebAssembly::ARGUMENT_exnref;
793 RC = &WebAssembly::EXNREFRegClass;
794 break;
795 default:
796 return false;
797 }
798 Register ResultReg = createResultReg(RC);
799 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
800 .addImm(I);
801 updateValueMap(&Arg, ResultReg);
802
803 ++I;
804 }
805
806 MRI.addLiveIn(WebAssembly::ARGUMENTS);
807
808 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
809 for (auto const &Arg : F->args()) {
810 MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
811 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
812 MFI->clearParamsAndResults();
813 return false;
814 }
815 MFI->addParam(ArgTy);
816 }
817
818 if (!F->getReturnType()->isVoidTy()) {
820 getLegalType(getSimpleType(F->getReturnType()));
821 if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
822 MFI->clearParamsAndResults();
823 return false;
824 }
825 MFI->addResult(RetTy);
826 }
827
828 return true;
829}
830
831bool WebAssemblyFastISel::selectCall(const Instruction *I) {
832 const auto *Call = cast<CallInst>(I);
833
834 // TODO: Support tail calls in FastISel
835 if (Call->isMustTailCall() || Call->isInlineAsm() ||
837 return false;
838
840 if (Func && Func->isIntrinsic())
841 return false;
842
843 if (Call->getCallingConv() == CallingConv::Swift)
844 return false;
845
846 bool IsDirect = Func != nullptr;
847 if (!IsDirect && isa<ConstantExpr>(Call->getCalledOperand()))
848 return false;
849
850 FunctionType *FuncTy = Call->getFunctionType();
851 unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
852 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
853 unsigned ResultReg;
854 if (!IsVoid) {
855 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
856 return false;
857
858 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
859 switch (RetTy) {
860 case MVT::i1:
861 case MVT::i8:
862 case MVT::i16:
863 case MVT::i32:
864 ResultReg = createResultReg(&WebAssembly::I32RegClass);
865 break;
866 case MVT::i64:
867 ResultReg = createResultReg(&WebAssembly::I64RegClass);
868 break;
869 case MVT::f32:
870 ResultReg = createResultReg(&WebAssembly::F32RegClass);
871 break;
872 case MVT::f64:
873 ResultReg = createResultReg(&WebAssembly::F64RegClass);
874 break;
875 case MVT::v16i8:
876 ResultReg = createResultReg(&WebAssembly::V128RegClass);
877 break;
878 case MVT::v8i16:
879 ResultReg = createResultReg(&WebAssembly::V128RegClass);
880 break;
881 case MVT::v4i32:
882 ResultReg = createResultReg(&WebAssembly::V128RegClass);
883 break;
884 case MVT::v2i64:
885 ResultReg = createResultReg(&WebAssembly::V128RegClass);
886 break;
887 case MVT::v4f32:
888 ResultReg = createResultReg(&WebAssembly::V128RegClass);
889 break;
890 case MVT::v2f64:
891 ResultReg = createResultReg(&WebAssembly::V128RegClass);
892 break;
893 case MVT::funcref:
894 ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
895 break;
896 case MVT::externref:
897 ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
898 break;
899 case MVT::exnref:
900 ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
901 break;
902 default:
903 return false;
904 }
905 }
906
907 SmallVector<unsigned, 8> Args;
908 for (unsigned I = 0, E = Call->arg_size(); I < E; ++I) {
910 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
912 return false;
913
914 const AttributeList &Attrs = Call->getAttributes();
915 if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
916 Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
917 Attrs.hasParamAttr(I, Attribute::SwiftError) ||
918 Attrs.hasParamAttr(I, Attribute::InAlloca) ||
919 Attrs.hasParamAttr(I, Attribute::Nest))
920 return false;
921
922 unsigned Reg;
923
924 if (Call->paramHasAttr(I, Attribute::SExt))
925 Reg = getRegForSignedValue(V);
926 else if (Call->paramHasAttr(I, Attribute::ZExt))
927 Reg = getRegForUnsignedValue(V);
928 else
929 Reg = getRegForValue(V);
930
931 if (Reg == 0)
932 return false;
933
934 Args.push_back(Reg);
935 }
936
937 unsigned CalleeReg = 0;
938 // A call through a funcref is expressed as a call through the pointer
939 // produced by llvm.wasm.funcref.to_ptr. Recover the funcref operand, place it
940 // into __funcref_call_table, and call it.
941 //
942 // TODO: Use call_ref if wasm-gc feature is available, would lead to simpler
943 // code here.
944 const Value *FuncrefArg = nullptr;
945 if (const auto *Conv = dyn_cast<CallInst>(Call->getCalledOperand()))
946 if (Conv->getIntrinsicID() == Intrinsic::wasm_funcref_to_ptr)
947 FuncrefArg = Conv->getArgOperand(0);
948
949 const bool IsFuncrefCall = FuncrefArg != nullptr;
950 MCSymbolWasm *Table = nullptr;
951
952 if (!IsDirect) {
953 if (!IsFuncrefCall) {
954 // Table is ___indirect_function_table
955 Table = WebAssembly::getOrCreateFunctionTableSymbol(MF->getContext(),
956 Subtarget);
957 CalleeReg = getRegForValue(Call->getCalledOperand());
958 if (!CalleeReg)
959 return false;
960 } else {
961 // Table is __funcref_call_table
962 Table = WebAssembly::getOrCreateFuncrefCallTableSymbol(MF->getContext(),
963 Subtarget);
964 CalleeReg = getRegForValue(FuncrefArg);
965 // Put the funcref in slot 0 of __funcref_call_table
966 unsigned ZeroReg = createResultReg(&WebAssembly::I32RegClass);
967 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
968 TII.get(WebAssembly::CONST_I32), ZeroReg)
969 .addImm(0);
970 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
971 TII.get(WebAssembly::TABLE_SET_FUNCREF))
972 .addSym(Table)
973 .addReg(ZeroReg)
974 .addReg(CalleeReg);
975 // Set CalleeReg to an immediate 0
976 CalleeReg = createResultReg(&WebAssembly::I32RegClass);
977 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
978 TII.get(WebAssembly::CONST_I32), CalleeReg)
979 .addImm(0);
980 }
981 }
982
983 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
984
985 if (!IsVoid)
986 MIB.addReg(ResultReg, RegState::Define);
987
988 if (IsDirect) {
989 MIB.addGlobalAddress(Func);
990 } else {
991 // Placeholder for the type index.
992 MIB.addImm(0);
993 if (Subtarget->hasCallIndirectOverlong()) {
994 MIB.addSym(Table);
995 } else {
996 // Otherwise for the MVP there is at most one table whose number is 0, but
997 // we can't write a table symbol or issue relocations. Instead we just
998 // ensure the table is live.
999 Table->setNoStrip();
1000 MIB.addImm(0);
1001 }
1002 }
1003
1004 for (unsigned ArgReg : Args)
1005 MIB.addReg(ArgReg);
1006
1007 if (!IsDirect)
1008 MIB.addReg(CalleeReg);
1009
1010 if (IsFuncrefCall) {
1011 // Clear slot 0 of the funcref call table after the call.
1012 unsigned ZeroReg = createResultReg(&WebAssembly::I32RegClass);
1013 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1014 TII.get(WebAssembly::CONST_I32), ZeroReg)
1015 .addImm(0);
1016 unsigned NullReg = createResultReg(&WebAssembly::FUNCREFRegClass);
1017 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1018 TII.get(WebAssembly::REF_NULL_FUNCREF), NullReg);
1019 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1020 TII.get(WebAssembly::TABLE_SET_FUNCREF))
1021 .addSym(Table)
1022 .addReg(ZeroReg)
1023 .addReg(NullReg);
1024 }
1025
1026 if (!IsVoid)
1027 updateValueMap(Call, ResultReg);
1028
1030 return true;
1031}
1032
1033bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
1034 const auto *Select = cast<SelectInst>(I);
1035
1036 bool Not;
1037 unsigned CondReg =
1038 getRegForI1Value(Select->getCondition(), I->getParent(), Not);
1039 if (CondReg == 0)
1040 return false;
1041
1042 Register TrueReg = getRegForValue(Select->getTrueValue());
1043 if (TrueReg == 0)
1044 return false;
1045
1046 Register FalseReg = getRegForValue(Select->getFalseValue());
1047 if (FalseReg == 0)
1048 return false;
1049
1050 if (Not)
1051 std::swap(TrueReg, FalseReg);
1052
1053 unsigned Opc;
1054 const TargetRegisterClass *RC;
1055 switch (getSimpleType(Select->getType())) {
1056 case MVT::i1:
1057 case MVT::i8:
1058 case MVT::i16:
1059 case MVT::i32:
1060 Opc = WebAssembly::SELECT_I32;
1061 RC = &WebAssembly::I32RegClass;
1062 break;
1063 case MVT::i64:
1064 Opc = WebAssembly::SELECT_I64;
1065 RC = &WebAssembly::I64RegClass;
1066 break;
1067 case MVT::f32:
1068 Opc = WebAssembly::SELECT_F32;
1069 RC = &WebAssembly::F32RegClass;
1070 break;
1071 case MVT::f64:
1072 Opc = WebAssembly::SELECT_F64;
1073 RC = &WebAssembly::F64RegClass;
1074 break;
1075 case MVT::funcref:
1076 Opc = WebAssembly::SELECT_FUNCREF;
1077 RC = &WebAssembly::FUNCREFRegClass;
1078 break;
1079 case MVT::externref:
1080 Opc = WebAssembly::SELECT_EXTERNREF;
1081 RC = &WebAssembly::EXTERNREFRegClass;
1082 break;
1083 case MVT::exnref:
1084 Opc = WebAssembly::SELECT_EXNREF;
1085 RC = &WebAssembly::EXNREFRegClass;
1086 break;
1087 default:
1088 return false;
1089 }
1090
1091 Register ResultReg = createResultReg(RC);
1092 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1093 .addReg(TrueReg)
1094 .addReg(FalseReg)
1095 .addReg(CondReg);
1096
1097 updateValueMap(Select, ResultReg);
1098 return true;
1099}
1100
1101bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
1102 const auto *Trunc = cast<TruncInst>(I);
1103
1104 const Value *Op = Trunc->getOperand(0);
1105 MVT::SimpleValueType From = getSimpleType(Op->getType());
1106 MVT::SimpleValueType To = getLegalType(getSimpleType(Trunc->getType()));
1107 Register In = getRegForValue(Op);
1108 if (In == 0)
1109 return false;
1110
1111 auto Truncate = [&](Register Reg) -> unsigned {
1112 if (From == MVT::i64) {
1113 if (To == MVT::i64)
1114 return copyValue(Reg);
1115
1116 if (To == MVT::i1 || To == MVT::i8 || To == MVT::i16 || To == MVT::i32) {
1117 Register Result = createResultReg(&WebAssembly::I32RegClass);
1118 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1119 TII.get(WebAssembly::I32_WRAP_I64), Result)
1120 .addReg(Reg);
1121 return Result;
1122 }
1123 }
1124
1125 if (From == MVT::i32)
1126 return copyValue(Reg);
1127
1128 return 0;
1129 };
1130
1131 unsigned Reg = Truncate(In);
1132 if (Reg == 0)
1133 return false;
1134
1135 updateValueMap(Trunc, Reg);
1136 return true;
1137}
1138
1139bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
1140 const auto *ZExt = cast<ZExtInst>(I);
1141
1142 const Value *Op = ZExt->getOperand(0);
1143 MVT::SimpleValueType From = getSimpleType(Op->getType());
1144 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
1145 Register In = getRegForValue(Op);
1146 if (In == 0)
1147 return false;
1148 unsigned Reg = zeroExtend(In, Op, From, To);
1149 if (Reg == 0)
1150 return false;
1151
1152 updateValueMap(ZExt, Reg);
1153 return true;
1154}
1155
1156bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
1157 const auto *SExt = cast<SExtInst>(I);
1158
1159 const Value *Op = SExt->getOperand(0);
1160 MVT::SimpleValueType From = getSimpleType(Op->getType());
1161 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
1162 Register In = getRegForValue(Op);
1163 if (In == 0)
1164 return false;
1165 unsigned Reg = signExtend(In, Op, From, To);
1166 if (Reg == 0)
1167 return false;
1168
1169 updateValueMap(SExt, Reg);
1170 return true;
1171}
1172
1173bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
1174 const auto *ICmp = cast<ICmpInst>(I);
1175
1176 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1177 unsigned Opc;
1178 bool IsSigned = false;
1179 switch (ICmp->getPredicate()) {
1180 case ICmpInst::ICMP_EQ:
1181 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1182 break;
1183 case ICmpInst::ICMP_NE:
1184 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1185 break;
1186 case ICmpInst::ICMP_UGT:
1187 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1188 break;
1189 case ICmpInst::ICMP_UGE:
1190 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1191 break;
1192 case ICmpInst::ICMP_ULT:
1193 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1194 break;
1195 case ICmpInst::ICMP_ULE:
1196 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1197 break;
1198 case ICmpInst::ICMP_SGT:
1199 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1200 IsSigned = true;
1201 break;
1202 case ICmpInst::ICMP_SGE:
1203 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1204 IsSigned = true;
1205 break;
1206 case ICmpInst::ICMP_SLT:
1207 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1208 IsSigned = true;
1209 break;
1210 case ICmpInst::ICMP_SLE:
1211 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1212 IsSigned = true;
1213 break;
1214 default:
1215 return false;
1216 }
1217
1218 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1219 if (LHS == 0)
1220 return false;
1221
1222 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1223 if (RHS == 0)
1224 return false;
1225
1226 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1227 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1228 .addReg(LHS)
1229 .addReg(RHS);
1230 updateValueMap(ICmp, ResultReg);
1231 return true;
1232}
1233
1234bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1235 const auto *FCmp = cast<FCmpInst>(I);
1236
1237 Register LHS = getRegForValue(FCmp->getOperand(0));
1238 if (LHS == 0)
1239 return false;
1240
1241 Register RHS = getRegForValue(FCmp->getOperand(1));
1242 if (RHS == 0)
1243 return false;
1244
1245 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1246 unsigned Opc;
1247 bool Not = false;
1248 switch (FCmp->getPredicate()) {
1249 case FCmpInst::FCMP_OEQ:
1250 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1251 break;
1252 case FCmpInst::FCMP_UNE:
1253 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1254 break;
1255 case FCmpInst::FCMP_OGT:
1256 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1257 break;
1258 case FCmpInst::FCMP_OGE:
1259 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1260 break;
1261 case FCmpInst::FCMP_OLT:
1262 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1263 break;
1264 case FCmpInst::FCMP_OLE:
1265 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1266 break;
1267 case FCmpInst::FCMP_UGT:
1268 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1269 Not = true;
1270 break;
1271 case FCmpInst::FCMP_UGE:
1272 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1273 Not = true;
1274 break;
1275 case FCmpInst::FCMP_ULT:
1276 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1277 Not = true;
1278 break;
1279 case FCmpInst::FCMP_ULE:
1280 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1281 Not = true;
1282 break;
1283 default:
1284 return false;
1285 }
1286
1287 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1288 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1289 .addReg(LHS)
1290 .addReg(RHS);
1291
1292 if (Not)
1293 ResultReg = notValue(ResultReg);
1294
1295 updateValueMap(FCmp, ResultReg);
1296 return true;
1297}
1298
1299bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1300 // Target-independent code can handle this, except it doesn't set the dead
1301 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1302 // to satisfy code that expects this of isBitcast() instructions.
1303 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1304 EVT RetVT = TLI.getValueType(DL, I->getType());
1305 if (!VT.isSimple() || !RetVT.isSimple())
1306 return false;
1307
1308 Register In = getRegForValue(I->getOperand(0));
1309 if (In == 0)
1310 return false;
1311
1312 if (VT == RetVT) {
1313 // No-op bitcast.
1314 updateValueMap(I, In);
1315 return true;
1316 }
1317
1318 Register Reg =
1319 fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(), In);
1320 if (!Reg)
1321 return false;
1322 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1323 --Iter;
1324 assert(Iter->isBitcast());
1325 Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI);
1326 updateValueMap(I, Reg);
1327 return true;
1328}
1329
1330static unsigned getSExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64) {
1331 if (I64Result) {
1332 switch (LoadSize) {
1333 default:
1334 return WebAssembly::INSTRUCTION_LIST_END;
1335 case 8:
1336 return A64 ? WebAssembly::LOAD8_S_I64_A64 : WebAssembly::LOAD8_S_I64_A32;
1337 case 16:
1338 return A64 ? WebAssembly::LOAD16_S_I64_A64
1339 : WebAssembly::LOAD16_S_I64_A32;
1340 case 32:
1341 return A64 ? WebAssembly::LOAD32_S_I64_A64
1342 : WebAssembly::LOAD32_S_I64_A32;
1343 }
1344 }
1345
1346 switch (LoadSize) {
1347 default:
1348 return WebAssembly::INSTRUCTION_LIST_END;
1349 case 8:
1350 return A64 ? WebAssembly::LOAD8_S_I32_A64 : WebAssembly::LOAD8_S_I32_A32;
1351 case 16:
1352 return A64 ? WebAssembly::LOAD16_S_I32_A64 : WebAssembly::LOAD16_S_I32_A32;
1353 }
1354}
1355
1356static unsigned getZExtLoadOpcode(unsigned LoadSize, bool I64Result, bool A64) {
1357 if (I64Result) {
1358 switch (LoadSize) {
1359 default:
1360 return WebAssembly::INSTRUCTION_LIST_END;
1361 case 8:
1362 return A64 ? WebAssembly::LOAD8_U_I64_A64 : WebAssembly::LOAD8_U_I64_A32;
1363 case 16:
1364 return A64 ? WebAssembly::LOAD16_U_I64_A64
1365 : WebAssembly::LOAD16_U_I64_A32;
1366 case 32:
1367 return A64 ? WebAssembly::LOAD32_U_I64_A64
1368 : WebAssembly::LOAD32_U_I64_A32;
1369 }
1370 }
1371
1372 switch (LoadSize) {
1373 default:
1374 return WebAssembly::INSTRUCTION_LIST_END;
1375 case 8:
1376 return A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1377 case 16:
1378 return A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1379 }
1380}
1381
1382static bool isFoldableSExtOpcode(unsigned Opc) {
1383 switch (Opc) {
1384 default:
1385 return false;
1386 case WebAssembly::I32_EXTEND8_S_I32:
1387 case WebAssembly::I32_EXTEND16_S_I32:
1388 case WebAssembly::I64_EXTEND8_S_I64:
1389 case WebAssembly::I64_EXTEND16_S_I64:
1390 case WebAssembly::I64_EXTEND32_S_I64:
1391 case WebAssembly::I64_EXTEND_S_I32:
1392 return true;
1393 }
1394}
1395
1396static bool isI64SExtResult(unsigned Opc) {
1397 switch (Opc) {
1398 default:
1399 llvm_unreachable("unexpected opcode");
1400 case WebAssembly::I32_EXTEND8_S_I32:
1401 case WebAssembly::I32_EXTEND16_S_I32:
1402 return false;
1403 case WebAssembly::I64_EXTEND8_S_I64:
1404 case WebAssembly::I64_EXTEND16_S_I64:
1405 case WebAssembly::I64_EXTEND32_S_I64:
1406 case WebAssembly::I64_EXTEND_S_I32:
1407 return true;
1408 }
1409}
1410
1412 const LoadInst *LI, bool A64) {
1413 unsigned Opc = MI->getOpcode();
1414
1416 unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
1417 return getSExtLoadOpcode(LoadSize, isI64SExtResult(Opc), A64);
1418 }
1419
1420 return WebAssembly::INSTRUCTION_LIST_END;
1421}
1422
1423static unsigned getFoldedI64LoadOpcode(Register DestReg, const LoadInst *LI,
1424 MachineRegisterInfo &MRI, bool A64,
1425 MachineInstr *&OuterUserMI,
1426 unsigned NarrowOpc) {
1427 if (!MRI.hasOneNonDBGUse(DestReg))
1428 return NarrowOpc;
1429
1430 MachineInstr *UserMI = &*MRI.use_instr_nodbg_begin(DestReg);
1431 unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
1432 switch (UserMI->getOpcode()) {
1433 case WebAssembly::I64_EXTEND_U_I32:
1434 OuterUserMI = UserMI;
1435 return getZExtLoadOpcode(LoadSize, /*I64Result=*/true, A64);
1436 case WebAssembly::I64_EXTEND_S_I32:
1437 OuterUserMI = UserMI;
1438 return getSExtLoadOpcode(LoadSize, /*I64Result=*/true, A64);
1439 default:
1440 return NarrowOpc;
1441 }
1442}
1443
1444/// Matches a sign-extension pattern (shl + shr_s) to fold it into a signed
1445/// load. FastISel assumes that 'sext' from i8 or i16 will first be lowered to a
1446/// 32-bit zero-extending load (i32.load8_u / i32.load16_u) followed by 32-bit
1447/// shifts, even when extending to i64. Therefore, this function only matches
1448/// 32-bit shifts (SHL_I32 / SHR_S_I32) and specifically checks if both shift
1449/// amounts are identical, compile-time constants that match the exact extension
1450/// size (32 - LoadBitWidth).
1451static unsigned matchFoldableShift(MachineInstr *MI, const LoadInst *LI,
1452 MachineRegisterInfo &MRI, bool A64,
1453 MachineInstr *&UserMI,
1454 MachineInstr *&OuterUserMI) {
1455 unsigned Opc = MI->getOpcode();
1456 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1457 if (Opc != WebAssembly::SHL_I32)
1458 return NewOpc;
1459
1460 Register DestReg = MI->getOperand(0).getReg();
1461 if (!MRI.hasOneNonDBGUse(DestReg))
1462 return NewOpc;
1463
1464 UserMI = &*MRI.use_instr_nodbg_begin(DestReg);
1465 unsigned UserOpc = UserMI->getOpcode();
1466 if (UserOpc != WebAssembly::SHR_S_I32)
1467 return NewOpc;
1468
1469 Type *LoadTy = LI->getType();
1470 if (!LoadTy->isIntegerTy(8) && !LoadTy->isIntegerTy(16))
1471 return NewOpc;
1472
1473 int64_t ExpectedShiftAmt = 32 - LoadTy->getIntegerBitWidth();
1474 Register ShlAmtReg = MI->getOperand(2).getReg();
1475 Register ShrAmtReg = UserMI->getOperand(2).getReg();
1476 MachineInstr *ShlAmtDef = MRI.getUniqueVRegDef(ShlAmtReg);
1477 MachineInstr *ShrAmtDef = MRI.getUniqueVRegDef(ShrAmtReg);
1478 auto IsExpectedConst = [ExpectedShiftAmt](MachineInstr *MI) {
1479 return MI && MI->getOpcode() == WebAssembly::CONST_I32 &&
1480 MI->getOperand(1).getImm() == ExpectedShiftAmt;
1481 };
1482 if (!IsExpectedConst(ShlAmtDef) || !IsExpectedConst(ShrAmtDef))
1483 return NewOpc;
1484
1485 unsigned LoadSize = LoadTy->getIntegerBitWidth();
1486 unsigned NarrowOpc = getSExtLoadOpcode(LoadSize, /*I64Result=*/false, A64);
1487 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1488 return WebAssembly::INSTRUCTION_LIST_END;
1489
1490 return getFoldedI64LoadOpcode(UserMI->getOperand(0).getReg(), LI, MRI, A64,
1491 OuterUserMI, NarrowOpc);
1492}
1493
1495 const LoadInst *LI,
1497 bool A64,
1498 MachineInstr *&UserMI) {
1499 if (MI->getOpcode() != WebAssembly::I64_EXTEND_U_I32)
1500 return WebAssembly::INSTRUCTION_LIST_END;
1501
1502 unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
1503 Register DestReg = MI->getOperand(0).getReg();
1504 if (!MRI.hasOneNonDBGUse(DestReg))
1505 return WebAssembly::INSTRUCTION_LIST_END;
1506
1507 UserMI = &*MRI.use_instr_nodbg_begin(DestReg);
1508 switch (UserMI->getOpcode()) {
1509 default:
1510 return WebAssembly::INSTRUCTION_LIST_END;
1511 case WebAssembly::I64_EXTEND8_S_I64:
1512 if (LoadSize != 8)
1513 return WebAssembly::INSTRUCTION_LIST_END;
1514 return getSExtLoadOpcode(LoadSize, true, A64);
1515 case WebAssembly::I64_EXTEND16_S_I64:
1516 if (LoadSize != 16)
1517 return WebAssembly::INSTRUCTION_LIST_END;
1518 return getSExtLoadOpcode(LoadSize, true, A64);
1519 }
1520}
1521
1523 MachineRegisterInfo &MRI, bool A64,
1524 MachineInstr *&OuterUserMI) {
1525 if (MI->getOpcode() != WebAssembly::COPY)
1526 return WebAssembly::INSTRUCTION_LIST_END;
1527
1528 unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
1529 if (LoadSize != 32)
1530 return WebAssembly::INSTRUCTION_LIST_END;
1531
1532 Register CopyDst = MI->getOperand(0).getReg();
1533 if (!MRI.hasOneNonDBGUse(CopyDst))
1534 return WebAssembly::INSTRUCTION_LIST_END;
1535
1536 OuterUserMI = &*MRI.use_instr_nodbg_begin(CopyDst);
1537 switch (OuterUserMI->getOpcode()) {
1538 default:
1539 return WebAssembly::INSTRUCTION_LIST_END;
1540 case WebAssembly::I64_EXTEND_U_I32:
1541 return getZExtLoadOpcode(LoadSize, true, A64);
1542 case WebAssembly::I64_EXTEND_S_I32:
1543 return getSExtLoadOpcode(LoadSize, true, A64);
1544 }
1545}
1546
1547static unsigned matchFoldableAnd(MachineInstr *MI, const LoadInst *LI,
1548 MachineRegisterInfo &MRI, bool A64,
1549 MachineInstr *&OuterUserMI) {
1550 if (MI->getOpcode() != WebAssembly::AND_I32 &&
1551 MI->getOpcode() != WebAssembly::AND_I64)
1552 return WebAssembly::INSTRUCTION_LIST_END;
1553
1554 uint64_t Mask = 0;
1555 bool IsConstant = false;
1556 for (unsigned I = 1; I <= 2; ++I) {
1557 Register Reg = MI->getOperand(I).getReg();
1559 if (DefMI && (DefMI->getOpcode() == WebAssembly::CONST_I32 ||
1560 DefMI->getOpcode() == WebAssembly::CONST_I64)) {
1561 Mask = DefMI->getOperand(1).getImm();
1562 IsConstant = true;
1563 break;
1564 }
1565 }
1566
1567 if (!IsConstant)
1568 return WebAssembly::INSTRUCTION_LIST_END;
1569
1570 unsigned LoadSize = LI->getType()->getPrimitiveSizeInBits();
1571 if (Mask != llvm::maskTrailingOnes<uint64_t>(LoadSize))
1572 return WebAssembly::INSTRUCTION_LIST_END;
1573
1574 if (MI->getOpcode() == WebAssembly::AND_I64)
1575 return getZExtLoadOpcode(LoadSize, /*I64Result=*/true, A64);
1576
1577 unsigned NarrowOpc = getZExtLoadOpcode(LoadSize, /*I64Result=*/false, A64);
1578 if (NarrowOpc == WebAssembly::INSTRUCTION_LIST_END)
1579 return WebAssembly::INSTRUCTION_LIST_END;
1580
1581 return getFoldedI64LoadOpcode(MI->getOperand(0).getReg(), LI, MRI, A64,
1582 OuterUserMI, NarrowOpc);
1583}
1584
1585bool WebAssemblyFastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
1586 const LoadInst *LI) {
1587 bool A64 = Subtarget->hasAddr64();
1588 MachineRegisterInfo &MRI = FuncInfo.MF->getRegInfo();
1589 Register ResultReg;
1590 MachineInstr *UserMI = nullptr;
1591 MachineInstr *OuterUserMI = nullptr;
1592 unsigned NewOpc = WebAssembly::INSTRUCTION_LIST_END;
1593 if ((NewOpc = matchFoldableSExtFromPromotedI32(MI, LI, MRI, A64, UserMI)) !=
1594 WebAssembly::INSTRUCTION_LIST_END) {
1595 ResultReg = UserMI->getOperand(0).getReg();
1596 } else if ((NewOpc =
1597 matchFoldableCopyToI64Ext(MI, LI, MRI, A64, OuterUserMI)) !=
1598 WebAssembly::INSTRUCTION_LIST_END) {
1599 ResultReg = OuterUserMI->getOperand(0).getReg();
1600 } else if ((NewOpc = matchFoldableAnd(MI, LI, MRI, A64, OuterUserMI)) !=
1601 WebAssembly::INSTRUCTION_LIST_END) {
1602 ResultReg = OuterUserMI ? OuterUserMI->getOperand(0).getReg()
1603 : MI->getOperand(0).getReg();
1604 } else if ((NewOpc = getFoldedLoadOpcode(MI, MRI, LI, A64)) !=
1605 WebAssembly::INSTRUCTION_LIST_END) {
1606 ResultReg = MI->getOperand(0).getReg();
1607 } else if ((NewOpc =
1608 matchFoldableShift(MI, LI, MRI, A64, UserMI, OuterUserMI)) !=
1609 WebAssembly::INSTRUCTION_LIST_END) {
1610 ResultReg = OuterUserMI ? OuterUserMI->getOperand(0).getReg()
1611 : UserMI->getOperand(0).getReg();
1612 } else {
1613 return false;
1614 }
1615
1616 if (!emitLoad(ResultReg, NewOpc, LI))
1617 return false;
1618
1619 if (OuterUserMI) {
1620 MachineBasicBlock::iterator OuterIter(OuterUserMI);
1621 removeDeadCode(OuterIter, std::next(OuterIter));
1622 }
1623
1624 if (UserMI) {
1625 MachineBasicBlock::iterator UserIter(UserMI);
1626 removeDeadCode(UserIter, std::next(UserIter));
1627 }
1628
1630 removeDeadCode(Iter, std::next(Iter));
1631 return true;
1632}
1633
1634bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1635 const auto *Load = cast<LoadInst>(I);
1636 if (Load->isAtomic())
1637 return false;
1638 if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace()))
1639 return false;
1640 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1641 return false;
1642
1643 // TODO: Fold a following sign-/zero-extend into the load instruction.
1644
1645 unsigned Opc;
1646 const TargetRegisterClass *RC;
1647 bool A64 = Subtarget->hasAddr64();
1648 switch (getSimpleType(Load->getType())) {
1649 case MVT::i1:
1650 case MVT::i8:
1651 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1652 RC = &WebAssembly::I32RegClass;
1653 break;
1654 case MVT::i16:
1655 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1656 RC = &WebAssembly::I32RegClass;
1657 break;
1658 case MVT::i32:
1659 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1660 RC = &WebAssembly::I32RegClass;
1661 break;
1662 case MVT::i64:
1663 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1664 RC = &WebAssembly::I64RegClass;
1665 break;
1666 case MVT::f32:
1667 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1668 RC = &WebAssembly::F32RegClass;
1669 break;
1670 case MVT::f64:
1671 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1672 RC = &WebAssembly::F64RegClass;
1673 break;
1674 default:
1675 return false;
1676 }
1677
1678 Register ResultReg = createResultReg(RC);
1679 if (!emitLoad(ResultReg, Opc, Load))
1680 return false;
1681
1682 updateValueMap(Load, ResultReg);
1683 return true;
1684}
1685
1686bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1687 const auto *Store = cast<StoreInst>(I);
1688 if (Store->isAtomic())
1689 return false;
1690 if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace()))
1691 return false;
1692 if (!Subtarget->hasSIMD128() &&
1693 Store->getValueOperand()->getType()->isVectorTy())
1694 return false;
1695
1696 Address Addr;
1697 if (!computeAddress(Store->getPointerOperand(), Addr))
1698 return false;
1699
1700 unsigned Opc;
1701 bool VTIsi1 = false;
1702 bool A64 = Subtarget->hasAddr64();
1703 switch (getSimpleType(Store->getValueOperand()->getType())) {
1704 case MVT::i1:
1705 VTIsi1 = true;
1706 [[fallthrough]];
1707 case MVT::i8:
1708 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1709 break;
1710 case MVT::i16:
1711 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1712 break;
1713 case MVT::i32:
1714 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1715 break;
1716 case MVT::i64:
1717 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1718 break;
1719 case MVT::f32:
1720 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1721 break;
1722 case MVT::f64:
1723 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1724 break;
1725 default:
1726 return false;
1727 }
1728
1729 materializeLoadStoreOperands(Addr);
1730
1731 Register ValueReg = getRegForValue(Store->getValueOperand());
1732 if (ValueReg == 0)
1733 return false;
1734 if (VTIsi1)
1735 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1736
1737 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
1738
1739 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1740
1741 MIB.addReg(ValueReg);
1742 return true;
1743}
1744
1745bool WebAssemblyFastISel::selectCondBr(const Instruction *I) {
1746 const auto *Br = cast<CondBrInst>(I);
1747
1748 MachineBasicBlock *TBB = FuncInfo.getMBB(Br->getSuccessor(0));
1749 MachineBasicBlock *FBB = FuncInfo.getMBB(Br->getSuccessor(1));
1750
1751 bool Not;
1752 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1753 if (CondReg == 0)
1754 return false;
1755
1756 unsigned Opc = WebAssembly::BR_IF;
1757 if (Not)
1758 Opc = WebAssembly::BR_UNLESS;
1759
1760 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc))
1761 .addMBB(TBB)
1762 .addReg(CondReg);
1763
1764 finishCondBranch(Br->getParent(), TBB, FBB);
1765 return true;
1766}
1767
1768bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1769 if (!FuncInfo.CanLowerReturn)
1770 return false;
1771
1772 const auto *Ret = cast<ReturnInst>(I);
1773
1774 if (Ret->getNumOperands() == 0) {
1775 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1776 TII.get(WebAssembly::RETURN));
1777 return true;
1778 }
1779
1780 // TODO: support multiple return in FastISel
1781 if (Ret->getNumOperands() > 1)
1782 return false;
1783
1784 Value *RV = Ret->getOperand(0);
1785 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1786 return false;
1787
1788 switch (getSimpleType(RV->getType())) {
1789 case MVT::i1:
1790 case MVT::i8:
1791 case MVT::i16:
1792 case MVT::i32:
1793 case MVT::i64:
1794 case MVT::f32:
1795 case MVT::f64:
1796 case MVT::v16i8:
1797 case MVT::v8i16:
1798 case MVT::v4i32:
1799 case MVT::v2i64:
1800 case MVT::v4f32:
1801 case MVT::v2f64:
1802 case MVT::funcref:
1803 case MVT::externref:
1804 case MVT::exnref:
1805 break;
1806 default:
1807 return false;
1808 }
1809
1810 unsigned Reg;
1811 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1812 Reg = getRegForSignedValue(RV);
1813 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1814 Reg = getRegForUnsignedValue(RV);
1815 else
1816 Reg = getRegForValue(RV);
1817
1818 if (Reg == 0)
1819 return false;
1820
1821 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::RETURN))
1822 .addReg(Reg);
1823 return true;
1824}
1825
1826bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1827 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1828 TII.get(WebAssembly::UNREACHABLE));
1829 return true;
1830}
1831
1832bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1833 switch (I->getOpcode()) {
1834 case Instruction::Call:
1835 if (selectCall(I))
1836 return true;
1837 break;
1838 case Instruction::Select:
1839 return selectSelect(I);
1840 case Instruction::Trunc:
1841 return selectTrunc(I);
1842 case Instruction::ZExt:
1843 return selectZExt(I);
1844 case Instruction::SExt:
1845 return selectSExt(I);
1846 case Instruction::ICmp:
1847 return selectICmp(I);
1848 case Instruction::FCmp:
1849 return selectFCmp(I);
1850 case Instruction::BitCast:
1851 return selectBitCast(I);
1852 case Instruction::Load:
1853 return selectLoad(I);
1854 case Instruction::Store:
1855 return selectStore(I);
1856 case Instruction::CondBr:
1857 return selectCondBr(I);
1858 case Instruction::Ret:
1859 return selectRet(I);
1860 case Instruction::Unreachable:
1861 return selectUnreachable(I);
1862 default:
1863 break;
1864 }
1865
1866 // Fall back to target-independent instruction selection.
1867 return selectOperator(I, I->getOpcode());
1868}
1869
1870FastISel *
1872 const TargetLibraryInfo *LibInfo,
1873 const LibcallLoweringInfo *LibcallLowering) {
1874 return new WebAssemblyFastISel(FuncInfo, LibInfo, LibcallLowering);
1875}
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!")
unsigned Imm
unsigned uint64_t
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
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 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: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:356
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 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.
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 LLVM_READONLY 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.
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
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: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:145
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:339