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