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