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