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 using BaseKind = enum { 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 Register Reg = getRegForValue(Trunc->getOperand(0));
992 if (Reg == 0)
993 return false;
994
995 unsigned FromBitWidth = Trunc->getOperand(0)->getType()->getIntegerBitWidth();
996 unsigned ToBitWidth = Trunc->getType()->getIntegerBitWidth();
997
998 if (ToBitWidth <= 32 && (32 < FromBitWidth && FromBitWidth <= 64)) {
999 Register Result = createResultReg(&WebAssembly::I32RegClass);
1000 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1001 TII.get(WebAssembly::I32_WRAP_I64), Result)
1002 .addReg(Reg);
1003 Reg = Result;
1004 }
1005
1006 updateValueMap(Trunc, Reg);
1007 return true;
1008}
1009
1010bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
1011 const auto *ZExt = cast<ZExtInst>(I);
1012
1013 const Value *Op = ZExt->getOperand(0);
1014 MVT::SimpleValueType From = getSimpleType(Op->getType());
1015 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
1016 Register In = getRegForValue(Op);
1017 if (In == 0)
1018 return false;
1019 unsigned Reg = zeroExtend(In, Op, From, To);
1020 if (Reg == 0)
1021 return false;
1022
1023 updateValueMap(ZExt, Reg);
1024 return true;
1025}
1026
1027bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
1028 const auto *SExt = cast<SExtInst>(I);
1029
1030 const Value *Op = SExt->getOperand(0);
1031 MVT::SimpleValueType From = getSimpleType(Op->getType());
1032 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
1033 Register In = getRegForValue(Op);
1034 if (In == 0)
1035 return false;
1036 unsigned Reg = signExtend(In, Op, From, To);
1037 if (Reg == 0)
1038 return false;
1039
1040 updateValueMap(SExt, Reg);
1041 return true;
1042}
1043
1044bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
1045 const auto *ICmp = cast<ICmpInst>(I);
1046
1047 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1048 unsigned Opc;
1049 bool IsSigned = false;
1050 switch (ICmp->getPredicate()) {
1051 case ICmpInst::ICMP_EQ:
1052 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1053 break;
1054 case ICmpInst::ICMP_NE:
1055 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1056 break;
1057 case ICmpInst::ICMP_UGT:
1058 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1059 break;
1060 case ICmpInst::ICMP_UGE:
1061 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1062 break;
1063 case ICmpInst::ICMP_ULT:
1064 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1065 break;
1066 case ICmpInst::ICMP_ULE:
1067 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1068 break;
1069 case ICmpInst::ICMP_SGT:
1070 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1071 IsSigned = true;
1072 break;
1073 case ICmpInst::ICMP_SGE:
1074 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1075 IsSigned = true;
1076 break;
1077 case ICmpInst::ICMP_SLT:
1078 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1079 IsSigned = true;
1080 break;
1081 case ICmpInst::ICMP_SLE:
1082 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1083 IsSigned = true;
1084 break;
1085 default:
1086 return false;
1087 }
1088
1089 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1090 if (LHS == 0)
1091 return false;
1092
1093 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1094 if (RHS == 0)
1095 return false;
1096
1097 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1098 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1099 .addReg(LHS)
1100 .addReg(RHS);
1101 updateValueMap(ICmp, ResultReg);
1102 return true;
1103}
1104
1105bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1106 const auto *FCmp = cast<FCmpInst>(I);
1107
1108 Register LHS = getRegForValue(FCmp->getOperand(0));
1109 if (LHS == 0)
1110 return false;
1111
1112 Register RHS = getRegForValue(FCmp->getOperand(1));
1113 if (RHS == 0)
1114 return false;
1115
1116 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1117 unsigned Opc;
1118 bool Not = false;
1119 switch (FCmp->getPredicate()) {
1120 case FCmpInst::FCMP_OEQ:
1121 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1122 break;
1123 case FCmpInst::FCMP_UNE:
1124 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1125 break;
1126 case FCmpInst::FCMP_OGT:
1127 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1128 break;
1129 case FCmpInst::FCMP_OGE:
1130 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1131 break;
1132 case FCmpInst::FCMP_OLT:
1133 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1134 break;
1135 case FCmpInst::FCMP_OLE:
1136 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1137 break;
1138 case FCmpInst::FCMP_UGT:
1139 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1140 Not = true;
1141 break;
1142 case FCmpInst::FCMP_UGE:
1143 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1144 Not = true;
1145 break;
1146 case FCmpInst::FCMP_ULT:
1147 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1148 Not = true;
1149 break;
1150 case FCmpInst::FCMP_ULE:
1151 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1152 Not = true;
1153 break;
1154 default:
1155 return false;
1156 }
1157
1158 Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1159 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1160 .addReg(LHS)
1161 .addReg(RHS);
1162
1163 if (Not)
1164 ResultReg = notValue(ResultReg);
1165
1166 updateValueMap(FCmp, ResultReg);
1167 return true;
1168}
1169
1170bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1171 // Target-independent code can handle this, except it doesn't set the dead
1172 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1173 // to satisfy code that expects this of isBitcast() instructions.
1174 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1175 EVT RetVT = TLI.getValueType(DL, I->getType());
1176 if (!VT.isSimple() || !RetVT.isSimple())
1177 return false;
1178
1179 Register In = getRegForValue(I->getOperand(0));
1180 if (In == 0)
1181 return false;
1182
1183 if (VT == RetVT) {
1184 // No-op bitcast.
1185 updateValueMap(I, In);
1186 return true;
1187 }
1188
1189 Register Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1190 In);
1191 if (!Reg)
1192 return false;
1193 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1194 --Iter;
1195 assert(Iter->isBitcast());
1196 Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI);
1197 updateValueMap(I, Reg);
1198 return true;
1199}
1200
1201bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1202 const auto *Load = cast<LoadInst>(I);
1203 if (Load->isAtomic())
1204 return false;
1205 if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace()))
1206 return false;
1207 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1208 return false;
1209
1210 Address Addr;
1211 if (!computeAddress(Load->getPointerOperand(), Addr))
1212 return false;
1213
1214 // TODO: Fold a following sign-/zero-extend into the load instruction.
1215
1216 unsigned Opc;
1217 const TargetRegisterClass *RC;
1218 bool A64 = Subtarget->hasAddr64();
1219 switch (getSimpleType(Load->getType())) {
1220 case MVT::i1:
1221 case MVT::i8:
1222 Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1223 RC = &WebAssembly::I32RegClass;
1224 break;
1225 case MVT::i16:
1226 Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1227 RC = &WebAssembly::I32RegClass;
1228 break;
1229 case MVT::i32:
1230 Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1231 RC = &WebAssembly::I32RegClass;
1232 break;
1233 case MVT::i64:
1234 Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1235 RC = &WebAssembly::I64RegClass;
1236 break;
1237 case MVT::f32:
1238 Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1239 RC = &WebAssembly::F32RegClass;
1240 break;
1241 case MVT::f64:
1242 Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1243 RC = &WebAssembly::F64RegClass;
1244 break;
1245 default:
1246 return false;
1247 }
1248
1249 materializeLoadStoreOperands(Addr);
1250
1251 Register ResultReg = createResultReg(RC);
1252 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc),
1253 ResultReg);
1254
1255 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1256
1257 updateValueMap(Load, ResultReg);
1258 return true;
1259}
1260
1261bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1262 const auto *Store = cast<StoreInst>(I);
1263 if (Store->isAtomic())
1264 return false;
1265 if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace()))
1266 return false;
1267 if (!Subtarget->hasSIMD128() &&
1268 Store->getValueOperand()->getType()->isVectorTy())
1269 return false;
1270
1271 Address Addr;
1272 if (!computeAddress(Store->getPointerOperand(), Addr))
1273 return false;
1274
1275 unsigned Opc;
1276 bool VTIsi1 = false;
1277 bool A64 = Subtarget->hasAddr64();
1278 switch (getSimpleType(Store->getValueOperand()->getType())) {
1279 case MVT::i1:
1280 VTIsi1 = true;
1281 [[fallthrough]];
1282 case MVT::i8:
1283 Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1284 break;
1285 case MVT::i16:
1286 Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1287 break;
1288 case MVT::i32:
1289 Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1290 break;
1291 case MVT::i64:
1292 Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1293 break;
1294 case MVT::f32:
1295 Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1296 break;
1297 case MVT::f64:
1298 Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1299 break;
1300 default:
1301 return false;
1302 }
1303
1304 materializeLoadStoreOperands(Addr);
1305
1306 Register ValueReg = getRegForValue(Store->getValueOperand());
1307 if (ValueReg == 0)
1308 return false;
1309 if (VTIsi1)
1310 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1311
1312 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
1313
1314 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1315
1316 MIB.addReg(ValueReg);
1317 return true;
1318}
1319
1320bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1321 const auto *Br = cast<BranchInst>(I);
1322 if (Br->isUnconditional()) {
1323 MachineBasicBlock *MSucc = FuncInfo.getMBB(Br->getSuccessor(0));
1324 fastEmitBranch(MSucc, Br->getDebugLoc());
1325 return true;
1326 }
1327
1328 MachineBasicBlock *TBB = FuncInfo.getMBB(Br->getSuccessor(0));
1329 MachineBasicBlock *FBB = FuncInfo.getMBB(Br->getSuccessor(1));
1330
1331 bool Not;
1332 unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1333 if (CondReg == 0)
1334 return false;
1335
1336 unsigned Opc = WebAssembly::BR_IF;
1337 if (Not)
1338 Opc = WebAssembly::BR_UNLESS;
1339
1340 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc))
1341 .addMBB(TBB)
1342 .addReg(CondReg);
1343
1344 finishCondBranch(Br->getParent(), TBB, FBB);
1345 return true;
1346}
1347
1348bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1349 if (!FuncInfo.CanLowerReturn)
1350 return false;
1351
1352 const auto *Ret = cast<ReturnInst>(I);
1353
1354 if (Ret->getNumOperands() == 0) {
1355 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1356 TII.get(WebAssembly::RETURN));
1357 return true;
1358 }
1359
1360 // TODO: support multiple return in FastISel
1361 if (Ret->getNumOperands() > 1)
1362 return false;
1363
1364 Value *RV = Ret->getOperand(0);
1365 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1366 return false;
1367
1368 switch (getSimpleType(RV->getType())) {
1369 case MVT::i1:
1370 case MVT::i8:
1371 case MVT::i16:
1372 case MVT::i32:
1373 case MVT::i64:
1374 case MVT::f32:
1375 case MVT::f64:
1376 case MVT::v16i8:
1377 case MVT::v8i16:
1378 case MVT::v4i32:
1379 case MVT::v2i64:
1380 case MVT::v4f32:
1381 case MVT::v2f64:
1382 case MVT::funcref:
1383 case MVT::externref:
1384 case MVT::exnref:
1385 break;
1386 default:
1387 return false;
1388 }
1389
1390 unsigned Reg;
1391 if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1392 Reg = getRegForSignedValue(RV);
1393 else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1394 Reg = getRegForUnsignedValue(RV);
1395 else
1396 Reg = getRegForValue(RV);
1397
1398 if (Reg == 0)
1399 return false;
1400
1401 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1402 TII.get(WebAssembly::RETURN))
1403 .addReg(Reg);
1404 return true;
1405}
1406
1407bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1408 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1409 TII.get(WebAssembly::UNREACHABLE));
1410 return true;
1411}
1412
1413bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1414 switch (I->getOpcode()) {
1415 case Instruction::Call:
1416 if (selectCall(I))
1417 return true;
1418 break;
1419 case Instruction::Select:
1420 return selectSelect(I);
1421 case Instruction::Trunc:
1422 return selectTrunc(I);
1423 case Instruction::ZExt:
1424 return selectZExt(I);
1425 case Instruction::SExt:
1426 return selectSExt(I);
1427 case Instruction::ICmp:
1428 return selectICmp(I);
1429 case Instruction::FCmp:
1430 return selectFCmp(I);
1431 case Instruction::BitCast:
1432 return selectBitCast(I);
1433 case Instruction::Load:
1434 return selectLoad(I);
1435 case Instruction::Store:
1436 return selectStore(I);
1437 case Instruction::Br:
1438 return selectBr(I);
1439 case Instruction::Ret:
1440 return selectRet(I);
1441 case Instruction::Unreachable:
1442 return selectUnreachable(I);
1443 default:
1444 break;
1445 }
1446
1447 // Fall back to target-independent instruction selection.
1448 return selectOperator(I, I->getOpcode());
1449}
1450
1452 const TargetLibraryInfo *LibInfo) {
1453 return new WebAssemblyFastISel(FuncInfo, LibInfo);
1454}
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:55
#define I(x, y, z)
Definition MD5.cpp:58
#define G(x, y, z)
Definition MD5.cpp:56
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 unsigned 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:19
TypeSize getElementOffset(unsigned Idx) const
Definition DataLayout.h:652
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:477
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:649
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:548
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:565
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:853
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