Lowering-shared-inl.h (29233B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_shared_Lowering_shared_inl_h 8 #define jit_shared_Lowering_shared_inl_h 9 10 #include "jit/shared/Lowering-shared.h" 11 12 #include "jit/MIR-wasm.h" 13 #include "jit/MIR.h" 14 #include "jit/MIRGenerator.h" 15 16 namespace js { 17 namespace jit { 18 19 void LIRGeneratorShared::emitAtUses(MInstruction* mir) { 20 MOZ_ASSERT(mir->canEmitAtUses()); 21 mir->setEmittedAtUses(); 22 mir->setVirtualRegister(0); 23 } 24 25 LUse LIRGeneratorShared::use(MDefinition* mir, LUse policy) { 26 // It is illegal to call use() on an instruction with two defs. 27 MOZ_ASSERT_IF(BOX_PIECES > 1, mir->type() != MIRType::Value); 28 MOZ_ASSERT_IF(INT64_PIECES > 1, mir->type() != MIRType::Int64); 29 ensureDefined(mir); 30 policy.setVirtualRegister(mir->virtualRegister()); 31 return policy; 32 } 33 34 template <size_t X> 35 void LIRGeneratorShared::define( 36 details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir, 37 LDefinition::Policy policy) { 38 LDefinition::Type type = LDefinition::TypeFrom(mir->type()); 39 define(lir, mir, LDefinition(type, policy)); 40 } 41 42 template <size_t X> 43 void LIRGeneratorShared::define( 44 details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir, 45 const LDefinition& def) { 46 // Call instructions should use defineReturn. 47 MOZ_ASSERT(!lir->isCall()); 48 49 uint32_t vreg = getVirtualRegister(); 50 51 // Assign the definition and a virtual register. Then, propagate this 52 // virtual register to the MIR, so we can map MIR to LIR during lowering. 53 lir->setDef(0, def); 54 lir->getDef(0)->setVirtualRegister(vreg); 55 lir->setMir(mir); 56 mir->setVirtualRegister(vreg); 57 addUnchecked(lir); 58 } 59 60 template <size_t X, size_t Y> 61 void LIRGeneratorShared::defineFixed(LInstructionHelper<1, X, Y>* lir, 62 MDefinition* mir, 63 const LAllocation& output) { 64 LDefinition::Type type = LDefinition::TypeFrom(mir->type()); 65 66 LDefinition def(type, LDefinition::FIXED); 67 def.setOutput(output); 68 69 define(lir, mir, def); 70 } 71 72 template <size_t Ops, size_t Temps> 73 void LIRGeneratorShared::defineInt64Fixed( 74 LInstructionHelper<INT64_PIECES, Ops, Temps>* lir, MDefinition* mir, 75 const LInt64Allocation& output) { 76 uint32_t vreg = getVirtualRegister(); 77 78 #if JS_BITS_PER_WORD == 64 79 LDefinition def(LDefinition::GENERAL, LDefinition::FIXED); 80 def.setOutput(output.value()); 81 lir->setDef(0, def); 82 lir->getDef(0)->setVirtualRegister(vreg); 83 #else 84 LDefinition def0(LDefinition::GENERAL, LDefinition::FIXED); 85 def0.setOutput(output.low()); 86 lir->setDef(0, def0); 87 lir->getDef(0)->setVirtualRegister(vreg); 88 89 getVirtualRegister(); 90 LDefinition def1(LDefinition::GENERAL, LDefinition::FIXED); 91 def1.setOutput(output.high()); 92 lir->setDef(1, def1); 93 lir->getDef(1)->setVirtualRegister(vreg + 1); 94 #endif 95 96 lir->setMir(mir); 97 mir->setVirtualRegister(vreg); 98 addUnchecked(lir); 99 } 100 101 template <size_t Ops, size_t Temps> 102 void LIRGeneratorShared::defineReuseInput( 103 LInstructionHelper<1, Ops, Temps>* lir, MDefinition* mir, 104 uint32_t operand) { 105 // Note: Any other operand that is not the same as this operand should be 106 // marked as not being "atStart". The regalloc cannot handle those and can 107 // overwrite the inputs! 108 109 // The input should be used at the start of the instruction, to avoid moves. 110 MOZ_ASSERT(lir->getOperand(operand)->toUse()->usedAtStart()); 111 112 LDefinition::Type type = LDefinition::TypeFrom(mir->type()); 113 114 LDefinition def(type, LDefinition::MUST_REUSE_INPUT); 115 def.setReusedInput(operand); 116 117 define(lir, mir, def); 118 } 119 120 template <size_t Ops, size_t Temps> 121 void LIRGeneratorShared::defineInt64ReuseInput( 122 LInstructionHelper<INT64_PIECES, Ops, Temps>* lir, MDefinition* mir, 123 uint32_t operand) { 124 // Note: Any other operand that is not the same as this operand should be 125 // marked as not being "atStart". The regalloc cannot handle those and can 126 // overwrite the inputs! 127 128 // The input should be used at the start of the instruction, to avoid moves. 129 MOZ_ASSERT(lir->getOperand(operand)->toUse()->usedAtStart()); 130 #if JS_BITS_PER_WORD == 32 131 MOZ_ASSERT(lir->getOperand(operand + 1)->toUse()->usedAtStart()); 132 #endif 133 MOZ_ASSERT(!lir->isCall()); 134 135 uint32_t vreg = getVirtualRegister(); 136 137 LDefinition def1(LDefinition::GENERAL, LDefinition::MUST_REUSE_INPUT); 138 def1.setReusedInput(operand); 139 lir->setDef(0, def1); 140 lir->getDef(0)->setVirtualRegister(vreg); 141 142 #if JS_BITS_PER_WORD == 32 143 getVirtualRegister(); 144 LDefinition def2(LDefinition::GENERAL, LDefinition::MUST_REUSE_INPUT); 145 def2.setReusedInput(operand + 1); 146 lir->setDef(1, def2); 147 lir->getDef(1)->setVirtualRegister(vreg + 1); 148 #endif 149 150 lir->setMir(mir); 151 mir->setVirtualRegister(vreg); 152 addUnchecked(lir); 153 } 154 155 template <size_t Ops, size_t Temps> 156 void LIRGeneratorShared::defineBoxReuseInput( 157 LInstructionHelper<BOX_PIECES, Ops, Temps>* lir, MDefinition* mir, 158 uint32_t operand) { 159 // The input should be used at the start of the instruction, to avoid moves. 160 MOZ_ASSERT(lir->getOperand(operand)->toUse()->usedAtStart()); 161 #ifdef JS_NUNBOX32 162 MOZ_ASSERT(lir->getOperand(operand + 1)->toUse()->usedAtStart()); 163 #endif 164 MOZ_ASSERT(!lir->isCall()); 165 MOZ_ASSERT(mir->type() == MIRType::Value); 166 167 uint32_t vreg = getVirtualRegister(); 168 169 #ifdef JS_NUNBOX32 170 static_assert(VREG_TYPE_OFFSET == 0, 171 "Code below assumes VREG_TYPE_OFFSET == 0"); 172 static_assert(VREG_DATA_OFFSET == 1, 173 "Code below assumes VREG_DATA_OFFSET == 1"); 174 175 LDefinition def1(LDefinition::TYPE, LDefinition::MUST_REUSE_INPUT); 176 def1.setReusedInput(operand); 177 def1.setVirtualRegister(vreg); 178 lir->setDef(0, def1); 179 180 getVirtualRegister(); 181 LDefinition def2(LDefinition::PAYLOAD, LDefinition::MUST_REUSE_INPUT); 182 def2.setReusedInput(operand + 1); 183 def2.setVirtualRegister(vreg + 1); 184 lir->setDef(1, def2); 185 #else 186 LDefinition def(LDefinition::BOX, LDefinition::MUST_REUSE_INPUT); 187 def.setReusedInput(operand); 188 def.setVirtualRegister(vreg); 189 lir->setDef(0, def); 190 #endif 191 192 lir->setMir(mir); 193 mir->setVirtualRegister(vreg); 194 addUnchecked(lir); 195 } 196 197 template <size_t Temps> 198 void LIRGeneratorShared::defineBox( 199 details::LInstructionFixedDefsTempsHelper<BOX_PIECES, Temps>* lir, 200 MDefinition* mir, LDefinition::Policy policy) { 201 // Call instructions should use defineReturn. 202 MOZ_ASSERT(!lir->isCall()); 203 MOZ_ASSERT(mir->type() == MIRType::Value); 204 205 uint32_t vreg = getVirtualRegister(); 206 207 #if defined(JS_NUNBOX32) 208 lir->setDef(0, 209 LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, policy)); 210 lir->setDef( 211 1, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, policy)); 212 getVirtualRegister(); 213 #elif defined(JS_PUNBOX64) 214 lir->setDef(0, LDefinition(vreg, LDefinition::BOX, policy)); 215 #endif 216 lir->setMir(mir); 217 218 mir->setVirtualRegister(vreg); 219 addUnchecked(lir); 220 } 221 222 template <size_t Ops, size_t Temps> 223 void LIRGeneratorShared::defineInt64( 224 LInstructionHelper<INT64_PIECES, Ops, Temps>* lir, MDefinition* mir, 225 LDefinition::Policy policy) { 226 // Call instructions should use defineReturn. 227 MOZ_ASSERT(!lir->isCall()); 228 229 #ifdef JS_64BIT 230 MOZ_ASSERT(mir->type() == MIRType::Int64 || mir->type() == MIRType::IntPtr); 231 #else 232 MOZ_ASSERT(mir->type() == MIRType::Int64); 233 #endif 234 235 uint32_t vreg = getVirtualRegister(); 236 237 #if JS_BITS_PER_WORD == 32 238 lir->setDef(0, 239 LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL, policy)); 240 lir->setDef( 241 1, LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL, policy)); 242 getVirtualRegister(); 243 #else 244 lir->setDef(0, LDefinition(vreg, LDefinition::GENERAL, policy)); 245 #endif 246 lir->setMir(mir); 247 248 mir->setVirtualRegister(vreg); 249 addUnchecked(lir); 250 } 251 252 void LIRGeneratorShared::defineReturn(LInstruction* lir, MDefinition* mir) { 253 lir->setMir(mir); 254 255 MOZ_ASSERT(lir->isCall()); 256 257 uint32_t vreg = getVirtualRegister(); 258 259 switch (mir->type()) { 260 case MIRType::Value: 261 #if defined(JS_NUNBOX32) 262 lir->setDef(TYPE_INDEX, 263 LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE, 264 LGeneralReg(JSReturnReg_Type))); 265 lir->setDef(PAYLOAD_INDEX, 266 LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD, 267 LGeneralReg(JSReturnReg_Data))); 268 getVirtualRegister(); 269 #elif defined(JS_PUNBOX64) 270 lir->setDef( 271 0, LDefinition(vreg, LDefinition::BOX, LGeneralReg(JSReturnReg))); 272 #endif 273 break; 274 case MIRType::Int64: 275 #if defined(JS_NUNBOX32) 276 lir->setDef(INT64LOW_INDEX, 277 LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL, 278 LGeneralReg(ReturnReg64.low))); 279 lir->setDef(INT64HIGH_INDEX, 280 LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL, 281 LGeneralReg(ReturnReg64.high))); 282 getVirtualRegister(); 283 #elif defined(JS_PUNBOX64) 284 lir->setDef( 285 0, LDefinition(vreg, LDefinition::GENERAL, LGeneralReg(ReturnReg))); 286 #endif 287 break; 288 case MIRType::Float32: 289 lir->setDef(0, LDefinition(vreg, LDefinition::FLOAT32, 290 LFloatReg(ReturnFloat32Reg))); 291 break; 292 case MIRType::Double: 293 lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, 294 LFloatReg(ReturnDoubleReg))); 295 break; 296 case MIRType::Simd128: 297 #ifdef ENABLE_WASM_SIMD 298 lir->setDef(0, LDefinition(vreg, LDefinition::SIMD128, 299 LFloatReg(ReturnSimd128Reg))); 300 break; 301 #else 302 MOZ_CRASH("No SIMD support"); 303 #endif 304 default: 305 LDefinition::Type type = LDefinition::TypeFrom(mir->type()); 306 switch (type) { 307 case LDefinition::GENERAL: 308 case LDefinition::INT32: 309 case LDefinition::OBJECT: 310 case LDefinition::SLOTS: 311 case LDefinition::STACKRESULTS: 312 case LDefinition::WASM_ANYREF: 313 lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ReturnReg))); 314 break; 315 case LDefinition::DOUBLE: 316 case LDefinition::FLOAT32: 317 case LDefinition::SIMD128: 318 MOZ_CRASH("Float cases must have been handled earlier"); 319 default: 320 MOZ_CRASH("Unexpected type"); 321 } 322 break; 323 } 324 325 mir->setVirtualRegister(vreg); 326 addUnchecked(lir); 327 } 328 329 #ifdef DEBUG 330 // This function checks that when making redefinitions, we don't accidentally 331 // coerce two incompatible types. 332 static inline bool IsCompatibleLIRCoercion(MIRType to, MIRType from) { 333 if (to == from) { 334 return true; 335 } 336 // In LIR, we treat boolean and int32 as the same low-level type (INTEGER). 337 // When snapshotting, we recover the actual JS type from MIR. 338 if ((to == MIRType::Int32 || to == MIRType::Boolean) && 339 (from == MIRType::Int32 || from == MIRType::Boolean)) { 340 return true; 341 } 342 // On 32-bit platforms Int32 can be redefined as IntPtr and vice versa. 343 // On 64-bit platforms we can redefine non-negative Int32 values as IntPtr. 344 if (from == MIRType::Int32 && to == MIRType::IntPtr) { 345 return true; 346 } 347 # ifndef JS_64BIT 348 if (from == MIRType::IntPtr && to == MIRType::Int32) { 349 return true; 350 } 351 # endif 352 353 # ifdef JS_64BIT 354 // On 64-bit platforms IntPtr and Int64 are both 64-bit integers. 355 if ((to == MIRType::IntPtr || to == MIRType::Int64) && 356 (from == MIRType::IntPtr || from == MIRType::Int64)) { 357 return true; 358 } 359 # endif 360 return false; 361 } 362 #endif 363 364 void LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as) { 365 MOZ_ASSERT(IsCompatibleLIRCoercion(def->type(), as->type())); 366 367 // Try to emit MIR marked as emitted-at-uses at, well, uses. For 368 // snapshotting reasons we delay the MIRTypes match, or when we are 369 // coercing between bool and int32 constants. 370 if (as->isEmittedAtUses() && 371 (def->type() == as->type() || 372 (as->isConstant() && 373 (def->type() == MIRType::Int32 || def->type() == MIRType::Boolean) && 374 (as->type() == MIRType::Int32 || as->type() == MIRType::Boolean)))) { 375 MInstruction* replacement; 376 if (def->type() != as->type()) { 377 if (as->type() == MIRType::Int32) { 378 replacement = 379 MConstant::NewBoolean(alloc(), as->toConstant()->toInt32()); 380 } else { 381 replacement = 382 MConstant::NewInt32(alloc(), as->toConstant()->toBoolean()); 383 } 384 def->block()->insertBefore(def->toInstruction(), replacement); 385 emitAtUses(replacement->toInstruction()); 386 } else { 387 replacement = as->toInstruction(); 388 } 389 def->replaceAllUsesWith(replacement); 390 } else { 391 ensureDefined(as); 392 def->setVirtualRegister(as->virtualRegister()); 393 } 394 } 395 396 void LIRGeneratorShared::ensureDefined(MDefinition* mir) { 397 if (mir->isEmittedAtUses()) { 398 visitEmittedAtUses(mir->toInstruction()); 399 MOZ_ASSERT(mir->isLowered()); 400 } 401 } 402 403 bool LIRGeneratorShared::willHaveDifferentLIRNodes(MDefinition* mir1, 404 MDefinition* mir2) { 405 if (mir1 != mir2) { 406 return true; 407 } 408 if (mir1->isEmittedAtUses()) { 409 return true; 410 } 411 return false; 412 } 413 414 template <typename LClass, typename... Args> 415 LClass* LIRGeneratorShared::allocateVariadic(uint32_t numOperands, 416 Args&&... args) { 417 size_t numBytes = sizeof(LClass) + numOperands * sizeof(LAllocation); 418 void* buf = alloc().allocate(numBytes); 419 if (!buf) { 420 return nullptr; 421 } 422 423 LClass* ins = static_cast<LClass*>(buf); 424 new (ins) LClass(numOperands, std::forward<Args>(args)...); 425 426 ins->initOperandsOffset(sizeof(LClass)); 427 428 for (uint32_t i = 0; i < numOperands; i++) { 429 ins->setOperand(i, LAllocation()); 430 } 431 432 return ins; 433 } 434 435 LUse LIRGeneratorShared::useRegister(MDefinition* mir) { 436 return use(mir, LUse(LUse::REGISTER)); 437 } 438 439 LUse LIRGeneratorShared::useRegisterAtStart(MDefinition* mir) { 440 return use(mir, LUse(LUse::REGISTER, true)); 441 } 442 443 LUse LIRGeneratorShared::use(MDefinition* mir) { 444 return use(mir, LUse(LUse::ANY)); 445 } 446 447 LUse LIRGeneratorShared::useAtStart(MDefinition* mir) { 448 return use(mir, LUse(LUse::ANY, true)); 449 } 450 451 LAllocation LIRGeneratorShared::useOrConstant(MDefinition* mir) { 452 if (mir->isConstant()) { 453 return LAllocation(mir->toConstant()); 454 } 455 return use(mir); 456 } 457 458 LAllocation LIRGeneratorShared::useOrConstantAtStart(MDefinition* mir) { 459 if (mir->isConstant()) { 460 return LAllocation(mir->toConstant()); 461 } 462 return useAtStart(mir); 463 } 464 465 LAllocation LIRGeneratorShared::useRegisterOrConstant(MDefinition* mir) { 466 if (mir->isConstant()) { 467 return LAllocation(mir->toConstant()); 468 } 469 return useRegister(mir); 470 } 471 472 LAllocation LIRGeneratorShared::useRegisterOrConstantAtStart(MDefinition* mir) { 473 if (mir->isConstant()) { 474 return LAllocation(mir->toConstant()); 475 } 476 return useRegisterAtStart(mir); 477 } 478 479 inline bool CanUseInt32Constant(MDefinition* mir) { 480 if (!mir->isConstant()) { 481 return false; 482 } 483 MConstant* cst = mir->toConstant(); 484 if (cst->type() == MIRType::IntPtr) { 485 return INT32_MIN <= cst->toIntPtr() && cst->toIntPtr() <= INT32_MAX; 486 } 487 MOZ_ASSERT(cst->type() == MIRType::Int32); 488 return true; 489 } 490 491 LAllocation LIRGeneratorShared::useRegisterOrInt32Constant(MDefinition* mir) { 492 if (CanUseInt32Constant(mir)) { 493 return LAllocation(mir->toConstant()); 494 } 495 return useRegister(mir); 496 } 497 498 LAllocation LIRGeneratorShared::useAnyOrInt32Constant(MDefinition* mir) { 499 if (CanUseInt32Constant(mir)) { 500 return LAllocation(mir->toConstant()); 501 } 502 return useAny(mir); 503 } 504 505 LAllocation LIRGeneratorShared::useRegisterOrZero(MDefinition* mir) { 506 if (mir->isConstant() && 507 (mir->toConstant()->isInt32(0) || mir->toConstant()->isInt64(0))) { 508 return LAllocation(); 509 } 510 return useRegister(mir); 511 } 512 513 LAllocation LIRGeneratorShared::useRegisterOrZeroAtStart(MDefinition* mir) { 514 if (mir->isConstant() && 515 (mir->toConstant()->isInt32(0) || mir->toConstant()->isInt64(0))) { 516 return LAllocation(); 517 } 518 return useRegisterAtStart(mir); 519 } 520 521 LAllocation LIRGeneratorShared::useRegisterOrNonDoubleConstant( 522 MDefinition* mir) { 523 if (mir->isConstant() && mir->type() != MIRType::Double && 524 mir->type() != MIRType::Float32) { 525 return LAllocation(mir->toConstant()); 526 } 527 return useRegister(mir); 528 } 529 530 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ 531 defined(JS_CODEGEN_LOONG64) || defined(JS_CODEGEN_MIPS64) || \ 532 defined(JS_CODEGEN_RISCV64) 533 LAllocation LIRGeneratorShared::useAnyOrConstant(MDefinition* mir) { 534 return useRegisterOrConstant(mir); 535 } 536 LAllocation LIRGeneratorShared::useStorable(MDefinition* mir) { 537 return useRegister(mir); 538 } 539 LAllocation LIRGeneratorShared::useStorableAtStart(MDefinition* mir) { 540 return useRegisterAtStart(mir); 541 } 542 543 LAllocation LIRGeneratorShared::useAny(MDefinition* mir) { 544 return useRegister(mir); 545 } 546 LAllocation LIRGeneratorShared::useAnyAtStart(MDefinition* mir) { 547 return useRegisterAtStart(mir); 548 } 549 #else 550 LAllocation LIRGeneratorShared::useAnyOrConstant(MDefinition* mir) { 551 return useOrConstant(mir); 552 } 553 554 LAllocation LIRGeneratorShared::useAny(MDefinition* mir) { return use(mir); } 555 LAllocation LIRGeneratorShared::useAnyAtStart(MDefinition* mir) { 556 return useAtStart(mir); 557 } 558 LAllocation LIRGeneratorShared::useStorable(MDefinition* mir) { 559 return useRegisterOrConstant(mir); 560 } 561 LAllocation LIRGeneratorShared::useStorableAtStart(MDefinition* mir) { 562 return useRegisterOrConstantAtStart(mir); 563 } 564 565 #endif 566 567 LAllocation LIRGeneratorShared::useKeepalive(MDefinition* mir) { 568 return use(mir, LUse(LUse::KEEPALIVE)); 569 } 570 571 LAllocation LIRGeneratorShared::useKeepaliveOrConstant(MDefinition* mir) { 572 if (mir->isConstant()) { 573 return LAllocation(mir->toConstant()); 574 } 575 return useKeepalive(mir); 576 } 577 578 LUse LIRGeneratorShared::useFixed(MDefinition* mir, Register reg) { 579 return use(mir, LUse(reg)); 580 } 581 582 LUse LIRGeneratorShared::useFixedAtStart(MDefinition* mir, Register reg) { 583 return use(mir, LUse(reg, true)); 584 } 585 586 LUse LIRGeneratorShared::useFixed(MDefinition* mir, FloatRegister reg) { 587 return use(mir, LUse(reg)); 588 } 589 590 LUse LIRGeneratorShared::useFixed(MDefinition* mir, AnyRegister reg) { 591 return reg.isFloat() ? use(mir, LUse(reg.fpu())) : use(mir, LUse(reg.gpr())); 592 } 593 594 LUse LIRGeneratorShared::useFixedAtStart(MDefinition* mir, AnyRegister reg) { 595 return reg.isFloat() ? use(mir, LUse(reg.fpu(), true)) 596 : use(mir, LUse(reg.gpr(), true)); 597 } 598 599 LDefinition LIRGeneratorShared::temp(LDefinition::Type type, 600 LDefinition::Policy policy) { 601 return LDefinition(getVirtualRegister(), type, policy); 602 } 603 604 LInt64Definition LIRGeneratorShared::tempInt64(LDefinition::Policy policy) { 605 #if JS_BITS_PER_WORD == 32 606 LDefinition high = temp(LDefinition::GENERAL, policy); 607 LDefinition low = temp(LDefinition::GENERAL, policy); 608 return LInt64Definition(high, low); 609 #else 610 return LInt64Definition(temp(LDefinition::GENERAL, policy)); 611 #endif 612 } 613 614 LDefinition LIRGeneratorShared::tempFixed(Register reg) { 615 LDefinition t = temp(LDefinition::GENERAL); 616 t.setOutput(LGeneralReg(reg)); 617 return t; 618 } 619 620 LInt64Definition LIRGeneratorShared::tempInt64Fixed(Register64 reg) { 621 #if JS_BITS_PER_WORD == 32 622 LDefinition high = temp(LDefinition::GENERAL); 623 LDefinition low = temp(LDefinition::GENERAL); 624 high.setOutput(LGeneralReg(reg.high)); 625 low.setOutput(LGeneralReg(reg.low)); 626 return LInt64Definition(high, low); 627 #else 628 LDefinition t = temp(LDefinition::GENERAL); 629 t.setOutput(LGeneralReg(reg.reg)); 630 return LInt64Definition(t); 631 #endif 632 } 633 634 LDefinition LIRGeneratorShared::tempFixed(FloatRegister reg) { 635 LDefinition t = temp(LDefinition::DOUBLE); 636 t.setOutput(LFloatReg(reg)); 637 return t; 638 } 639 640 LDefinition LIRGeneratorShared::tempFloat32() { 641 return temp(LDefinition::FLOAT32); 642 } 643 644 LDefinition LIRGeneratorShared::tempDouble() { 645 return temp(LDefinition::DOUBLE); 646 } 647 648 #ifdef ENABLE_WASM_SIMD 649 LDefinition LIRGeneratorShared::tempSimd128() { 650 return temp(LDefinition::SIMD128); 651 } 652 #endif 653 654 LDefinition LIRGeneratorShared::tempCopy(MDefinition* input, 655 uint32_t reusedInput) { 656 MOZ_ASSERT(input->virtualRegister()); 657 LDefinition t = 658 temp(LDefinition::TypeFrom(input->type()), LDefinition::MUST_REUSE_INPUT); 659 t.setReusedInput(reusedInput); 660 return t; 661 } 662 663 void LIRGeneratorShared::annotate(LNode* ins) { 664 ins->setId(lirGraph_.getInstructionId()); 665 } 666 667 void LIRGeneratorShared::addUnchecked(LInstruction* ins, MInstruction* mir) { 668 MOZ_ASSERT(!ins->isPhi()); 669 current->add(ins); 670 if (mir) { 671 MOZ_ASSERT(current == mir->block()->lir()); 672 ins->setMir(mir); 673 } 674 annotate(ins); 675 if (ins->isCall()) { 676 lirGraph_.incNumCallInstructions(); 677 gen->setNeedsOverrecursedCheck(); 678 gen->setNeedsStaticStackAlignment(); 679 } 680 } 681 682 #ifdef JS_NUNBOX32 683 // Returns the virtual register of a js::Value-defining instruction. This is 684 // abstracted because MBox is a special value-returning instruction that 685 // redefines its input payload if its input is not constant. Therefore, it is 686 // illegal to request a box's payload by adding VREG_DATA_OFFSET to its raw id. 687 static inline uint32_t VirtualRegisterOfPayload(MDefinition* mir) { 688 if (mir->isBox()) { 689 MDefinition* inner = mir->toBox()->getOperand(0); 690 if (!inner->isConstant() && inner->type() != MIRType::Double && 691 inner->type() != MIRType::Float32) { 692 return inner->virtualRegister(); 693 } 694 } 695 return mir->virtualRegister() + VREG_DATA_OFFSET; 696 } 697 698 // Note: always call ensureDefined before calling useType/usePayload, 699 // so that emitted-at-use operands are handled correctly. 700 LUse LIRGeneratorShared::useType(MDefinition* mir, LUse::Policy policy) { 701 MOZ_ASSERT(mir->type() == MIRType::Value); 702 703 return LUse(mir->virtualRegister() + VREG_TYPE_OFFSET, policy); 704 } 705 706 LUse LIRGeneratorShared::usePayload(MDefinition* mir, LUse::Policy policy) { 707 MOZ_ASSERT(mir->type() == MIRType::Value); 708 709 return LUse(VirtualRegisterOfPayload(mir), policy); 710 } 711 712 LUse LIRGeneratorShared::usePayloadAtStart(MDefinition* mir, 713 LUse::Policy policy) { 714 MOZ_ASSERT(mir->type() == MIRType::Value); 715 716 return LUse(VirtualRegisterOfPayload(mir), policy, true); 717 } 718 719 LUse LIRGeneratorShared::usePayloadInRegisterAtStart(MDefinition* mir) { 720 return usePayloadAtStart(mir, LUse::REGISTER); 721 } 722 723 void LIRGeneratorShared::fillBoxUses(LInstruction* lir, size_t n, 724 MDefinition* mir) { 725 ensureDefined(mir); 726 lir->getOperand(n)->toUse()->setVirtualRegister(mir->virtualRegister() + 727 VREG_TYPE_OFFSET); 728 lir->getOperand(n + 1)->toUse()->setVirtualRegister( 729 VirtualRegisterOfPayload(mir)); 730 } 731 #endif 732 733 LUse LIRGeneratorShared::useRegisterForTypedLoad(MDefinition* mir, 734 MIRType type) { 735 MOZ_ASSERT(type != MIRType::Value && type != MIRType::None); 736 MOZ_ASSERT(mir->type() == MIRType::Object || mir->type() == MIRType::Slots); 737 738 #ifdef JS_PUNBOX64 739 // On x64, masm.loadUnboxedValue emits slightly less efficient code when 740 // the input and output use the same register and we're not loading an 741 // int32/bool/double, so we just call useRegister in this case. 742 if (type != MIRType::Int32 && type != MIRType::Boolean && 743 type != MIRType::Double) { 744 return useRegister(mir); 745 } 746 #endif 747 748 return useRegisterAtStart(mir); 749 } 750 751 LBoxAllocation LIRGeneratorShared::useBox(MDefinition* mir, LUse::Policy policy, 752 bool useAtStart) { 753 MOZ_ASSERT(mir->type() == MIRType::Value); 754 755 ensureDefined(mir); 756 757 #if defined(JS_NUNBOX32) 758 return LBoxAllocation( 759 LUse(mir->virtualRegister(), policy, useAtStart), 760 LUse(VirtualRegisterOfPayload(mir), policy, useAtStart)); 761 #else 762 return LBoxAllocation(LUse(mir->virtualRegister(), policy, useAtStart)); 763 #endif 764 } 765 766 LBoxAllocation LIRGeneratorShared::useBoxOrTyped(MDefinition* mir, 767 bool useAtStart) { 768 if (mir->type() == MIRType::Value) { 769 return useBox(mir, LUse::REGISTER, useAtStart); 770 } 771 772 #if defined(JS_NUNBOX32) 773 return LBoxAllocation(useAtStart ? useRegisterAtStart(mir) : useRegister(mir), 774 LAllocation()); 775 #else 776 return LBoxAllocation(useAtStart ? useRegisterAtStart(mir) 777 : useRegister(mir)); 778 #endif 779 } 780 781 LBoxAllocation LIRGeneratorShared::useBoxOrTypedOrConstant(MDefinition* mir, 782 bool useConstant, 783 bool useAtStart) { 784 if (useConstant && mir->isConstant()) { 785 #if defined(JS_NUNBOX32) 786 return LBoxAllocation(LAllocation(mir->toConstant()), LAllocation()); 787 #else 788 return LBoxAllocation(LAllocation(mir->toConstant())); 789 #endif 790 } 791 792 return useBoxOrTyped(mir, useAtStart); 793 } 794 795 LInt64Allocation LIRGeneratorShared::useInt64(MDefinition* mir, 796 LUse::Policy policy, 797 bool useAtStart) { 798 MOZ_ASSERT(mir->type() == MIRType::Int64); 799 800 ensureDefined(mir); 801 802 uint32_t vreg = mir->virtualRegister(); 803 #if JS_BITS_PER_WORD == 32 804 return LInt64Allocation(LUse(vreg + INT64HIGH_INDEX, policy, useAtStart), 805 LUse(vreg + INT64LOW_INDEX, policy, useAtStart)); 806 #else 807 return LInt64Allocation(LUse(vreg, policy, useAtStart)); 808 #endif 809 } 810 811 LInt64Allocation LIRGeneratorShared::useInt64Fixed(MDefinition* mir, 812 Register64 regs, 813 bool useAtStart) { 814 MOZ_ASSERT(mir->type() == MIRType::Int64); 815 816 ensureDefined(mir); 817 818 uint32_t vreg = mir->virtualRegister(); 819 #if JS_BITS_PER_WORD == 32 820 return LInt64Allocation(LUse(regs.high, vreg + INT64HIGH_INDEX, useAtStart), 821 LUse(regs.low, vreg + INT64LOW_INDEX, useAtStart)); 822 #else 823 return LInt64Allocation(LUse(regs.reg, vreg, useAtStart)); 824 #endif 825 } 826 827 LInt64Allocation LIRGeneratorShared::useInt64FixedAtStart(MDefinition* mir, 828 Register64 regs) { 829 return useInt64Fixed(mir, regs, true); 830 } 831 832 LInt64Allocation LIRGeneratorShared::useInt64(MDefinition* mir, 833 bool useAtStart) { 834 // On 32-bit platforms, always load the value in registers. 835 #if JS_BITS_PER_WORD == 32 836 return useInt64(mir, LUse::REGISTER, useAtStart); 837 #else 838 return useInt64(mir, LUse::ANY, useAtStart); 839 #endif 840 } 841 842 LInt64Allocation LIRGeneratorShared::useInt64AtStart(MDefinition* mir) { 843 return useInt64(mir, /* useAtStart = */ true); 844 } 845 846 LInt64Allocation LIRGeneratorShared::useInt64Register(MDefinition* mir, 847 bool useAtStart) { 848 return useInt64(mir, LUse::REGISTER, useAtStart); 849 } 850 851 LInt64Allocation LIRGeneratorShared::useInt64OrConstant(MDefinition* mir, 852 bool useAtStart) { 853 if (mir->isConstant()) { 854 #if defined(JS_NUNBOX32) 855 return LInt64Allocation(LAllocation(mir->toConstant()), LAllocation()); 856 #else 857 return LInt64Allocation(LAllocation(mir->toConstant())); 858 #endif 859 } 860 return useInt64(mir, useAtStart); 861 } 862 863 LInt64Allocation LIRGeneratorShared::useInt64RegisterOrConstant( 864 MDefinition* mir, bool useAtStart) { 865 if (mir->isConstant()) { 866 #if defined(JS_NUNBOX32) 867 return LInt64Allocation(LAllocation(mir->toConstant()), LAllocation()); 868 #else 869 return LInt64Allocation(LAllocation(mir->toConstant())); 870 #endif 871 } 872 return useInt64Register(mir, useAtStart); 873 } 874 875 LInt64Allocation LIRGeneratorShared::useInt64RegisterAtStart(MDefinition* mir) { 876 return useInt64Register(mir, /* useAtStart = */ true); 877 } 878 879 LInt64Allocation LIRGeneratorShared::useInt64RegisterOrConstantAtStart( 880 MDefinition* mir) { 881 return useInt64RegisterOrConstant(mir, /* useAtStart = */ true); 882 } 883 884 LInt64Allocation LIRGeneratorShared::useInt64OrConstantAtStart( 885 MDefinition* mir) { 886 return useInt64OrConstant(mir, /* useAtStart = */ true); 887 } 888 889 #ifdef JS_NUNBOX32 890 LUse LIRGeneratorShared::useLowWord(MDefinition* mir, LUse policy) { 891 MOZ_ASSERT(mir->type() == MIRType::Int64); 892 893 // This returns the low word of the Int64 input. 894 ensureDefined(mir); 895 policy.setVirtualRegister(mir->virtualRegister() + INT64LOW_INDEX); 896 return policy; 897 } 898 899 LUse LIRGeneratorShared::useLowWordRegister(MDefinition* mir) { 900 return useLowWord(mir, LUse(LUse::REGISTER)); 901 } 902 903 LUse LIRGeneratorShared::useLowWordRegisterAtStart(MDefinition* mir) { 904 return useLowWord(mir, LUse(LUse::REGISTER, true)); 905 } 906 907 LUse LIRGeneratorShared::useLowWordFixed(MDefinition* mir, Register reg) { 908 return useLowWord(mir, LUse(reg)); 909 } 910 #endif 911 912 void LIRGeneratorShared::lowerConstantDouble(double d, MInstruction* mir) { 913 define(new (alloc()) LDouble(d), mir); 914 } 915 void LIRGeneratorShared::lowerConstantFloat32(float f, MInstruction* mir) { 916 define(new (alloc()) LFloat32(f), mir); 917 } 918 919 } // namespace jit 920 } // namespace js 921 922 #endif /* jit_shared_Lowering_shared_inl_h */