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