1 //===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief This file defines the WebAssembly-specific support for the FastISel 12 /// class. Some of the target-specific code is generated by tablegen in the file 13 /// WebAssemblyGenFastISel.inc, which is #included here. 14 /// 15 /// TODO: kill flags 16 /// 17 //===----------------------------------------------------------------------===// 18 19 #include "MCTargetDesc/WebAssemblyMCTargetDesc.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/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/GlobalAlias.h" 36 #include "llvm/IR/GlobalVariable.h" 37 #include "llvm/IR/Instructions.h" 38 #include "llvm/IR/IntrinsicInst.h" 39 #include "llvm/IR/Operator.h" 40 using namespace llvm; 41 42 #define DEBUG_TYPE "wasm-fastisel" 43 44 namespace { 45 46 class WebAssemblyFastISel final : public FastISel { 47 // All possible address modes. 48 class Address { 49 public: 50 typedef enum { RegBase, FrameIndexBase } BaseKind; 51 52 private: 53 BaseKind Kind; 54 union { 55 unsigned Reg; 56 int FI; 57 } Base; 58 59 int64_t Offset; 60 61 const GlobalValue *GV; 62 63 public: 64 // Innocuous defaults for our address. 65 Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; } 66 void setKind(BaseKind K) { 67 assert(!isSet() && "Can't change kind with non-zero base"); 68 Kind = K; 69 } 70 BaseKind getKind() const { return Kind; } 71 bool isRegBase() const { return Kind == RegBase; } 72 bool isFIBase() const { return Kind == FrameIndexBase; } 73 void setReg(unsigned Reg) { 74 assert(isRegBase() && "Invalid base register access!"); 75 assert(Base.Reg == 0 && "Overwriting non-zero register"); 76 Base.Reg = Reg; 77 } 78 unsigned getReg() const { 79 assert(isRegBase() && "Invalid base register access!"); 80 return Base.Reg; 81 } 82 void setFI(unsigned FI) { 83 assert(isFIBase() && "Invalid base frame index access!"); 84 assert(Base.FI == 0 && "Overwriting non-zero frame index"); 85 Base.FI = FI; 86 } 87 unsigned getFI() const { 88 assert(isFIBase() && "Invalid base frame index access!"); 89 return Base.FI; 90 } 91 92 void setOffset(int64_t Offset_) { 93 assert(Offset_ >= 0 && "Offsets must be non-negative"); 94 Offset = Offset_; 95 } 96 int64_t getOffset() const { return Offset; } 97 void setGlobalValue(const GlobalValue *G) { GV = G; } 98 const GlobalValue *getGlobalValue() const { return GV; } 99 bool isSet() const { 100 if (isRegBase()) { 101 return Base.Reg != 0; 102 } else { 103 return Base.FI != 0; 104 } 105 } 106 }; 107 108 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the 109 /// right decision when generating code for different targets. 110 const WebAssemblySubtarget *Subtarget; 111 LLVMContext *Context; 112 113 private: 114 // Utility helper routines 115 MVT::SimpleValueType getSimpleType(Type *Ty) { 116 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true); 117 return VT.isSimple() ? VT.getSimpleVT().SimpleTy : 118 MVT::INVALID_SIMPLE_VALUE_TYPE; 119 } 120 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) { 121 switch (VT) { 122 case MVT::i1: 123 case MVT::i8: 124 case MVT::i16: 125 return MVT::i32; 126 case MVT::i32: 127 case MVT::i64: 128 case MVT::f32: 129 case MVT::f64: 130 return VT; 131 case MVT::f16: 132 return MVT::f32; 133 case MVT::v16i8: 134 case MVT::v8i16: 135 case MVT::v4i32: 136 case MVT::v4f32: 137 if (Subtarget->hasSIMD128()) 138 return VT; 139 break; 140 default: 141 break; 142 } 143 return MVT::INVALID_SIMPLE_VALUE_TYPE; 144 } 145 bool computeAddress(const Value *Obj, Address &Addr); 146 void materializeLoadStoreOperands(Address &Addr); 147 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB, 148 MachineMemOperand *MMO); 149 unsigned maskI1Value(unsigned Reg, const Value *V); 150 unsigned getRegForI1Value(const Value *V, bool &Not); 151 unsigned zeroExtendToI32(unsigned Reg, const Value *V, 152 MVT::SimpleValueType From); 153 unsigned signExtendToI32(unsigned Reg, const Value *V, 154 MVT::SimpleValueType From); 155 unsigned zeroExtend(unsigned Reg, const Value *V, 156 MVT::SimpleValueType From, 157 MVT::SimpleValueType To); 158 unsigned signExtend(unsigned Reg, const Value *V, 159 MVT::SimpleValueType From, 160 MVT::SimpleValueType To); 161 unsigned getRegForUnsignedValue(const Value *V); 162 unsigned getRegForSignedValue(const Value *V); 163 unsigned getRegForPromotedValue(const Value *V, bool IsSigned); 164 unsigned notValue(unsigned Reg); 165 unsigned copyValue(unsigned Reg); 166 167 // Backend specific FastISel code. 168 unsigned fastMaterializeAlloca(const AllocaInst *AI) override; 169 unsigned fastMaterializeConstant(const Constant *C) override; 170 bool fastLowerArguments() override; 171 172 // Selection routines. 173 bool selectCall(const Instruction *I); 174 bool selectSelect(const Instruction *I); 175 bool selectTrunc(const Instruction *I); 176 bool selectZExt(const Instruction *I); 177 bool selectSExt(const Instruction *I); 178 bool selectICmp(const Instruction *I); 179 bool selectFCmp(const Instruction *I); 180 bool selectBitCast(const Instruction *I); 181 bool selectLoad(const Instruction *I); 182 bool selectStore(const Instruction *I); 183 bool selectBr(const Instruction *I); 184 bool selectRet(const Instruction *I); 185 bool selectUnreachable(const Instruction *I); 186 187 public: 188 // Backend specific FastISel code. 189 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo, 190 const TargetLibraryInfo *LibInfo) 191 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) { 192 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>(); 193 Context = &FuncInfo.Fn->getContext(); 194 } 195 196 bool fastSelectInstruction(const Instruction *I) override; 197 198 #include "WebAssemblyGenFastISel.inc" 199 }; 200 201 } // end anonymous namespace 202 203 bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) { 204 205 const User *U = nullptr; 206 unsigned Opcode = Instruction::UserOp1; 207 if (const Instruction *I = dyn_cast<Instruction>(Obj)) { 208 // Don't walk into other basic blocks unless the object is an alloca from 209 // another block, otherwise it may not have a virtual register assigned. 210 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) || 211 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) { 212 Opcode = I->getOpcode(); 213 U = I; 214 } 215 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) { 216 Opcode = C->getOpcode(); 217 U = C; 218 } 219 220 if (auto *Ty = dyn_cast<PointerType>(Obj->getType())) 221 if (Ty->getAddressSpace() > 255) 222 // Fast instruction selection doesn't support the special 223 // address spaces. 224 return false; 225 226 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) { 227 if (Addr.getGlobalValue()) 228 return false; 229 Addr.setGlobalValue(GV); 230 return true; 231 } 232 233 switch (Opcode) { 234 default: 235 break; 236 case Instruction::BitCast: { 237 // Look through bitcasts. 238 return computeAddress(U->getOperand(0), Addr); 239 } 240 case Instruction::IntToPtr: { 241 // Look past no-op inttoptrs. 242 if (TLI.getValueType(DL, U->getOperand(0)->getType()) == 243 TLI.getPointerTy(DL)) 244 return computeAddress(U->getOperand(0), Addr); 245 break; 246 } 247 case Instruction::PtrToInt: { 248 // Look past no-op ptrtoints. 249 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL)) 250 return computeAddress(U->getOperand(0), Addr); 251 break; 252 } 253 case Instruction::GetElementPtr: { 254 Address SavedAddr = Addr; 255 uint64_t TmpOffset = Addr.getOffset(); 256 // Non-inbounds geps can wrap; wasm's offsets can't. 257 if (!cast<GEPOperator>(U)->isInBounds()) 258 goto unsupported_gep; 259 // Iterate through the GEP folding the constants into offsets where 260 // we can. 261 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U); 262 GTI != E; ++GTI) { 263 const Value *Op = GTI.getOperand(); 264 if (StructType *STy = GTI.getStructTypeOrNull()) { 265 const StructLayout *SL = DL.getStructLayout(STy); 266 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue(); 267 TmpOffset += SL->getElementOffset(Idx); 268 } else { 269 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType()); 270 for (;;) { 271 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) { 272 // Constant-offset addressing. 273 TmpOffset += CI->getSExtValue() * S; 274 break; 275 } 276 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) { 277 // An unscaled add of a register. Set it as the new base. 278 Addr.setReg(getRegForValue(Op)); 279 break; 280 } 281 if (canFoldAddIntoGEP(U, Op)) { 282 // A compatible add with a constant operand. Fold the constant. 283 ConstantInt *CI = 284 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1)); 285 TmpOffset += CI->getSExtValue() * S; 286 // Iterate on the other operand. 287 Op = cast<AddOperator>(Op)->getOperand(0); 288 continue; 289 } 290 // Unsupported 291 goto unsupported_gep; 292 } 293 } 294 } 295 // Don't fold in negative offsets. 296 if (int64_t(TmpOffset) >= 0) { 297 // Try to grab the base operand now. 298 Addr.setOffset(TmpOffset); 299 if (computeAddress(U->getOperand(0), Addr)) 300 return true; 301 } 302 // We failed, restore everything and try the other options. 303 Addr = SavedAddr; 304 unsupported_gep: 305 break; 306 } 307 case Instruction::Alloca: { 308 const AllocaInst *AI = cast<AllocaInst>(Obj); 309 DenseMap<const AllocaInst *, int>::iterator SI = 310 FuncInfo.StaticAllocaMap.find(AI); 311 if (SI != FuncInfo.StaticAllocaMap.end()) { 312 if (Addr.isSet()) { 313 return false; 314 } 315 Addr.setKind(Address::FrameIndexBase); 316 Addr.setFI(SI->second); 317 return true; 318 } 319 break; 320 } 321 case Instruction::Add: { 322 // Adds of constants are common and easy enough. 323 const Value *LHS = U->getOperand(0); 324 const Value *RHS = U->getOperand(1); 325 326 if (isa<ConstantInt>(LHS)) 327 std::swap(LHS, RHS); 328 329 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) { 330 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue(); 331 if (int64_t(TmpOffset) >= 0) { 332 Addr.setOffset(TmpOffset); 333 return computeAddress(LHS, Addr); 334 } 335 } 336 337 Address Backup = Addr; 338 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr)) 339 return true; 340 Addr = Backup; 341 342 break; 343 } 344 case Instruction::Sub: { 345 // Subs of constants are common and easy enough. 346 const Value *LHS = U->getOperand(0); 347 const Value *RHS = U->getOperand(1); 348 349 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) { 350 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue(); 351 if (TmpOffset >= 0) { 352 Addr.setOffset(TmpOffset); 353 return computeAddress(LHS, Addr); 354 } 355 } 356 break; 357 } 358 } 359 if (Addr.isSet()) { 360 return false; 361 } 362 Addr.setReg(getRegForValue(Obj)); 363 return Addr.getReg() != 0; 364 } 365 366 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) { 367 if (Addr.isRegBase()) { 368 unsigned Reg = Addr.getReg(); 369 if (Reg == 0) { 370 Reg = createResultReg(Subtarget->hasAddr64() ? 371 &WebAssembly::I64RegClass : 372 &WebAssembly::I32RegClass); 373 unsigned Opc = Subtarget->hasAddr64() ? 374 WebAssembly::CONST_I64 : 375 WebAssembly::CONST_I32; 376 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg) 377 .addImm(0); 378 Addr.setReg(Reg); 379 } 380 } 381 } 382 383 void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr, 384 const MachineInstrBuilder &MIB, 385 MachineMemOperand *MMO) { 386 // Set the alignment operand (this is rewritten in SetP2AlignOperands). 387 // TODO: Disable SetP2AlignOperands for FastISel and just do it here. 388 MIB.addImm(0); 389 390 if (const GlobalValue *GV = Addr.getGlobalValue()) 391 MIB.addGlobalAddress(GV, Addr.getOffset()); 392 else 393 MIB.addImm(Addr.getOffset()); 394 395 if (Addr.isRegBase()) 396 MIB.addReg(Addr.getReg()); 397 else 398 MIB.addFrameIndex(Addr.getFI()); 399 400 MIB.addMemOperand(MMO); 401 } 402 403 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) { 404 return zeroExtendToI32(Reg, V, MVT::i1); 405 } 406 407 unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) { 408 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V)) 409 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1))) 410 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) { 411 Not = ICmp->isTrueWhenEqual(); 412 return getRegForValue(ICmp->getOperand(0)); 413 } 414 415 if (BinaryOperator::isNot(V)) { 416 Not = true; 417 return getRegForValue(BinaryOperator::getNotArgument(V)); 418 } 419 420 Not = false; 421 return maskI1Value(getRegForValue(V), V); 422 } 423 424 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V, 425 MVT::SimpleValueType From) { 426 if (Reg == 0) 427 return 0; 428 429 switch (From) { 430 case MVT::i1: 431 // If the value is naturally an i1, we don't need to mask it. 432 // TODO: Recursively examine selects, phis, and, or, xor, constants. 433 if (From == MVT::i1 && V != nullptr) { 434 if (isa<CmpInst>(V) || 435 (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())) 436 return copyValue(Reg); 437 } 438 case MVT::i8: 439 case MVT::i16: 440 break; 441 case MVT::i32: 442 return copyValue(Reg); 443 default: 444 return 0; 445 } 446 447 unsigned Imm = createResultReg(&WebAssembly::I32RegClass); 448 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 449 TII.get(WebAssembly::CONST_I32), Imm) 450 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits())); 451 452 unsigned Result = createResultReg(&WebAssembly::I32RegClass); 453 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 454 TII.get(WebAssembly::AND_I32), Result) 455 .addReg(Reg) 456 .addReg(Imm); 457 458 return Result; 459 } 460 461 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V, 462 MVT::SimpleValueType From) { 463 if (Reg == 0) 464 return 0; 465 466 switch (From) { 467 case MVT::i1: 468 case MVT::i8: 469 case MVT::i16: 470 break; 471 case MVT::i32: 472 return copyValue(Reg); 473 default: 474 return 0; 475 } 476 477 unsigned Imm = createResultReg(&WebAssembly::I32RegClass); 478 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 479 TII.get(WebAssembly::CONST_I32), Imm) 480 .addImm(32 - MVT(From).getSizeInBits()); 481 482 unsigned Left = createResultReg(&WebAssembly::I32RegClass); 483 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 484 TII.get(WebAssembly::SHL_I32), Left) 485 .addReg(Reg) 486 .addReg(Imm); 487 488 unsigned Right = createResultReg(&WebAssembly::I32RegClass); 489 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 490 TII.get(WebAssembly::SHR_S_I32), Right) 491 .addReg(Left) 492 .addReg(Imm); 493 494 return Right; 495 } 496 497 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V, 498 MVT::SimpleValueType From, 499 MVT::SimpleValueType To) { 500 if (To == MVT::i64) { 501 if (From == MVT::i64) 502 return copyValue(Reg); 503 504 Reg = zeroExtendToI32(Reg, V, From); 505 506 unsigned Result = createResultReg(&WebAssembly::I64RegClass); 507 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 508 TII.get(WebAssembly::I64_EXTEND_U_I32), Result) 509 .addReg(Reg); 510 return Result; 511 } 512 513 return zeroExtendToI32(Reg, V, From); 514 } 515 516 unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V, 517 MVT::SimpleValueType From, 518 MVT::SimpleValueType To) { 519 if (To == MVT::i64) { 520 if (From == MVT::i64) 521 return copyValue(Reg); 522 523 Reg = signExtendToI32(Reg, V, From); 524 525 unsigned Result = createResultReg(&WebAssembly::I64RegClass); 526 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 527 TII.get(WebAssembly::I64_EXTEND_S_I32), Result) 528 .addReg(Reg); 529 return Result; 530 } 531 532 return signExtendToI32(Reg, V, From); 533 } 534 535 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) { 536 MVT::SimpleValueType From = getSimpleType(V->getType()); 537 MVT::SimpleValueType To = getLegalType(From); 538 return zeroExtend(getRegForValue(V), V, From, To); 539 } 540 541 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) { 542 MVT::SimpleValueType From = getSimpleType(V->getType()); 543 MVT::SimpleValueType To = getLegalType(From); 544 return zeroExtend(getRegForValue(V), V, From, To); 545 } 546 547 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V, 548 bool IsSigned) { 549 return IsSigned ? getRegForSignedValue(V) : 550 getRegForUnsignedValue(V); 551 } 552 553 unsigned WebAssemblyFastISel::notValue(unsigned Reg) { 554 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass); 555 556 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass); 557 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 558 TII.get(WebAssembly::EQZ_I32), NotReg) 559 .addReg(Reg); 560 return NotReg; 561 } 562 563 unsigned WebAssemblyFastISel::copyValue(unsigned Reg) { 564 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg)); 565 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 566 TII.get(WebAssembly::COPY), ResultReg) 567 .addReg(Reg); 568 return ResultReg; 569 } 570 571 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) { 572 DenseMap<const AllocaInst *, int>::iterator SI = 573 FuncInfo.StaticAllocaMap.find(AI); 574 575 if (SI != FuncInfo.StaticAllocaMap.end()) { 576 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ? 577 &WebAssembly::I64RegClass : 578 &WebAssembly::I32RegClass); 579 unsigned Opc = Subtarget->hasAddr64() ? 580 WebAssembly::COPY_I64 : 581 WebAssembly::COPY_I32; 582 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 583 .addFrameIndex(SI->second); 584 return ResultReg; 585 } 586 587 return 0; 588 } 589 590 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) { 591 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) { 592 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ? 593 &WebAssembly::I64RegClass : 594 &WebAssembly::I32RegClass); 595 unsigned Opc = Subtarget->hasAddr64() ? 596 WebAssembly::CONST_I64 : 597 WebAssembly::CONST_I32; 598 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 599 .addGlobalAddress(GV); 600 return ResultReg; 601 } 602 603 // Let target-independent code handle it. 604 return 0; 605 } 606 607 bool WebAssemblyFastISel::fastLowerArguments() { 608 if (!FuncInfo.CanLowerReturn) 609 return false; 610 611 const Function *F = FuncInfo.Fn; 612 if (F->isVarArg()) 613 return false; 614 615 unsigned i = 0; 616 for (auto const &Arg : F->args()) { 617 const AttributeList &Attrs = F->getAttributes(); 618 if (Attrs.hasParamAttribute(i, Attribute::ByVal) || 619 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) || 620 Attrs.hasParamAttribute(i, Attribute::SwiftError) || 621 Attrs.hasParamAttribute(i, Attribute::InAlloca) || 622 Attrs.hasParamAttribute(i, Attribute::Nest)) 623 return false; 624 625 Type *ArgTy = Arg.getType(); 626 if (ArgTy->isStructTy() || ArgTy->isArrayTy()) 627 return false; 628 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy()) 629 return false; 630 631 unsigned Opc; 632 const TargetRegisterClass *RC; 633 switch (getSimpleType(ArgTy)) { 634 case MVT::i1: 635 case MVT::i8: 636 case MVT::i16: 637 case MVT::i32: 638 Opc = WebAssembly::ARGUMENT_I32; 639 RC = &WebAssembly::I32RegClass; 640 break; 641 case MVT::i64: 642 Opc = WebAssembly::ARGUMENT_I64; 643 RC = &WebAssembly::I64RegClass; 644 break; 645 case MVT::f32: 646 Opc = WebAssembly::ARGUMENT_F32; 647 RC = &WebAssembly::F32RegClass; 648 break; 649 case MVT::f64: 650 Opc = WebAssembly::ARGUMENT_F64; 651 RC = &WebAssembly::F64RegClass; 652 break; 653 case MVT::v16i8: 654 Opc = WebAssembly::ARGUMENT_v16i8; 655 RC = &WebAssembly::V128RegClass; 656 break; 657 case MVT::v8i16: 658 Opc = WebAssembly::ARGUMENT_v8i16; 659 RC = &WebAssembly::V128RegClass; 660 break; 661 case MVT::v4i32: 662 Opc = WebAssembly::ARGUMENT_v4i32; 663 RC = &WebAssembly::V128RegClass; 664 break; 665 case MVT::v4f32: 666 Opc = WebAssembly::ARGUMENT_v4f32; 667 RC = &WebAssembly::V128RegClass; 668 break; 669 default: 670 return false; 671 } 672 unsigned ResultReg = createResultReg(RC); 673 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 674 .addImm(i); 675 updateValueMap(&Arg, ResultReg); 676 677 ++i; 678 } 679 680 MRI.addLiveIn(WebAssembly::ARGUMENTS); 681 682 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>(); 683 for (auto const &Arg : F->args()) 684 MFI->addParam(getLegalType(getSimpleType(Arg.getType()))); 685 686 if (!F->getReturnType()->isVoidTy()) 687 MFI->addResult(getLegalType(getSimpleType(F->getReturnType()))); 688 689 return true; 690 } 691 692 bool WebAssemblyFastISel::selectCall(const Instruction *I) { 693 const CallInst *Call = cast<CallInst>(I); 694 695 if (Call->isMustTailCall() || Call->isInlineAsm() || 696 Call->getFunctionType()->isVarArg()) 697 return false; 698 699 Function *Func = Call->getCalledFunction(); 700 if (Func && Func->isIntrinsic()) 701 return false; 702 703 bool IsDirect = Func != nullptr; 704 if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue())) 705 return false; 706 707 FunctionType *FuncTy = Call->getFunctionType(); 708 unsigned Opc; 709 bool IsVoid = FuncTy->getReturnType()->isVoidTy(); 710 unsigned ResultReg; 711 if (IsVoid) { 712 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID; 713 } else { 714 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy()) 715 return false; 716 717 MVT::SimpleValueType RetTy = getSimpleType(Call->getType()); 718 switch (RetTy) { 719 case MVT::i1: 720 case MVT::i8: 721 case MVT::i16: 722 case MVT::i32: 723 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32; 724 ResultReg = createResultReg(&WebAssembly::I32RegClass); 725 break; 726 case MVT::i64: 727 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64; 728 ResultReg = createResultReg(&WebAssembly::I64RegClass); 729 break; 730 case MVT::f32: 731 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32; 732 ResultReg = createResultReg(&WebAssembly::F32RegClass); 733 break; 734 case MVT::f64: 735 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64; 736 ResultReg = createResultReg(&WebAssembly::F64RegClass); 737 break; 738 case MVT::v16i8: 739 Opc = 740 IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8; 741 ResultReg = createResultReg(&WebAssembly::V128RegClass); 742 break; 743 case MVT::v8i16: 744 Opc = 745 IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16; 746 ResultReg = createResultReg(&WebAssembly::V128RegClass); 747 break; 748 case MVT::v4i32: 749 Opc = 750 IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32; 751 ResultReg = createResultReg(&WebAssembly::V128RegClass); 752 break; 753 case MVT::v4f32: 754 Opc = 755 IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32; 756 ResultReg = createResultReg(&WebAssembly::V128RegClass); 757 break; 758 default: 759 return false; 760 } 761 } 762 763 SmallVector<unsigned, 8> Args; 764 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) { 765 Value *V = Call->getArgOperand(i); 766 MVT::SimpleValueType ArgTy = getSimpleType(V->getType()); 767 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) 768 return false; 769 770 const AttributeList &Attrs = Call->getAttributes(); 771 if (Attrs.hasParamAttribute(i, Attribute::ByVal) || 772 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) || 773 Attrs.hasParamAttribute(i, Attribute::SwiftError) || 774 Attrs.hasParamAttribute(i, Attribute::InAlloca) || 775 Attrs.hasParamAttribute(i, Attribute::Nest)) 776 return false; 777 778 unsigned Reg; 779 780 if (Attrs.hasParamAttribute(i, Attribute::SExt)) 781 Reg = getRegForSignedValue(V); 782 else if (Attrs.hasParamAttribute(i, Attribute::ZExt)) 783 Reg = getRegForUnsignedValue(V); 784 else 785 Reg = getRegForValue(V); 786 787 if (Reg == 0) 788 return false; 789 790 Args.push_back(Reg); 791 } 792 793 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); 794 795 if (!IsVoid) 796 MIB.addReg(ResultReg, RegState::Define); 797 798 if (IsDirect) 799 MIB.addGlobalAddress(Func); 800 else 801 MIB.addReg(getRegForValue(Call->getCalledValue())); 802 803 for (unsigned ArgReg : Args) 804 MIB.addReg(ArgReg); 805 806 if (!IsVoid) 807 updateValueMap(Call, ResultReg); 808 return true; 809 } 810 811 bool WebAssemblyFastISel::selectSelect(const Instruction *I) { 812 const SelectInst *Select = cast<SelectInst>(I); 813 814 bool Not; 815 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not); 816 if (CondReg == 0) 817 return false; 818 819 unsigned TrueReg = getRegForValue(Select->getTrueValue()); 820 if (TrueReg == 0) 821 return false; 822 823 unsigned FalseReg = getRegForValue(Select->getFalseValue()); 824 if (FalseReg == 0) 825 return false; 826 827 if (Not) 828 std::swap(TrueReg, FalseReg); 829 830 unsigned Opc; 831 const TargetRegisterClass *RC; 832 switch (getSimpleType(Select->getType())) { 833 case MVT::i1: 834 case MVT::i8: 835 case MVT::i16: 836 case MVT::i32: 837 Opc = WebAssembly::SELECT_I32; 838 RC = &WebAssembly::I32RegClass; 839 break; 840 case MVT::i64: 841 Opc = WebAssembly::SELECT_I64; 842 RC = &WebAssembly::I64RegClass; 843 break; 844 case MVT::f32: 845 Opc = WebAssembly::SELECT_F32; 846 RC = &WebAssembly::F32RegClass; 847 break; 848 case MVT::f64: 849 Opc = WebAssembly::SELECT_F64; 850 RC = &WebAssembly::F64RegClass; 851 break; 852 default: 853 return false; 854 } 855 856 unsigned ResultReg = createResultReg(RC); 857 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 858 .addReg(TrueReg) 859 .addReg(FalseReg) 860 .addReg(CondReg); 861 862 updateValueMap(Select, ResultReg); 863 return true; 864 } 865 866 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) { 867 const TruncInst *Trunc = cast<TruncInst>(I); 868 869 unsigned Reg = getRegForValue(Trunc->getOperand(0)); 870 if (Reg == 0) 871 return false; 872 873 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) { 874 unsigned Result = createResultReg(&WebAssembly::I32RegClass); 875 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 876 TII.get(WebAssembly::I32_WRAP_I64), Result) 877 .addReg(Reg); 878 Reg = Result; 879 } 880 881 updateValueMap(Trunc, Reg); 882 return true; 883 } 884 885 bool WebAssemblyFastISel::selectZExt(const Instruction *I) { 886 const ZExtInst *ZExt = cast<ZExtInst>(I); 887 888 const Value *Op = ZExt->getOperand(0); 889 MVT::SimpleValueType From = getSimpleType(Op->getType()); 890 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType())); 891 unsigned Reg = zeroExtend(getRegForValue(Op), Op, From, To); 892 if (Reg == 0) 893 return false; 894 895 updateValueMap(ZExt, Reg); 896 return true; 897 } 898 899 bool WebAssemblyFastISel::selectSExt(const Instruction *I) { 900 const SExtInst *SExt = cast<SExtInst>(I); 901 902 const Value *Op = SExt->getOperand(0); 903 MVT::SimpleValueType From = getSimpleType(Op->getType()); 904 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType())); 905 unsigned Reg = signExtend(getRegForValue(Op), Op, From, To); 906 if (Reg == 0) 907 return false; 908 909 updateValueMap(SExt, Reg); 910 return true; 911 } 912 913 bool WebAssemblyFastISel::selectICmp(const Instruction *I) { 914 const ICmpInst *ICmp = cast<ICmpInst>(I); 915 916 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64; 917 unsigned Opc; 918 bool isSigned = false; 919 switch (ICmp->getPredicate()) { 920 case ICmpInst::ICMP_EQ: 921 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64; 922 break; 923 case ICmpInst::ICMP_NE: 924 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64; 925 break; 926 case ICmpInst::ICMP_UGT: 927 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64; 928 break; 929 case ICmpInst::ICMP_UGE: 930 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64; 931 break; 932 case ICmpInst::ICMP_ULT: 933 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64; 934 break; 935 case ICmpInst::ICMP_ULE: 936 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64; 937 break; 938 case ICmpInst::ICMP_SGT: 939 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64; 940 isSigned = true; 941 break; 942 case ICmpInst::ICMP_SGE: 943 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64; 944 isSigned = true; 945 break; 946 case ICmpInst::ICMP_SLT: 947 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64; 948 isSigned = true; 949 break; 950 case ICmpInst::ICMP_SLE: 951 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64; 952 isSigned = true; 953 break; 954 default: return false; 955 } 956 957 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned); 958 if (LHS == 0) 959 return false; 960 961 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned); 962 if (RHS == 0) 963 return false; 964 965 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass); 966 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 967 .addReg(LHS) 968 .addReg(RHS); 969 updateValueMap(ICmp, ResultReg); 970 return true; 971 } 972 973 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) { 974 const FCmpInst *FCmp = cast<FCmpInst>(I); 975 976 unsigned LHS = getRegForValue(FCmp->getOperand(0)); 977 if (LHS == 0) 978 return false; 979 980 unsigned RHS = getRegForValue(FCmp->getOperand(1)); 981 if (RHS == 0) 982 return false; 983 984 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64; 985 unsigned Opc; 986 bool Not = false; 987 switch (FCmp->getPredicate()) { 988 case FCmpInst::FCMP_OEQ: 989 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64; 990 break; 991 case FCmpInst::FCMP_UNE: 992 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64; 993 break; 994 case FCmpInst::FCMP_OGT: 995 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64; 996 break; 997 case FCmpInst::FCMP_OGE: 998 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64; 999 break; 1000 case FCmpInst::FCMP_OLT: 1001 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64; 1002 break; 1003 case FCmpInst::FCMP_OLE: 1004 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64; 1005 break; 1006 case FCmpInst::FCMP_UGT: 1007 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64; 1008 Not = true; 1009 break; 1010 case FCmpInst::FCMP_UGE: 1011 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64; 1012 Not = true; 1013 break; 1014 case FCmpInst::FCMP_ULT: 1015 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64; 1016 Not = true; 1017 break; 1018 case FCmpInst::FCMP_ULE: 1019 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64; 1020 Not = true; 1021 break; 1022 default: 1023 return false; 1024 } 1025 1026 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass); 1027 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 1028 .addReg(LHS) 1029 .addReg(RHS); 1030 1031 if (Not) 1032 ResultReg = notValue(ResultReg); 1033 1034 updateValueMap(FCmp, ResultReg); 1035 return true; 1036 } 1037 1038 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) { 1039 // Target-independent code can handle this, except it doesn't set the dead 1040 // flag on the ARGUMENTS clobber, so we have to do that manually in order 1041 // to satisfy code that expects this of isBitcast() instructions. 1042 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType()); 1043 EVT RetVT = TLI.getValueType(DL, I->getType()); 1044 if (!VT.isSimple() || !RetVT.isSimple()) 1045 return false; 1046 1047 if (VT == RetVT) { 1048 // No-op bitcast. 1049 updateValueMap(I, getRegForValue(I->getOperand(0))); 1050 return true; 1051 } 1052 1053 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(), 1054 getRegForValue(I->getOperand(0)), 1055 I->getOperand(0)->hasOneUse()); 1056 if (!Reg) 1057 return false; 1058 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt; 1059 --Iter; 1060 assert(Iter->isBitcast()); 1061 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI); 1062 updateValueMap(I, Reg); 1063 return true; 1064 } 1065 1066 bool WebAssemblyFastISel::selectLoad(const Instruction *I) { 1067 const LoadInst *Load = cast<LoadInst>(I); 1068 if (Load->isAtomic()) 1069 return false; 1070 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy()) 1071 return false; 1072 1073 Address Addr; 1074 if (!computeAddress(Load->getPointerOperand(), Addr)) 1075 return false; 1076 1077 // TODO: Fold a following sign-/zero-extend into the load instruction. 1078 1079 unsigned Opc; 1080 const TargetRegisterClass *RC; 1081 switch (getSimpleType(Load->getType())) { 1082 case MVT::i1: 1083 case MVT::i8: 1084 Opc = WebAssembly::LOAD8_U_I32; 1085 RC = &WebAssembly::I32RegClass; 1086 break; 1087 case MVT::i16: 1088 Opc = WebAssembly::LOAD16_U_I32; 1089 RC = &WebAssembly::I32RegClass; 1090 break; 1091 case MVT::i32: 1092 Opc = WebAssembly::LOAD_I32; 1093 RC = &WebAssembly::I32RegClass; 1094 break; 1095 case MVT::i64: 1096 Opc = WebAssembly::LOAD_I64; 1097 RC = &WebAssembly::I64RegClass; 1098 break; 1099 case MVT::f32: 1100 Opc = WebAssembly::LOAD_F32; 1101 RC = &WebAssembly::F32RegClass; 1102 break; 1103 case MVT::f64: 1104 Opc = WebAssembly::LOAD_F64; 1105 RC = &WebAssembly::F64RegClass; 1106 break; 1107 default: 1108 return false; 1109 } 1110 1111 materializeLoadStoreOperands(Addr); 1112 1113 unsigned ResultReg = createResultReg(RC); 1114 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), 1115 ResultReg); 1116 1117 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load)); 1118 1119 updateValueMap(Load, ResultReg); 1120 return true; 1121 } 1122 1123 bool WebAssemblyFastISel::selectStore(const Instruction *I) { 1124 const StoreInst *Store = cast<StoreInst>(I); 1125 if (Store->isAtomic()) 1126 return false; 1127 if (!Subtarget->hasSIMD128() && 1128 Store->getValueOperand()->getType()->isVectorTy()) 1129 return false; 1130 1131 Address Addr; 1132 if (!computeAddress(Store->getPointerOperand(), Addr)) 1133 return false; 1134 1135 unsigned Opc; 1136 bool VTIsi1 = false; 1137 switch (getSimpleType(Store->getValueOperand()->getType())) { 1138 case MVT::i1: 1139 VTIsi1 = true; 1140 case MVT::i8: 1141 Opc = WebAssembly::STORE8_I32; 1142 break; 1143 case MVT::i16: 1144 Opc = WebAssembly::STORE16_I32; 1145 break; 1146 case MVT::i32: 1147 Opc = WebAssembly::STORE_I32; 1148 break; 1149 case MVT::i64: 1150 Opc = WebAssembly::STORE_I64; 1151 break; 1152 case MVT::f32: 1153 Opc = WebAssembly::STORE_F32; 1154 break; 1155 case MVT::f64: 1156 Opc = WebAssembly::STORE_F64; 1157 break; 1158 default: return false; 1159 } 1160 1161 materializeLoadStoreOperands(Addr); 1162 1163 unsigned ValueReg = getRegForValue(Store->getValueOperand()); 1164 if (ValueReg == 0) 1165 return false; 1166 if (VTIsi1) 1167 ValueReg = maskI1Value(ValueReg, Store->getValueOperand()); 1168 1169 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); 1170 1171 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store)); 1172 1173 MIB.addReg(ValueReg); 1174 return true; 1175 } 1176 1177 bool WebAssemblyFastISel::selectBr(const Instruction *I) { 1178 const BranchInst *Br = cast<BranchInst>(I); 1179 if (Br->isUnconditional()) { 1180 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)]; 1181 fastEmitBranch(MSucc, Br->getDebugLoc()); 1182 return true; 1183 } 1184 1185 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)]; 1186 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)]; 1187 1188 bool Not; 1189 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not); 1190 if (CondReg == 0) 1191 return false; 1192 1193 unsigned Opc = WebAssembly::BR_IF; 1194 if (Not) 1195 Opc = WebAssembly::BR_UNLESS; 1196 1197 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)) 1198 .addMBB(TBB) 1199 .addReg(CondReg); 1200 1201 finishCondBranch(Br->getParent(), TBB, FBB); 1202 return true; 1203 } 1204 1205 bool WebAssemblyFastISel::selectRet(const Instruction *I) { 1206 if (!FuncInfo.CanLowerReturn) 1207 return false; 1208 1209 const ReturnInst *Ret = cast<ReturnInst>(I); 1210 1211 if (Ret->getNumOperands() == 0) { 1212 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 1213 TII.get(WebAssembly::RETURN_VOID)); 1214 return true; 1215 } 1216 1217 Value *RV = Ret->getOperand(0); 1218 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy()) 1219 return false; 1220 1221 unsigned Opc; 1222 switch (getSimpleType(RV->getType())) { 1223 case MVT::i1: case MVT::i8: 1224 case MVT::i16: case MVT::i32: 1225 Opc = WebAssembly::RETURN_I32; 1226 break; 1227 case MVT::i64: 1228 Opc = WebAssembly::RETURN_I64; 1229 break; 1230 case MVT::f32: 1231 Opc = WebAssembly::RETURN_F32; 1232 break; 1233 case MVT::f64: 1234 Opc = WebAssembly::RETURN_F64; 1235 break; 1236 case MVT::v16i8: 1237 Opc = WebAssembly::RETURN_v16i8; 1238 break; 1239 case MVT::v8i16: 1240 Opc = WebAssembly::RETURN_v8i16; 1241 break; 1242 case MVT::v4i32: 1243 Opc = WebAssembly::RETURN_v4i32; 1244 break; 1245 case MVT::v4f32: 1246 Opc = WebAssembly::RETURN_v4f32; 1247 break; 1248 default: return false; 1249 } 1250 1251 unsigned Reg; 1252 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt)) 1253 Reg = getRegForSignedValue(RV); 1254 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt)) 1255 Reg = getRegForUnsignedValue(RV); 1256 else 1257 Reg = getRegForValue(RV); 1258 1259 if (Reg == 0) 1260 return false; 1261 1262 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg); 1263 return true; 1264 } 1265 1266 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) { 1267 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 1268 TII.get(WebAssembly::UNREACHABLE)); 1269 return true; 1270 } 1271 1272 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) { 1273 switch (I->getOpcode()) { 1274 case Instruction::Call: 1275 if (selectCall(I)) 1276 return true; 1277 break; 1278 case Instruction::Select: return selectSelect(I); 1279 case Instruction::Trunc: return selectTrunc(I); 1280 case Instruction::ZExt: return selectZExt(I); 1281 case Instruction::SExt: return selectSExt(I); 1282 case Instruction::ICmp: return selectICmp(I); 1283 case Instruction::FCmp: return selectFCmp(I); 1284 case Instruction::BitCast: return selectBitCast(I); 1285 case Instruction::Load: return selectLoad(I); 1286 case Instruction::Store: return selectStore(I); 1287 case Instruction::Br: return selectBr(I); 1288 case Instruction::Ret: return selectRet(I); 1289 case Instruction::Unreachable: return selectUnreachable(I); 1290 default: break; 1291 } 1292 1293 // Fall back to target-independent instruction selection. 1294 return selectOperator(I, I->getOpcode()); 1295 } 1296 1297 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo, 1298 const TargetLibraryInfo *LibInfo) { 1299 return new WebAssemblyFastISel(FuncInfo, LibInfo); 1300 } 1301