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