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