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