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 unsigned Reg = getRegForValue(Op); 279 if (Reg == 0) 280 return false; 281 Addr.setReg(Reg); 282 break; 283 } 284 if (canFoldAddIntoGEP(U, Op)) { 285 // A compatible add with a constant operand. Fold the constant. 286 ConstantInt *CI = 287 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1)); 288 TmpOffset += CI->getSExtValue() * S; 289 // Iterate on the other operand. 290 Op = cast<AddOperator>(Op)->getOperand(0); 291 continue; 292 } 293 // Unsupported 294 goto unsupported_gep; 295 } 296 } 297 } 298 // Don't fold in negative offsets. 299 if (int64_t(TmpOffset) >= 0) { 300 // Try to grab the base operand now. 301 Addr.setOffset(TmpOffset); 302 if (computeAddress(U->getOperand(0), Addr)) 303 return true; 304 } 305 // We failed, restore everything and try the other options. 306 Addr = SavedAddr; 307 unsupported_gep: 308 break; 309 } 310 case Instruction::Alloca: { 311 const AllocaInst *AI = cast<AllocaInst>(Obj); 312 DenseMap<const AllocaInst *, int>::iterator SI = 313 FuncInfo.StaticAllocaMap.find(AI); 314 if (SI != FuncInfo.StaticAllocaMap.end()) { 315 if (Addr.isSet()) { 316 return false; 317 } 318 Addr.setKind(Address::FrameIndexBase); 319 Addr.setFI(SI->second); 320 return true; 321 } 322 break; 323 } 324 case Instruction::Add: { 325 // Adds of constants are common and easy enough. 326 const Value *LHS = U->getOperand(0); 327 const Value *RHS = U->getOperand(1); 328 329 if (isa<ConstantInt>(LHS)) 330 std::swap(LHS, RHS); 331 332 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) { 333 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue(); 334 if (int64_t(TmpOffset) >= 0) { 335 Addr.setOffset(TmpOffset); 336 return computeAddress(LHS, Addr); 337 } 338 } 339 340 Address Backup = Addr; 341 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr)) 342 return true; 343 Addr = Backup; 344 345 break; 346 } 347 case Instruction::Sub: { 348 // Subs of constants are common and easy enough. 349 const Value *LHS = U->getOperand(0); 350 const Value *RHS = U->getOperand(1); 351 352 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) { 353 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue(); 354 if (TmpOffset >= 0) { 355 Addr.setOffset(TmpOffset); 356 return computeAddress(LHS, Addr); 357 } 358 } 359 break; 360 } 361 } 362 if (Addr.isSet()) { 363 return false; 364 } 365 unsigned Reg = getRegForValue(Obj); 366 if (Reg == 0) 367 return false; 368 Addr.setReg(Reg); 369 return Addr.getReg() != 0; 370 } 371 372 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) { 373 if (Addr.isRegBase()) { 374 unsigned Reg = Addr.getReg(); 375 if (Reg == 0) { 376 Reg = createResultReg(Subtarget->hasAddr64() ? 377 &WebAssembly::I64RegClass : 378 &WebAssembly::I32RegClass); 379 unsigned Opc = Subtarget->hasAddr64() ? 380 WebAssembly::CONST_I64 : 381 WebAssembly::CONST_I32; 382 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), Reg) 383 .addImm(0); 384 Addr.setReg(Reg); 385 } 386 } 387 } 388 389 void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr, 390 const MachineInstrBuilder &MIB, 391 MachineMemOperand *MMO) { 392 // Set the alignment operand (this is rewritten in SetP2AlignOperands). 393 // TODO: Disable SetP2AlignOperands for FastISel and just do it here. 394 MIB.addImm(0); 395 396 if (const GlobalValue *GV = Addr.getGlobalValue()) 397 MIB.addGlobalAddress(GV, Addr.getOffset()); 398 else 399 MIB.addImm(Addr.getOffset()); 400 401 if (Addr.isRegBase()) 402 MIB.addReg(Addr.getReg()); 403 else 404 MIB.addFrameIndex(Addr.getFI()); 405 406 MIB.addMemOperand(MMO); 407 } 408 409 unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) { 410 return zeroExtendToI32(Reg, V, MVT::i1); 411 } 412 413 unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V, bool &Not) { 414 if (const ICmpInst *ICmp = dyn_cast<ICmpInst>(V)) 415 if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1))) 416 if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32)) { 417 Not = ICmp->isTrueWhenEqual(); 418 return getRegForValue(ICmp->getOperand(0)); 419 } 420 421 if (BinaryOperator::isNot(V)) { 422 Not = true; 423 return getRegForValue(BinaryOperator::getNotArgument(V)); 424 } 425 426 Not = false; 427 unsigned Reg = getRegForValue(V); 428 if (Reg == 0) 429 return 0; 430 return maskI1Value(Reg, V); 431 } 432 433 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V, 434 MVT::SimpleValueType From) { 435 if (Reg == 0) 436 return 0; 437 438 switch (From) { 439 case MVT::i1: 440 // If the value is naturally an i1, we don't need to mask it. 441 // TODO: Recursively examine selects, phis, and, or, xor, constants. 442 if (From == MVT::i1 && V != nullptr) { 443 if (isa<CmpInst>(V) || 444 (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())) 445 return copyValue(Reg); 446 } 447 case MVT::i8: 448 case MVT::i16: 449 break; 450 case MVT::i32: 451 return copyValue(Reg); 452 default: 453 return 0; 454 } 455 456 unsigned Imm = createResultReg(&WebAssembly::I32RegClass); 457 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 458 TII.get(WebAssembly::CONST_I32), Imm) 459 .addImm(~(~uint64_t(0) << MVT(From).getSizeInBits())); 460 461 unsigned Result = createResultReg(&WebAssembly::I32RegClass); 462 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 463 TII.get(WebAssembly::AND_I32), Result) 464 .addReg(Reg) 465 .addReg(Imm); 466 467 return Result; 468 } 469 470 unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V, 471 MVT::SimpleValueType From) { 472 if (Reg == 0) 473 return 0; 474 475 switch (From) { 476 case MVT::i1: 477 case MVT::i8: 478 case MVT::i16: 479 break; 480 case MVT::i32: 481 return copyValue(Reg); 482 default: 483 return 0; 484 } 485 486 unsigned Imm = createResultReg(&WebAssembly::I32RegClass); 487 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 488 TII.get(WebAssembly::CONST_I32), Imm) 489 .addImm(32 - MVT(From).getSizeInBits()); 490 491 unsigned Left = createResultReg(&WebAssembly::I32RegClass); 492 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 493 TII.get(WebAssembly::SHL_I32), Left) 494 .addReg(Reg) 495 .addReg(Imm); 496 497 unsigned Right = createResultReg(&WebAssembly::I32RegClass); 498 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 499 TII.get(WebAssembly::SHR_S_I32), Right) 500 .addReg(Left) 501 .addReg(Imm); 502 503 return Right; 504 } 505 506 unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V, 507 MVT::SimpleValueType From, 508 MVT::SimpleValueType To) { 509 if (To == MVT::i64) { 510 if (From == MVT::i64) 511 return copyValue(Reg); 512 513 Reg = zeroExtendToI32(Reg, V, From); 514 515 unsigned Result = createResultReg(&WebAssembly::I64RegClass); 516 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 517 TII.get(WebAssembly::I64_EXTEND_U_I32), Result) 518 .addReg(Reg); 519 return Result; 520 } 521 522 return zeroExtendToI32(Reg, V, From); 523 } 524 525 unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V, 526 MVT::SimpleValueType From, 527 MVT::SimpleValueType To) { 528 if (To == MVT::i64) { 529 if (From == MVT::i64) 530 return copyValue(Reg); 531 532 Reg = signExtendToI32(Reg, V, From); 533 534 unsigned Result = createResultReg(&WebAssembly::I64RegClass); 535 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 536 TII.get(WebAssembly::I64_EXTEND_S_I32), Result) 537 .addReg(Reg); 538 return Result; 539 } 540 541 return signExtendToI32(Reg, V, From); 542 } 543 544 unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) { 545 MVT::SimpleValueType From = getSimpleType(V->getType()); 546 MVT::SimpleValueType To = getLegalType(From); 547 unsigned VReg = getRegForValue(V); 548 if (VReg == 0) 549 return 0; 550 return zeroExtend(VReg, V, From, To); 551 } 552 553 unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) { 554 MVT::SimpleValueType From = getSimpleType(V->getType()); 555 MVT::SimpleValueType To = getLegalType(From); 556 unsigned VReg = getRegForValue(V); 557 if (VReg == 0) 558 return 0; 559 return signExtend(VReg, V, From, To); 560 } 561 562 unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V, 563 bool IsSigned) { 564 return IsSigned ? getRegForSignedValue(V) : 565 getRegForUnsignedValue(V); 566 } 567 568 unsigned WebAssemblyFastISel::notValue(unsigned Reg) { 569 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass); 570 571 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass); 572 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 573 TII.get(WebAssembly::EQZ_I32), NotReg) 574 .addReg(Reg); 575 return NotReg; 576 } 577 578 unsigned WebAssemblyFastISel::copyValue(unsigned Reg) { 579 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg)); 580 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 581 TII.get(WebAssembly::COPY), ResultReg) 582 .addReg(Reg); 583 return ResultReg; 584 } 585 586 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) { 587 DenseMap<const AllocaInst *, int>::iterator SI = 588 FuncInfo.StaticAllocaMap.find(AI); 589 590 if (SI != FuncInfo.StaticAllocaMap.end()) { 591 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ? 592 &WebAssembly::I64RegClass : 593 &WebAssembly::I32RegClass); 594 unsigned Opc = Subtarget->hasAddr64() ? 595 WebAssembly::COPY_I64 : 596 WebAssembly::COPY_I32; 597 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 598 .addFrameIndex(SI->second); 599 return ResultReg; 600 } 601 602 return 0; 603 } 604 605 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) { 606 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) { 607 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ? 608 &WebAssembly::I64RegClass : 609 &WebAssembly::I32RegClass); 610 unsigned Opc = Subtarget->hasAddr64() ? 611 WebAssembly::CONST_I64 : 612 WebAssembly::CONST_I32; 613 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 614 .addGlobalAddress(GV); 615 return ResultReg; 616 } 617 618 // Let target-independent code handle it. 619 return 0; 620 } 621 622 bool WebAssemblyFastISel::fastLowerArguments() { 623 if (!FuncInfo.CanLowerReturn) 624 return false; 625 626 const Function *F = FuncInfo.Fn; 627 if (F->isVarArg()) 628 return false; 629 630 unsigned i = 0; 631 for (auto const &Arg : F->args()) { 632 const AttributeList &Attrs = F->getAttributes(); 633 if (Attrs.hasParamAttribute(i, Attribute::ByVal) || 634 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) || 635 Attrs.hasParamAttribute(i, Attribute::SwiftError) || 636 Attrs.hasParamAttribute(i, Attribute::InAlloca) || 637 Attrs.hasParamAttribute(i, Attribute::Nest)) 638 return false; 639 640 Type *ArgTy = Arg.getType(); 641 if (ArgTy->isStructTy() || ArgTy->isArrayTy()) 642 return false; 643 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy()) 644 return false; 645 646 unsigned Opc; 647 const TargetRegisterClass *RC; 648 switch (getSimpleType(ArgTy)) { 649 case MVT::i1: 650 case MVT::i8: 651 case MVT::i16: 652 case MVT::i32: 653 Opc = WebAssembly::ARGUMENT_I32; 654 RC = &WebAssembly::I32RegClass; 655 break; 656 case MVT::i64: 657 Opc = WebAssembly::ARGUMENT_I64; 658 RC = &WebAssembly::I64RegClass; 659 break; 660 case MVT::f32: 661 Opc = WebAssembly::ARGUMENT_F32; 662 RC = &WebAssembly::F32RegClass; 663 break; 664 case MVT::f64: 665 Opc = WebAssembly::ARGUMENT_F64; 666 RC = &WebAssembly::F64RegClass; 667 break; 668 case MVT::v16i8: 669 Opc = WebAssembly::ARGUMENT_v16i8; 670 RC = &WebAssembly::V128RegClass; 671 break; 672 case MVT::v8i16: 673 Opc = WebAssembly::ARGUMENT_v8i16; 674 RC = &WebAssembly::V128RegClass; 675 break; 676 case MVT::v4i32: 677 Opc = WebAssembly::ARGUMENT_v4i32; 678 RC = &WebAssembly::V128RegClass; 679 break; 680 case MVT::v4f32: 681 Opc = WebAssembly::ARGUMENT_v4f32; 682 RC = &WebAssembly::V128RegClass; 683 break; 684 default: 685 return false; 686 } 687 unsigned ResultReg = createResultReg(RC); 688 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 689 .addImm(i); 690 updateValueMap(&Arg, ResultReg); 691 692 ++i; 693 } 694 695 MRI.addLiveIn(WebAssembly::ARGUMENTS); 696 697 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>(); 698 for (auto const &Arg : F->args()) 699 MFI->addParam(getLegalType(getSimpleType(Arg.getType()))); 700 701 if (!F->getReturnType()->isVoidTy()) 702 MFI->addResult(getLegalType(getSimpleType(F->getReturnType()))); 703 704 return true; 705 } 706 707 bool WebAssemblyFastISel::selectCall(const Instruction *I) { 708 const CallInst *Call = cast<CallInst>(I); 709 710 if (Call->isMustTailCall() || Call->isInlineAsm() || 711 Call->getFunctionType()->isVarArg()) 712 return false; 713 714 Function *Func = Call->getCalledFunction(); 715 if (Func && Func->isIntrinsic()) 716 return false; 717 718 bool IsDirect = Func != nullptr; 719 if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue())) 720 return false; 721 722 FunctionType *FuncTy = Call->getFunctionType(); 723 unsigned Opc; 724 bool IsVoid = FuncTy->getReturnType()->isVoidTy(); 725 unsigned ResultReg; 726 if (IsVoid) { 727 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID; 728 } else { 729 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy()) 730 return false; 731 732 MVT::SimpleValueType RetTy = getSimpleType(Call->getType()); 733 switch (RetTy) { 734 case MVT::i1: 735 case MVT::i8: 736 case MVT::i16: 737 case MVT::i32: 738 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32; 739 ResultReg = createResultReg(&WebAssembly::I32RegClass); 740 break; 741 case MVT::i64: 742 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64; 743 ResultReg = createResultReg(&WebAssembly::I64RegClass); 744 break; 745 case MVT::f32: 746 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32; 747 ResultReg = createResultReg(&WebAssembly::F32RegClass); 748 break; 749 case MVT::f64: 750 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64; 751 ResultReg = createResultReg(&WebAssembly::F64RegClass); 752 break; 753 case MVT::v16i8: 754 Opc = 755 IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8; 756 ResultReg = createResultReg(&WebAssembly::V128RegClass); 757 break; 758 case MVT::v8i16: 759 Opc = 760 IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16; 761 ResultReg = createResultReg(&WebAssembly::V128RegClass); 762 break; 763 case MVT::v4i32: 764 Opc = 765 IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32; 766 ResultReg = createResultReg(&WebAssembly::V128RegClass); 767 break; 768 case MVT::v4f32: 769 Opc = 770 IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32; 771 ResultReg = createResultReg(&WebAssembly::V128RegClass); 772 break; 773 default: 774 return false; 775 } 776 } 777 778 SmallVector<unsigned, 8> Args; 779 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) { 780 Value *V = Call->getArgOperand(i); 781 MVT::SimpleValueType ArgTy = getSimpleType(V->getType()); 782 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) 783 return false; 784 785 const AttributeList &Attrs = Call->getAttributes(); 786 if (Attrs.hasParamAttribute(i, Attribute::ByVal) || 787 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) || 788 Attrs.hasParamAttribute(i, Attribute::SwiftError) || 789 Attrs.hasParamAttribute(i, Attribute::InAlloca) || 790 Attrs.hasParamAttribute(i, Attribute::Nest)) 791 return false; 792 793 unsigned Reg; 794 795 if (Attrs.hasParamAttribute(i, Attribute::SExt)) 796 Reg = getRegForSignedValue(V); 797 else if (Attrs.hasParamAttribute(i, Attribute::ZExt)) 798 Reg = getRegForUnsignedValue(V); 799 else 800 Reg = getRegForValue(V); 801 802 if (Reg == 0) 803 return false; 804 805 Args.push_back(Reg); 806 } 807 808 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); 809 810 if (!IsVoid) 811 MIB.addReg(ResultReg, RegState::Define); 812 813 if (IsDirect) 814 MIB.addGlobalAddress(Func); 815 else { 816 unsigned Reg = getRegForValue(Call->getCalledValue()); 817 if (Reg == 0) 818 return false; 819 MIB.addReg(Reg); 820 } 821 822 for (unsigned ArgReg : Args) 823 MIB.addReg(ArgReg); 824 825 if (!IsVoid) 826 updateValueMap(Call, ResultReg); 827 return true; 828 } 829 830 bool WebAssemblyFastISel::selectSelect(const Instruction *I) { 831 const SelectInst *Select = cast<SelectInst>(I); 832 833 bool Not; 834 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not); 835 if (CondReg == 0) 836 return false; 837 838 unsigned TrueReg = getRegForValue(Select->getTrueValue()); 839 if (TrueReg == 0) 840 return false; 841 842 unsigned FalseReg = getRegForValue(Select->getFalseValue()); 843 if (FalseReg == 0) 844 return false; 845 846 if (Not) 847 std::swap(TrueReg, FalseReg); 848 849 unsigned Opc; 850 const TargetRegisterClass *RC; 851 switch (getSimpleType(Select->getType())) { 852 case MVT::i1: 853 case MVT::i8: 854 case MVT::i16: 855 case MVT::i32: 856 Opc = WebAssembly::SELECT_I32; 857 RC = &WebAssembly::I32RegClass; 858 break; 859 case MVT::i64: 860 Opc = WebAssembly::SELECT_I64; 861 RC = &WebAssembly::I64RegClass; 862 break; 863 case MVT::f32: 864 Opc = WebAssembly::SELECT_F32; 865 RC = &WebAssembly::F32RegClass; 866 break; 867 case MVT::f64: 868 Opc = WebAssembly::SELECT_F64; 869 RC = &WebAssembly::F64RegClass; 870 break; 871 default: 872 return false; 873 } 874 875 unsigned ResultReg = createResultReg(RC); 876 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 877 .addReg(TrueReg) 878 .addReg(FalseReg) 879 .addReg(CondReg); 880 881 updateValueMap(Select, ResultReg); 882 return true; 883 } 884 885 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) { 886 const TruncInst *Trunc = cast<TruncInst>(I); 887 888 unsigned Reg = getRegForValue(Trunc->getOperand(0)); 889 if (Reg == 0) 890 return false; 891 892 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) { 893 unsigned Result = createResultReg(&WebAssembly::I32RegClass); 894 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 895 TII.get(WebAssembly::I32_WRAP_I64), Result) 896 .addReg(Reg); 897 Reg = Result; 898 } 899 900 updateValueMap(Trunc, Reg); 901 return true; 902 } 903 904 bool WebAssemblyFastISel::selectZExt(const Instruction *I) { 905 const ZExtInst *ZExt = cast<ZExtInst>(I); 906 907 const Value *Op = ZExt->getOperand(0); 908 MVT::SimpleValueType From = getSimpleType(Op->getType()); 909 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType())); 910 unsigned In = getRegForValue(Op); 911 if (In == 0) 912 return false; 913 unsigned Reg = zeroExtend(In, Op, From, To); 914 if (Reg == 0) 915 return false; 916 917 updateValueMap(ZExt, Reg); 918 return true; 919 } 920 921 bool WebAssemblyFastISel::selectSExt(const Instruction *I) { 922 const SExtInst *SExt = cast<SExtInst>(I); 923 924 const Value *Op = SExt->getOperand(0); 925 MVT::SimpleValueType From = getSimpleType(Op->getType()); 926 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType())); 927 unsigned In = getRegForValue(Op); 928 if (In == 0) 929 return false; 930 unsigned Reg = signExtend(In, Op, From, To); 931 if (Reg == 0) 932 return false; 933 934 updateValueMap(SExt, Reg); 935 return true; 936 } 937 938 bool WebAssemblyFastISel::selectICmp(const Instruction *I) { 939 const ICmpInst *ICmp = cast<ICmpInst>(I); 940 941 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64; 942 unsigned Opc; 943 bool isSigned = false; 944 switch (ICmp->getPredicate()) { 945 case ICmpInst::ICMP_EQ: 946 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64; 947 break; 948 case ICmpInst::ICMP_NE: 949 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64; 950 break; 951 case ICmpInst::ICMP_UGT: 952 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64; 953 break; 954 case ICmpInst::ICMP_UGE: 955 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64; 956 break; 957 case ICmpInst::ICMP_ULT: 958 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64; 959 break; 960 case ICmpInst::ICMP_ULE: 961 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64; 962 break; 963 case ICmpInst::ICMP_SGT: 964 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64; 965 isSigned = true; 966 break; 967 case ICmpInst::ICMP_SGE: 968 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64; 969 isSigned = true; 970 break; 971 case ICmpInst::ICMP_SLT: 972 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64; 973 isSigned = true; 974 break; 975 case ICmpInst::ICMP_SLE: 976 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64; 977 isSigned = true; 978 break; 979 default: return false; 980 } 981 982 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned); 983 if (LHS == 0) 984 return false; 985 986 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned); 987 if (RHS == 0) 988 return false; 989 990 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass); 991 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 992 .addReg(LHS) 993 .addReg(RHS); 994 updateValueMap(ICmp, ResultReg); 995 return true; 996 } 997 998 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) { 999 const FCmpInst *FCmp = cast<FCmpInst>(I); 1000 1001 unsigned LHS = getRegForValue(FCmp->getOperand(0)); 1002 if (LHS == 0) 1003 return false; 1004 1005 unsigned RHS = getRegForValue(FCmp->getOperand(1)); 1006 if (RHS == 0) 1007 return false; 1008 1009 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64; 1010 unsigned Opc; 1011 bool Not = false; 1012 switch (FCmp->getPredicate()) { 1013 case FCmpInst::FCMP_OEQ: 1014 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64; 1015 break; 1016 case FCmpInst::FCMP_UNE: 1017 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64; 1018 break; 1019 case FCmpInst::FCMP_OGT: 1020 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64; 1021 break; 1022 case FCmpInst::FCMP_OGE: 1023 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64; 1024 break; 1025 case FCmpInst::FCMP_OLT: 1026 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64; 1027 break; 1028 case FCmpInst::FCMP_OLE: 1029 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64; 1030 break; 1031 case FCmpInst::FCMP_UGT: 1032 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64; 1033 Not = true; 1034 break; 1035 case FCmpInst::FCMP_UGE: 1036 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64; 1037 Not = true; 1038 break; 1039 case FCmpInst::FCMP_ULT: 1040 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64; 1041 Not = true; 1042 break; 1043 case FCmpInst::FCMP_ULE: 1044 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64; 1045 Not = true; 1046 break; 1047 default: 1048 return false; 1049 } 1050 1051 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass); 1052 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 1053 .addReg(LHS) 1054 .addReg(RHS); 1055 1056 if (Not) 1057 ResultReg = notValue(ResultReg); 1058 1059 updateValueMap(FCmp, ResultReg); 1060 return true; 1061 } 1062 1063 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) { 1064 // Target-independent code can handle this, except it doesn't set the dead 1065 // flag on the ARGUMENTS clobber, so we have to do that manually in order 1066 // to satisfy code that expects this of isBitcast() instructions. 1067 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType()); 1068 EVT RetVT = TLI.getValueType(DL, I->getType()); 1069 if (!VT.isSimple() || !RetVT.isSimple()) 1070 return false; 1071 1072 unsigned In = getRegForValue(I->getOperand(0)); 1073 if (In == 0) 1074 return false; 1075 1076 if (VT == RetVT) { 1077 // No-op bitcast. 1078 updateValueMap(I, In); 1079 return true; 1080 } 1081 1082 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(), 1083 In, I->getOperand(0)->hasOneUse()); 1084 if (!Reg) 1085 return false; 1086 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt; 1087 --Iter; 1088 assert(Iter->isBitcast()); 1089 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI); 1090 updateValueMap(I, Reg); 1091 return true; 1092 } 1093 1094 bool WebAssemblyFastISel::selectLoad(const Instruction *I) { 1095 const LoadInst *Load = cast<LoadInst>(I); 1096 if (Load->isAtomic()) 1097 return false; 1098 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy()) 1099 return false; 1100 1101 Address Addr; 1102 if (!computeAddress(Load->getPointerOperand(), Addr)) 1103 return false; 1104 1105 // TODO: Fold a following sign-/zero-extend into the load instruction. 1106 1107 unsigned Opc; 1108 const TargetRegisterClass *RC; 1109 switch (getSimpleType(Load->getType())) { 1110 case MVT::i1: 1111 case MVT::i8: 1112 Opc = WebAssembly::LOAD8_U_I32; 1113 RC = &WebAssembly::I32RegClass; 1114 break; 1115 case MVT::i16: 1116 Opc = WebAssembly::LOAD16_U_I32; 1117 RC = &WebAssembly::I32RegClass; 1118 break; 1119 case MVT::i32: 1120 Opc = WebAssembly::LOAD_I32; 1121 RC = &WebAssembly::I32RegClass; 1122 break; 1123 case MVT::i64: 1124 Opc = WebAssembly::LOAD_I64; 1125 RC = &WebAssembly::I64RegClass; 1126 break; 1127 case MVT::f32: 1128 Opc = WebAssembly::LOAD_F32; 1129 RC = &WebAssembly::F32RegClass; 1130 break; 1131 case MVT::f64: 1132 Opc = WebAssembly::LOAD_F64; 1133 RC = &WebAssembly::F64RegClass; 1134 break; 1135 default: 1136 return false; 1137 } 1138 1139 materializeLoadStoreOperands(Addr); 1140 1141 unsigned ResultReg = createResultReg(RC); 1142 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), 1143 ResultReg); 1144 1145 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load)); 1146 1147 updateValueMap(Load, ResultReg); 1148 return true; 1149 } 1150 1151 bool WebAssemblyFastISel::selectStore(const Instruction *I) { 1152 const StoreInst *Store = cast<StoreInst>(I); 1153 if (Store->isAtomic()) 1154 return false; 1155 if (!Subtarget->hasSIMD128() && 1156 Store->getValueOperand()->getType()->isVectorTy()) 1157 return false; 1158 1159 Address Addr; 1160 if (!computeAddress(Store->getPointerOperand(), Addr)) 1161 return false; 1162 1163 unsigned Opc; 1164 bool VTIsi1 = false; 1165 switch (getSimpleType(Store->getValueOperand()->getType())) { 1166 case MVT::i1: 1167 VTIsi1 = true; 1168 case MVT::i8: 1169 Opc = WebAssembly::STORE8_I32; 1170 break; 1171 case MVT::i16: 1172 Opc = WebAssembly::STORE16_I32; 1173 break; 1174 case MVT::i32: 1175 Opc = WebAssembly::STORE_I32; 1176 break; 1177 case MVT::i64: 1178 Opc = WebAssembly::STORE_I64; 1179 break; 1180 case MVT::f32: 1181 Opc = WebAssembly::STORE_F32; 1182 break; 1183 case MVT::f64: 1184 Opc = WebAssembly::STORE_F64; 1185 break; 1186 default: return false; 1187 } 1188 1189 materializeLoadStoreOperands(Addr); 1190 1191 unsigned ValueReg = getRegForValue(Store->getValueOperand()); 1192 if (ValueReg == 0) 1193 return false; 1194 if (VTIsi1) 1195 ValueReg = maskI1Value(ValueReg, Store->getValueOperand()); 1196 1197 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); 1198 1199 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store)); 1200 1201 MIB.addReg(ValueReg); 1202 return true; 1203 } 1204 1205 bool WebAssemblyFastISel::selectBr(const Instruction *I) { 1206 const BranchInst *Br = cast<BranchInst>(I); 1207 if (Br->isUnconditional()) { 1208 MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)]; 1209 fastEmitBranch(MSucc, Br->getDebugLoc()); 1210 return true; 1211 } 1212 1213 MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)]; 1214 MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)]; 1215 1216 bool Not; 1217 unsigned CondReg = getRegForI1Value(Br->getCondition(), Not); 1218 if (CondReg == 0) 1219 return false; 1220 1221 unsigned Opc = WebAssembly::BR_IF; 1222 if (Not) 1223 Opc = WebAssembly::BR_UNLESS; 1224 1225 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)) 1226 .addMBB(TBB) 1227 .addReg(CondReg); 1228 1229 finishCondBranch(Br->getParent(), TBB, FBB); 1230 return true; 1231 } 1232 1233 bool WebAssemblyFastISel::selectRet(const Instruction *I) { 1234 if (!FuncInfo.CanLowerReturn) 1235 return false; 1236 1237 const ReturnInst *Ret = cast<ReturnInst>(I); 1238 1239 if (Ret->getNumOperands() == 0) { 1240 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 1241 TII.get(WebAssembly::RETURN_VOID)); 1242 return true; 1243 } 1244 1245 Value *RV = Ret->getOperand(0); 1246 if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy()) 1247 return false; 1248 1249 unsigned Opc; 1250 switch (getSimpleType(RV->getType())) { 1251 case MVT::i1: case MVT::i8: 1252 case MVT::i16: case MVT::i32: 1253 Opc = WebAssembly::RETURN_I32; 1254 break; 1255 case MVT::i64: 1256 Opc = WebAssembly::RETURN_I64; 1257 break; 1258 case MVT::f32: 1259 Opc = WebAssembly::RETURN_F32; 1260 break; 1261 case MVT::f64: 1262 Opc = WebAssembly::RETURN_F64; 1263 break; 1264 case MVT::v16i8: 1265 Opc = WebAssembly::RETURN_v16i8; 1266 break; 1267 case MVT::v8i16: 1268 Opc = WebAssembly::RETURN_v8i16; 1269 break; 1270 case MVT::v4i32: 1271 Opc = WebAssembly::RETURN_v4i32; 1272 break; 1273 case MVT::v4f32: 1274 Opc = WebAssembly::RETURN_v4f32; 1275 break; 1276 default: return false; 1277 } 1278 1279 unsigned Reg; 1280 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt)) 1281 Reg = getRegForSignedValue(RV); 1282 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt)) 1283 Reg = getRegForUnsignedValue(RV); 1284 else 1285 Reg = getRegForValue(RV); 1286 1287 if (Reg == 0) 1288 return false; 1289 1290 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg); 1291 return true; 1292 } 1293 1294 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) { 1295 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 1296 TII.get(WebAssembly::UNREACHABLE)); 1297 return true; 1298 } 1299 1300 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) { 1301 switch (I->getOpcode()) { 1302 case Instruction::Call: 1303 if (selectCall(I)) 1304 return true; 1305 break; 1306 case Instruction::Select: return selectSelect(I); 1307 case Instruction::Trunc: return selectTrunc(I); 1308 case Instruction::ZExt: return selectZExt(I); 1309 case Instruction::SExt: return selectSExt(I); 1310 case Instruction::ICmp: return selectICmp(I); 1311 case Instruction::FCmp: return selectFCmp(I); 1312 case Instruction::BitCast: return selectBitCast(I); 1313 case Instruction::Load: return selectLoad(I); 1314 case Instruction::Store: return selectStore(I); 1315 case Instruction::Br: return selectBr(I); 1316 case Instruction::Ret: return selectRet(I); 1317 case Instruction::Unreachable: return selectUnreachable(I); 1318 default: break; 1319 } 1320 1321 // Fall back to target-independent instruction selection. 1322 return selectOperator(I, I->getOpcode()); 1323 } 1324 1325 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo, 1326 const TargetLibraryInfo *LibInfo) { 1327 return new WebAssemblyFastISel(FuncInfo, LibInfo); 1328 } 1329