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