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