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 FunctionType *FuncTy = Call->getFunctionType(); 704 unsigned Opc; 705 bool IsDirect = Func != nullptr; 706 bool IsVoid = FuncTy->getReturnType()->isVoidTy(); 707 unsigned ResultReg; 708 if (IsVoid) { 709 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID; 710 } else { 711 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy()) 712 return false; 713 714 MVT::SimpleValueType RetTy = getSimpleType(Call->getType()); 715 switch (RetTy) { 716 case MVT::i1: 717 case MVT::i8: 718 case MVT::i16: 719 case MVT::i32: 720 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32; 721 ResultReg = createResultReg(&WebAssembly::I32RegClass); 722 break; 723 case MVT::i64: 724 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64; 725 ResultReg = createResultReg(&WebAssembly::I64RegClass); 726 break; 727 case MVT::f32: 728 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32; 729 ResultReg = createResultReg(&WebAssembly::F32RegClass); 730 break; 731 case MVT::f64: 732 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64; 733 ResultReg = createResultReg(&WebAssembly::F64RegClass); 734 break; 735 case MVT::v16i8: 736 Opc = 737 IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8; 738 ResultReg = createResultReg(&WebAssembly::V128RegClass); 739 break; 740 case MVT::v8i16: 741 Opc = 742 IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16; 743 ResultReg = createResultReg(&WebAssembly::V128RegClass); 744 break; 745 case MVT::v4i32: 746 Opc = 747 IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32; 748 ResultReg = createResultReg(&WebAssembly::V128RegClass); 749 break; 750 case MVT::v4f32: 751 Opc = 752 IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32; 753 ResultReg = createResultReg(&WebAssembly::V128RegClass); 754 break; 755 default: 756 return false; 757 } 758 } 759 760 SmallVector<unsigned, 8> Args; 761 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) { 762 Value *V = Call->getArgOperand(i); 763 MVT::SimpleValueType ArgTy = getSimpleType(V->getType()); 764 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) 765 return false; 766 767 const AttributeList &Attrs = Call->getAttributes(); 768 if (Attrs.hasParamAttribute(i, Attribute::ByVal) || 769 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) || 770 Attrs.hasParamAttribute(i, Attribute::SwiftError) || 771 Attrs.hasParamAttribute(i, Attribute::InAlloca) || 772 Attrs.hasParamAttribute(i, Attribute::Nest)) 773 return false; 774 775 unsigned Reg; 776 777 if (Attrs.hasParamAttribute(i, Attribute::SExt)) 778 Reg = getRegForSignedValue(V); 779 else if (Attrs.hasParamAttribute(i, Attribute::ZExt)) 780 Reg = getRegForUnsignedValue(V); 781 else 782 Reg = getRegForValue(V); 783 784 if (Reg == 0) 785 return false; 786 787 Args.push_back(Reg); 788 } 789 790 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); 791 792 if (!IsVoid) 793 MIB.addReg(ResultReg, RegState::Define); 794 795 if (IsDirect) 796 MIB.addGlobalAddress(Func); 797 else 798 MIB.addReg(getRegForValue(Call->getCalledValue())); 799 800 for (unsigned ArgReg : Args) 801 MIB.addReg(ArgReg); 802 803 if (!IsVoid) 804 updateValueMap(Call, ResultReg); 805 return true; 806 } 807 808 bool WebAssemblyFastISel::selectSelect(const Instruction *I) { 809 const SelectInst *Select = cast<SelectInst>(I); 810 811 bool Not; 812 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not); 813 if (CondReg == 0) 814 return false; 815 816 unsigned TrueReg = getRegForValue(Select->getTrueValue()); 817 if (TrueReg == 0) 818 return false; 819 820 unsigned FalseReg = getRegForValue(Select->getFalseValue()); 821 if (FalseReg == 0) 822 return false; 823 824 if (Not) 825 std::swap(TrueReg, FalseReg); 826 827 unsigned Opc; 828 const TargetRegisterClass *RC; 829 switch (getSimpleType(Select->getType())) { 830 case MVT::i1: 831 case MVT::i8: 832 case MVT::i16: 833 case MVT::i32: 834 Opc = WebAssembly::SELECT_I32; 835 RC = &WebAssembly::I32RegClass; 836 break; 837 case MVT::i64: 838 Opc = WebAssembly::SELECT_I64; 839 RC = &WebAssembly::I64RegClass; 840 break; 841 case MVT::f32: 842 Opc = WebAssembly::SELECT_F32; 843 RC = &WebAssembly::F32RegClass; 844 break; 845 case MVT::f64: 846 Opc = WebAssembly::SELECT_F64; 847 RC = &WebAssembly::F64RegClass; 848 break; 849 default: 850 return false; 851 } 852 853 unsigned ResultReg = createResultReg(RC); 854 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 855 .addReg(TrueReg) 856 .addReg(FalseReg) 857 .addReg(CondReg); 858 859 updateValueMap(Select, ResultReg); 860 return true; 861 } 862 863 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) { 864 const TruncInst *Trunc = cast<TruncInst>(I); 865 866 unsigned Reg = getRegForValue(Trunc->getOperand(0)); 867 if (Reg == 0) 868 return false; 869 870 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) { 871 unsigned Result = createResultReg(&WebAssembly::I32RegClass); 872 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 873 TII.get(WebAssembly::I32_WRAP_I64), Result) 874 .addReg(Reg); 875 Reg = Result; 876 } 877 878 updateValueMap(Trunc, Reg); 879 return true; 880 } 881 882 bool WebAssemblyFastISel::selectZExt(const Instruction *I) { 883 const ZExtInst *ZExt = cast<ZExtInst>(I); 884 885 const Value *Op = ZExt->getOperand(0); 886 MVT::SimpleValueType From = getSimpleType(Op->getType()); 887 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType())); 888 unsigned Reg = zeroExtend(getRegForValue(Op), Op, From, To); 889 if (Reg == 0) 890 return false; 891 892 updateValueMap(ZExt, Reg); 893 return true; 894 } 895 896 bool WebAssemblyFastISel::selectSExt(const Instruction *I) { 897 const SExtInst *SExt = cast<SExtInst>(I); 898 899 const Value *Op = SExt->getOperand(0); 900 MVT::SimpleValueType From = getSimpleType(Op->getType()); 901 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType())); 902 unsigned Reg = signExtend(getRegForValue(Op), Op, From, To); 903 if (Reg == 0) 904 return false; 905 906 updateValueMap(SExt, Reg); 907 return true; 908 } 909 910 bool WebAssemblyFastISel::selectICmp(const Instruction *I) { 911 const ICmpInst *ICmp = cast<ICmpInst>(I); 912 913 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64; 914 unsigned Opc; 915 bool isSigned = false; 916 switch (ICmp->getPredicate()) { 917 case ICmpInst::ICMP_EQ: 918 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64; 919 break; 920 case ICmpInst::ICMP_NE: 921 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64; 922 break; 923 case ICmpInst::ICMP_UGT: 924 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64; 925 break; 926 case ICmpInst::ICMP_UGE: 927 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64; 928 break; 929 case ICmpInst::ICMP_ULT: 930 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64; 931 break; 932 case ICmpInst::ICMP_ULE: 933 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64; 934 break; 935 case ICmpInst::ICMP_SGT: 936 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64; 937 isSigned = true; 938 break; 939 case ICmpInst::ICMP_SGE: 940 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64; 941 isSigned = true; 942 break; 943 case ICmpInst::ICMP_SLT: 944 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64; 945 isSigned = true; 946 break; 947 case ICmpInst::ICMP_SLE: 948 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64; 949 isSigned = true; 950 break; 951 default: return false; 952 } 953 954 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned); 955 if (LHS == 0) 956 return false; 957 958 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned); 959 if (RHS == 0) 960 return false; 961 962 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass); 963 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 964 .addReg(LHS) 965 .addReg(RHS); 966 updateValueMap(ICmp, ResultReg); 967 return true; 968 } 969 970 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) { 971 const FCmpInst *FCmp = cast<FCmpInst>(I); 972 973 unsigned LHS = getRegForValue(FCmp->getOperand(0)); 974 if (LHS == 0) 975 return false; 976 977 unsigned RHS = getRegForValue(FCmp->getOperand(1)); 978 if (RHS == 0) 979 return false; 980 981 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64; 982 unsigned Opc; 983 bool Not = false; 984 switch (FCmp->getPredicate()) { 985 case FCmpInst::FCMP_OEQ: 986 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64; 987 break; 988 case FCmpInst::FCMP_UNE: 989 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64; 990 break; 991 case FCmpInst::FCMP_OGT: 992 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64; 993 break; 994 case FCmpInst::FCMP_OGE: 995 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64; 996 break; 997 case FCmpInst::FCMP_OLT: 998 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64; 999 break; 1000 case FCmpInst::FCMP_OLE: 1001 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64; 1002 break; 1003 case FCmpInst::FCMP_UGT: 1004 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64; 1005 Not = true; 1006 break; 1007 case FCmpInst::FCMP_UGE: 1008 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64; 1009 Not = true; 1010 break; 1011 case FCmpInst::FCMP_ULT: 1012 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64; 1013 Not = true; 1014 break; 1015 case FCmpInst::FCMP_ULE: 1016 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64; 1017 Not = true; 1018 break; 1019 default: 1020 return false; 1021 } 1022 1023 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass); 1024 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 1025 .addReg(LHS) 1026 .addReg(RHS); 1027 1028 if (Not) 1029 ResultReg = notValue(ResultReg); 1030 1031 updateValueMap(FCmp, ResultReg); 1032 return true; 1033 } 1034 1035 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) { 1036 // Target-independent code can handle this, except it doesn't set the dead 1037 // flag on the ARGUMENTS clobber, so we have to do that manually in order 1038 // to satisfy code that expects this of isBitcast() instructions. 1039 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType()); 1040 EVT RetVT = TLI.getValueType(DL, I->getType()); 1041 if (!VT.isSimple() || !RetVT.isSimple()) 1042 return false; 1043 1044 if (VT == RetVT) { 1045 // No-op bitcast. 1046 updateValueMap(I, getRegForValue(I->getOperand(0))); 1047 return true; 1048 } 1049 1050 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(), 1051 getRegForValue(I->getOperand(0)), 1052 I->getOperand(0)->hasOneUse()); 1053 if (!Reg) 1054 return false; 1055 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt; 1056 --Iter; 1057 assert(Iter->isBitcast()); 1058 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI); 1059 updateValueMap(I, Reg); 1060 return true; 1061 } 1062 1063 bool WebAssemblyFastISel::selectLoad(const Instruction *I) { 1064 const LoadInst *Load = cast<LoadInst>(I); 1065 if (Load->isAtomic()) 1066 return false; 1067 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy()) 1068 return false; 1069 1070 Address Addr; 1071 if (!computeAddress(Load->getPointerOperand(), Addr)) 1072 return false; 1073 1074 // TODO: Fold a following sign-/zero-extend into the load instruction. 1075 1076 unsigned Opc; 1077 const TargetRegisterClass *RC; 1078 switch (getSimpleType(Load->getType())) { 1079 case MVT::i1: 1080 case MVT::i8: 1081 Opc = WebAssembly::LOAD8_U_I32; 1082 RC = &WebAssembly::I32RegClass; 1083 break; 1084 case MVT::i16: 1085 Opc = WebAssembly::LOAD16_U_I32; 1086 RC = &WebAssembly::I32RegClass; 1087 break; 1088 case MVT::i32: 1089 Opc = WebAssembly::LOAD_I32; 1090 RC = &WebAssembly::I32RegClass; 1091 break; 1092 case MVT::i64: 1093 Opc = WebAssembly::LOAD_I64; 1094 RC = &WebAssembly::I64RegClass; 1095 break; 1096 case MVT::f32: 1097 Opc = WebAssembly::LOAD_F32; 1098 RC = &WebAssembly::F32RegClass; 1099 break; 1100 case MVT::f64: 1101 Opc = WebAssembly::LOAD_F64; 1102 RC = &WebAssembly::F64RegClass; 1103 break; 1104 default: 1105 return false; 1106 } 1107 1108 materializeLoadStoreOperands(Addr); 1109 1110 unsigned ResultReg = createResultReg(RC); 1111 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), 1112 ResultReg); 1113 1114 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load)); 1115 1116 updateValueMap(Load, ResultReg); 1117 return true; 1118 } 1119 1120 bool WebAssemblyFastISel::selectStore(const Instruction *I) { 1121 const StoreInst *Store = cast<StoreInst>(I); 1122 if (Store->isAtomic()) 1123 return false; 1124 if (!Subtarget->hasSIMD128() && 1125 Store->getValueOperand()->getType()->isVectorTy()) 1126 return false; 1127 1128 Address Addr; 1129 if (!computeAddress(Store->getPointerOperand(), Addr)) 1130 return false; 1131 1132 unsigned Opc; 1133 bool VTIsi1 = false; 1134 switch (getSimpleType(Store->getValueOperand()->getType())) { 1135 case MVT::i1: 1136 VTIsi1 = true; 1137 case MVT::i8: 1138 Opc = WebAssembly::STORE8_I32; 1139 break; 1140 case MVT::i16: 1141 Opc = WebAssembly::STORE16_I32; 1142 break; 1143 case MVT::i32: 1144 Opc = WebAssembly::STORE_I32; 1145 break; 1146 case MVT::i64: 1147 Opc = WebAssembly::STORE_I64; 1148 break; 1149 case MVT::f32: 1150 Opc = WebAssembly::STORE_F32; 1151 break; 1152 case MVT::f64: 1153 Opc = WebAssembly::STORE_F64; 1154 break; 1155 default: return false; 1156 } 1157 1158 materializeLoadStoreOperands(Addr); 1159 1160 unsigned ValueReg = getRegForValue(Store->getValueOperand()); 1161 if (ValueReg == 0) 1162 return false; 1163 if (VTIsi1) 1164 ValueReg = maskI1Value(ValueReg, Store->getValueOperand()); 1165 1166 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); 1167 1168 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store)); 1169 1170 MIB.addReg(ValueReg); 1171 return true; 1172 } 1173 1174 bool WebAssemblyFastISel::selectBr(const Instruction *I) { 1175 const BranchInst *Br = cast<BranchInst>(I); 1176 if (Br->isUnconditional()) { 1177 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)]; 1178 fastEmitBranch(MSucc, Br->getDebugLoc()); 1179 return true; 1180 } 1181 1182 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)]; 1183 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)]; 1184 1185 bool Not; 1186 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not); 1187 if (CondReg == 0) 1188 return false; 1189 1190 unsigned Opc = WebAssembly::BR_IF; 1191 if (Not) 1192 Opc = WebAssembly::BR_UNLESS; 1193 1194 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)) 1195 .addMBB(TBB) 1196 .addReg(CondReg); 1197 1198 finishCondBranch(Br->getParent(), TBB, FBB); 1199 return true; 1200 } 1201 1202 bool WebAssemblyFastISel::selectRet(const Instruction *I) { 1203 if (!FuncInfo.CanLowerReturn) 1204 return false; 1205 1206 const ReturnInst *Ret = cast<ReturnInst>(I); 1207 1208 if (Ret->getNumOperands() == 0) { 1209 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 1210 TII.get(WebAssembly::RETURN_VOID)); 1211 return true; 1212 } 1213 1214 Value *RV = Ret->getOperand(0); 1215 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy()) 1216 return false; 1217 1218 unsigned Opc; 1219 switch (getSimpleType(RV->getType())) { 1220 case MVT::i1: case MVT::i8: 1221 case MVT::i16: case MVT::i32: 1222 Opc = WebAssembly::RETURN_I32; 1223 break; 1224 case MVT::i64: 1225 Opc = WebAssembly::RETURN_I64; 1226 break; 1227 case MVT::f32: 1228 Opc = WebAssembly::RETURN_F32; 1229 break; 1230 case MVT::f64: 1231 Opc = WebAssembly::RETURN_F64; 1232 break; 1233 case MVT::v16i8: 1234 Opc = WebAssembly::RETURN_v16i8; 1235 break; 1236 case MVT::v8i16: 1237 Opc = WebAssembly::RETURN_v8i16; 1238 break; 1239 case MVT::v4i32: 1240 Opc = WebAssembly::RETURN_v4i32; 1241 break; 1242 case MVT::v4f32: 1243 Opc = WebAssembly::RETURN_v4f32; 1244 break; 1245 default: return false; 1246 } 1247 1248 unsigned Reg; 1249 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt)) 1250 Reg = getRegForSignedValue(RV); 1251 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt)) 1252 Reg = getRegForUnsignedValue(RV); 1253 else 1254 Reg = getRegForValue(RV); 1255 1256 if (Reg == 0) 1257 return false; 1258 1259 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg); 1260 return true; 1261 } 1262 1263 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) { 1264 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 1265 TII.get(WebAssembly::UNREACHABLE)); 1266 return true; 1267 } 1268 1269 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) { 1270 switch (I->getOpcode()) { 1271 case Instruction::Call: 1272 if (selectCall(I)) 1273 return true; 1274 break; 1275 case Instruction::Select: return selectSelect(I); 1276 case Instruction::Trunc: return selectTrunc(I); 1277 case Instruction::ZExt: return selectZExt(I); 1278 case Instruction::SExt: return selectSExt(I); 1279 case Instruction::ICmp: return selectICmp(I); 1280 case Instruction::FCmp: return selectFCmp(I); 1281 case Instruction::BitCast: return selectBitCast(I); 1282 case Instruction::Load: return selectLoad(I); 1283 case Instruction::Store: return selectStore(I); 1284 case Instruction::Br: return selectBr(I); 1285 case Instruction::Ret: return selectRet(I); 1286 case Instruction::Unreachable: return selectUnreachable(I); 1287 default: break; 1288 } 1289 1290 // Fall back to target-independent instruction selection. 1291 return selectOperator(I, I->getOpcode()); 1292 } 1293 1294 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo, 1295 const TargetLibraryInfo *LibInfo) { 1296 return new WebAssemblyFastISel(FuncInfo, LibInfo); 1297 } 1298