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