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