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