tor-browser

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

MoveEmitter-loong64.cpp (11097B)


      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 #include "jit/loong64/MoveEmitter-loong64.h"
      8 
      9 #include "jit/MacroAssembler-inl.h"
     10 
     11 using namespace js;
     12 using namespace js::jit;
     13 
     14 void MoveEmitterLOONG64::breakCycle(const MoveOperand& from,
     15                                    const MoveOperand& to, MoveOp::Type type,
     16                                    uint32_t slotId) {
     17  // There is some pattern:
     18  //   (A -> B)
     19  //   (B -> A)
     20  //
     21  // This case handles (A -> B), which we reach first. We save B, then allow
     22  // the original move to continue.
     23  switch (type) {
     24    case MoveOp::FLOAT32:
     25      if (to.isMemory()) {
     26        ScratchFloat32Scope fpscratch32(masm);
     27        masm.loadFloat32(getAdjustedAddress(to), fpscratch32);
     28        masm.storeFloat32(fpscratch32, cycleSlot(slotId));
     29      } else {
     30        masm.storeFloat32(to.floatReg(), cycleSlot(slotId));
     31      }
     32      break;
     33    case MoveOp::DOUBLE:
     34      if (to.isMemory()) {
     35        ScratchDoubleScope fpscratch64(masm);
     36        masm.loadDouble(getAdjustedAddress(to), fpscratch64);
     37        masm.storeDouble(fpscratch64, cycleSlot(slotId));
     38      } else {
     39        masm.storeDouble(to.floatReg(), cycleSlot(slotId));
     40      }
     41      break;
     42    case MoveOp::INT32:
     43      if (to.isMemory()) {
     44        UseScratchRegisterScope temps(masm);
     45        Register scratch = temps.Acquire();
     46        masm.load32(getAdjustedAddress(to), scratch);
     47        masm.store32(scratch, cycleSlot(0));
     48      } else {
     49        masm.store32(to.reg(), cycleSlot(0));
     50      }
     51      break;
     52    case MoveOp::GENERAL:
     53      if (to.isMemory()) {
     54        UseScratchRegisterScope temps(masm);
     55        Register scratch = temps.Acquire();
     56        masm.loadPtr(getAdjustedAddress(to), scratch);
     57        masm.storePtr(scratch, cycleSlot(0));
     58      } else {
     59        masm.storePtr(to.reg(), cycleSlot(0));
     60      }
     61      break;
     62    default:
     63      MOZ_CRASH("Unexpected move type");
     64  }
     65 }
     66 
     67 void MoveEmitterLOONG64::completeCycle(const MoveOperand& from,
     68                                       const MoveOperand& to, MoveOp::Type type,
     69                                       uint32_t slotId) {
     70  // There is some pattern:
     71  //   (A -> B)
     72  //   (B -> A)
     73  //
     74  // This case handles (B -> A), which we reach last. We emit a move from the
     75  // saved value of B, to A.
     76  switch (type) {
     77    case MoveOp::FLOAT32:
     78      if (to.isMemory()) {
     79        ScratchFloat32Scope fpscratch32(masm);
     80        masm.loadFloat32(cycleSlot(slotId), fpscratch32);
     81        masm.storeFloat32(fpscratch32, getAdjustedAddress(to));
     82      } else {
     83        masm.loadFloat32(cycleSlot(slotId), to.floatReg());
     84      }
     85      break;
     86    case MoveOp::DOUBLE:
     87      if (to.isMemory()) {
     88        ScratchDoubleScope fpscratch64(masm);
     89        masm.loadDouble(cycleSlot(slotId), fpscratch64);
     90        masm.storeDouble(fpscratch64, getAdjustedAddress(to));
     91      } else {
     92        masm.loadDouble(cycleSlot(slotId), to.floatReg());
     93      }
     94      break;
     95    case MoveOp::INT32:
     96      MOZ_ASSERT(slotId == 0);
     97      if (to.isMemory()) {
     98        UseScratchRegisterScope temps(masm);
     99        Register scratch = temps.Acquire();
    100        masm.load32(cycleSlot(0), scratch);
    101        masm.store32(scratch, getAdjustedAddress(to));
    102      } else {
    103        masm.load32(cycleSlot(0), to.reg());
    104      }
    105      break;
    106    case MoveOp::GENERAL:
    107      MOZ_ASSERT(slotId == 0);
    108      if (to.isMemory()) {
    109        UseScratchRegisterScope temps(masm);
    110        Register scratch = temps.Acquire();
    111        masm.loadPtr(cycleSlot(0), scratch);
    112        masm.storePtr(scratch, getAdjustedAddress(to));
    113      } else {
    114        masm.loadPtr(cycleSlot(0), to.reg());
    115      }
    116      break;
    117    default:
    118      MOZ_CRASH("Unexpected move type");
    119  }
    120 }
    121 
    122 void MoveEmitterLOONG64::emit(const MoveResolver& moves) {
    123  if (moves.numCycles()) {
    124    // Reserve stack for cycle resolution
    125    static_assert(SpillSlotSize == 8);
    126    masm.reserveStack(moves.numCycles() * SpillSlotSize);
    127    pushedAtCycle_ = masm.framePushed();
    128  }
    129 
    130  for (size_t i = 0; i < moves.numMoves(); i++) {
    131    emit(moves.getMove(i));
    132  }
    133 }
    134 
    135 Address MoveEmitterLOONG64::cycleSlot(uint32_t slot, uint32_t subslot) const {
    136  int32_t offset = masm.framePushed() - pushedAtCycle_;
    137  MOZ_ASSERT(Imm16::IsInSignedRange(offset));
    138  return Address(StackPointer, offset + slot * sizeof(double) + subslot);
    139 }
    140 
    141 int32_t MoveEmitterLOONG64::getAdjustedOffset(const MoveOperand& operand) {
    142  MOZ_ASSERT(operand.isMemoryOrEffectiveAddress());
    143  if (operand.base() != StackPointer) {
    144    return operand.disp();
    145  }
    146 
    147  // Adjust offset if stack pointer has been moved.
    148  return operand.disp() + masm.framePushed() - pushedAtStart_;
    149 }
    150 
    151 Address MoveEmitterLOONG64::getAdjustedAddress(const MoveOperand& operand) {
    152  return Address(operand.base(), getAdjustedOffset(operand));
    153 }
    154 
    155 void MoveEmitterLOONG64::emitMove(const MoveOperand& from,
    156                                  const MoveOperand& to) {
    157  if (from.isGeneralReg()) {
    158    if (to.isGeneralReg()) {
    159      masm.movePtr(from.reg(), to.reg());
    160    } else if (to.isMemory()) {
    161      masm.storePtr(from.reg(), getAdjustedAddress(to));
    162    } else {
    163      MOZ_CRASH("Invalid emitMove arguments.");
    164    }
    165  } else if (from.isMemory()) {
    166    if (to.isGeneralReg()) {
    167      masm.loadPtr(getAdjustedAddress(from), to.reg());
    168    } else if (to.isMemory()) {
    169      UseScratchRegisterScope temps(masm);
    170      Register scratch = temps.Acquire();
    171      masm.loadPtr(getAdjustedAddress(from), scratch);
    172      masm.storePtr(scratch, getAdjustedAddress(to));
    173    } else {
    174      MOZ_CRASH("Invalid emitMove arguments.");
    175    }
    176  } else if (from.isEffectiveAddress()) {
    177    if (to.isGeneralReg()) {
    178      masm.computeEffectiveAddress(getAdjustedAddress(from), to.reg());
    179    } else if (to.isMemory()) {
    180      UseScratchRegisterScope temps(masm);
    181      Register scratch = temps.Acquire();
    182      masm.computeEffectiveAddress(getAdjustedAddress(from), scratch);
    183      masm.storePtr(scratch, getAdjustedAddress(to));
    184    } else {
    185      MOZ_CRASH("Invalid emitMove arguments.");
    186    }
    187  } else {
    188    MOZ_CRASH("Invalid emitMove arguments.");
    189  }
    190 }
    191 
    192 void MoveEmitterLOONG64::emitInt32Move(const MoveOperand& from,
    193                                       const MoveOperand& to) {
    194  if (from.isGeneralReg()) {
    195    if (to.isGeneralReg()) {
    196      masm.move32(from.reg(), to.reg());
    197    } else if (to.isMemory()) {
    198      masm.store32(from.reg(), getAdjustedAddress(to));
    199    } else {
    200      MOZ_CRASH("Invalid emitInt32Move arguments.");
    201    }
    202  } else if (from.isMemory()) {
    203    if (to.isGeneralReg()) {
    204      masm.load32(getAdjustedAddress(from), to.reg());
    205    } else if (to.isMemory()) {
    206      UseScratchRegisterScope temps(masm);
    207      Register scratch = temps.Acquire();
    208      masm.load32(getAdjustedAddress(from), scratch);
    209      masm.store32(scratch, getAdjustedAddress(to));
    210    } else {
    211      MOZ_CRASH("Invalid emitInt32Move arguments.");
    212    }
    213  } else if (from.isEffectiveAddress()) {
    214    if (to.isGeneralReg()) {
    215      masm.computeEffectiveAddress(getAdjustedAddress(from), to.reg());
    216    } else if (to.isMemory()) {
    217      UseScratchRegisterScope temps(masm);
    218      Register scratch = temps.Acquire();
    219      masm.computeEffectiveAddress(getAdjustedAddress(from), scratch);
    220      masm.store32(scratch, getAdjustedAddress(to));
    221    } else {
    222      MOZ_CRASH("Invalid emitInt32Move arguments.");
    223    }
    224  } else {
    225    MOZ_CRASH("Invalid emitInt32Move arguments.");
    226  }
    227 }
    228 
    229 void MoveEmitterLOONG64::emitFloat32Move(const MoveOperand& from,
    230                                         const MoveOperand& to) {
    231  if (from.isFloatReg()) {
    232    if (to.isFloatReg()) {
    233      masm.moveFloat32(from.floatReg(), to.floatReg());
    234    } else if (to.isGeneralReg()) {
    235      // This should only be used when passing float parameter in a1,a2,a3
    236      MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
    237      masm.moveFromFloat32(from.floatReg(), to.reg());
    238    } else {
    239      MOZ_ASSERT(to.isMemory());
    240      masm.storeFloat32(from.floatReg(), getAdjustedAddress(to));
    241    }
    242  } else if (to.isFloatReg()) {
    243    MOZ_ASSERT(from.isMemory());
    244    masm.loadFloat32(getAdjustedAddress(from), to.floatReg());
    245  } else if (to.isGeneralReg()) {
    246    MOZ_ASSERT(from.isMemory());
    247    // This should only be used when passing float parameter in a1,a2,a3
    248    MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
    249    masm.loadPtr(getAdjustedAddress(from), to.reg());
    250  } else {
    251    MOZ_ASSERT(from.isMemory());
    252    MOZ_ASSERT(to.isMemory());
    253    ScratchFloat32Scope fpscratch32(masm);
    254    masm.loadFloat32(getAdjustedAddress(from), fpscratch32);
    255    masm.storeFloat32(fpscratch32, getAdjustedAddress(to));
    256  }
    257 }
    258 
    259 void MoveEmitterLOONG64::emitDoubleMove(const MoveOperand& from,
    260                                        const MoveOperand& to) {
    261  if (from.isFloatReg()) {
    262    if (to.isFloatReg()) {
    263      masm.moveDouble(from.floatReg(), to.floatReg());
    264    } else if (to.isGeneralReg()) {
    265      masm.moveFromDouble(from.floatReg(), to.reg());
    266    } else {
    267      MOZ_ASSERT(to.isMemory());
    268      masm.storeDouble(from.floatReg(), getAdjustedAddress(to));
    269    }
    270  } else if (to.isFloatReg()) {
    271    if (from.isMemory()) {
    272      masm.loadDouble(getAdjustedAddress(from), to.floatReg());
    273    } else {
    274      masm.moveToDouble(from.reg(), to.floatReg());
    275    }
    276  } else {
    277    MOZ_ASSERT(from.isMemory());
    278    MOZ_ASSERT(to.isMemory());
    279    ScratchDoubleScope fpscratch64(masm);
    280    masm.loadDouble(getAdjustedAddress(from), fpscratch64);
    281    masm.storeDouble(fpscratch64, getAdjustedAddress(to));
    282  }
    283 }
    284 
    285 void MoveEmitterLOONG64::emit(const MoveOp& move) {
    286  const MoveOperand& from = move.from();
    287  const MoveOperand& to = move.to();
    288 
    289  if (move.isCycleEnd() && move.isCycleBegin()) {
    290    // A fun consequence of aliased registers is you can have multiple
    291    // cycles at once, and one can end exactly where another begins.
    292    breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot());
    293    completeCycle(from, to, move.type(), move.cycleEndSlot());
    294    return;
    295  }
    296 
    297  if (move.isCycleEnd()) {
    298    MOZ_ASSERT(inCycle_);
    299    completeCycle(from, to, move.type(), move.cycleEndSlot());
    300    MOZ_ASSERT(inCycle_ > 0);
    301    inCycle_--;
    302    return;
    303  }
    304 
    305  if (move.isCycleBegin()) {
    306    breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot());
    307    inCycle_++;
    308  }
    309 
    310  switch (move.type()) {
    311    case MoveOp::FLOAT32:
    312      emitFloat32Move(from, to);
    313      break;
    314    case MoveOp::DOUBLE:
    315      emitDoubleMove(from, to);
    316      break;
    317    case MoveOp::INT32:
    318      emitInt32Move(from, to);
    319      break;
    320    case MoveOp::GENERAL:
    321      emitMove(from, to);
    322      break;
    323    default:
    324      MOZ_CRASH("Unexpected move type");
    325  }
    326 }
    327 
    328 void MoveEmitterLOONG64::assertDone() { MOZ_ASSERT(inCycle_ == 0); }
    329 
    330 void MoveEmitterLOONG64::finish() {
    331  assertDone();
    332 
    333  masm.freeStack(masm.framePushed() - pushedAtStart_);
    334 }