tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */