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