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