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.

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

mercurial