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