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