1 //===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// This file defines the WebAssembly-specific support for the FastISel 12 /// class. Some of the target-specific code is generated by tablegen in the file 13 /// WebAssemblyGenFastISel.inc, which is #included here. 14 /// 15 /// TODO: kill flags 16 /// 17 //===----------------------------------------------------------------------===// 18 19 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 20 #include "WebAssembly.h" 21 #include "WebAssemblyMachineFunctionInfo.h" 22 #include "WebAssemblySubtarget.h" 23 #include "WebAssemblyTargetMachine.h" 24 #include "llvm/Analysis/BranchProbabilityInfo.h" 25 #include "llvm/CodeGen/FastISel.h" 26 #include "llvm/CodeGen/FunctionLoweringInfo.h" 27 #include "llvm/CodeGen/MachineConstantPool.h" 28 #include "llvm/CodeGen/MachineFrameInfo.h" 29 #include "llvm/CodeGen/MachineInstrBuilder.h" 30 #include "llvm/CodeGen/MachineRegisterInfo.h" 31 #include "llvm/IR/DataLayout.h" 32 #include "llvm/IR/DerivedTypes.h" 33 #include "llvm/IR/Function.h" 34 #include "llvm/IR/GetElementPtrTypeIterator.h" 35 #include "llvm/IR/GlobalAlias.h" 36 #include "llvm/IR/GlobalVariable.h" 37 #include "llvm/IR/Instructions.h" 38 #include "llvm/IR/IntrinsicInst.h" 39 #include "llvm/IR/Operator.h" 40 using namespace llvm; 41 42 #define DEBUG_TYPE "wasm-fastisel" 43 44 namespace { 45 46 class WebAssemblyFastISel final : public FastISel { 47 // All possible address modes. 48 class Address { 49 public: 50 typedef enum { RegBase, FrameIndexBase } BaseKind; 51 52 private: 53 BaseKind Kind; 54 union { 55 unsigned Reg; 56 int FI; 57 } Base; 58 59 int64_t Offset; 60 61 const GlobalValue *GV; 62 63 public: 64 // Innocuous defaults for our address. 65 Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; } 66 void setKind(BaseKind K) { 67 assert(!isSet() && "Can't change kind with non-zero base"); 68 Kind = K; 69 } 70 BaseKind getKind() const { return Kind; } 71 bool isRegBase() const { return Kind == RegBase; } 72 bool isFIBase() const { return Kind == FrameIndexBase; } 73 void setReg(unsigned Reg) { 74 assert(isRegBase() && "Invalid base register access!"); 75 assert(Base.Reg == 0 && "Overwriting non-zero register"); 76 Base.Reg = Reg; 77 } 78 unsigned getReg() const { 79 assert(isRegBase() && "Invalid base register access!"); 80 return Base.Reg; 81 } 82 void setFI(unsigned FI) { 83 assert(isFIBase() && "Invalid base frame index access!"); 84 assert(Base.FI == 0 && "Overwriting non-zero frame index"); 85 Base.FI = FI; 86 } 87 unsigned getFI() const { 88 assert(isFIBase() && "Invalid base frame index access!"); 89 return Base.FI; 90 } 91 92 void setOffset(int64_t Offset_) { 93 assert(Offset_ >= 0 && "Offsets must be non-negative"); 94 Offset = Offset_; 95 } 96 int64_t getOffset() const { return Offset; } 97 void setGlobalValue(const GlobalValue *G) { GV = G; } 98 const GlobalValue *getGlobalValue() const { return GV; } 99 bool isSet() const { 100 if (isRegBase()) { 101 return Base.Reg != 0; 102 } else { 103 return Base.FI != 0; 104 } 105 } 106 }; 107 108 /// Keep a pointer to the WebAssemblySubtarget around so that we can make the 109 /// right decision when generating code for different targets. 110 const WebAssemblySubtarget *Subtarget; 111 LLVMContext *Context; 112 113 private: 114 // Utility helper routines 115 MVT::SimpleValueType getSimpleType(Type *Ty) { 116 EVT VT = TLI.getValueType(DL, Ty, /*HandleUnknown=*/true); 117 return VT.isSimple() ? VT.getSimpleVT().SimpleTy : 118 MVT::INVALID_SIMPLE_VALUE_TYPE; 119 } 120 MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) { 121 switch (VT) { 122 case MVT::i1: 123 case MVT::i8: 124 case MVT::i16: 125 return MVT::i32; 126 case MVT::i32: 127 case MVT::i64: 128 case MVT::f32: 129 case MVT::f64: 130 case MVT::ExceptRef: 131 return VT; 132 case MVT::f16: 133 return MVT::f32; 134 case MVT::v16i8: 135 case MVT::v8i16: 136 case MVT::v4i32: 137 case MVT::v2i64: 138 case MVT::v4f32: 139 case MVT::v2f64: 140 if (Subtarget->hasSIMD128()) 141 return VT; 142 break; 143 default: 144 break; 145 } 146 return MVT::INVALID_SIMPLE_VALUE_TYPE; 147 } 148 bool computeAddress(const Value *Obj, Address &Addr); 149 void materializeLoadStoreOperands(Address &Addr); 150 void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB, 151 MachineMemOperand *MMO); 152 unsigned maskI1Value(unsigned Reg, const Value *V); 153 unsigned getRegForI1Value(const Value *V, bool &Not); 154 unsigned zeroExtendToI32(unsigned Reg, const Value *V, 155 MVT::SimpleValueType From); 156 unsigned signExtendToI32(unsigned Reg, const Value *V, 157 MVT::SimpleValueType From); 158 unsigned zeroExtend(unsigned Reg, const Value *V, 159 MVT::SimpleValueType From, 160 MVT::SimpleValueType To); 161 unsigned signExtend(unsigned Reg, const Value *V, 162 MVT::SimpleValueType From, 163 MVT::SimpleValueType To); 164 unsigned getRegForUnsignedValue(const Value *V); 165 unsigned getRegForSignedValue(const Value *V); 166 unsigned getRegForPromotedValue(const Value *V, bool IsSigned); 167 unsigned notValue(unsigned Reg); 168 unsigned copyValue(unsigned Reg); 169 170 // Backend specific FastISel code. 171 unsigned fastMaterializeAlloca(const AllocaInst *AI) override; 172 unsigned fastMaterializeConstant(const Constant *C) override; 173 bool fastLowerArguments() override; 174 175 // Selection routines. 176 bool selectCall(const Instruction *I); 177 bool selectSelect(const Instruction *I); 178 bool selectTrunc(const Instruction *I); 179 bool selectZExt(const Instruction *I); 180 bool selectSExt(const Instruction *I); 181 bool selectICmp(const Instruction *I); 182 bool selectFCmp(const Instruction *I); 183 bool selectBitCast(const Instruction *I); 184 bool selectLoad(const Instruction *I); 185 bool selectStore(const Instruction *I); 186 bool selectBr(const Instruction *I); 187 bool selectRet(const Instruction *I); 188 bool selectUnreachable(const Instruction *I); 189 190 public: 191 // Backend specific FastISel code. 192 WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo, 193 const TargetLibraryInfo *LibInfo) 194 : FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) { 195 Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>(); 196 Context = &FuncInfo.Fn->getContext(); 197 } 198 199 bool fastSelectInstruction(const Instruction *I) override; 200 201 #include "WebAssemblyGenFastISel.inc" 202 }; 203 204 } // end anonymous namespace 205 206 bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) { 207 208 const User *U = nullptr; 209 unsigned Opcode = Instruction::UserOp1; 210 if (const Instruction *I = dyn_cast<Instruction>(Obj)) { 211 // Don't walk into other basic blocks unless the object is an alloca from 212 // another block, otherwise it may not have a virtual register assigned. 213 if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) || 214 FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) { 215 Opcode = I->getOpcode(); 216 U = I; 217 } 218 } else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) { 219 Opcode = C->getOpcode(); 220 U = C; 221 } 222 223 if (auto *Ty = dyn_cast<PointerType>(Obj->getType())) 224 if (Ty->getAddressSpace() > 255) 225 // Fast instruction selection doesn't support the special 226 // address spaces. 227 return false; 228 229 if (const GlobalValue *GV = dyn_cast<GlobalValue>(Obj)) { 230 if (Addr.getGlobalValue()) 231 return false; 232 Addr.setGlobalValue(GV); 233 return true; 234 } 235 236 switch (Opcode) { 237 default: 238 break; 239 case Instruction::BitCast: { 240 // Look through bitcasts. 241 return computeAddress(U->getOperand(0), Addr); 242 } 243 case Instruction::IntToPtr: { 244 // Look past no-op inttoptrs. 245 if (TLI.getValueType(DL, U->getOperand(0)->getType()) == 246 TLI.getPointerTy(DL)) 247 return computeAddress(U->getOperand(0), Addr); 248 break; 249 } 250 case Instruction::PtrToInt: { 251 // Look past no-op ptrtoints. 252 if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL)) 253 return computeAddress(U->getOperand(0), Addr); 254 break; 255 } 256 case Instruction::GetElementPtr: { 257 Address SavedAddr = Addr; 258 uint64_t TmpOffset = Addr.getOffset(); 259 // Non-inbounds geps can wrap; wasm's offsets can't. 260 if (!cast<GEPOperator>(U)->isInBounds()) 261 goto unsupported_gep; 262 // Iterate through the GEP folding the constants into offsets where 263 // we can. 264 for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U); 265 GTI != E; ++GTI) { 266 const Value *Op = GTI.getOperand(); 267 if (StructType *STy = GTI.getStructTypeOrNull()) { 268 const StructLayout *SL = DL.getStructLayout(STy); 269 unsigned Idx = cast<ConstantInt>(Op)->getZExtValue(); 270 TmpOffset += SL->getElementOffset(Idx); 271 } else { 272 uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType()); 273 for (;;) { 274 if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) { 275 // Constant-offset addressing. 276 TmpOffset += CI->getSExtValue() * S; 277 break; 278 } 279 if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) { 280 // An unscaled add of a register. Set it as the new base. 281 unsigned Reg = getRegForValue(Op); 282 if (Reg == 0) 283 return false; 284 Addr.setReg(Reg); 285 break; 286 } 287 if (canFoldAddIntoGEP(U, Op)) { 288 // A compatible add with a constant operand. Fold the constant. 289 ConstantInt *CI = 290 cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1)); 291 TmpOffset += CI->getSExtValue() * S; 292 // Iterate on the other operand. 293 Op = cast<AddOperator>(Op)->getOperand(0); 294 continue; 295 } 296 // Unsupported 297 goto unsupported_gep; 298 } 299 } 300 } 301 // Don't fold in negative offsets. 302 if (int64_t(TmpOffset) >= 0) { 303 // Try to grab the base operand now. 304 Addr.setOffset(TmpOffset); 305 if (computeAddress(U->getOperand(0), Addr)) 306 return true; 307 } 308 // We failed, restore everything and try the other options. 309 Addr = SavedAddr; 310 unsupported_gep: 311 break; 312 } 313 case Instruction::Alloca: { 314 const AllocaInst *AI = cast<AllocaInst>(Obj); 315 DenseMap<const AllocaInst *, int>::iterator SI = 316 FuncInfo.StaticAllocaMap.find(AI); 317 if (SI != FuncInfo.StaticAllocaMap.end()) { 318 if (Addr.isSet()) { 319 return false; 320 } 321 Addr.setKind(Address::FrameIndexBase); 322 Addr.setFI(SI->second); 323 return true; 324 } 325 break; 326 } 327 case Instruction::Add: { 328 // Adds of constants are common and easy enough. 329 const Value *LHS = U->getOperand(0); 330 const Value *RHS = U->getOperand(1); 331 332 if (isa<ConstantInt>(LHS)) 333 std::swap(LHS, RHS); 334 335 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) { 336 uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue(); 337 if (int64_t(TmpOffset) >= 0) { 338 Addr.setOffset(TmpOffset); 339 return computeAddress(LHS, Addr); 340 } 341 } 342 343 Address Backup = Addr; 344 if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr)) 345 return true; 346 Addr = Backup; 347 348 break; 349 } 350 case Instruction::Sub: { 351 // Subs of constants are common and easy enough. 352 const Value *LHS = U->getOperand(0); 353 const Value *RHS = U->getOperand(1); 354 355 if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) { 356 int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue(); 357 if (TmpOffset >= 0) { 358 Addr.setOffset(TmpOffset); 359 return computeAddress(LHS, Addr); 360 } 361 } 362 break; 363 } 364 } 365 if (Addr.isSet()) { 366 return false; 367 } 368 unsigned Reg = getRegForValue(Obj); 369 if (Reg == 0) 370 return false; 371 Addr.setReg(Reg); 372 return Addr.getReg() != 0; 373 } 374 375 void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) { 376 if (Addr.isRegBase()) { 377 unsigned Reg = Addr.getReg(); 378 if (Reg == 0) { 379 Reg = createResultReg(Subtarget->hasAddr64() ? 380 &WebAssembly::I64RegClass : 381 &WebAssembly::I32RegClass); 382 unsigned Opc = Subtarget->hasAddr64() ? 383 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 ICmpInst *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 if (BinaryOperator::isNot(V) && V->getType()->isIntegerTy(32)) { 425 Not = true; 426 return getRegForValue(BinaryOperator::getNotArgument(V)); 427 } 428 429 Not = false; 430 unsigned Reg = getRegForValue(V); 431 if (Reg == 0) 432 return 0; 433 return maskI1Value(Reg, V); 434 } 435 436 unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V, 437 MVT::SimpleValueType From) { 438 if (Reg == 0) 439 return 0; 440 441 switch (From) { 442 case MVT::i1: 443 // If the value is naturally an i1, we don't need to mask it. 444 // TODO: Recursively examine selects, phis, and, or, xor, constants. 445 if (From == MVT::i1 && V != nullptr) { 446 if (isa<CmpInst>(V) || 447 (isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())) 448 return copyValue(Reg); 449 } 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) : 568 getRegForUnsignedValue(V); 569 } 570 571 unsigned WebAssemblyFastISel::notValue(unsigned Reg) { 572 assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass); 573 574 unsigned NotReg = createResultReg(&WebAssembly::I32RegClass); 575 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 576 TII.get(WebAssembly::EQZ_I32), NotReg) 577 .addReg(Reg); 578 return NotReg; 579 } 580 581 unsigned WebAssemblyFastISel::copyValue(unsigned Reg) { 582 unsigned ResultReg = createResultReg(MRI.getRegClass(Reg)); 583 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 584 TII.get(WebAssembly::COPY), ResultReg) 585 .addReg(Reg); 586 return ResultReg; 587 } 588 589 unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) { 590 DenseMap<const AllocaInst *, int>::iterator SI = 591 FuncInfo.StaticAllocaMap.find(AI); 592 593 if (SI != FuncInfo.StaticAllocaMap.end()) { 594 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ? 595 &WebAssembly::I64RegClass : 596 &WebAssembly::I32RegClass); 597 unsigned Opc = Subtarget->hasAddr64() ? 598 WebAssembly::COPY_I64 : 599 WebAssembly::COPY_I32; 600 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 601 .addFrameIndex(SI->second); 602 return ResultReg; 603 } 604 605 return 0; 606 } 607 608 unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) { 609 if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) { 610 unsigned ResultReg = createResultReg(Subtarget->hasAddr64() ? 611 &WebAssembly::I64RegClass : 612 &WebAssembly::I32RegClass); 613 unsigned Opc = Subtarget->hasAddr64() ? 614 WebAssembly::CONST_I64 : 615 WebAssembly::CONST_I32; 616 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 617 .addGlobalAddress(GV); 618 return ResultReg; 619 } 620 621 // Let target-independent code handle it. 622 return 0; 623 } 624 625 bool WebAssemblyFastISel::fastLowerArguments() { 626 if (!FuncInfo.CanLowerReturn) 627 return false; 628 629 const Function *F = FuncInfo.Fn; 630 if (F->isVarArg()) 631 return false; 632 633 unsigned i = 0; 634 for (auto const &Arg : F->args()) { 635 const AttributeList &Attrs = F->getAttributes(); 636 if (Attrs.hasParamAttribute(i, Attribute::ByVal) || 637 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) || 638 Attrs.hasParamAttribute(i, Attribute::SwiftError) || 639 Attrs.hasParamAttribute(i, Attribute::InAlloca) || 640 Attrs.hasParamAttribute(i, Attribute::Nest)) 641 return false; 642 643 Type *ArgTy = Arg.getType(); 644 if (ArgTy->isStructTy() || ArgTy->isArrayTy()) 645 return false; 646 if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy()) 647 return false; 648 649 unsigned Opc; 650 const TargetRegisterClass *RC; 651 switch (getSimpleType(ArgTy)) { 652 case MVT::i1: 653 case MVT::i8: 654 case MVT::i16: 655 case MVT::i32: 656 Opc = WebAssembly::ARGUMENT_I32; 657 RC = &WebAssembly::I32RegClass; 658 break; 659 case MVT::i64: 660 Opc = WebAssembly::ARGUMENT_I64; 661 RC = &WebAssembly::I64RegClass; 662 break; 663 case MVT::f32: 664 Opc = WebAssembly::ARGUMENT_F32; 665 RC = &WebAssembly::F32RegClass; 666 break; 667 case MVT::f64: 668 Opc = WebAssembly::ARGUMENT_F64; 669 RC = &WebAssembly::F64RegClass; 670 break; 671 case MVT::v16i8: 672 Opc = WebAssembly::ARGUMENT_v16i8; 673 RC = &WebAssembly::V128RegClass; 674 break; 675 case MVT::v8i16: 676 Opc = WebAssembly::ARGUMENT_v8i16; 677 RC = &WebAssembly::V128RegClass; 678 break; 679 case MVT::v4i32: 680 Opc = WebAssembly::ARGUMENT_v4i32; 681 RC = &WebAssembly::V128RegClass; 682 break; 683 case MVT::v2i64: 684 Opc = WebAssembly::ARGUMENT_v2i64; 685 RC = &WebAssembly::V128RegClass; 686 break; 687 case MVT::v4f32: 688 Opc = WebAssembly::ARGUMENT_v4f32; 689 RC = &WebAssembly::V128RegClass; 690 break; 691 case MVT::v2f64: 692 Opc = WebAssembly::ARGUMENT_v2f64; 693 RC = &WebAssembly::V128RegClass; 694 break; 695 case MVT::ExceptRef: 696 Opc = WebAssembly::ARGUMENT_EXCEPT_REF; 697 RC = &WebAssembly::EXCEPT_REFRegClass; 698 break; 699 default: 700 return false; 701 } 702 unsigned ResultReg = createResultReg(RC); 703 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 704 .addImm(i); 705 updateValueMap(&Arg, ResultReg); 706 707 ++i; 708 } 709 710 MRI.addLiveIn(WebAssembly::ARGUMENTS); 711 712 auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>(); 713 for (auto const &Arg : F->args()) { 714 MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType())); 715 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) { 716 MFI->clearParamsAndResults(); 717 return false; 718 } 719 MFI->addParam(ArgTy); 720 } 721 722 if (!F->getReturnType()->isVoidTy()) { 723 MVT::SimpleValueType RetTy = getLegalType(getSimpleType(F->getReturnType())); 724 if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) { 725 MFI->clearParamsAndResults(); 726 return false; 727 } 728 MFI->addResult(RetTy); 729 } 730 731 return true; 732 } 733 734 bool WebAssemblyFastISel::selectCall(const Instruction *I) { 735 const CallInst *Call = cast<CallInst>(I); 736 737 if (Call->isMustTailCall() || Call->isInlineAsm() || 738 Call->getFunctionType()->isVarArg()) 739 return false; 740 741 Function *Func = Call->getCalledFunction(); 742 if (Func && Func->isIntrinsic()) 743 return false; 744 745 bool IsDirect = Func != nullptr; 746 if (!IsDirect && isa<ConstantExpr>(Call->getCalledValue())) 747 return false; 748 749 FunctionType *FuncTy = Call->getFunctionType(); 750 unsigned Opc; 751 bool IsVoid = FuncTy->getReturnType()->isVoidTy(); 752 unsigned ResultReg; 753 if (IsVoid) { 754 Opc = IsDirect ? WebAssembly::CALL_VOID : WebAssembly::PCALL_INDIRECT_VOID; 755 } else { 756 if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy()) 757 return false; 758 759 MVT::SimpleValueType RetTy = getSimpleType(Call->getType()); 760 switch (RetTy) { 761 case MVT::i1: 762 case MVT::i8: 763 case MVT::i16: 764 case MVT::i32: 765 Opc = IsDirect ? WebAssembly::CALL_I32 : WebAssembly::PCALL_INDIRECT_I32; 766 ResultReg = createResultReg(&WebAssembly::I32RegClass); 767 break; 768 case MVT::i64: 769 Opc = IsDirect ? WebAssembly::CALL_I64 : WebAssembly::PCALL_INDIRECT_I64; 770 ResultReg = createResultReg(&WebAssembly::I64RegClass); 771 break; 772 case MVT::f32: 773 Opc = IsDirect ? WebAssembly::CALL_F32 : WebAssembly::PCALL_INDIRECT_F32; 774 ResultReg = createResultReg(&WebAssembly::F32RegClass); 775 break; 776 case MVT::f64: 777 Opc = IsDirect ? WebAssembly::CALL_F64 : WebAssembly::PCALL_INDIRECT_F64; 778 ResultReg = createResultReg(&WebAssembly::F64RegClass); 779 break; 780 case MVT::v16i8: 781 Opc = 782 IsDirect ? WebAssembly::CALL_v16i8 : WebAssembly::PCALL_INDIRECT_v16i8; 783 ResultReg = createResultReg(&WebAssembly::V128RegClass); 784 break; 785 case MVT::v8i16: 786 Opc = 787 IsDirect ? WebAssembly::CALL_v8i16 : WebAssembly::PCALL_INDIRECT_v8i16; 788 ResultReg = createResultReg(&WebAssembly::V128RegClass); 789 break; 790 case MVT::v4i32: 791 Opc = 792 IsDirect ? WebAssembly::CALL_v4i32 : WebAssembly::PCALL_INDIRECT_v4i32; 793 ResultReg = createResultReg(&WebAssembly::V128RegClass); 794 break; 795 case MVT::v2i64: 796 Opc = 797 IsDirect ? WebAssembly::CALL_v2i64 : WebAssembly::PCALL_INDIRECT_v2i64; 798 ResultReg = createResultReg(&WebAssembly::V128RegClass); 799 break; 800 case MVT::v4f32: 801 Opc = 802 IsDirect ? WebAssembly::CALL_v4f32 : WebAssembly::PCALL_INDIRECT_v4f32; 803 ResultReg = createResultReg(&WebAssembly::V128RegClass); 804 break; 805 case MVT::v2f64: 806 Opc = 807 IsDirect ? WebAssembly::CALL_v2f64 : WebAssembly::PCALL_INDIRECT_v2f64; 808 ResultReg = createResultReg(&WebAssembly::V128RegClass); 809 break; 810 case MVT::ExceptRef: 811 Opc = IsDirect ? WebAssembly::CALL_EXCEPT_REF 812 : WebAssembly::PCALL_INDIRECT_EXCEPT_REF; 813 ResultReg = createResultReg(&WebAssembly::EXCEPT_REFRegClass); 814 break; 815 default: 816 return false; 817 } 818 } 819 820 SmallVector<unsigned, 8> Args; 821 for (unsigned i = 0, e = Call->getNumArgOperands(); i < e; ++i) { 822 Value *V = Call->getArgOperand(i); 823 MVT::SimpleValueType ArgTy = getSimpleType(V->getType()); 824 if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) 825 return false; 826 827 const AttributeList &Attrs = Call->getAttributes(); 828 if (Attrs.hasParamAttribute(i, Attribute::ByVal) || 829 Attrs.hasParamAttribute(i, Attribute::SwiftSelf) || 830 Attrs.hasParamAttribute(i, Attribute::SwiftError) || 831 Attrs.hasParamAttribute(i, Attribute::InAlloca) || 832 Attrs.hasParamAttribute(i, Attribute::Nest)) 833 return false; 834 835 unsigned Reg; 836 837 if (Attrs.hasParamAttribute(i, Attribute::SExt)) 838 Reg = getRegForSignedValue(V); 839 else if (Attrs.hasParamAttribute(i, Attribute::ZExt)) 840 Reg = getRegForUnsignedValue(V); 841 else 842 Reg = getRegForValue(V); 843 844 if (Reg == 0) 845 return false; 846 847 Args.push_back(Reg); 848 } 849 850 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); 851 852 if (!IsVoid) 853 MIB.addReg(ResultReg, RegState::Define); 854 855 if (IsDirect) 856 MIB.addGlobalAddress(Func); 857 else { 858 unsigned Reg = getRegForValue(Call->getCalledValue()); 859 if (Reg == 0) 860 return false; 861 MIB.addReg(Reg); 862 } 863 864 for (unsigned ArgReg : Args) 865 MIB.addReg(ArgReg); 866 867 if (!IsVoid) 868 updateValueMap(Call, ResultReg); 869 return true; 870 } 871 872 bool WebAssemblyFastISel::selectSelect(const Instruction *I) { 873 const SelectInst *Select = cast<SelectInst>(I); 874 875 bool Not; 876 unsigned CondReg = getRegForI1Value(Select->getCondition(), Not); 877 if (CondReg == 0) 878 return false; 879 880 unsigned TrueReg = getRegForValue(Select->getTrueValue()); 881 if (TrueReg == 0) 882 return false; 883 884 unsigned FalseReg = getRegForValue(Select->getFalseValue()); 885 if (FalseReg == 0) 886 return false; 887 888 if (Not) 889 std::swap(TrueReg, FalseReg); 890 891 unsigned Opc; 892 const TargetRegisterClass *RC; 893 switch (getSimpleType(Select->getType())) { 894 case MVT::i1: 895 case MVT::i8: 896 case MVT::i16: 897 case MVT::i32: 898 Opc = WebAssembly::SELECT_I32; 899 RC = &WebAssembly::I32RegClass; 900 break; 901 case MVT::i64: 902 Opc = WebAssembly::SELECT_I64; 903 RC = &WebAssembly::I64RegClass; 904 break; 905 case MVT::f32: 906 Opc = WebAssembly::SELECT_F32; 907 RC = &WebAssembly::F32RegClass; 908 break; 909 case MVT::f64: 910 Opc = WebAssembly::SELECT_F64; 911 RC = &WebAssembly::F64RegClass; 912 break; 913 case MVT::ExceptRef: 914 Opc = WebAssembly::SELECT_EXCEPT_REF; 915 RC = &WebAssembly::EXCEPT_REFRegClass; 916 break; 917 default: 918 return false; 919 } 920 921 unsigned ResultReg = createResultReg(RC); 922 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 923 .addReg(TrueReg) 924 .addReg(FalseReg) 925 .addReg(CondReg); 926 927 updateValueMap(Select, ResultReg); 928 return true; 929 } 930 931 bool WebAssemblyFastISel::selectTrunc(const Instruction *I) { 932 const TruncInst *Trunc = cast<TruncInst>(I); 933 934 unsigned Reg = getRegForValue(Trunc->getOperand(0)); 935 if (Reg == 0) 936 return false; 937 938 if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) { 939 unsigned Result = createResultReg(&WebAssembly::I32RegClass); 940 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 941 TII.get(WebAssembly::I32_WRAP_I64), Result) 942 .addReg(Reg); 943 Reg = Result; 944 } 945 946 updateValueMap(Trunc, Reg); 947 return true; 948 } 949 950 bool WebAssemblyFastISel::selectZExt(const Instruction *I) { 951 const ZExtInst *ZExt = cast<ZExtInst>(I); 952 953 const Value *Op = ZExt->getOperand(0); 954 MVT::SimpleValueType From = getSimpleType(Op->getType()); 955 MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType())); 956 unsigned In = getRegForValue(Op); 957 if (In == 0) 958 return false; 959 unsigned Reg = zeroExtend(In, Op, From, To); 960 if (Reg == 0) 961 return false; 962 963 updateValueMap(ZExt, Reg); 964 return true; 965 } 966 967 bool WebAssemblyFastISel::selectSExt(const Instruction *I) { 968 const SExtInst *SExt = cast<SExtInst>(I); 969 970 const Value *Op = SExt->getOperand(0); 971 MVT::SimpleValueType From = getSimpleType(Op->getType()); 972 MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType())); 973 unsigned In = getRegForValue(Op); 974 if (In == 0) 975 return false; 976 unsigned Reg = signExtend(In, Op, From, To); 977 if (Reg == 0) 978 return false; 979 980 updateValueMap(SExt, Reg); 981 return true; 982 } 983 984 bool WebAssemblyFastISel::selectICmp(const Instruction *I) { 985 const ICmpInst *ICmp = cast<ICmpInst>(I); 986 987 bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64; 988 unsigned Opc; 989 bool isSigned = false; 990 switch (ICmp->getPredicate()) { 991 case ICmpInst::ICMP_EQ: 992 Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64; 993 break; 994 case ICmpInst::ICMP_NE: 995 Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64; 996 break; 997 case ICmpInst::ICMP_UGT: 998 Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64; 999 break; 1000 case ICmpInst::ICMP_UGE: 1001 Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64; 1002 break; 1003 case ICmpInst::ICMP_ULT: 1004 Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64; 1005 break; 1006 case ICmpInst::ICMP_ULE: 1007 Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64; 1008 break; 1009 case ICmpInst::ICMP_SGT: 1010 Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64; 1011 isSigned = true; 1012 break; 1013 case ICmpInst::ICMP_SGE: 1014 Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64; 1015 isSigned = true; 1016 break; 1017 case ICmpInst::ICMP_SLT: 1018 Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64; 1019 isSigned = true; 1020 break; 1021 case ICmpInst::ICMP_SLE: 1022 Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64; 1023 isSigned = true; 1024 break; 1025 default: return false; 1026 } 1027 1028 unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), isSigned); 1029 if (LHS == 0) 1030 return false; 1031 1032 unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), isSigned); 1033 if (RHS == 0) 1034 return false; 1035 1036 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass); 1037 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 1038 .addReg(LHS) 1039 .addReg(RHS); 1040 updateValueMap(ICmp, ResultReg); 1041 return true; 1042 } 1043 1044 bool WebAssemblyFastISel::selectFCmp(const Instruction *I) { 1045 const FCmpInst *FCmp = cast<FCmpInst>(I); 1046 1047 unsigned LHS = getRegForValue(FCmp->getOperand(0)); 1048 if (LHS == 0) 1049 return false; 1050 1051 unsigned RHS = getRegForValue(FCmp->getOperand(1)); 1052 if (RHS == 0) 1053 return false; 1054 1055 bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64; 1056 unsigned Opc; 1057 bool Not = false; 1058 switch (FCmp->getPredicate()) { 1059 case FCmpInst::FCMP_OEQ: 1060 Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64; 1061 break; 1062 case FCmpInst::FCMP_UNE: 1063 Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64; 1064 break; 1065 case FCmpInst::FCMP_OGT: 1066 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64; 1067 break; 1068 case FCmpInst::FCMP_OGE: 1069 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64; 1070 break; 1071 case FCmpInst::FCMP_OLT: 1072 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64; 1073 break; 1074 case FCmpInst::FCMP_OLE: 1075 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64; 1076 break; 1077 case FCmpInst::FCMP_UGT: 1078 Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64; 1079 Not = true; 1080 break; 1081 case FCmpInst::FCMP_UGE: 1082 Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64; 1083 Not = true; 1084 break; 1085 case FCmpInst::FCMP_ULT: 1086 Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64; 1087 Not = true; 1088 break; 1089 case FCmpInst::FCMP_ULE: 1090 Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64; 1091 Not = true; 1092 break; 1093 default: 1094 return false; 1095 } 1096 1097 unsigned ResultReg = createResultReg(&WebAssembly::I32RegClass); 1098 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) 1099 .addReg(LHS) 1100 .addReg(RHS); 1101 1102 if (Not) 1103 ResultReg = notValue(ResultReg); 1104 1105 updateValueMap(FCmp, ResultReg); 1106 return true; 1107 } 1108 1109 bool WebAssemblyFastISel::selectBitCast(const Instruction *I) { 1110 // Target-independent code can handle this, except it doesn't set the dead 1111 // flag on the ARGUMENTS clobber, so we have to do that manually in order 1112 // to satisfy code that expects this of isBitcast() instructions. 1113 EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType()); 1114 EVT RetVT = TLI.getValueType(DL, I->getType()); 1115 if (!VT.isSimple() || !RetVT.isSimple()) 1116 return false; 1117 1118 unsigned In = getRegForValue(I->getOperand(0)); 1119 if (In == 0) 1120 return false; 1121 1122 if (VT == RetVT) { 1123 // No-op bitcast. 1124 updateValueMap(I, In); 1125 return true; 1126 } 1127 1128 unsigned Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(), 1129 In, I->getOperand(0)->hasOneUse()); 1130 if (!Reg) 1131 return false; 1132 MachineBasicBlock::iterator Iter = FuncInfo.InsertPt; 1133 --Iter; 1134 assert(Iter->isBitcast()); 1135 Iter->setPhysRegsDeadExcept(ArrayRef<unsigned>(), TRI); 1136 updateValueMap(I, Reg); 1137 return true; 1138 } 1139 1140 bool WebAssemblyFastISel::selectLoad(const Instruction *I) { 1141 const LoadInst *Load = cast<LoadInst>(I); 1142 if (Load->isAtomic()) 1143 return false; 1144 if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy()) 1145 return false; 1146 1147 Address Addr; 1148 if (!computeAddress(Load->getPointerOperand(), Addr)) 1149 return false; 1150 1151 // TODO: Fold a following sign-/zero-extend into the load instruction. 1152 1153 unsigned Opc; 1154 const TargetRegisterClass *RC; 1155 switch (getSimpleType(Load->getType())) { 1156 case MVT::i1: 1157 case MVT::i8: 1158 Opc = WebAssembly::LOAD8_U_I32; 1159 RC = &WebAssembly::I32RegClass; 1160 break; 1161 case MVT::i16: 1162 Opc = WebAssembly::LOAD16_U_I32; 1163 RC = &WebAssembly::I32RegClass; 1164 break; 1165 case MVT::i32: 1166 Opc = WebAssembly::LOAD_I32; 1167 RC = &WebAssembly::I32RegClass; 1168 break; 1169 case MVT::i64: 1170 Opc = WebAssembly::LOAD_I64; 1171 RC = &WebAssembly::I64RegClass; 1172 break; 1173 case MVT::f32: 1174 Opc = WebAssembly::LOAD_F32; 1175 RC = &WebAssembly::F32RegClass; 1176 break; 1177 case MVT::f64: 1178 Opc = WebAssembly::LOAD_F64; 1179 RC = &WebAssembly::F64RegClass; 1180 break; 1181 default: 1182 return false; 1183 } 1184 1185 materializeLoadStoreOperands(Addr); 1186 1187 unsigned ResultReg = createResultReg(RC); 1188 auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), 1189 ResultReg); 1190 1191 addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load)); 1192 1193 updateValueMap(Load, ResultReg); 1194 return true; 1195 } 1196 1197 bool WebAssemblyFastISel::selectStore(const Instruction *I) { 1198 const StoreInst *Store = cast<StoreInst>(I); 1199 if (Store->isAtomic()) 1200 return false; 1201 if (!Subtarget->hasSIMD128() && 1202 Store->getValueOperand()->getType()->isVectorTy()) 1203 return false; 1204 1205 Address Addr; 1206 if (!computeAddress(Store->getPointerOperand(), Addr)) 1207 return false; 1208 1209 unsigned Opc; 1210 bool VTIsi1 = false; 1211 switch (getSimpleType(Store->getValueOperand()->getType())) { 1212 case MVT::i1: 1213 VTIsi1 = true; 1214 LLVM_FALLTHROUGH; 1215 case MVT::i8: 1216 Opc = WebAssembly::STORE8_I32; 1217 break; 1218 case MVT::i16: 1219 Opc = WebAssembly::STORE16_I32; 1220 break; 1221 case MVT::i32: 1222 Opc = WebAssembly::STORE_I32; 1223 break; 1224 case MVT::i64: 1225 Opc = WebAssembly::STORE_I64; 1226 break; 1227 case MVT::f32: 1228 Opc = WebAssembly::STORE_F32; 1229 break; 1230 case MVT::f64: 1231 Opc = WebAssembly::STORE_F64; 1232 break; 1233 default: 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 BranchInst *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 ReturnInst *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: case MVT::i8: 1299 case MVT::i16: case MVT::i32: 1300 Opc = WebAssembly::RETURN_I32; 1301 break; 1302 case MVT::i64: 1303 Opc = WebAssembly::RETURN_I64; 1304 break; 1305 case MVT::f32: 1306 Opc = WebAssembly::RETURN_F32; 1307 break; 1308 case MVT::f64: 1309 Opc = WebAssembly::RETURN_F64; 1310 break; 1311 case MVT::v16i8: 1312 Opc = WebAssembly::RETURN_v16i8; 1313 break; 1314 case MVT::v8i16: 1315 Opc = WebAssembly::RETURN_v8i16; 1316 break; 1317 case MVT::v4i32: 1318 Opc = WebAssembly::RETURN_v4i32; 1319 break; 1320 case MVT::v2i64: 1321 Opc = WebAssembly::RETURN_v2i64; 1322 break; 1323 case MVT::v4f32: 1324 Opc = WebAssembly::RETURN_v4f32; 1325 break; 1326 case MVT::v2f64: 1327 Opc = WebAssembly::RETURN_v2f64; 1328 break; 1329 case MVT::ExceptRef: 1330 Opc = WebAssembly::RETURN_EXCEPT_REF; 1331 break; 1332 default: return false; 1333 } 1334 1335 unsigned Reg; 1336 if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::SExt)) 1337 Reg = getRegForSignedValue(RV); 1338 else if (FuncInfo.Fn->getAttributes().hasAttribute(0, Attribute::ZExt)) 1339 Reg = getRegForUnsignedValue(RV); 1340 else 1341 Reg = getRegForValue(RV); 1342 1343 if (Reg == 0) 1344 return false; 1345 1346 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)).addReg(Reg); 1347 return true; 1348 } 1349 1350 bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) { 1351 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 1352 TII.get(WebAssembly::UNREACHABLE)); 1353 return true; 1354 } 1355 1356 bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) { 1357 switch (I->getOpcode()) { 1358 case Instruction::Call: 1359 if (selectCall(I)) 1360 return true; 1361 break; 1362 case Instruction::Select: return selectSelect(I); 1363 case Instruction::Trunc: return selectTrunc(I); 1364 case Instruction::ZExt: return selectZExt(I); 1365 case Instruction::SExt: return selectSExt(I); 1366 case Instruction::ICmp: return selectICmp(I); 1367 case Instruction::FCmp: return selectFCmp(I); 1368 case Instruction::BitCast: return selectBitCast(I); 1369 case Instruction::Load: return selectLoad(I); 1370 case Instruction::Store: return selectStore(I); 1371 case Instruction::Br: return selectBr(I); 1372 case Instruction::Ret: return selectRet(I); 1373 case Instruction::Unreachable: return selectUnreachable(I); 1374 default: break; 1375 } 1376 1377 // Fall back to target-independent instruction selection. 1378 return selectOperator(I, I->getOpcode()); 1379 } 1380 1381 FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo, 1382 const TargetLibraryInfo *LibInfo) { 1383 return new WebAssemblyFastISel(FuncInfo, LibInfo); 1384 } 1385