Revert r354244 "[DAGCombiner] Eliminate dead stores to stack."
[llvm-complete.git] / lib / Target / WebAssembly / WebAssemblyFastISel.cpp
blob15df3d4ba0653d225e5a77f44cc2f442bbf2bcd4
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 "WebAssembly.h"
20 #include "WebAssemblyMachineFunctionInfo.h"
21 #include "WebAssemblySubtarget.h"
22 #include "WebAssemblyTargetMachine.h"
23 #include "llvm/Analysis/BranchProbabilityInfo.h"
24 #include "llvm/CodeGen/FastISel.h"
25 #include "llvm/CodeGen/FunctionLoweringInfo.h"
26 #include "llvm/CodeGen/MachineConstantPool.h"
27 #include "llvm/CodeGen/MachineFrameInfo.h"
28 #include "llvm/CodeGen/MachineInstrBuilder.h"
29 #include "llvm/CodeGen/MachineRegisterInfo.h"
30 #include "llvm/IR/DataLayout.h"
31 #include "llvm/IR/DerivedTypes.h"
32 #include "llvm/IR/Function.h"
33 #include "llvm/IR/GetElementPtrTypeIterator.h"
34 #include "llvm/IR/GlobalAlias.h"
35 #include "llvm/IR/GlobalVariable.h"
36 #include "llvm/IR/Instructions.h"
37 #include "llvm/IR/IntrinsicInst.h"
38 #include "llvm/IR/Operator.h"
39 #include "llvm/IR/PatternMatch.h"
41 using namespace llvm;
42 using namespace PatternMatch;
44 #define DEBUG_TYPE "wasm-fastisel"
46 namespace {
48 class WebAssemblyFastISel final : public FastISel {
49 // All possible address modes.
50 class Address {
51 public:
52 using BaseKind = enum { RegBase, FrameIndexBase };
54 private:
55 BaseKind Kind = RegBase;
56 union {
57 unsigned Reg;
58 int FI;
59 } Base;
61 int64_t Offset = 0;
63 const GlobalValue *GV = nullptr;
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;
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(Base.Reg == 0 && "Overwriting non-zero register");
78 Base.Reg = Reg;
80 unsigned getReg() const {
81 assert(isRegBase() && "Invalid base register access!");
82 return Base.Reg;
84 void setFI(unsigned FI) {
85 assert(isFIBase() && "Invalid base frame index access!");
86 assert(Base.FI == 0 && "Overwriting non-zero frame index");
87 Base.FI = FI;
89 unsigned getFI() const {
90 assert(isFIBase() && "Invalid base frame index access!");
91 return Base.FI;
94 void setOffset(int64_t NewOffset) {
95 assert(NewOffset >= 0 && "Offsets must be non-negative");
96 Offset = NewOffset;
98 int64_t getOffset() const { return Offset; }
99 void setGlobalValue(const GlobalValue *G) { GV = G; }
100 const GlobalValue *getGlobalValue() const { return GV; }
101 bool isSet() const {
102 if (isRegBase()) {
103 return Base.Reg != 0;
104 } else {
105 return Base.FI != 0;
110 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the
111 /// right decision when generating code for different targets.
112 const WebAssemblySubtarget *Subtarget;
113 LLVMContext *Context;
115 private:
116 // Utility helper routines
117 MVT::SimpleValueType getSimpleType(Type *Ty) {
118 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true);
119 return VT.isSimple() ? VT.getSimpleVT().SimpleTy
120 : MVT::INVALID_SIMPLE_VALUE_TYPE;
122 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
123 switch (VT) {
124 case MVT::i1:
125 case MVT::i8:
126 case MVT::i16:
127 return MVT::i32;
128 case MVT::i32:
129 case MVT::i64:
130 case MVT::f32:
131 case MVT::f64:
132 case MVT::ExceptRef:
133 return VT;
134 case MVT::f16:
135 return MVT::f32;
136 case MVT::v16i8:
137 case MVT::v8i16:
138 case MVT::v4i32:
139 case MVT::v4f32:
140 if (Subtarget->hasSIMD128())
141 return VT;
142 break;
143 case MVT::v2i64:
144 case MVT::v2f64:
145 if (Subtarget->hasUnimplementedSIMD128())
146 return VT;
147 break;
148 default:
149 break;
151 return MVT::INVALID_SIMPLE_VALUE_TYPE;
153 bool computeAddress(const Value *Obj, Address &Addr);
154 void materializeLoadStoreOperands(Address &Addr);
155 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
156 MachineMemOperand *MMO);
157 unsigned maskI1Value(unsigned Reg, const Value *V);
158 unsigned getRegForI1Value(const Value *V, bool &Not);
159 unsigned zeroExtendToI32(unsigned Reg, const Value *V,
160 MVT::SimpleValueType From);
161 unsigned signExtendToI32(unsigned Reg, const Value *V,
162 MVT::SimpleValueType From);
163 unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
164 MVT::SimpleValueType To);
165 unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
166 MVT::SimpleValueType To);
167 unsigned getRegForUnsignedValue(const Value *V);
168 unsigned getRegForSignedValue(const Value *V);
169 unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
170 unsigned notValue(unsigned Reg);
171 unsigned copyValue(unsigned Reg);
173 // Backend specific FastISel code.
174 unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
175 unsigned fastMaterializeConstant(const Constant *C) override;
176 bool fastLowerArguments() override;
178 // Selection routines.
179 bool selectCall(const Instruction *I);
180 bool selectSelect(const Instruction *I);
181 bool selectTrunc(const Instruction *I);
182 bool selectZExt(const Instruction *I);
183 bool selectSExt(const Instruction *I);
184 bool selectICmp(const Instruction *I);
185 bool selectFCmp(const Instruction *I);
186 bool selectBitCast(const Instruction *I);
187 bool selectLoad(const Instruction *I);
188 bool selectStore(const Instruction *I);
189 bool selectBr(const Instruction *I);
190 bool selectRet(const Instruction *I);
191 bool selectUnreachable(const Instruction *I);
193 public:
194 // Backend specific FastISel code.
195 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
196 const TargetLibraryInfo *LibInfo)
197 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
198 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
199 Context = &FuncInfo.Fn->getContext();
202 bool fastSelectInstruction(const Instruction *I) override;
204 #include "WebAssemblyGenFastISel.inc"
207 } // end anonymous namespace
209 bool 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.MBBMap[I->getParent()] == FuncInfo.MBB) {
218 Opcode = I->getOpcode();
219 U = I;
221 } else if (const auto *C = dyn_cast<ConstantExpr>(Obj)) {
222 Opcode = C->getOpcode();
223 U = C;
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;
232 if (const auto *GV = dyn_cast<GlobalValue>(Obj)) {
233 if (Addr.getGlobalValue())
234 return false;
235 Addr.setGlobalValue(GV);
236 return true;
239 switch (Opcode) {
240 default:
241 break;
242 case Instruction::BitCast: {
243 // Look through bitcasts.
244 return computeAddress(U->getOperand(0), Addr);
246 case Instruction::IntToPtr: {
247 // Look past no-op inttoptrs.
248 if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
249 TLI.getPointerTy(DL))
250 return computeAddress(U->getOperand(0), Addr);
251 break;
253 case Instruction::PtrToInt: {
254 // Look past no-op ptrtoints.
255 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
256 return computeAddress(U->getOperand(0), Addr);
257 break;
259 case Instruction::GetElementPtr: {
260 Address SavedAddr = Addr;
261 uint64_t TmpOffset = Addr.getOffset();
262 // Non-inbounds geps can wrap; wasm's offsets can't.
263 if (!cast<GEPOperator>(U)->isInBounds())
264 goto unsupported_gep;
265 // Iterate through the GEP folding the constants into offsets where
266 // we can.
267 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
268 GTI != E; ++GTI) {
269 const Value *Op = GTI.getOperand();
270 if (StructType *STy = GTI.getStructTypeOrNull()) {
271 const StructLayout *SL = DL.getStructLayout(STy);
272 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
273 TmpOffset += SL->getElementOffset(Idx);
274 } else {
275 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
276 for (;;) {
277 if (const auto *CI = dyn_cast<ConstantInt>(Op)) {
278 // Constant-offset addressing.
279 TmpOffset += CI->getSExtValue() * S;
280 break;
282 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
283 // An unscaled add of a register. Set it as the new base.
284 unsigned Reg = getRegForValue(Op);
285 if (Reg == 0)
286 return false;
287 Addr.setReg(Reg);
288 break;
290 if (canFoldAddIntoGEP(U, Op)) {
291 // A compatible add with a constant operand. Fold the constant.
292 auto *CI = cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
293 TmpOffset += CI->getSExtValue() * S;
294 // Iterate on the other operand.
295 Op = cast<AddOperator>(Op)->getOperand(0);
296 continue;
298 // Unsupported
299 goto unsupported_gep;
303 // Don't fold in negative offsets.
304 if (int64_t(TmpOffset) >= 0) {
305 // Try to grab the base operand now.
306 Addr.setOffset(TmpOffset);
307 if (computeAddress(U->getOperand(0), Addr))
308 return true;
310 // We failed, restore everything and try the other options.
311 Addr = SavedAddr;
312 unsupported_gep:
313 break;
315 case Instruction::Alloca: {
316 const auto *AI = cast<AllocaInst>(Obj);
317 DenseMap<const AllocaInst *, int>::iterator SI =
318 FuncInfo.StaticAllocaMap.find(AI);
319 if (SI != FuncInfo.StaticAllocaMap.end()) {
320 if (Addr.isSet()) {
321 return false;
323 Addr.setKind(Address::FrameIndexBase);
324 Addr.setFI(SI->second);
325 return true;
327 break;
329 case Instruction::Add: {
330 // Adds of constants are common and easy enough.
331 const Value *LHS = U->getOperand(0);
332 const Value *RHS = U->getOperand(1);
334 if (isa<ConstantInt>(LHS))
335 std::swap(LHS, RHS);
337 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
338 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
339 if (int64_t(TmpOffset) >= 0) {
340 Addr.setOffset(TmpOffset);
341 return computeAddress(LHS, Addr);
345 Address Backup = Addr;
346 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
347 return true;
348 Addr = Backup;
350 break;
352 case Instruction::Sub: {
353 // Subs of constants are common and easy enough.
354 const Value *LHS = U->getOperand(0);
355 const Value *RHS = U->getOperand(1);
357 if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
358 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
359 if (TmpOffset >= 0) {
360 Addr.setOffset(TmpOffset);
361 return computeAddress(LHS, Addr);
364 break;
367 if (Addr.isSet()) {
368 return false;
370 unsigned Reg = getRegForValue(Obj);
371 if (Reg == 0)
372 return false;
373 Addr.setReg(Reg);
374 return Addr.getReg() != 0;
377 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
378 if (Addr.isRegBase()) {
379 unsigned Reg = Addr.getReg();
380 if (Reg == 0) {
381 Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
382 : &WebAssembly::I32RegClass);
383 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
384 : WebAssembly::CONST_I32;
385 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg)
386 .addImm(0);
387 Addr.setReg(Reg);
392 void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
393 const MachineInstrBuilder &MIB,
394 MachineMemOperand *MMO) {
395 // Set the alignment operand (this is rewritten in SetP2AlignOperands).
396 // TODO: Disable SetP2AlignOperands for FastISel and just do it here.
397 MIB.addImm(0);
399 if (const GlobalValue *GV = Addr.getGlobalValue())
400 MIB.addGlobalAddress(GV, Addr.getOffset());
401 else
402 MIB.addImm(Addr.getOffset());
404 if (Addr.isRegBase())
405 MIB.addReg(Addr.getReg());
406 else
407 MIB.addFrameIndex(Addr.getFI());
409 MIB.addMemOperand(MMO);
412 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
413 return zeroExtendToI32(Reg, V, MVT::i1);
416 unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) {
417 if (const auto *ICmp = dyn_cast<ICmpInst>(V))
418 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
419 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) {
420 Not = ICmp->isTrueWhenEqual();
421 return getRegForValue(ICmp->getOperand(0));
424 Value *NotV;
425 if (match(V, m_Not(m_Value(NotV))) && V->getType()->isIntegerTy(32)) {
426 Not = true;
427 return getRegForValue(NotV);
430 Not = false;
431 unsigned Reg = getRegForValue(V);
432 if (Reg == 0)
433 return 0;
434 return maskI1Value(Reg, V);
437 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
438 MVT::SimpleValueType From) {
439 if (Reg == 0)
440 return 0;
442 switch (From) {
443 case MVT::i1:
444 // If the value is naturally an i1, we don't need to mask it. We only know
445 // if a value is naturally an i1 if it is definitely lowered by FastISel,
446 // not a DAG ISel fallback.
447 if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
448 return copyValue(Reg);
449 break;
450 case MVT::i8:
451 case MVT::i16:
452 break;
453 case MVT::i32:
454 return copyValue(Reg);
455 default:
456 return 0;
459 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
460 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
461 TII.get(WebAssembly::CONST_I32), Imm)
462 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
464 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
465 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
466 TII.get(WebAssembly::AND_I32), Result)
467 .addReg(Reg)
468 .addReg(Imm);
470 return Result;
473 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
474 MVT::SimpleValueType From) {
475 if (Reg == 0)
476 return 0;
478 switch (From) {
479 case MVT::i1:
480 case MVT::i8:
481 case MVT::i16:
482 break;
483 case MVT::i32:
484 return copyValue(Reg);
485 default:
486 return 0;
489 unsigned Imm = createResultReg(&WebAssembly::I32RegClass);
490 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
491 TII.get(WebAssembly::CONST_I32), Imm)
492 .addImm(32 - MVT(From).getSizeInBits());
494 unsigned Left = createResultReg(&WebAssembly::I32RegClass);
495 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
496 TII.get(WebAssembly::SHL_I32), Left)
497 .addReg(Reg)
498 .addReg(Imm);
500 unsigned Right = createResultReg(&WebAssembly::I32RegClass);
501 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
502 TII.get(WebAssembly::SHR_S_I32), Right)
503 .addReg(Left)
504 .addReg(Imm);
506 return Right;
509 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
510 MVT::SimpleValueType From,
511 MVT::SimpleValueType To) {
512 if (To == MVT::i64) {
513 if (From == MVT::i64)
514 return copyValue(Reg);
516 Reg = zeroExtendToI32(Reg, V, From);
518 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
519 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
520 TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
521 .addReg(Reg);
522 return Result;
525 return zeroExtendToI32(Reg, V, From);
528 unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
529 MVT::SimpleValueType From,
530 MVT::SimpleValueType To) {
531 if (To == MVT::i64) {
532 if (From == MVT::i64)
533 return copyValue(Reg);
535 Reg = signExtendToI32(Reg, V, From);
537 unsigned Result = createResultReg(&WebAssembly::I64RegClass);
538 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
539 TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
540 .addReg(Reg);
541 return Result;
544 return signExtendToI32(Reg, V, From);
547 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
548 MVT::SimpleValueType From = getSimpleType(V->getType());
549 MVT::SimpleValueType To = getLegalType(From);
550 unsigned VReg = getRegForValue(V);
551 if (VReg == 0)
552 return 0;
553 return zeroExtend(VReg, V, From, To);
556 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
557 MVT::SimpleValueType From = getSimpleType(V->getType());
558 MVT::SimpleValueType To = getLegalType(From);
559 unsigned VReg = getRegForValue(V);
560 if (VReg == 0)
561 return 0;
562 return signExtend(VReg, V, From, To);
565 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
566 bool IsSigned) {
567 return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
570 unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
571 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
573 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass);
574 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
575 TII.get(WebAssembly::EQZ_I32), NotReg)
576 .addReg(Reg);
577 return NotReg;
580 unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
581 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg));
582 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(WebAssembly::COPY),
583 ResultReg)
584 .addReg(Reg);
585 return ResultReg;
588 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
589 DenseMap<const AllocaInst *, int>::iterator SI =
590 FuncInfo.StaticAllocaMap.find(AI);
592 if (SI != FuncInfo.StaticAllocaMap.end()) {
593 unsigned ResultReg =
594 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
595 : &WebAssembly::I32RegClass);
596 unsigned Opc =
597 Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
598 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
599 .addFrameIndex(SI->second);
600 return ResultReg;
603 return 0;
606 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
607 if (const auto *GV = dyn_cast<GlobalValue>(C)) {
608 unsigned ResultReg =
609 createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
610 : &WebAssembly::I32RegClass);
611 unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
612 : WebAssembly::CONST_I32;
613 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
614 .addGlobalAddress(GV);
615 return ResultReg;
618 // Let target-independent code handle it.
619 return 0;
622 bool WebAssemblyFastISel::fastLowerArguments() {
623 if (!FuncInfo.CanLowerReturn)
624 return false;
626 const Function *F = FuncInfo.Fn;
627 if (F->isVarArg())
628 return false;
630 unsigned I = 0;
631 for (auto const &Arg : F->args()) {
632 const AttributeList &Attrs = F->getAttributes();
633 if (Attrs.hasParamAttribute(I, Attribute::ByVal) ||
634 Attrs.hasParamAttribute(I, Attribute::SwiftSelf) ||
635 Attrs.hasParamAttribute(I, Attribute::SwiftError) ||
636 Attrs.hasParamAttribute(I, Attribute::InAlloca) ||
637 Attrs.hasParamAttribute(I, Attribute::Nest))
638 return false;
640 Type *ArgTy = Arg.getType();
641 if (ArgTy->isStructTy() || ArgTy->isArrayTy())
642 return false;
643 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
644 return false;
646 unsigned Opc;
647 const TargetRegisterClass *RC;
648 switch (getSimpleType(ArgTy)) {
649 case MVT::i1:
650 case MVT::i8:
651 case MVT::i16:
652 case MVT::i32:
653 Opc = WebAssembly::ARGUMENT_i32;
654 RC = &WebAssembly::I32RegClass;
655 break;
656 case MVT::i64:
657 Opc = WebAssembly::ARGUMENT_i64;
658 RC = &WebAssembly::I64RegClass;
659 break;
660 case MVT::f32:
661 Opc = WebAssembly::ARGUMENT_f32;
662 RC = &WebAssembly::F32RegClass;
663 break;
664 case MVT::f64:
665 Opc = WebAssembly::ARGUMENT_f64;
666 RC = &WebAssembly::F64RegClass;
667 break;
668 case MVT::v16i8:
669 Opc = WebAssembly::ARGUMENT_v16i8;
670 RC = &WebAssembly::V128RegClass;
671 break;
672 case MVT::v8i16:
673 Opc = WebAssembly::ARGUMENT_v8i16;
674 RC = &WebAssembly::V128RegClass;
675 break;
676 case MVT::v4i32:
677 Opc = WebAssembly::ARGUMENT_v4i32;
678 RC = &WebAssembly::V128RegClass;
679 break;
680 case MVT::v2i64:
681 Opc = WebAssembly::ARGUMENT_v2i64;
682 RC = &WebAssembly::V128RegClass;
683 break;
684 case MVT::v4f32:
685 Opc = WebAssembly::ARGUMENT_v4f32;
686 RC = &WebAssembly::V128RegClass;
687 break;
688 case MVT::v2f64:
689 Opc = WebAssembly::ARGUMENT_v2f64;
690 RC = &WebAssembly::V128RegClass;
691 break;
692 case MVT::ExceptRef:
693 Opc = WebAssembly::ARGUMENT_ExceptRef;
694 RC = &WebAssembly::EXCEPT_REFRegClass;
695 break;
696 default:
697 return false;
699 unsigned ResultReg = createResultReg(RC);
700 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
701 .addImm(I);
702 updateValueMap(&Arg, ResultReg);
704 ++I;
707 MRI.addLiveIn(WebAssembly::ARGUMENTS);
709 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
710 for (auto const &Arg : F->args()) {
711 MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
712 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
713 MFI->clearParamsAndResults();
714 return false;
716 MFI->addParam(ArgTy);
719 if (!F->getReturnType()->isVoidTy()) {
720 MVT::SimpleValueType RetTy =
721 getLegalType(getSimpleType(F->getReturnType()));
722 if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
723 MFI->clearParamsAndResults();
724 return false;
726 MFI->addResult(RetTy);
729 return true;
732 bool WebAssemblyFastISel::selectCall(const Instruction *I) {
733 const auto *Call = cast<CallInst>(I);
735 if (Call->isMustTailCall() || Call->isInlineAsm() ||
736 Call->getFunctionType()->isVarArg())
737 return false;
739 Function *Func = Call->getCalledFunction();
740 if (Func && Func->isIntrinsic())
741 return false;
743 bool IsDirect = Func != nullptr;
744 if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue()))
745 return false;
747 FunctionType *FuncTy = Call->getFunctionType();
748 unsigned Opc;
749 bool IsVoid = FuncTy->getReturnType()->isVoidTy();
750 unsigned ResultReg;
751 if (IsVoid) {
752 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID;
753 } else {
754 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
755 return false;
757 MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
758 switch (RetTy) {
759 case MVT::i1:
760 case MVT::i8:
761 case MVT::i16:
762 case MVT::i32:
763 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32;
764 ResultReg = createResultReg(&WebAssembly::I32RegClass);
765 break;
766 case MVT::i64:
767 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64;
768 ResultReg = createResultReg(&WebAssembly::I64RegClass);
769 break;
770 case MVT::f32:
771 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32;
772 ResultReg = createResultReg(&WebAssembly::F32RegClass);
773 break;
774 case MVT::f64:
775 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64;
776 ResultReg = createResultReg(&WebAssembly::F64RegClass);
777 break;
778 case MVT::v16i8:
779 Opc = IsDirect ? WebAssembly::CALL_v16i8
780 : WebAssembly::PCALL_INDIRECT_v16i8;
781 ResultReg = createResultReg(&WebAssembly::V128RegClass);
782 break;
783 case MVT::v8i16:
784 Opc = IsDirect ? WebAssembly::CALL_v8i16
785 : WebAssembly::PCALL_INDIRECT_v8i16;
786 ResultReg = createResultReg(&WebAssembly::V128RegClass);
787 break;
788 case MVT::v4i32:
789 Opc = IsDirect ? WebAssembly::CALL_v4i32
790 : WebAssembly::PCALL_INDIRECT_v4i32;
791 ResultReg = createResultReg(&WebAssembly::V128RegClass);
792 break;
793 case MVT::v2i64:
794 Opc = IsDirect ? WebAssembly::CALL_v2i64
795 : WebAssembly::PCALL_INDIRECT_v2i64;
796 ResultReg = createResultReg(&WebAssembly::V128RegClass);
797 break;
798 case MVT::v4f32:
799 Opc = IsDirect ? WebAssembly::CALL_v4f32
800 : WebAssembly::PCALL_INDIRECT_v4f32;
801 ResultReg = createResultReg(&WebAssembly::V128RegClass);
802 break;
803 case MVT::v2f64:
804 Opc = IsDirect ? WebAssembly::CALL_v2f64
805 : WebAssembly::PCALL_INDIRECT_v2f64;
806 ResultReg = createResultReg(&WebAssembly::V128RegClass);
807 break;
808 case MVT::ExceptRef:
809 Opc = IsDirect ? WebAssembly::CALL_EXCEPT_REF
810 : WebAssembly::PCALL_INDIRECT_EXCEPT_REF;
811 ResultReg = createResultReg(&WebAssembly::EXCEPT_REFRegClass);
812 break;
813 default:
814 return false;
818 SmallVector<unsigned, 8> Args;
819 for (unsigned I = 0, E = Call->getNumArgOperands(); I < E; ++I) {
820 Value *V = Call->getArgOperand(I);
821 MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
822 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
823 return false;
825 const AttributeList &Attrs = Call->getAttributes();
826 if (Attrs.hasParamAttribute(I, Attribute::ByVal) ||
827 Attrs.hasParamAttribute(I, Attribute::SwiftSelf) ||
828 Attrs.hasParamAttribute(I, Attribute::SwiftError) ||
829 Attrs.hasParamAttribute(I, Attribute::InAlloca) ||
830 Attrs.hasParamAttribute(I, Attribute::Nest))
831 return false;
833 unsigned Reg;
835 if (Attrs.hasParamAttribute(I, Attribute::SExt))
836 Reg = getRegForSignedValue(V);
837 else if (Attrs.hasParamAttribute(I, Attribute::ZExt))
838 Reg = getRegForUnsignedValue(V);
839 else
840 Reg = getRegForValue(V);
842 if (Reg == 0)
843 return false;
845 Args.push_back(Reg);
848 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
850 if (!IsVoid)
851 MIB.addReg(ResultReg, RegState::Define);
853 if (IsDirect)
854 MIB.addGlobalAddress(Func);
855 else {
856 unsigned Reg = getRegForValue(Call->getCalledValue());
857 if (Reg == 0)
858 return false;
859 MIB.addReg(Reg);
862 for (unsigned ArgReg : Args)
863 MIB.addReg(ArgReg);
865 if (!IsVoid)
866 updateValueMap(Call, ResultReg);
867 return true;
870 bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
871 const auto *Select = cast<SelectInst>(I);
873 bool Not;
874 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not);
875 if (CondReg == 0)
876 return false;
878 unsigned TrueReg = getRegForValue(Select->getTrueValue());
879 if (TrueReg == 0)
880 return false;
882 unsigned FalseReg = getRegForValue(Select->getFalseValue());
883 if (FalseReg == 0)
884 return false;
886 if (Not)
887 std::swap(TrueReg, FalseReg);
889 unsigned Opc;
890 const TargetRegisterClass *RC;
891 switch (getSimpleType(Select->getType())) {
892 case MVT::i1:
893 case MVT::i8:
894 case MVT::i16:
895 case MVT::i32:
896 Opc = WebAssembly::SELECT_I32;
897 RC = &WebAssembly::I32RegClass;
898 break;
899 case MVT::i64:
900 Opc = WebAssembly::SELECT_I64;
901 RC = &WebAssembly::I64RegClass;
902 break;
903 case MVT::f32:
904 Opc = WebAssembly::SELECT_F32;
905 RC = &WebAssembly::F32RegClass;
906 break;
907 case MVT::f64:
908 Opc = WebAssembly::SELECT_F64;
909 RC = &WebAssembly::F64RegClass;
910 break;
911 case MVT::ExceptRef:
912 Opc = WebAssembly::SELECT_EXCEPT_REF;
913 RC = &WebAssembly::EXCEPT_REFRegClass;
914 break;
915 default:
916 return false;
919 unsigned ResultReg = createResultReg(RC);
920 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
921 .addReg(TrueReg)
922 .addReg(FalseReg)
923 .addReg(CondReg);
925 updateValueMap(Select, ResultReg);
926 return true;
929 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
930 const auto *Trunc = cast<TruncInst>(I);
932 unsigned Reg = getRegForValue(Trunc->getOperand(0));
933 if (Reg == 0)
934 return false;
936 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
937 unsigned Result = createResultReg(&WebAssembly::I32RegClass);
938 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
939 TII.get(WebAssembly::I32_WRAP_I64), Result)
940 .addReg(Reg);
941 Reg = Result;
944 updateValueMap(Trunc, Reg);
945 return true;
948 bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
949 const auto *ZExt = cast<ZExtInst>(I);
951 const Value *Op = ZExt->getOperand(0);
952 MVT::SimpleValueType From = getSimpleType(Op->getType());
953 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
954 unsigned In = getRegForValue(Op);
955 if (In == 0)
956 return false;
957 unsigned Reg = zeroExtend(In, Op, From, To);
958 if (Reg == 0)
959 return false;
961 updateValueMap(ZExt, Reg);
962 return true;
965 bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
966 const auto *SExt = cast<SExtInst>(I);
968 const Value *Op = SExt->getOperand(0);
969 MVT::SimpleValueType From = getSimpleType(Op->getType());
970 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
971 unsigned In = getRegForValue(Op);
972 if (In == 0)
973 return false;
974 unsigned Reg = signExtend(In, Op, From, To);
975 if (Reg == 0)
976 return false;
978 updateValueMap(SExt, Reg);
979 return true;
982 bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
983 const auto *ICmp = cast<ICmpInst>(I);
985 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
986 unsigned Opc;
987 bool IsSigned = false;
988 switch (ICmp->getPredicate()) {
989 case ICmpInst::ICMP_EQ:
990 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
991 break;
992 case ICmpInst::ICMP_NE:
993 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
994 break;
995 case ICmpInst::ICMP_UGT:
996 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
997 break;
998 case ICmpInst::ICMP_UGE:
999 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1000 break;
1001 case ICmpInst::ICMP_ULT:
1002 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1003 break;
1004 case ICmpInst::ICMP_ULE:
1005 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1006 break;
1007 case ICmpInst::ICMP_SGT:
1008 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1009 IsSigned = true;
1010 break;
1011 case ICmpInst::ICMP_SGE:
1012 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1013 IsSigned = true;
1014 break;
1015 case ICmpInst::ICMP_SLT:
1016 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1017 IsSigned = true;
1018 break;
1019 case ICmpInst::ICMP_SLE:
1020 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1021 IsSigned = true;
1022 break;
1023 default:
1024 return false;
1027 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1028 if (LHS == 0)
1029 return false;
1031 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1032 if (RHS == 0)
1033 return false;
1035 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1036 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1037 .addReg(LHS)
1038 .addReg(RHS);
1039 updateValueMap(ICmp, ResultReg);
1040 return true;
1043 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1044 const auto *FCmp = cast<FCmpInst>(I);
1046 unsigned LHS = getRegForValue(FCmp->getOperand(0));
1047 if (LHS == 0)
1048 return false;
1050 unsigned RHS = getRegForValue(FCmp->getOperand(1));
1051 if (RHS == 0)
1052 return false;
1054 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1055 unsigned Opc;
1056 bool Not = false;
1057 switch (FCmp->getPredicate()) {
1058 case FCmpInst::FCMP_OEQ:
1059 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1060 break;
1061 case FCmpInst::FCMP_UNE:
1062 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1063 break;
1064 case FCmpInst::FCMP_OGT:
1065 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1066 break;
1067 case FCmpInst::FCMP_OGE:
1068 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1069 break;
1070 case FCmpInst::FCMP_OLT:
1071 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1072 break;
1073 case FCmpInst::FCMP_OLE:
1074 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1075 break;
1076 case FCmpInst::FCMP_UGT:
1077 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1078 Not = true;
1079 break;
1080 case FCmpInst::FCMP_UGE:
1081 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1082 Not = true;
1083 break;
1084 case FCmpInst::FCMP_ULT:
1085 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1086 Not = true;
1087 break;
1088 case FCmpInst::FCMP_ULE:
1089 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1090 Not = true;
1091 break;
1092 default:
1093 return false;
1096 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass);
1097 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg)
1098 .addReg(LHS)
1099 .addReg(RHS);
1101 if (Not)
1102 ResultReg = notValue(ResultReg);
1104 updateValueMap(FCmp, ResultReg);
1105 return true;
1108 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1109 // Target-independent code can handle this, except it doesn't set the dead
1110 // flag on the ARGUMENTS clobber, so we have to do that manually in order
1111 // to satisfy code that expects this of isBitcast() instructions.
1112 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1113 EVT RetVT = TLI.getValueType(DL, I->getType());
1114 if (!VT.isSimple() || !RetVT.isSimple())
1115 return false;
1117 unsigned In = getRegForValue(I->getOperand(0));
1118 if (In == 0)
1119 return false;
1121 if (VT == RetVT) {
1122 // No-op bitcast.
1123 updateValueMap(I, In);
1124 return true;
1127 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1128 In, I->getOperand(0)->hasOneUse());
1129 if (!Reg)
1130 return false;
1131 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1132 --Iter;
1133 assert(Iter->isBitcast());
1134 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI);
1135 updateValueMap(I, Reg);
1136 return true;
1139 bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1140 const auto *Load = cast<LoadInst>(I);
1141 if (Load->isAtomic())
1142 return false;
1143 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1144 return false;
1146 Address Addr;
1147 if (!computeAddress(Load->getPointerOperand(), Addr))
1148 return false;
1150 // TODO: Fold a following sign-/zero-extend into the load instruction.
1152 unsigned Opc;
1153 const TargetRegisterClass *RC;
1154 switch (getSimpleType(Load->getType())) {
1155 case MVT::i1:
1156 case MVT::i8:
1157 Opc = WebAssembly::LOAD8_U_I32;
1158 RC = &WebAssembly::I32RegClass;
1159 break;
1160 case MVT::i16:
1161 Opc = WebAssembly::LOAD16_U_I32;
1162 RC = &WebAssembly::I32RegClass;
1163 break;
1164 case MVT::i32:
1165 Opc = WebAssembly::LOAD_I32;
1166 RC = &WebAssembly::I32RegClass;
1167 break;
1168 case MVT::i64:
1169 Opc = WebAssembly::LOAD_I64;
1170 RC = &WebAssembly::I64RegClass;
1171 break;
1172 case MVT::f32:
1173 Opc = WebAssembly::LOAD_F32;
1174 RC = &WebAssembly::F32RegClass;
1175 break;
1176 case MVT::f64:
1177 Opc = WebAssembly::LOAD_F64;
1178 RC = &WebAssembly::F64RegClass;
1179 break;
1180 default:
1181 return false;
1184 materializeLoadStoreOperands(Addr);
1186 unsigned ResultReg = createResultReg(RC);
1187 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
1188 ResultReg);
1190 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1192 updateValueMap(Load, ResultReg);
1193 return true;
1196 bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1197 const auto *Store = cast<StoreInst>(I);
1198 if (Store->isAtomic())
1199 return false;
1200 if (!Subtarget->hasSIMD128() &&
1201 Store->getValueOperand()->getType()->isVectorTy())
1202 return false;
1204 Address Addr;
1205 if (!computeAddress(Store->getPointerOperand(), Addr))
1206 return false;
1208 unsigned Opc;
1209 bool VTIsi1 = false;
1210 switch (getSimpleType(Store->getValueOperand()->getType())) {
1211 case MVT::i1:
1212 VTIsi1 = true;
1213 LLVM_FALLTHROUGH;
1214 case MVT::i8:
1215 Opc = WebAssembly::STORE8_I32;
1216 break;
1217 case MVT::i16:
1218 Opc = WebAssembly::STORE16_I32;
1219 break;
1220 case MVT::i32:
1221 Opc = WebAssembly::STORE_I32;
1222 break;
1223 case MVT::i64:
1224 Opc = WebAssembly::STORE_I64;
1225 break;
1226 case MVT::f32:
1227 Opc = WebAssembly::STORE_F32;
1228 break;
1229 case MVT::f64:
1230 Opc = WebAssembly::STORE_F64;
1231 break;
1232 default:
1233 return false;
1236 materializeLoadStoreOperands(Addr);
1238 unsigned ValueReg = getRegForValue(Store->getValueOperand());
1239 if (ValueReg == 0)
1240 return false;
1241 if (VTIsi1)
1242 ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1244 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc));
1246 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1248 MIB.addReg(ValueReg);
1249 return true;
1252 bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1253 const auto *Br = cast<BranchInst>(I);
1254 if (Br->isUnconditional()) {
1255 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1256 fastEmitBranch(MSucc, Br->getDebugLoc());
1257 return true;
1260 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1261 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1263 bool Not;
1264 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not);
1265 if (CondReg == 0)
1266 return false;
1268 unsigned Opc = WebAssembly::BR_IF;
1269 if (Not)
1270 Opc = WebAssembly::BR_UNLESS;
1272 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
1273 .addMBB(TBB)
1274 .addReg(CondReg);
1276 finishCondBranch(Br->getParent(), TBB, FBB);
1277 return true;
1280 bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1281 if (!FuncInfo.CanLowerReturn)
1282 return false;
1284 const auto *Ret = cast<ReturnInst>(I);
1286 if (Ret->getNumOperands() == 0) {
1287 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1288 TII.get(WebAssembly::RETURN_VOID));
1289 return true;
1292 Value *RV = Ret->getOperand(0);
1293 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1294 return false;
1296 unsigned Opc;
1297 switch (getSimpleType(RV->getType())) {
1298 case MVT::i1:
1299 case MVT::i8:
1300 case MVT::i16:
1301 case MVT::i32:
1302 Opc = WebAssembly::RETURN_I32;
1303 break;
1304 case MVT::i64:
1305 Opc = WebAssembly::RETURN_I64;
1306 break;
1307 case MVT::f32:
1308 Opc = WebAssembly::RETURN_F32;
1309 break;
1310 case MVT::f64:
1311 Opc = WebAssembly::RETURN_F64;
1312 break;
1313 case MVT::v16i8:
1314 Opc = WebAssembly::RETURN_v16i8;
1315 break;
1316 case MVT::v8i16:
1317 Opc = WebAssembly::RETURN_v8i16;
1318 break;
1319 case MVT::v4i32:
1320 Opc = WebAssembly::RETURN_v4i32;
1321 break;
1322 case MVT::v2i64:
1323 Opc = WebAssembly::RETURN_v2i64;
1324 break;
1325 case MVT::v4f32:
1326 Opc = WebAssembly::RETURN_v4f32;
1327 break;
1328 case MVT::v2f64:
1329 Opc = WebAssembly::RETURN_v2f64;
1330 break;
1331 case MVT::ExceptRef:
1332 Opc = WebAssembly::RETURN_EXCEPT_REF;
1333 break;
1334 default:
1335 return false;
1338 unsigned Reg;
1339 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt))
1340 Reg = getRegForSignedValue(RV);
1341 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt))
1342 Reg = getRegForUnsignedValue(RV);
1343 else
1344 Reg = getRegForValue(RV);
1346 if (Reg == 0)
1347 return false;
1349 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg);
1350 return true;
1353 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1354 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
1355 TII.get(WebAssembly::UNREACHABLE));
1356 return true;
1359 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1360 switch (I->getOpcode()) {
1361 case Instruction::Call:
1362 if (selectCall(I))
1363 return true;
1364 break;
1365 case Instruction::Select:
1366 return selectSelect(I);
1367 case Instruction::Trunc:
1368 return selectTrunc(I);
1369 case Instruction::ZExt:
1370 return selectZExt(I);
1371 case Instruction::SExt:
1372 return selectSExt(I);
1373 case Instruction::ICmp:
1374 return selectICmp(I);
1375 case Instruction::FCmp:
1376 return selectFCmp(I);
1377 case Instruction::BitCast:
1378 return selectBitCast(I);
1379 case Instruction::Load:
1380 return selectLoad(I);
1381 case Instruction::Store:
1382 return selectStore(I);
1383 case Instruction::Br:
1384 return selectBr(I);
1385 case Instruction::Ret:
1386 return selectRet(I);
1387 case Instruction::Unreachable:
1388 return selectUnreachable(I);
1389 default:
1390 break;
1393 // Fall back to target-independent instruction selection.
1394 return selectOperator(I, I->getOpcode());
1397 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1398 const TargetLibraryInfo *LibInfo) {
1399 return new WebAssemblyFastISel(FuncInfo, LibInfo);