js/src/jit/arm/MoveEmitter-arm.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     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/. */
     7 #include "jit/arm/MoveEmitter-arm.h"
     9 using namespace js;
    10 using namespace js::jit;
    12 MoveEmitterARM::MoveEmitterARM(MacroAssemblerARMCompat &masm)
    13   : inCycle_(false),
    14     masm(masm),
    15     pushedAtCycle_(-1),
    16     pushedAtSpill_(-1),
    17     spilledReg_(InvalidReg),
    18     spilledFloatReg_(InvalidFloatReg)
    19 {
    20     pushedAtStart_ = masm.framePushed();
    21 }
    23 void
    24 MoveEmitterARM::emit(const MoveResolver &moves)
    25 {
    26     if (moves.hasCycles()) {
    27         // Reserve stack for cycle resolution
    28         masm.reserveStack(sizeof(double));
    29         pushedAtCycle_ = masm.framePushed();
    30     }
    32     for (size_t i = 0; i < moves.numMoves(); i++)
    33         emit(moves.getMove(i));
    34 }
    36 MoveEmitterARM::~MoveEmitterARM()
    37 {
    38     assertDone();
    39 }
    41 Operand
    42 MoveEmitterARM::cycleSlot() const
    43 {
    44     int offset =  masm.framePushed() - pushedAtCycle_;
    45     JS_ASSERT(offset < 4096 && offset > -4096);
    46     return Operand(StackPointer, offset);
    47 }
    49 // THIS IS ALWAYS AN LDRAddr.  It should not be wrapped in an operand, methinks
    50 Operand
    51 MoveEmitterARM::spillSlot() const
    52 {
    53     int offset =  masm.framePushed() - pushedAtSpill_;
    54     JS_ASSERT(offset < 4096 && offset > -4096);
    55     return Operand(StackPointer, offset);
    56 }
    58 Operand
    59 MoveEmitterARM::toOperand(const MoveOperand &operand, bool isFloat) const
    60 {
    61     if (operand.isMemoryOrEffectiveAddress()) {
    62         if (operand.base() != StackPointer) {
    63             JS_ASSERT(operand.disp() < 1024 && operand.disp() > -1024);
    64             return Operand(operand.base(), operand.disp());
    65         }
    67         JS_ASSERT(operand.disp() >= 0);
    69         // Otherwise, the stack offset may need to be adjusted.
    70         return Operand(StackPointer, operand.disp() + (masm.framePushed() - pushedAtStart_));
    71     }
    73     if (operand.isGeneralReg())
    74         return Operand(operand.reg());
    76     JS_ASSERT(operand.isFloatReg());
    77     return Operand(operand.floatReg());
    78 }
    80 Register
    81 MoveEmitterARM::tempReg()
    82 {
    83     if (spilledReg_ != InvalidReg)
    84         return spilledReg_;
    86     // For now, just pick r12/ip as the eviction point. This is totally
    87     // random, and if it ends up being bad, we can use actual heuristics later.
    88     // r12 is actually a bad choice.  it is the scratch register, which is frequently
    89     // used for address computations, such as those found when we attempt to access
    90     // values more than 4096 off of the stack pointer.
    91     // instead, use lr, the LinkRegister.
    92     spilledReg_ = r14;
    93     if (pushedAtSpill_ == -1) {
    94         masm.Push(spilledReg_);
    95         pushedAtSpill_ = masm.framePushed();
    96     } else {
    97         masm.ma_str(spilledReg_, spillSlot());
    98     }
    99     return spilledReg_;
   100 }
   102 void
   103 MoveEmitterARM::breakCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type)
   104 {
   105     // There is some pattern:
   106     //   (A -> B)
   107     //   (B -> A)
   108     //
   109     // This case handles (A -> B), which we reach first. We save B, then allow
   110     // the original move to continue.
   111     switch (type) {
   112       case MoveOp::FLOAT32:
   113       case MoveOp::DOUBLE:
   114         if (to.isMemory()) {
   115             FloatRegister temp = ScratchFloatReg;
   116             masm.ma_vldr(toOperand(to, true), temp);
   117             masm.ma_vstr(temp, cycleSlot());
   118         } else {
   119             masm.ma_vstr(to.floatReg(), cycleSlot());
   120         }
   121         break;
   122       case MoveOp::INT32:
   123       case MoveOp::GENERAL:
   124         // an non-vfp value
   125         if (to.isMemory()) {
   126             Register temp = tempReg();
   127             masm.ma_ldr(toOperand(to, false), temp);
   128             masm.ma_str(temp, cycleSlot());
   129         } else {
   130             if (to.reg() == spilledReg_) {
   131                 // If the destination was spilled, restore it first.
   132                 masm.ma_ldr(spillSlot(), spilledReg_);
   133                 spilledReg_ = InvalidReg;
   134             }
   135             masm.ma_str(to.reg(), cycleSlot());
   136         }
   137         break;
   138       default:
   139         MOZ_ASSUME_UNREACHABLE("Unexpected move type");
   140     }
   141 }
   143 void
   144 MoveEmitterARM::completeCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type)
   145 {
   146     // There is some pattern:
   147     //   (A -> B)
   148     //   (B -> A)
   149     //
   150     // This case handles (B -> A), which we reach last. We emit a move from the
   151     // saved value of B, to A.
   152     switch (type) {
   153       case MoveOp::FLOAT32:
   154       case MoveOp::DOUBLE:
   155         if (to.isMemory()) {
   156             FloatRegister temp = ScratchFloatReg;
   157             masm.ma_vldr(cycleSlot(), temp);
   158             masm.ma_vstr(temp, toOperand(to, true));
   159         } else {
   160             masm.ma_vldr(cycleSlot(), to.floatReg());
   161         }
   162         break;
   163       case MoveOp::INT32:
   164       case MoveOp::GENERAL:
   165         if (to.isMemory()) {
   166             Register temp = tempReg();
   167             masm.ma_ldr(cycleSlot(), temp);
   168             masm.ma_str(temp, toOperand(to, false));
   169         } else {
   170             if (to.reg() == spilledReg_) {
   171                 // Make sure we don't re-clobber the spilled register later.
   172                 spilledReg_ = InvalidReg;
   173             }
   174             masm.ma_ldr(cycleSlot(), to.reg());
   175         }
   176         break;
   177       default:
   178         MOZ_ASSUME_UNREACHABLE("Unexpected move type");
   179     }
   180 }
   182 void
   183 MoveEmitterARM::emitMove(const MoveOperand &from, const MoveOperand &to)
   184 {
   185     if (to.isGeneralReg() && to.reg() == spilledReg_) {
   186         // If the destination is the spilled register, make sure we
   187         // don't re-clobber its value.
   188         spilledReg_ = InvalidReg;
   189     }
   191     if (from.isGeneralReg()) {
   192         if (from.reg() == spilledReg_) {
   193             // If the source is a register that has been spilled, make sure
   194             // to load the source back into that register.
   195             masm.ma_ldr(spillSlot(), spilledReg_);
   196             spilledReg_ = InvalidReg;
   197         }
   198         switch (toOperand(to, false).getTag()) {
   199           case Operand::OP2:
   200             // secretly must be a register
   201             masm.ma_mov(from.reg(), to.reg());
   202             break;
   203           case Operand::MEM:
   204             masm.ma_str(from.reg(), toOperand(to, false));
   205             break;
   206           default:
   207             MOZ_ASSUME_UNREACHABLE("strange move!");
   208         }
   209     } else if (to.isGeneralReg()) {
   210         JS_ASSERT(from.isMemoryOrEffectiveAddress());
   211         if (from.isMemory())
   212             masm.ma_ldr(toOperand(from, false), to.reg());
   213         else
   214             masm.ma_add(from.base(), Imm32(from.disp()), to.reg());
   215     } else {
   216         // Memory to memory gpr move.
   217         Register reg = tempReg();
   219         JS_ASSERT(from.isMemoryOrEffectiveAddress());
   220         if (from.isMemory())
   221             masm.ma_ldr(toOperand(from, false), reg);
   222         else
   223             masm.ma_add(from.base(), Imm32(from.disp()), reg);
   224         JS_ASSERT(to.base() != reg);
   225         masm.ma_str(reg, toOperand(to, false));
   226     }
   227 }
   229 void
   230 MoveEmitterARM::emitFloat32Move(const MoveOperand &from, const MoveOperand &to)
   231 {
   232     if (from.isFloatReg()) {
   233         if (to.isFloatReg())
   234             masm.ma_vmov_f32(from.floatReg(), to.floatReg());
   235         else
   236             masm.ma_vstr(VFPRegister(from.floatReg()).singleOverlay(),
   237                          toOperand(to, true));
   238     } else if (to.isFloatReg()) {
   239         masm.ma_vldr(toOperand(from, true),
   240                      VFPRegister(to.floatReg()).singleOverlay());
   241     } else {
   242         // Memory to memory move.
   243         JS_ASSERT(from.isMemory());
   244         FloatRegister reg = ScratchFloatReg;
   245         masm.ma_vldr(toOperand(from, true),
   246                      VFPRegister(reg).singleOverlay());
   247         masm.ma_vstr(VFPRegister(reg).singleOverlay(),
   248                      toOperand(to, true));
   249     }
   250 }
   252 void
   253 MoveEmitterARM::emitDoubleMove(const MoveOperand &from, const MoveOperand &to)
   254 {
   255     if (from.isFloatReg()) {
   256         if (to.isFloatReg())
   257             masm.ma_vmov(from.floatReg(), to.floatReg());
   258         else
   259             masm.ma_vstr(from.floatReg(), toOperand(to, true));
   260     } else if (to.isFloatReg()) {
   261         masm.ma_vldr(toOperand(from, true), to.floatReg());
   262     } else {
   263         // Memory to memory move.
   264         JS_ASSERT(from.isMemory());
   265         FloatRegister reg = ScratchFloatReg;
   266         masm.ma_vldr(toOperand(from, true), reg);
   267         masm.ma_vstr(reg, toOperand(to, true));
   268     }
   269 }
   271 void
   272 MoveEmitterARM::emit(const MoveOp &move)
   273 {
   274     const MoveOperand &from = move.from();
   275     const MoveOperand &to = move.to();
   277     if (move.isCycleEnd()) {
   278         JS_ASSERT(inCycle_);
   279         completeCycle(from, to, move.type());
   280         inCycle_ = false;
   281         return;
   282     }
   284     if (move.isCycleBegin()) {
   285         JS_ASSERT(!inCycle_);
   286         breakCycle(from, to, move.endCycleType());
   287         inCycle_ = true;
   288     }
   290     switch (move.type()) {
   291       case MoveOp::FLOAT32:
   292         emitFloat32Move(from, to);
   293         break;
   294       case MoveOp::DOUBLE:
   295         emitDoubleMove(from, to);
   296         break;
   297       case MoveOp::INT32:
   298       case MoveOp::GENERAL:
   299         emitMove(from, to);
   300         break;
   301       default:
   302         MOZ_ASSUME_UNREACHABLE("Unexpected move type");
   303     }
   304 }
   306 void
   307 MoveEmitterARM::assertDone()
   308 {
   309     JS_ASSERT(!inCycle_);
   310 }
   312 void
   313 MoveEmitterARM::finish()
   314 {
   315     assertDone();
   317     if (pushedAtSpill_ != -1 && spilledReg_ != InvalidReg)
   318         masm.ma_ldr(spillSlot(), spilledReg_);
   319     masm.freeStack(masm.framePushed() - pushedAtStart_);
   320 }

mercurial