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