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