js/src/jit/mips/MacroAssembler-mips.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/mips/MacroAssembler-mips.h"
michael@0 8
michael@0 9 #include "mozilla/DebugOnly.h"
michael@0 10 #include "mozilla/MathAlgorithms.h"
michael@0 11
michael@0 12 #include "jit/Bailouts.h"
michael@0 13 #include "jit/BaselineFrame.h"
michael@0 14 #include "jit/BaselineRegisters.h"
michael@0 15 #include "jit/IonFrames.h"
michael@0 16 #include "jit/MoveEmitter.h"
michael@0 17
michael@0 18 using namespace js;
michael@0 19 using namespace jit;
michael@0 20
michael@0 21 using mozilla::Abs;
michael@0 22
michael@0 23 static const int32_t PAYLOAD_OFFSET = NUNBOX32_PAYLOAD_OFFSET;
michael@0 24 static const int32_t TAG_OFFSET = NUNBOX32_TYPE_OFFSET;
michael@0 25
michael@0 26 static_assert(sizeof(intptr_t) == 4, "Not 64-bit clean.");
michael@0 27
michael@0 28 void
michael@0 29 MacroAssemblerMIPS::convertBoolToInt32(Register src, Register dest)
michael@0 30 {
michael@0 31 // Note that C++ bool is only 1 byte, so zero extend it to clear the
michael@0 32 // higher-order bits.
michael@0 33 ma_and(dest, src, Imm32(0xff));
michael@0 34 }
michael@0 35
michael@0 36 void
michael@0 37 MacroAssemblerMIPS::convertInt32ToDouble(const Register &src, const FloatRegister &dest)
michael@0 38 {
michael@0 39 as_mtc1(src, dest);
michael@0 40 as_cvtdw(dest, dest);
michael@0 41 }
michael@0 42
michael@0 43 void
michael@0 44 MacroAssemblerMIPS::convertInt32ToDouble(const Address &src, FloatRegister dest)
michael@0 45 {
michael@0 46 ma_lw(ScratchRegister, src);
michael@0 47 as_mtc1(ScratchRegister, dest);
michael@0 48 as_cvtdw(dest, dest);
michael@0 49 }
michael@0 50
michael@0 51 void
michael@0 52 MacroAssemblerMIPS::convertUInt32ToDouble(const Register &src, const FloatRegister &dest)
michael@0 53 {
michael@0 54 // We use SecondScratchFloatReg because MacroAssembler::loadFromTypedArray
michael@0 55 // calls with ScratchFloatReg as dest.
michael@0 56 MOZ_ASSERT(dest != SecondScratchFloatReg);
michael@0 57
michael@0 58 // Subtract INT32_MIN to get a positive number
michael@0 59 ma_subu(ScratchRegister, src, Imm32(INT32_MIN));
michael@0 60
michael@0 61 // Convert value
michael@0 62 as_mtc1(ScratchRegister, dest);
michael@0 63 as_cvtdw(dest, dest);
michael@0 64
michael@0 65 // Add unsigned value of INT32_MIN
michael@0 66 ma_lid(SecondScratchFloatReg, 2147483648.0);
michael@0 67 as_addd(dest, dest, SecondScratchFloatReg);
michael@0 68 }
michael@0 69
michael@0 70 void
michael@0 71 MacroAssemblerMIPS::convertUInt32ToFloat32(const Register &src, const FloatRegister &dest)
michael@0 72 {
michael@0 73 MOZ_ASSUME_UNREACHABLE("NYI");
michael@0 74 }
michael@0 75
michael@0 76 void
michael@0 77 MacroAssemblerMIPS::convertDoubleToFloat32(const FloatRegister &src, const FloatRegister &dest)
michael@0 78 {
michael@0 79 as_cvtsd(dest, src);
michael@0 80 }
michael@0 81
michael@0 82 // Convert the floating point value to an integer, if it did not fit, then it
michael@0 83 // was clamped to INT32_MIN/INT32_MAX, and we can test it.
michael@0 84 // NOTE: if the value really was supposed to be INT32_MAX / INT32_MIN then it
michael@0 85 // will be wrong.
michael@0 86 void
michael@0 87 MacroAssemblerMIPS::branchTruncateDouble(const FloatRegister &src, const Register &dest,
michael@0 88 Label *fail)
michael@0 89 {
michael@0 90 Label test, success;
michael@0 91 as_truncwd(ScratchFloatReg, src);
michael@0 92 as_mfc1(dest, ScratchFloatReg);
michael@0 93
michael@0 94 ma_b(dest, Imm32(INT32_MAX), fail, Assembler::Equal);
michael@0 95 }
michael@0 96
michael@0 97 // Checks whether a double is representable as a 32-bit integer. If so, the
michael@0 98 // integer is written to the output register. Otherwise, a bailout is taken to
michael@0 99 // the given snapshot. This function overwrites the scratch float register.
michael@0 100 void
michael@0 101 MacroAssemblerMIPS::convertDoubleToInt32(const FloatRegister &src, const Register &dest,
michael@0 102 Label *fail, bool negativeZeroCheck)
michael@0 103 {
michael@0 104 // Convert double to int, then convert back and check if we have the
michael@0 105 // same number.
michael@0 106 as_cvtwd(ScratchFloatReg, src);
michael@0 107 as_mfc1(dest, ScratchFloatReg);
michael@0 108 as_cvtdw(ScratchFloatReg, ScratchFloatReg);
michael@0 109 ma_bc1d(src, ScratchFloatReg, fail, Assembler::DoubleNotEqualOrUnordered);
michael@0 110
michael@0 111 if (negativeZeroCheck) {
michael@0 112 Label notZero;
michael@0 113 ma_b(dest, Imm32(0), &notZero, Assembler::NotEqual, ShortJump);
michael@0 114 // Test and bail for -0.0, when integer result is 0
michael@0 115 // Move the top word of the double into the output reg, if it is
michael@0 116 // non-zero, then the original value was -0.0
michael@0 117 moveFromDoubleHi(src, dest);
michael@0 118 ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal);
michael@0 119 bind(&notZero);
michael@0 120 }
michael@0 121 }
michael@0 122
michael@0 123 // Checks whether a float32 is representable as a 32-bit integer. If so, the
michael@0 124 // integer is written to the output register. Otherwise, a bailout is taken to
michael@0 125 // the given snapshot. This function overwrites the scratch float register.
michael@0 126 void
michael@0 127 MacroAssemblerMIPS::convertFloat32ToInt32(const FloatRegister &src, const Register &dest,
michael@0 128 Label *fail, bool negativeZeroCheck)
michael@0 129 {
michael@0 130 // convert the floating point value to an integer, if it did not fit, then
michael@0 131 // when we convert it *back* to a float, it will have a different value,
michael@0 132 // which we can test.
michael@0 133 as_cvtws(ScratchFloatReg, src);
michael@0 134 as_mfc1(dest, ScratchFloatReg);
michael@0 135 as_cvtsw(ScratchFloatReg, ScratchFloatReg);
michael@0 136 ma_bc1s(src, ScratchFloatReg, fail, Assembler::DoubleNotEqualOrUnordered);
michael@0 137
michael@0 138 if (negativeZeroCheck) {
michael@0 139 Label notZero;
michael@0 140 ma_b(dest, Imm32(0), &notZero, Assembler::NotEqual, ShortJump);
michael@0 141 // Test and bail for -0.0, when integer result is 0
michael@0 142 // Move the top word of the double into the output reg,
michael@0 143 // if it is non-zero, then the original value was -0.0
michael@0 144 moveFromDoubleHi(src, dest);
michael@0 145 ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal);
michael@0 146 bind(&notZero);
michael@0 147 }
michael@0 148 }
michael@0 149
michael@0 150 void
michael@0 151 MacroAssemblerMIPS::convertFloat32ToDouble(const FloatRegister &src, const FloatRegister &dest)
michael@0 152 {
michael@0 153 as_cvtds(dest, src);
michael@0 154 }
michael@0 155
michael@0 156 void
michael@0 157 MacroAssemblerMIPS::branchTruncateFloat32(const FloatRegister &src, const Register &dest,
michael@0 158 Label *fail)
michael@0 159 {
michael@0 160 Label test, success;
michael@0 161 as_truncws(ScratchFloatReg, src);
michael@0 162 as_mfc1(dest, ScratchFloatReg);
michael@0 163
michael@0 164 ma_b(dest, Imm32(INT32_MAX), fail, Assembler::Equal);
michael@0 165 }
michael@0 166
michael@0 167 void
michael@0 168 MacroAssemblerMIPS::convertInt32ToFloat32(const Register &src, const FloatRegister &dest)
michael@0 169 {
michael@0 170 as_mtc1(src, dest);
michael@0 171 as_cvtsw(dest, dest);
michael@0 172 }
michael@0 173
michael@0 174 void
michael@0 175 MacroAssemblerMIPS::convertInt32ToFloat32(const Address &src, FloatRegister dest)
michael@0 176 {
michael@0 177 ma_lw(ScratchRegister, src);
michael@0 178 as_mtc1(ScratchRegister, dest);
michael@0 179 as_cvtsw(dest, dest);
michael@0 180 }
michael@0 181
michael@0 182 void
michael@0 183 MacroAssemblerMIPS::addDouble(FloatRegister src, FloatRegister dest)
michael@0 184 {
michael@0 185 as_addd(dest, dest, src);
michael@0 186 }
michael@0 187
michael@0 188 void
michael@0 189 MacroAssemblerMIPS::subDouble(FloatRegister src, FloatRegister dest)
michael@0 190 {
michael@0 191 as_subd(dest, dest, src);
michael@0 192 }
michael@0 193
michael@0 194 void
michael@0 195 MacroAssemblerMIPS::mulDouble(FloatRegister src, FloatRegister dest)
michael@0 196 {
michael@0 197 as_muld(dest, dest, src);
michael@0 198 }
michael@0 199
michael@0 200 void
michael@0 201 MacroAssemblerMIPS::divDouble(FloatRegister src, FloatRegister dest)
michael@0 202 {
michael@0 203 as_divd(dest, dest, src);
michael@0 204 }
michael@0 205
michael@0 206 void
michael@0 207 MacroAssemblerMIPS::negateDouble(FloatRegister reg)
michael@0 208 {
michael@0 209 as_negd(reg, reg);
michael@0 210 }
michael@0 211
michael@0 212 void
michael@0 213 MacroAssemblerMIPS::inc64(AbsoluteAddress dest)
michael@0 214 {
michael@0 215 ma_li(ScratchRegister, Imm32((int32_t)dest.addr));
michael@0 216 as_lw(SecondScratchReg, ScratchRegister, 0);
michael@0 217
michael@0 218 as_addiu(SecondScratchReg, SecondScratchReg, 1);
michael@0 219 as_sw(SecondScratchReg, ScratchRegister, 0);
michael@0 220
michael@0 221 as_sltiu(SecondScratchReg, SecondScratchReg, 1);
michael@0 222 as_lw(ScratchRegister, ScratchRegister, 4);
michael@0 223
michael@0 224 as_addu(SecondScratchReg, ScratchRegister, SecondScratchReg);
michael@0 225
michael@0 226 ma_li(ScratchRegister, Imm32((int32_t)dest.addr));
michael@0 227 as_sw(SecondScratchReg, ScratchRegister, 4);
michael@0 228 }
michael@0 229
michael@0 230 void
michael@0 231 MacroAssemblerMIPS::ma_move(Register rd, Register rs)
michael@0 232 {
michael@0 233 as_or(rd, rs, zero);
michael@0 234 }
michael@0 235
michael@0 236 void
michael@0 237 MacroAssemblerMIPS::ma_li(Register dest, const ImmGCPtr &ptr)
michael@0 238 {
michael@0 239 writeDataRelocation(ptr);
michael@0 240 ma_liPatchable(dest, Imm32(ptr.value));
michael@0 241 }
michael@0 242
michael@0 243 void
michael@0 244 MacroAssemblerMIPS::ma_li(const Register &dest, AbsoluteLabel *label)
michael@0 245 {
michael@0 246 MOZ_ASSERT(!label->bound());
michael@0 247 // Thread the patch list through the unpatched address word in the
michael@0 248 // instruction stream.
michael@0 249 BufferOffset bo = m_buffer.nextOffset();
michael@0 250 ma_liPatchable(dest, Imm32(label->prev()));
michael@0 251 label->setPrev(bo.getOffset());
michael@0 252 }
michael@0 253
michael@0 254 void
michael@0 255 MacroAssemblerMIPS::ma_li(Register dest, Imm32 imm)
michael@0 256 {
michael@0 257 if (Imm16::isInSignedRange(imm.value)) {
michael@0 258 as_addiu(dest, zero, imm.value);
michael@0 259 } else if (Imm16::isInUnsignedRange(imm.value)) {
michael@0 260 as_ori(dest, zero, Imm16::lower(imm).encode());
michael@0 261 } else if (Imm16::lower(imm).encode() == 0) {
michael@0 262 as_lui(dest, Imm16::upper(imm).encode());
michael@0 263 } else {
michael@0 264 as_lui(dest, Imm16::upper(imm).encode());
michael@0 265 as_ori(dest, dest, Imm16::lower(imm).encode());
michael@0 266 }
michael@0 267 }
michael@0 268
michael@0 269
michael@0 270 // This method generates lui and ori instruction pair that can be modified by
michael@0 271 // updateLuiOriValue, either during compilation (eg. Assembler::bind), or
michael@0 272 // during execution (eg. jit::PatchJump).
michael@0 273 void
michael@0 274 MacroAssemblerMIPS::ma_liPatchable(Register dest, Imm32 imm)
michael@0 275 {
michael@0 276 m_buffer.ensureSpace(2 * sizeof(uint32_t));
michael@0 277 as_lui(dest, Imm16::upper(imm).encode());
michael@0 278 as_ori(dest, dest, Imm16::lower(imm).encode());
michael@0 279 }
michael@0 280
michael@0 281 void
michael@0 282 MacroAssemblerMIPS::ma_liPatchable(Register dest, ImmPtr imm)
michael@0 283 {
michael@0 284 return ma_liPatchable(dest, Imm32(int32_t(imm.value)));
michael@0 285 }
michael@0 286
michael@0 287 // Shifts
michael@0 288 void
michael@0 289 MacroAssemblerMIPS::ma_sll(Register rd, Register rt, Imm32 shift)
michael@0 290 {
michael@0 291 as_sll(rd, rt, shift.value % 32);
michael@0 292 }
michael@0 293 void
michael@0 294 MacroAssemblerMIPS::ma_srl(Register rd, Register rt, Imm32 shift)
michael@0 295 {
michael@0 296 as_srl(rd, rt, shift.value % 32);
michael@0 297 }
michael@0 298
michael@0 299 void
michael@0 300 MacroAssemblerMIPS::ma_sra(Register rd, Register rt, Imm32 shift)
michael@0 301 {
michael@0 302 as_sra(rd, rt, shift.value % 32);
michael@0 303 }
michael@0 304
michael@0 305 void
michael@0 306 MacroAssemblerMIPS::ma_ror(Register rd, Register rt, Imm32 shift)
michael@0 307 {
michael@0 308 as_rotr(rd, rt, shift.value % 32);
michael@0 309 }
michael@0 310
michael@0 311 void
michael@0 312 MacroAssemblerMIPS::ma_rol(Register rd, Register rt, Imm32 shift)
michael@0 313 {
michael@0 314 as_rotr(rd, rt, 32 - (shift.value % 32));
michael@0 315 }
michael@0 316
michael@0 317 void
michael@0 318 MacroAssemblerMIPS::ma_sll(Register rd, Register rt, Register shift)
michael@0 319 {
michael@0 320 as_sllv(rd, rt, shift);
michael@0 321 }
michael@0 322
michael@0 323 void
michael@0 324 MacroAssemblerMIPS::ma_srl(Register rd, Register rt, Register shift)
michael@0 325 {
michael@0 326 as_srlv(rd, rt, shift);
michael@0 327 }
michael@0 328
michael@0 329 void
michael@0 330 MacroAssemblerMIPS::ma_sra(Register rd, Register rt, Register shift)
michael@0 331 {
michael@0 332 as_srav(rd, rt, shift);
michael@0 333 }
michael@0 334
michael@0 335 void
michael@0 336 MacroAssemblerMIPS::ma_ror(Register rd, Register rt, Register shift)
michael@0 337 {
michael@0 338 as_rotrv(rd, rt, shift);
michael@0 339 }
michael@0 340
michael@0 341 void
michael@0 342 MacroAssemblerMIPS::ma_rol(Register rd, Register rt, Register shift)
michael@0 343 {
michael@0 344 ma_negu(ScratchRegister, shift);
michael@0 345 as_rotrv(rd, rt, ScratchRegister);
michael@0 346 }
michael@0 347
michael@0 348 void
michael@0 349 MacroAssemblerMIPS::ma_negu(Register rd, Register rs)
michael@0 350 {
michael@0 351 as_subu(rd, zero, rs);
michael@0 352 }
michael@0 353
michael@0 354 void
michael@0 355 MacroAssemblerMIPS::ma_not(Register rd, Register rs)
michael@0 356 {
michael@0 357 as_nor(rd, rs, zero);
michael@0 358 }
michael@0 359
michael@0 360 // And.
michael@0 361 void
michael@0 362 MacroAssemblerMIPS::ma_and(Register rd, Register rs)
michael@0 363 {
michael@0 364 as_and(rd, rd, rs);
michael@0 365 }
michael@0 366
michael@0 367 void
michael@0 368 MacroAssemblerMIPS::ma_and(Register rd, Register rs, Register rt)
michael@0 369 {
michael@0 370 as_and(rd, rs, rt);
michael@0 371 }
michael@0 372
michael@0 373 void
michael@0 374 MacroAssemblerMIPS::ma_and(Register rd, Imm32 imm)
michael@0 375 {
michael@0 376 ma_and(rd, rd, imm);
michael@0 377 }
michael@0 378
michael@0 379 void
michael@0 380 MacroAssemblerMIPS::ma_and(Register rd, Register rs, Imm32 imm)
michael@0 381 {
michael@0 382 if (Imm16::isInUnsignedRange(imm.value)) {
michael@0 383 as_andi(rd, rs, imm.value);
michael@0 384 } else {
michael@0 385 ma_li(ScratchRegister, imm);
michael@0 386 as_and(rd, rs, ScratchRegister);
michael@0 387 }
michael@0 388 }
michael@0 389
michael@0 390 // Or.
michael@0 391 void
michael@0 392 MacroAssemblerMIPS::ma_or(Register rd, Register rs)
michael@0 393 {
michael@0 394 as_or(rd, rd, rs);
michael@0 395 }
michael@0 396
michael@0 397 void
michael@0 398 MacroAssemblerMIPS::ma_or(Register rd, Register rs, Register rt)
michael@0 399 {
michael@0 400 as_or(rd, rs, rt);
michael@0 401 }
michael@0 402
michael@0 403 void
michael@0 404 MacroAssemblerMIPS::ma_or(Register rd, Imm32 imm)
michael@0 405 {
michael@0 406 ma_or(rd, rd, imm);
michael@0 407 }
michael@0 408
michael@0 409 void
michael@0 410 MacroAssemblerMIPS::ma_or(Register rd, Register rs, Imm32 imm)
michael@0 411 {
michael@0 412 if (Imm16::isInUnsignedRange(imm.value)) {
michael@0 413 as_ori(rd, rs, imm.value);
michael@0 414 } else {
michael@0 415 ma_li(ScratchRegister, imm);
michael@0 416 as_or(rd, rs, ScratchRegister);
michael@0 417 }
michael@0 418 }
michael@0 419
michael@0 420 // xor
michael@0 421 void
michael@0 422 MacroAssemblerMIPS::ma_xor(Register rd, Register rs)
michael@0 423 {
michael@0 424 as_xor(rd, rd, rs);
michael@0 425 }
michael@0 426
michael@0 427 void
michael@0 428 MacroAssemblerMIPS::ma_xor(Register rd, Register rs, Register rt)
michael@0 429 {
michael@0 430 as_xor(rd, rs, rt);
michael@0 431 }
michael@0 432
michael@0 433 void
michael@0 434 MacroAssemblerMIPS::ma_xor(Register rd, Imm32 imm)
michael@0 435 {
michael@0 436 ma_xor(rd, rd, imm);
michael@0 437 }
michael@0 438
michael@0 439 void
michael@0 440 MacroAssemblerMIPS::ma_xor(Register rd, Register rs, Imm32 imm)
michael@0 441 {
michael@0 442 if (Imm16::isInUnsignedRange(imm.value)) {
michael@0 443 as_xori(rd, rs, imm.value);
michael@0 444 } else {
michael@0 445 ma_li(ScratchRegister, imm);
michael@0 446 as_xor(rd, rs, ScratchRegister);
michael@0 447 }
michael@0 448 }
michael@0 449
michael@0 450 // Arithmetic-based ops.
michael@0 451
michael@0 452 // Add.
michael@0 453 void
michael@0 454 MacroAssemblerMIPS::ma_addu(Register rd, Register rs, Imm32 imm)
michael@0 455 {
michael@0 456 if (Imm16::isInSignedRange(imm.value)) {
michael@0 457 as_addiu(rd, rs, imm.value);
michael@0 458 } else {
michael@0 459 ma_li(ScratchRegister, imm);
michael@0 460 as_addu(rd, rs, ScratchRegister);
michael@0 461 }
michael@0 462 }
michael@0 463
michael@0 464 void
michael@0 465 MacroAssemblerMIPS::ma_addu(Register rd, Register rs)
michael@0 466 {
michael@0 467 as_addu(rd, rd, rs);
michael@0 468 }
michael@0 469
michael@0 470 void
michael@0 471 MacroAssemblerMIPS::ma_addu(Register rd, Imm32 imm)
michael@0 472 {
michael@0 473 ma_addu(rd, rd, imm);
michael@0 474 }
michael@0 475
michael@0 476 void
michael@0 477 MacroAssemblerMIPS::ma_addTestOverflow(Register rd, Register rs, Register rt, Label *overflow)
michael@0 478 {
michael@0 479 Label goodAddition;
michael@0 480 as_addu(SecondScratchReg, rs, rt);
michael@0 481
michael@0 482 as_xor(ScratchRegister, rs, rt); // If different sign, no overflow
michael@0 483 ma_b(ScratchRegister, Imm32(0), &goodAddition, Assembler::LessThan, ShortJump);
michael@0 484
michael@0 485 // If different sign, then overflow
michael@0 486 as_xor(ScratchRegister, rs, SecondScratchReg);
michael@0 487 ma_b(ScratchRegister, Imm32(0), overflow, Assembler::LessThan);
michael@0 488
michael@0 489 bind(&goodAddition);
michael@0 490 ma_move(rd, SecondScratchReg);
michael@0 491 }
michael@0 492
michael@0 493 void
michael@0 494 MacroAssemblerMIPS::ma_addTestOverflow(Register rd, Register rs, Imm32 imm, Label *overflow)
michael@0 495 {
michael@0 496 // Check for signed range because of as_addiu
michael@0 497 // Check for unsigned range because of as_xori
michael@0 498 if (Imm16::isInSignedRange(imm.value) && Imm16::isInUnsignedRange(imm.value)) {
michael@0 499 Label goodAddition;
michael@0 500 as_addiu(SecondScratchReg, rs, imm.value);
michael@0 501
michael@0 502 // If different sign, no overflow
michael@0 503 as_xori(ScratchRegister, rs, imm.value);
michael@0 504 ma_b(ScratchRegister, Imm32(0), &goodAddition, Assembler::LessThan, ShortJump);
michael@0 505
michael@0 506 // If different sign, then overflow
michael@0 507 as_xor(ScratchRegister, rs, SecondScratchReg);
michael@0 508 ma_b(ScratchRegister, Imm32(0), overflow, Assembler::LessThan);
michael@0 509
michael@0 510 bind(&goodAddition);
michael@0 511 ma_move(rd, SecondScratchReg);
michael@0 512 } else {
michael@0 513 ma_li(ScratchRegister, imm);
michael@0 514 ma_addTestOverflow(rd, rs, ScratchRegister, overflow);
michael@0 515 }
michael@0 516 }
michael@0 517
michael@0 518 // Subtract.
michael@0 519 void
michael@0 520 MacroAssemblerMIPS::ma_subu(Register rd, Register rs, Register rt)
michael@0 521 {
michael@0 522 as_subu(rd, rs, rt);
michael@0 523 }
michael@0 524
michael@0 525 void
michael@0 526 MacroAssemblerMIPS::ma_subu(Register rd, Register rs, Imm32 imm)
michael@0 527 {
michael@0 528 if (Imm16::isInSignedRange(-imm.value)) {
michael@0 529 as_addiu(rd, rs, -imm.value);
michael@0 530 } else {
michael@0 531 ma_li(ScratchRegister, imm);
michael@0 532 as_subu(rd, rs, ScratchRegister);
michael@0 533 }
michael@0 534 }
michael@0 535
michael@0 536 void
michael@0 537 MacroAssemblerMIPS::ma_subu(Register rd, Imm32 imm)
michael@0 538 {
michael@0 539 ma_subu(rd, rd, imm);
michael@0 540 }
michael@0 541
michael@0 542 void
michael@0 543 MacroAssemblerMIPS::ma_subTestOverflow(Register rd, Register rs, Register rt, Label *overflow)
michael@0 544 {
michael@0 545 Label goodSubtraction;
michael@0 546 // Use second scratch. The instructions generated by ma_b don't use the
michael@0 547 // second scratch register.
michael@0 548 ma_subu(SecondScratchReg, rs, rt);
michael@0 549
michael@0 550 as_xor(ScratchRegister, rs, rt); // If same sign, no overflow
michael@0 551 ma_b(ScratchRegister, Imm32(0), &goodSubtraction, Assembler::GreaterThanOrEqual, ShortJump);
michael@0 552
michael@0 553 // If different sign, then overflow
michael@0 554 as_xor(ScratchRegister, rs, SecondScratchReg);
michael@0 555 ma_b(ScratchRegister, Imm32(0), overflow, Assembler::LessThan);
michael@0 556
michael@0 557 bind(&goodSubtraction);
michael@0 558 ma_move(rd, SecondScratchReg);
michael@0 559 }
michael@0 560
michael@0 561 void
michael@0 562 MacroAssemblerMIPS::ma_subTestOverflow(Register rd, Register rs, Imm32 imm, Label *overflow)
michael@0 563 {
michael@0 564 if (imm.value != INT32_MIN) {
michael@0 565 ma_addTestOverflow(rd, rs, Imm32(-imm.value), overflow);
michael@0 566 } else {
michael@0 567 ma_li(ScratchRegister, Imm32(imm.value));
michael@0 568 ma_subTestOverflow(rd, rs, ScratchRegister, overflow);
michael@0 569 }
michael@0 570 }
michael@0 571
michael@0 572 void
michael@0 573 MacroAssemblerMIPS::ma_mult(Register rs, Imm32 imm)
michael@0 574 {
michael@0 575 ma_li(ScratchRegister, imm);
michael@0 576 as_mult(rs, ScratchRegister);
michael@0 577 }
michael@0 578
michael@0 579 void
michael@0 580 MacroAssemblerMIPS::ma_mul_branch_overflow(Register rd, Register rs, Register rt, Label *overflow)
michael@0 581 {
michael@0 582 as_mult(rs, rt);
michael@0 583 as_mflo(rd);
michael@0 584 as_sra(ScratchRegister, rd, 31);
michael@0 585 as_mfhi(SecondScratchReg);
michael@0 586 ma_b(ScratchRegister, SecondScratchReg, overflow, Assembler::NotEqual);
michael@0 587 }
michael@0 588
michael@0 589 void
michael@0 590 MacroAssemblerMIPS::ma_mul_branch_overflow(Register rd, Register rs, Imm32 imm, Label *overflow)
michael@0 591 {
michael@0 592 ma_li(ScratchRegister, imm);
michael@0 593 ma_mul_branch_overflow(rd, rs, ScratchRegister, overflow);
michael@0 594 }
michael@0 595
michael@0 596 void
michael@0 597 MacroAssemblerMIPS::ma_div_branch_overflow(Register rd, Register rs, Register rt, Label *overflow)
michael@0 598 {
michael@0 599 as_div(rs, rt);
michael@0 600 as_mflo(rd);
michael@0 601 as_mfhi(ScratchRegister);
michael@0 602 ma_b(ScratchRegister, ScratchRegister, overflow, Assembler::NonZero);
michael@0 603 }
michael@0 604
michael@0 605 void
michael@0 606 MacroAssemblerMIPS::ma_div_branch_overflow(Register rd, Register rs, Imm32 imm, Label *overflow)
michael@0 607 {
michael@0 608 ma_li(ScratchRegister, imm);
michael@0 609 ma_div_branch_overflow(rd, rs, ScratchRegister, overflow);
michael@0 610 }
michael@0 611
michael@0 612 void
michael@0 613 MacroAssemblerMIPS::ma_mod_mask(Register src, Register dest, Register hold, int32_t shift,
michael@0 614 Label *negZero)
michael@0 615 {
michael@0 616 // MATH:
michael@0 617 // We wish to compute x % (1<<y) - 1 for a known constant, y.
michael@0 618 // First, let b = (1<<y) and C = (1<<y)-1, then think of the 32 bit
michael@0 619 // dividend as a number in base b, namely
michael@0 620 // c_0*1 + c_1*b + c_2*b^2 ... c_n*b^n
michael@0 621 // now, since both addition and multiplication commute with modulus,
michael@0 622 // x % C == (c_0 + c_1*b + ... + c_n*b^n) % C ==
michael@0 623 // (c_0 % C) + (c_1%C) * (b % C) + (c_2 % C) * (b^2 % C)...
michael@0 624 // now, since b == C + 1, b % C == 1, and b^n % C == 1
michael@0 625 // this means that the whole thing simplifies to:
michael@0 626 // c_0 + c_1 + c_2 ... c_n % C
michael@0 627 // each c_n can easily be computed by a shift/bitextract, and the modulus
michael@0 628 // can be maintained by simply subtracting by C whenever the number gets
michael@0 629 // over C.
michael@0 630 int32_t mask = (1 << shift) - 1;
michael@0 631 Label head, negative, sumSigned, done;
michael@0 632
michael@0 633 // hold holds -1 if the value was negative, 1 otherwise.
michael@0 634 // ScratchRegister holds the remaining bits that have not been processed
michael@0 635 // lr serves as a temporary location to store extracted bits into as well
michael@0 636 // as holding the trial subtraction as a temp value dest is the
michael@0 637 // accumulator (and holds the final result)
michael@0 638
michael@0 639 // move the whole value into the scratch register, setting the codition
michael@0 640 // codes so we can muck with them later.
michael@0 641 ma_move(ScratchRegister, src);
michael@0 642 // Zero out the dest.
michael@0 643 ma_subu(dest, dest, dest);
michael@0 644 // Set the hold appropriately.
michael@0 645 ma_b(ScratchRegister, ScratchRegister, &negative, Signed, ShortJump);
michael@0 646 ma_li(hold, Imm32(1));
michael@0 647 ma_b(&head, ShortJump);
michael@0 648
michael@0 649 bind(&negative);
michael@0 650 ma_li(hold, Imm32(-1));
michael@0 651 ma_negu(ScratchRegister, ScratchRegister);
michael@0 652
michael@0 653 // Begin the main loop.
michael@0 654 bind(&head);
michael@0 655
michael@0 656 // Extract the bottom bits into lr.
michael@0 657 ma_and(SecondScratchReg, ScratchRegister, Imm32(mask));
michael@0 658 // Add those bits to the accumulator.
michael@0 659 as_addu(dest, dest, SecondScratchReg);
michael@0 660 // Do a trial subtraction, this is the same operation as cmp, but we
michael@0 661 // store the dest
michael@0 662 ma_subu(SecondScratchReg, dest, Imm32(mask));
michael@0 663 // If (sum - C) > 0, store sum - C back into sum, thus performing a
michael@0 664 // modulus.
michael@0 665 ma_b(SecondScratchReg, SecondScratchReg, &sumSigned, Signed, ShortJump);
michael@0 666 ma_move(dest, SecondScratchReg);
michael@0 667 bind(&sumSigned);
michael@0 668 // Get rid of the bits that we extracted before.
michael@0 669 as_srl(ScratchRegister, ScratchRegister, shift);
michael@0 670 // If the shift produced zero, finish, otherwise, continue in the loop.
michael@0 671 ma_b(ScratchRegister, ScratchRegister, &head, NonZero, ShortJump);
michael@0 672 // Check the hold to see if we need to negate the result.
michael@0 673 ma_b(hold, hold, &done, NotSigned, ShortJump);
michael@0 674
michael@0 675 // If the hold was non-zero, negate the result to be in line with
michael@0 676 // what JS wants
michael@0 677 if (negZero != nullptr) {
michael@0 678 // Jump out in case of negative zero.
michael@0 679 ma_b(hold, hold, negZero, Zero);
michael@0 680 ma_negu(dest, dest);
michael@0 681 } else {
michael@0 682 ma_negu(dest, dest);
michael@0 683 }
michael@0 684
michael@0 685 bind(&done);
michael@0 686 }
michael@0 687
michael@0 688 // Memory.
michael@0 689
michael@0 690 void
michael@0 691 MacroAssemblerMIPS::ma_load(const Register &dest, Address address,
michael@0 692 LoadStoreSize size, LoadStoreExtension extension)
michael@0 693 {
michael@0 694 int16_t encodedOffset;
michael@0 695 Register base;
michael@0 696 if (!Imm16::isInSignedRange(address.offset)) {
michael@0 697 ma_li(ScratchRegister, Imm32(address.offset));
michael@0 698 as_addu(ScratchRegister, address.base, ScratchRegister);
michael@0 699 base = ScratchRegister;
michael@0 700 encodedOffset = Imm16(0).encode();
michael@0 701 } else {
michael@0 702 encodedOffset = Imm16(address.offset).encode();
michael@0 703 base = address.base;
michael@0 704 }
michael@0 705
michael@0 706 switch (size) {
michael@0 707 case SizeByte:
michael@0 708 if (ZeroExtend == extension)
michael@0 709 as_lbu(dest, base, encodedOffset);
michael@0 710 else
michael@0 711 as_lb(dest, base, encodedOffset);
michael@0 712 break;
michael@0 713 case SizeHalfWord:
michael@0 714 if (ZeroExtend == extension)
michael@0 715 as_lhu(dest, base, encodedOffset);
michael@0 716 else
michael@0 717 as_lh(dest, base, encodedOffset);
michael@0 718 break;
michael@0 719 case SizeWord:
michael@0 720 as_lw(dest, base, encodedOffset);
michael@0 721 break;
michael@0 722 default:
michael@0 723 MOZ_ASSUME_UNREACHABLE("Invalid argument for ma_load");
michael@0 724 break;
michael@0 725 }
michael@0 726 }
michael@0 727
michael@0 728 void
michael@0 729 MacroAssemblerMIPS::ma_load(const Register &dest, const BaseIndex &src,
michael@0 730 LoadStoreSize size, LoadStoreExtension extension)
michael@0 731 {
michael@0 732 computeScaledAddress(src, SecondScratchReg);
michael@0 733 ma_load(dest, Address(SecondScratchReg, src.offset), size, extension);
michael@0 734 }
michael@0 735
michael@0 736 void
michael@0 737 MacroAssemblerMIPS::ma_store(const Register &data, Address address, LoadStoreSize size,
michael@0 738 LoadStoreExtension extension)
michael@0 739 {
michael@0 740 int16_t encodedOffset;
michael@0 741 Register base;
michael@0 742 if (!Imm16::isInSignedRange(address.offset)) {
michael@0 743 ma_li(ScratchRegister, Imm32(address.offset));
michael@0 744 as_addu(ScratchRegister, address.base, ScratchRegister);
michael@0 745 base = ScratchRegister;
michael@0 746 encodedOffset = Imm16(0).encode();
michael@0 747 } else {
michael@0 748 encodedOffset = Imm16(address.offset).encode();
michael@0 749 base = address.base;
michael@0 750 }
michael@0 751
michael@0 752 switch (size) {
michael@0 753 case SizeByte:
michael@0 754 as_sb(data, base, encodedOffset);
michael@0 755 break;
michael@0 756 case SizeHalfWord:
michael@0 757 as_sh(data, base, encodedOffset);
michael@0 758 break;
michael@0 759 case SizeWord:
michael@0 760 as_sw(data, base, encodedOffset);
michael@0 761 break;
michael@0 762 default:
michael@0 763 MOZ_ASSUME_UNREACHABLE("Invalid argument for ma_store");
michael@0 764 break;
michael@0 765 }
michael@0 766 }
michael@0 767
michael@0 768 void
michael@0 769 MacroAssemblerMIPS::ma_store(const Register &data, const BaseIndex &dest,
michael@0 770 LoadStoreSize size, LoadStoreExtension extension)
michael@0 771 {
michael@0 772 computeScaledAddress(dest, SecondScratchReg);
michael@0 773 ma_store(data, Address(SecondScratchReg, dest.offset), size, extension);
michael@0 774 }
michael@0 775
michael@0 776 void
michael@0 777 MacroAssemblerMIPS::ma_store(const Imm32 &imm, const BaseIndex &dest,
michael@0 778 LoadStoreSize size, LoadStoreExtension extension)
michael@0 779 {
michael@0 780 // Make sure that SecondScratchReg contains absolute address so that
michael@0 781 // offset is 0.
michael@0 782 computeEffectiveAddress(dest, SecondScratchReg);
michael@0 783
michael@0 784 // Scrach register is free now, use it for loading imm value
michael@0 785 ma_li(ScratchRegister, imm);
michael@0 786
michael@0 787 // with offset=0 ScratchRegister will not be used in ma_store()
michael@0 788 // so we can use it as a parameter here
michael@0 789 ma_store(ScratchRegister, Address(SecondScratchReg, 0), size, extension);
michael@0 790 }
michael@0 791
michael@0 792 void
michael@0 793 MacroAssemblerMIPS::computeScaledAddress(const BaseIndex &address, Register dest)
michael@0 794 {
michael@0 795 int32_t shift = Imm32::ShiftOf(address.scale).value;
michael@0 796 if (shift) {
michael@0 797 ma_sll(dest, address.index, Imm32(shift));
michael@0 798 as_addu(dest, address.base, dest);
michael@0 799 } else {
michael@0 800 as_addu(dest, address.base, address.index);
michael@0 801 }
michael@0 802 }
michael@0 803
michael@0 804 // Shortcut for when we know we're transferring 32 bits of data.
michael@0 805 void
michael@0 806 MacroAssemblerMIPS::ma_lw(Register data, Address address)
michael@0 807 {
michael@0 808 ma_load(data, address, SizeWord);
michael@0 809 }
michael@0 810
michael@0 811 void
michael@0 812 MacroAssemblerMIPS::ma_sw(Register data, Address address)
michael@0 813 {
michael@0 814 ma_store(data, address, SizeWord);
michael@0 815 }
michael@0 816
michael@0 817 void
michael@0 818 MacroAssemblerMIPS::ma_sw(Imm32 imm, Address address)
michael@0 819 {
michael@0 820 MOZ_ASSERT(address.base != ScratchRegister);
michael@0 821 ma_li(ScratchRegister, imm);
michael@0 822
michael@0 823 if (Imm16::isInSignedRange(address.offset)) {
michael@0 824 as_sw(ScratchRegister, address.base, Imm16(address.offset).encode());
michael@0 825 } else {
michael@0 826 MOZ_ASSERT(address.base != SecondScratchReg);
michael@0 827
michael@0 828 ma_li(SecondScratchReg, Imm32(address.offset));
michael@0 829 as_addu(SecondScratchReg, address.base, SecondScratchReg);
michael@0 830 as_sw(ScratchRegister, SecondScratchReg, 0);
michael@0 831 }
michael@0 832 }
michael@0 833
michael@0 834 void
michael@0 835 MacroAssemblerMIPS::ma_pop(Register r)
michael@0 836 {
michael@0 837 as_lw(r, StackPointer, 0);
michael@0 838 as_addiu(StackPointer, StackPointer, sizeof(intptr_t));
michael@0 839 }
michael@0 840
michael@0 841 void
michael@0 842 MacroAssemblerMIPS::ma_push(Register r)
michael@0 843 {
michael@0 844 if (r == sp) {
michael@0 845 // Pushing sp requires one more instruction.
michael@0 846 ma_move(ScratchRegister, sp);
michael@0 847 r = ScratchRegister;
michael@0 848 }
michael@0 849
michael@0 850 as_addiu(StackPointer, StackPointer, -sizeof(intptr_t));
michael@0 851 as_sw(r, StackPointer, 0);
michael@0 852 }
michael@0 853
michael@0 854 // Branches when done from within mips-specific code.
michael@0 855 void
michael@0 856 MacroAssemblerMIPS::ma_b(Register lhs, Register rhs, Label *label, Condition c, JumpKind jumpKind)
michael@0 857 {
michael@0 858 switch (c) {
michael@0 859 case Equal :
michael@0 860 case NotEqual:
michael@0 861 branchWithCode(getBranchCode(lhs, rhs, c), label, jumpKind);
michael@0 862 break;
michael@0 863 case Always:
michael@0 864 ma_b(label, jumpKind);
michael@0 865 break;
michael@0 866 case Zero:
michael@0 867 case NonZero:
michael@0 868 case Signed:
michael@0 869 case NotSigned:
michael@0 870 MOZ_ASSERT(lhs == rhs);
michael@0 871 branchWithCode(getBranchCode(lhs, c), label, jumpKind);
michael@0 872 break;
michael@0 873 default:
michael@0 874 Condition cond = ma_cmp(ScratchRegister, lhs, rhs, c);
michael@0 875 branchWithCode(getBranchCode(ScratchRegister, cond), label, jumpKind);
michael@0 876 break;
michael@0 877 }
michael@0 878 }
michael@0 879
michael@0 880 void
michael@0 881 MacroAssemblerMIPS::ma_b(Register lhs, Imm32 imm, Label *label, Condition c, JumpKind jumpKind)
michael@0 882 {
michael@0 883 MOZ_ASSERT(c != Overflow);
michael@0 884 if (imm.value == 0) {
michael@0 885 if (c == Always || c == AboveOrEqual)
michael@0 886 ma_b(label, jumpKind);
michael@0 887 else if (c == Below)
michael@0 888 ; // This condition is always false. No branch required.
michael@0 889 else
michael@0 890 branchWithCode(getBranchCode(lhs, c), label, jumpKind);
michael@0 891 } else {
michael@0 892 MOZ_ASSERT(lhs != ScratchRegister);
michael@0 893 ma_li(ScratchRegister, imm);
michael@0 894 ma_b(lhs, ScratchRegister, label, c, jumpKind);
michael@0 895 }
michael@0 896 }
michael@0 897
michael@0 898 void
michael@0 899 MacroAssemblerMIPS::ma_b(Register lhs, Address addr, Label *label, Condition c, JumpKind jumpKind)
michael@0 900 {
michael@0 901 MOZ_ASSERT(lhs != ScratchRegister);
michael@0 902 ma_lw(ScratchRegister, addr);
michael@0 903 ma_b(lhs, ScratchRegister, label, c, jumpKind);
michael@0 904 }
michael@0 905
michael@0 906 void
michael@0 907 MacroAssemblerMIPS::ma_b(Address addr, Imm32 imm, Label *label, Condition c, JumpKind jumpKind)
michael@0 908 {
michael@0 909 ma_lw(SecondScratchReg, addr);
michael@0 910 ma_b(SecondScratchReg, imm, label, c, jumpKind);
michael@0 911 }
michael@0 912
michael@0 913 void
michael@0 914 MacroAssemblerMIPS::ma_b(Label *label, JumpKind jumpKind)
michael@0 915 {
michael@0 916 branchWithCode(getBranchCode(BranchIsJump), label, jumpKind);
michael@0 917 }
michael@0 918
michael@0 919 void
michael@0 920 MacroAssemblerMIPS::ma_bal(Label *label, JumpKind jumpKind)
michael@0 921 {
michael@0 922 branchWithCode(getBranchCode(BranchIsCall), label, jumpKind);
michael@0 923 }
michael@0 924
michael@0 925 void
michael@0 926 MacroAssemblerMIPS::branchWithCode(InstImm code, Label *label, JumpKind jumpKind)
michael@0 927 {
michael@0 928 InstImm inst_bgezal = InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
michael@0 929 InstImm inst_beq = InstImm(op_beq, zero, zero, BOffImm16(0));
michael@0 930
michael@0 931 if (label->bound()) {
michael@0 932 int32_t offset = label->offset() - m_buffer.nextOffset().getOffset();
michael@0 933
michael@0 934 if (BOffImm16::isInRange(offset))
michael@0 935 jumpKind = ShortJump;
michael@0 936
michael@0 937 if (jumpKind == ShortJump) {
michael@0 938 MOZ_ASSERT(BOffImm16::isInRange(offset));
michael@0 939 code.setBOffImm16(BOffImm16(offset));
michael@0 940 writeInst(code.encode());
michael@0 941 as_nop();
michael@0 942 return;
michael@0 943 }
michael@0 944
michael@0 945 // Generate long jump because target is out of range of short jump.
michael@0 946 if (code.encode() == inst_bgezal.encode()) {
michael@0 947 // Handle long call
michael@0 948 addLongJump(nextOffset());
michael@0 949 ma_liPatchable(ScratchRegister, Imm32(label->offset()));
michael@0 950 as_jalr(ScratchRegister);
michael@0 951 as_nop();
michael@0 952 return;
michael@0 953 }
michael@0 954 if (code.encode() == inst_beq.encode()) {
michael@0 955 // Handle long jump
michael@0 956 addLongJump(nextOffset());
michael@0 957 ma_liPatchable(ScratchRegister, Imm32(label->offset()));
michael@0 958 as_jr(ScratchRegister);
michael@0 959 as_nop();
michael@0 960 return;
michael@0 961 }
michael@0 962
michael@0 963 // Handle long conditional branch
michael@0 964 writeInst(invertBranch(code, BOffImm16(5 * sizeof(uint32_t))).encode());
michael@0 965 // No need for a "nop" here because we can clobber scratch.
michael@0 966 addLongJump(nextOffset());
michael@0 967 ma_liPatchable(ScratchRegister, Imm32(label->offset()));
michael@0 968 as_jr(ScratchRegister);
michael@0 969 as_nop();
michael@0 970 return;
michael@0 971 }
michael@0 972
michael@0 973 // Generate open jump and link it to a label.
michael@0 974
michael@0 975 // Second word holds a pointer to the next branch in label's chain.
michael@0 976 uint32_t nextInChain = label->used() ? label->offset() : LabelBase::INVALID_OFFSET;
michael@0 977
michael@0 978 if (jumpKind == ShortJump) {
michael@0 979 // Make the whole branch continous in the buffer.
michael@0 980 m_buffer.ensureSpace(2 * sizeof(uint32_t));
michael@0 981
michael@0 982 // Indicate that this is short jump with offset 4.
michael@0 983 code.setBOffImm16(BOffImm16(4));
michael@0 984 BufferOffset bo = writeInst(code.encode());
michael@0 985 writeInst(nextInChain);
michael@0 986 label->use(bo.getOffset());
michael@0 987 return;
michael@0 988 }
michael@0 989
michael@0 990 bool conditional = (code.encode() != inst_bgezal.encode() &&
michael@0 991 code.encode() != inst_beq.encode());
michael@0 992
michael@0 993 // Make the whole branch continous in the buffer.
michael@0 994 m_buffer.ensureSpace((conditional ? 5 : 4) * sizeof(uint32_t));
michael@0 995
michael@0 996 BufferOffset bo = writeInst(code.encode());
michael@0 997 writeInst(nextInChain);
michael@0 998 label->use(bo.getOffset());
michael@0 999 // Leave space for potential long jump.
michael@0 1000 as_nop();
michael@0 1001 as_nop();
michael@0 1002 if (conditional)
michael@0 1003 as_nop();
michael@0 1004 }
michael@0 1005
michael@0 1006 Assembler::Condition
michael@0 1007 MacroAssemblerMIPS::ma_cmp(Register scratch, Register lhs, Register rhs, Condition c)
michael@0 1008 {
michael@0 1009 switch (c) {
michael@0 1010 case Above:
michael@0 1011 // bgtu s,t,label =>
michael@0 1012 // sltu at,t,s
michael@0 1013 // bne at,$zero,offs
michael@0 1014 as_sltu(scratch, rhs, lhs);
michael@0 1015 return NotEqual;
michael@0 1016 case AboveOrEqual:
michael@0 1017 // bgeu s,t,label =>
michael@0 1018 // sltu at,s,t
michael@0 1019 // beq at,$zero,offs
michael@0 1020 as_sltu(scratch, lhs, rhs);
michael@0 1021 return Equal;
michael@0 1022 case Below:
michael@0 1023 // bltu s,t,label =>
michael@0 1024 // sltu at,s,t
michael@0 1025 // bne at,$zero,offs
michael@0 1026 as_sltu(scratch, lhs, rhs);
michael@0 1027 return NotEqual;
michael@0 1028 case BelowOrEqual:
michael@0 1029 // bleu s,t,label =>
michael@0 1030 // sltu at,t,s
michael@0 1031 // beq at,$zero,offs
michael@0 1032 as_sltu(scratch, rhs, lhs);
michael@0 1033 return Equal;
michael@0 1034 case GreaterThan:
michael@0 1035 // bgt s,t,label =>
michael@0 1036 // slt at,t,s
michael@0 1037 // bne at,$zero,offs
michael@0 1038 as_slt(scratch, rhs, lhs);
michael@0 1039 return NotEqual;
michael@0 1040 case GreaterThanOrEqual:
michael@0 1041 // bge s,t,label =>
michael@0 1042 // slt at,s,t
michael@0 1043 // beq at,$zero,offs
michael@0 1044 as_slt(scratch, lhs, rhs);
michael@0 1045 return Equal;
michael@0 1046 case LessThan:
michael@0 1047 // blt s,t,label =>
michael@0 1048 // slt at,s,t
michael@0 1049 // bne at,$zero,offs
michael@0 1050 as_slt(scratch, lhs, rhs);
michael@0 1051 return NotEqual;
michael@0 1052 case LessThanOrEqual:
michael@0 1053 // ble s,t,label =>
michael@0 1054 // slt at,t,s
michael@0 1055 // beq at,$zero,offs
michael@0 1056 as_slt(scratch, rhs, lhs);
michael@0 1057 return Equal;
michael@0 1058 case Equal :
michael@0 1059 case NotEqual:
michael@0 1060 case Zero:
michael@0 1061 case NonZero:
michael@0 1062 case Always:
michael@0 1063 case Signed:
michael@0 1064 case NotSigned:
michael@0 1065 MOZ_ASSUME_UNREACHABLE("There is a better way to compare for equality.");
michael@0 1066 break;
michael@0 1067 case Overflow:
michael@0 1068 MOZ_ASSUME_UNREACHABLE("Overflow condition not supported for MIPS.");
michael@0 1069 break;
michael@0 1070 default:
michael@0 1071 MOZ_ASSUME_UNREACHABLE("Invalid condition for branch.");
michael@0 1072 }
michael@0 1073 return Always;
michael@0 1074 }
michael@0 1075
michael@0 1076 void
michael@0 1077 MacroAssemblerMIPS::ma_cmp_set(Register rd, Register rs, Register rt, Condition c)
michael@0 1078 {
michael@0 1079 switch (c) {
michael@0 1080 case Equal :
michael@0 1081 // seq d,s,t =>
michael@0 1082 // xor d,s,t
michael@0 1083 // sltiu d,d,1
michael@0 1084 as_xor(rd, rs, rt);
michael@0 1085 as_sltiu(rd, rd, 1);
michael@0 1086 break;
michael@0 1087 case NotEqual:
michael@0 1088 // sne d,s,t =>
michael@0 1089 // xor d,s,t
michael@0 1090 // sltu d,$zero,d
michael@0 1091 as_xor(rd, rs, rt);
michael@0 1092 as_sltu(rd, zero, rd);
michael@0 1093 break;
michael@0 1094 case Above:
michael@0 1095 // sgtu d,s,t =>
michael@0 1096 // sltu d,t,s
michael@0 1097 as_sltu(rd, rt, rs);
michael@0 1098 break;
michael@0 1099 case AboveOrEqual:
michael@0 1100 // sgeu d,s,t =>
michael@0 1101 // sltu d,s,t
michael@0 1102 // xori d,d,1
michael@0 1103 as_sltu(rd, rs, rt);
michael@0 1104 as_xori(rd, rd, 1);
michael@0 1105 break;
michael@0 1106 case Below:
michael@0 1107 // sltu d,s,t
michael@0 1108 as_sltu(rd, rs, rt);
michael@0 1109 break;
michael@0 1110 case BelowOrEqual:
michael@0 1111 // sleu d,s,t =>
michael@0 1112 // sltu d,t,s
michael@0 1113 // xori d,d,1
michael@0 1114 as_sltu(rd, rt, rs);
michael@0 1115 as_xori(rd, rd, 1);
michael@0 1116 break;
michael@0 1117 case GreaterThan:
michael@0 1118 // sgt d,s,t =>
michael@0 1119 // slt d,t,s
michael@0 1120 as_slt(rd, rt, rs);
michael@0 1121 break;
michael@0 1122 case GreaterThanOrEqual:
michael@0 1123 // sge d,s,t =>
michael@0 1124 // slt d,s,t
michael@0 1125 // xori d,d,1
michael@0 1126 as_slt(rd, rs, rt);
michael@0 1127 as_xori(rd, rd, 1);
michael@0 1128 break;
michael@0 1129 case LessThan:
michael@0 1130 // slt d,s,t
michael@0 1131 as_slt(rd, rs, rt);
michael@0 1132 break;
michael@0 1133 case LessThanOrEqual:
michael@0 1134 // sle d,s,t =>
michael@0 1135 // slt d,t,s
michael@0 1136 // xori d,d,1
michael@0 1137 as_slt(rd, rt, rs);
michael@0 1138 as_xori(rd, rd, 1);
michael@0 1139 break;
michael@0 1140 case Zero:
michael@0 1141 MOZ_ASSERT(rs == rt);
michael@0 1142 // seq d,s,$zero =>
michael@0 1143 // xor d,s,$zero
michael@0 1144 // sltiu d,d,1
michael@0 1145 as_xor(rd, rs, zero);
michael@0 1146 as_sltiu(rd, rd, 1);
michael@0 1147 break;
michael@0 1148 case NonZero:
michael@0 1149 // sne d,s,$zero =>
michael@0 1150 // xor d,s,$zero
michael@0 1151 // sltu d,$zero,d
michael@0 1152 as_xor(rd, rs, zero);
michael@0 1153 as_sltu(rd, zero, rd);
michael@0 1154 break;
michael@0 1155 case Signed:
michael@0 1156 as_slt(rd, rs, zero);
michael@0 1157 break;
michael@0 1158 case NotSigned:
michael@0 1159 // sge d,s,$zero =>
michael@0 1160 // slt d,s,$zero
michael@0 1161 // xori d,d,1
michael@0 1162 as_slt(rd, rs, zero);
michael@0 1163 as_xori(rd, rd, 1);
michael@0 1164 break;
michael@0 1165 default:
michael@0 1166 MOZ_ASSUME_UNREACHABLE("Invalid condition for ma_cmp_set.");
michael@0 1167 break;
michael@0 1168 }
michael@0 1169 }
michael@0 1170
michael@0 1171 void
michael@0 1172 MacroAssemblerMIPS::compareFloatingPoint(FloatFormat fmt, FloatRegister lhs, FloatRegister rhs,
michael@0 1173 DoubleCondition c, FloatTestKind *testKind,
michael@0 1174 FPConditionBit fcc)
michael@0 1175 {
michael@0 1176 switch (c) {
michael@0 1177 case DoubleOrdered:
michael@0 1178 as_cun(fmt, lhs, rhs, fcc);
michael@0 1179 *testKind = TestForFalse;
michael@0 1180 break;
michael@0 1181 case DoubleEqual:
michael@0 1182 as_ceq(fmt, lhs, rhs, fcc);
michael@0 1183 *testKind = TestForTrue;
michael@0 1184 break;
michael@0 1185 case DoubleNotEqual:
michael@0 1186 as_cueq(fmt, lhs, rhs, fcc);
michael@0 1187 *testKind = TestForFalse;
michael@0 1188 break;
michael@0 1189 case DoubleGreaterThan:
michael@0 1190 as_colt(fmt, rhs, lhs, fcc);
michael@0 1191 *testKind = TestForTrue;
michael@0 1192 break;
michael@0 1193 case DoubleGreaterThanOrEqual:
michael@0 1194 as_cole(fmt, rhs, lhs, fcc);
michael@0 1195 *testKind = TestForTrue;
michael@0 1196 break;
michael@0 1197 case DoubleLessThan:
michael@0 1198 as_colt(fmt, lhs, rhs, fcc);
michael@0 1199 *testKind = TestForTrue;
michael@0 1200 break;
michael@0 1201 case DoubleLessThanOrEqual:
michael@0 1202 as_cole(fmt, lhs, rhs, fcc);
michael@0 1203 *testKind = TestForTrue;
michael@0 1204 break;
michael@0 1205 case DoubleUnordered:
michael@0 1206 as_cun(fmt, lhs, rhs, fcc);
michael@0 1207 *testKind = TestForTrue;
michael@0 1208 break;
michael@0 1209 case DoubleEqualOrUnordered:
michael@0 1210 as_cueq(fmt, lhs, rhs, fcc);
michael@0 1211 *testKind = TestForTrue;
michael@0 1212 break;
michael@0 1213 case DoubleNotEqualOrUnordered:
michael@0 1214 as_ceq(fmt, lhs, rhs, fcc);
michael@0 1215 *testKind = TestForFalse;
michael@0 1216 break;
michael@0 1217 case DoubleGreaterThanOrUnordered:
michael@0 1218 as_cult(fmt, rhs, lhs, fcc);
michael@0 1219 *testKind = TestForTrue;
michael@0 1220 break;
michael@0 1221 case DoubleGreaterThanOrEqualOrUnordered:
michael@0 1222 as_cule(fmt, rhs, lhs, fcc);
michael@0 1223 *testKind = TestForTrue;
michael@0 1224 break;
michael@0 1225 case DoubleLessThanOrUnordered:
michael@0 1226 as_cult(fmt, lhs, rhs, fcc);
michael@0 1227 *testKind = TestForTrue;
michael@0 1228 break;
michael@0 1229 case DoubleLessThanOrEqualOrUnordered:
michael@0 1230 as_cule(fmt, lhs, rhs, fcc);
michael@0 1231 *testKind = TestForTrue;
michael@0 1232 break;
michael@0 1233 default:
michael@0 1234 MOZ_ASSUME_UNREACHABLE("Invalid DoubleCondition.");
michael@0 1235 break;
michael@0 1236 }
michael@0 1237 }
michael@0 1238
michael@0 1239 void
michael@0 1240 MacroAssemblerMIPS::ma_cmp_set_double(Register dest, FloatRegister lhs, FloatRegister rhs,
michael@0 1241 DoubleCondition c)
michael@0 1242 {
michael@0 1243 ma_li(dest, Imm32(0));
michael@0 1244 ma_li(ScratchRegister, Imm32(1));
michael@0 1245
michael@0 1246 FloatTestKind moveCondition;
michael@0 1247 compareFloatingPoint(DoubleFloat, lhs, rhs, c, &moveCondition);
michael@0 1248
michael@0 1249 if (moveCondition == TestForTrue)
michael@0 1250 as_movt(dest, ScratchRegister);
michael@0 1251 else
michael@0 1252 as_movf(dest, ScratchRegister);
michael@0 1253 }
michael@0 1254
michael@0 1255 void
michael@0 1256 MacroAssemblerMIPS::ma_cmp_set_float32(Register dest, FloatRegister lhs, FloatRegister rhs,
michael@0 1257 DoubleCondition c)
michael@0 1258 {
michael@0 1259 ma_li(dest, Imm32(0));
michael@0 1260 ma_li(ScratchRegister, Imm32(1));
michael@0 1261
michael@0 1262 FloatTestKind moveCondition;
michael@0 1263 compareFloatingPoint(SingleFloat, lhs, rhs, c, &moveCondition);
michael@0 1264
michael@0 1265 if (moveCondition == TestForTrue)
michael@0 1266 as_movt(dest, ScratchRegister);
michael@0 1267 else
michael@0 1268 as_movf(dest, ScratchRegister);
michael@0 1269 }
michael@0 1270
michael@0 1271 void
michael@0 1272 MacroAssemblerMIPS::ma_cmp_set(Register rd, Register rs, Imm32 imm, Condition c)
michael@0 1273 {
michael@0 1274 ma_li(ScratchRegister, imm);
michael@0 1275 ma_cmp_set(rd, rs, ScratchRegister, c);
michael@0 1276 }
michael@0 1277
michael@0 1278 void
michael@0 1279 MacroAssemblerMIPS::ma_cmp_set(Register rd, Register rs, Address addr, Condition c)
michael@0 1280 {
michael@0 1281 ma_lw(ScratchRegister, addr);
michael@0 1282 ma_cmp_set(rd, rs, ScratchRegister, c);
michael@0 1283 }
michael@0 1284
michael@0 1285 void
michael@0 1286 MacroAssemblerMIPS::ma_cmp_set(Register dst, Address lhs, Register rhs, Condition c)
michael@0 1287 {
michael@0 1288 ma_lw(ScratchRegister, lhs);
michael@0 1289 ma_cmp_set(dst, ScratchRegister, rhs, c);
michael@0 1290 }
michael@0 1291
michael@0 1292 // fp instructions
michael@0 1293 void
michael@0 1294 MacroAssemblerMIPS::ma_lis(FloatRegister dest, float value)
michael@0 1295 {
michael@0 1296 Imm32 imm(mozilla::BitwiseCast<uint32_t>(value));
michael@0 1297
michael@0 1298 ma_li(ScratchRegister, imm);
michael@0 1299 moveToFloat32(ScratchRegister, dest);
michael@0 1300 }
michael@0 1301
michael@0 1302 void
michael@0 1303 MacroAssemblerMIPS::ma_lid(FloatRegister dest, double value)
michael@0 1304 {
michael@0 1305 struct DoubleStruct {
michael@0 1306 uint32_t lo;
michael@0 1307 uint32_t hi;
michael@0 1308 } ;
michael@0 1309 DoubleStruct intStruct = mozilla::BitwiseCast<DoubleStruct>(value);
michael@0 1310
michael@0 1311 // put hi part of 64 bit value into the odd register
michael@0 1312 if (intStruct.hi == 0) {
michael@0 1313 moveToDoubleHi(zero, dest);
michael@0 1314 } else {
michael@0 1315 ma_li(ScratchRegister, Imm32(intStruct.hi));
michael@0 1316 moveToDoubleHi(ScratchRegister, dest);
michael@0 1317 }
michael@0 1318
michael@0 1319 // put low part of 64 bit value into the even register
michael@0 1320 if (intStruct.lo == 0) {
michael@0 1321 moveToDoubleLo(zero, dest);
michael@0 1322 } else {
michael@0 1323 ma_li(ScratchRegister, Imm32(intStruct.lo));
michael@0 1324 moveToDoubleLo(ScratchRegister, dest);
michael@0 1325 }
michael@0 1326 }
michael@0 1327
michael@0 1328 void
michael@0 1329 MacroAssemblerMIPS::ma_liNegZero(FloatRegister dest)
michael@0 1330 {
michael@0 1331 moveToDoubleLo(zero, dest);
michael@0 1332 ma_li(ScratchRegister, Imm32(INT_MIN));
michael@0 1333 moveToDoubleHi(ScratchRegister, dest);
michael@0 1334 }
michael@0 1335
michael@0 1336 void
michael@0 1337 MacroAssemblerMIPS::ma_mv(FloatRegister src, ValueOperand dest)
michael@0 1338 {
michael@0 1339 moveFromDoubleLo(src, dest.payloadReg());
michael@0 1340 moveFromDoubleHi(src, dest.typeReg());
michael@0 1341 }
michael@0 1342
michael@0 1343 void
michael@0 1344 MacroAssemblerMIPS::ma_mv(ValueOperand src, FloatRegister dest)
michael@0 1345 {
michael@0 1346 moveToDoubleLo(src.payloadReg(), dest);
michael@0 1347 moveToDoubleHi(src.typeReg(), dest);
michael@0 1348 }
michael@0 1349
michael@0 1350 void
michael@0 1351 MacroAssemblerMIPS::ma_ls(FloatRegister ft, Address address)
michael@0 1352 {
michael@0 1353 if (Imm16::isInSignedRange(address.offset)) {
michael@0 1354 as_ls(ft, address.base, Imm16(address.offset).encode());
michael@0 1355 } else {
michael@0 1356 MOZ_ASSERT(address.base != ScratchRegister);
michael@0 1357 ma_li(ScratchRegister, Imm32(address.offset));
michael@0 1358 as_addu(ScratchRegister, address.base, ScratchRegister);
michael@0 1359 as_ls(ft, ScratchRegister, 0);
michael@0 1360 }
michael@0 1361 }
michael@0 1362
michael@0 1363 void
michael@0 1364 MacroAssemblerMIPS::ma_ld(FloatRegister ft, Address address)
michael@0 1365 {
michael@0 1366 // Use single precision load instructions so we don't have to worry about
michael@0 1367 // alignment.
michael@0 1368
michael@0 1369 int32_t off2 = address.offset + TAG_OFFSET;
michael@0 1370 if (Imm16::isInSignedRange(address.offset) && Imm16::isInSignedRange(off2)) {
michael@0 1371 as_ls(ft, address.base, Imm16(address.offset).encode());
michael@0 1372 as_ls(getOddPair(ft), address.base, Imm16(off2).encode());
michael@0 1373 } else {
michael@0 1374 ma_li(ScratchRegister, Imm32(address.offset));
michael@0 1375 as_addu(ScratchRegister, address.base, ScratchRegister);
michael@0 1376 as_ls(ft, ScratchRegister, PAYLOAD_OFFSET);
michael@0 1377 as_ls(getOddPair(ft), ScratchRegister, TAG_OFFSET);
michael@0 1378 }
michael@0 1379 }
michael@0 1380
michael@0 1381 void
michael@0 1382 MacroAssemblerMIPS::ma_sd(FloatRegister ft, Address address)
michael@0 1383 {
michael@0 1384 int32_t off2 = address.offset + TAG_OFFSET;
michael@0 1385 if (Imm16::isInSignedRange(address.offset) && Imm16::isInSignedRange(off2)) {
michael@0 1386 as_ss(ft, address.base, Imm16(address.offset).encode());
michael@0 1387 as_ss(getOddPair(ft), address.base, Imm16(off2).encode());
michael@0 1388 } else {
michael@0 1389 ma_li(ScratchRegister, Imm32(address.offset));
michael@0 1390 as_addu(ScratchRegister, address.base, ScratchRegister);
michael@0 1391 as_ss(ft, ScratchRegister, PAYLOAD_OFFSET);
michael@0 1392 as_ss(getOddPair(ft), ScratchRegister, TAG_OFFSET);
michael@0 1393 }
michael@0 1394 }
michael@0 1395
michael@0 1396 void
michael@0 1397 MacroAssemblerMIPS::ma_sd(FloatRegister ft, BaseIndex address)
michael@0 1398 {
michael@0 1399 computeScaledAddress(address, SecondScratchReg);
michael@0 1400 ma_sd(ft, Address(SecondScratchReg, address.offset));
michael@0 1401 }
michael@0 1402
michael@0 1403 void
michael@0 1404 MacroAssemblerMIPS::ma_ss(FloatRegister ft, Address address)
michael@0 1405 {
michael@0 1406 if (Imm16::isInSignedRange(address.offset)) {
michael@0 1407 as_ss(ft, address.base, Imm16(address.offset).encode());
michael@0 1408 } else {
michael@0 1409 ma_li(ScratchRegister, Imm32(address.offset));
michael@0 1410 as_addu(ScratchRegister, address.base, ScratchRegister);
michael@0 1411 as_ss(ft, ScratchRegister, 0);
michael@0 1412 }
michael@0 1413 }
michael@0 1414
michael@0 1415 void
michael@0 1416 MacroAssemblerMIPS::ma_ss(FloatRegister ft, BaseIndex address)
michael@0 1417 {
michael@0 1418 computeScaledAddress(address, SecondScratchReg);
michael@0 1419 ma_ss(ft, Address(SecondScratchReg, address.offset));
michael@0 1420 }
michael@0 1421
michael@0 1422 void
michael@0 1423 MacroAssemblerMIPS::ma_pop(FloatRegister fs)
michael@0 1424 {
michael@0 1425 ma_ld(fs, Address(StackPointer, 0));
michael@0 1426 as_addiu(StackPointer, StackPointer, sizeof(double));
michael@0 1427 }
michael@0 1428
michael@0 1429 void
michael@0 1430 MacroAssemblerMIPS::ma_push(FloatRegister fs)
michael@0 1431 {
michael@0 1432 as_addiu(StackPointer, StackPointer, -sizeof(double));
michael@0 1433 ma_sd(fs, Address(StackPointer, 0));
michael@0 1434 }
michael@0 1435
michael@0 1436 void
michael@0 1437 MacroAssemblerMIPS::ma_bc1s(FloatRegister lhs, FloatRegister rhs, Label *label,
michael@0 1438 DoubleCondition c, JumpKind jumpKind, FPConditionBit fcc)
michael@0 1439 {
michael@0 1440 FloatTestKind testKind;
michael@0 1441 compareFloatingPoint(SingleFloat, lhs, rhs, c, &testKind, fcc);
michael@0 1442 branchWithCode(getBranchCode(testKind, fcc), label, jumpKind);
michael@0 1443 }
michael@0 1444
michael@0 1445 void
michael@0 1446 MacroAssemblerMIPS::ma_bc1d(FloatRegister lhs, FloatRegister rhs, Label *label,
michael@0 1447 DoubleCondition c, JumpKind jumpKind, FPConditionBit fcc)
michael@0 1448 {
michael@0 1449 FloatTestKind testKind;
michael@0 1450 compareFloatingPoint(DoubleFloat, lhs, rhs, c, &testKind, fcc);
michael@0 1451 branchWithCode(getBranchCode(testKind, fcc), label, jumpKind);
michael@0 1452 }
michael@0 1453
michael@0 1454 bool
michael@0 1455 MacroAssemblerMIPSCompat::buildFakeExitFrame(const Register &scratch, uint32_t *offset)
michael@0 1456 {
michael@0 1457 mozilla::DebugOnly<uint32_t> initialDepth = framePushed();
michael@0 1458
michael@0 1459 CodeLabel cl;
michael@0 1460 ma_li(scratch, cl.dest());
michael@0 1461
michael@0 1462 uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
michael@0 1463 Push(Imm32(descriptor));
michael@0 1464 Push(scratch);
michael@0 1465
michael@0 1466 bind(cl.src());
michael@0 1467 *offset = currentOffset();
michael@0 1468
michael@0 1469 MOZ_ASSERT(framePushed() == initialDepth + IonExitFrameLayout::Size());
michael@0 1470 return addCodeLabel(cl);
michael@0 1471 }
michael@0 1472
michael@0 1473 bool
michael@0 1474 MacroAssemblerMIPSCompat::buildOOLFakeExitFrame(void *fakeReturnAddr)
michael@0 1475 {
michael@0 1476 DebugOnly<uint32_t> initialDepth = framePushed();
michael@0 1477 uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
michael@0 1478
michael@0 1479 Push(Imm32(descriptor)); // descriptor_
michael@0 1480 Push(ImmPtr(fakeReturnAddr));
michael@0 1481
michael@0 1482 return true;
michael@0 1483 }
michael@0 1484
michael@0 1485 void
michael@0 1486 MacroAssemblerMIPSCompat::callWithExitFrame(JitCode *target)
michael@0 1487 {
michael@0 1488 uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
michael@0 1489 Push(Imm32(descriptor)); // descriptor
michael@0 1490
michael@0 1491 addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
michael@0 1492 ma_liPatchable(ScratchRegister, ImmPtr(target->raw()));
michael@0 1493 ma_callIonHalfPush(ScratchRegister);
michael@0 1494 }
michael@0 1495
michael@0 1496 void
michael@0 1497 MacroAssemblerMIPSCompat::callWithExitFrame(JitCode *target, Register dynStack)
michael@0 1498 {
michael@0 1499 ma_addu(dynStack, dynStack, Imm32(framePushed()));
michael@0 1500 makeFrameDescriptor(dynStack, JitFrame_IonJS);
michael@0 1501 Push(dynStack); // descriptor
michael@0 1502
michael@0 1503 addPendingJump(m_buffer.nextOffset(), ImmPtr(target->raw()), Relocation::JITCODE);
michael@0 1504 ma_liPatchable(ScratchRegister, ImmPtr(target->raw()));
michael@0 1505 ma_callIonHalfPush(ScratchRegister);
michael@0 1506 }
michael@0 1507
michael@0 1508 void
michael@0 1509 MacroAssemblerMIPSCompat::callIon(const Register &callee)
michael@0 1510 {
michael@0 1511 MOZ_ASSERT((framePushed() & 3) == 0);
michael@0 1512 if ((framePushed() & 7) == 4) {
michael@0 1513 ma_callIonHalfPush(callee);
michael@0 1514 } else {
michael@0 1515 adjustFrame(sizeof(uint32_t));
michael@0 1516 ma_callIon(callee);
michael@0 1517 }
michael@0 1518 }
michael@0 1519
michael@0 1520 void
michael@0 1521 MacroAssemblerMIPSCompat::reserveStack(uint32_t amount)
michael@0 1522 {
michael@0 1523 if (amount)
michael@0 1524 ma_subu(StackPointer, StackPointer, Imm32(amount));
michael@0 1525 adjustFrame(amount);
michael@0 1526 }
michael@0 1527
michael@0 1528 void
michael@0 1529 MacroAssemblerMIPSCompat::freeStack(uint32_t amount)
michael@0 1530 {
michael@0 1531 MOZ_ASSERT(amount <= framePushed_);
michael@0 1532 if (amount)
michael@0 1533 ma_addu(StackPointer, StackPointer, Imm32(amount));
michael@0 1534 adjustFrame(-amount);
michael@0 1535 }
michael@0 1536
michael@0 1537 void
michael@0 1538 MacroAssemblerMIPSCompat::freeStack(Register amount)
michael@0 1539 {
michael@0 1540 as_addu(StackPointer, StackPointer, amount);
michael@0 1541 }
michael@0 1542
michael@0 1543 void
michael@0 1544 MacroAssembler::PushRegsInMask(RegisterSet set)
michael@0 1545 {
michael@0 1546 int32_t diffF = set.fpus().size() * sizeof(double);
michael@0 1547 int32_t diffG = set.gprs().size() * sizeof(intptr_t);
michael@0 1548
michael@0 1549 reserveStack(diffG);
michael@0 1550 for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
michael@0 1551 diffG -= sizeof(intptr_t);
michael@0 1552 storePtr(*iter, Address(StackPointer, diffG));
michael@0 1553 }
michael@0 1554 MOZ_ASSERT(diffG == 0);
michael@0 1555
michael@0 1556 // Double values have to be aligned. We reserve extra space so that we can
michael@0 1557 // start writing from the first aligned location.
michael@0 1558 // We reserve a whole extra double so that the buffer has even size.
michael@0 1559 ma_and(SecondScratchReg, sp, Imm32(~(StackAlignment - 1)));
michael@0 1560 reserveStack(diffF + sizeof(double));
michael@0 1561
michael@0 1562 for (FloatRegisterForwardIterator iter(set.fpus()); iter.more(); iter++) {
michael@0 1563 // Use assembly s.d because we have alligned the stack.
michael@0 1564 // :TODO: (Bug 972836) Fix this once odd regs can be used as
michael@0 1565 // float32 only. For now we skip saving odd regs for O32 ABI.
michael@0 1566
michael@0 1567 // :TODO: (Bug 985881) Make a switch for N32 ABI.
michael@0 1568 if ((*iter).code() % 2 == 0)
michael@0 1569 as_sd(*iter, SecondScratchReg, -diffF);
michael@0 1570 diffF -= sizeof(double);
michael@0 1571 }
michael@0 1572 MOZ_ASSERT(diffF == 0);
michael@0 1573 }
michael@0 1574
michael@0 1575 void
michael@0 1576 MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore)
michael@0 1577 {
michael@0 1578 int32_t diffG = set.gprs().size() * sizeof(intptr_t);
michael@0 1579 int32_t diffF = set.fpus().size() * sizeof(double);
michael@0 1580 const int32_t reservedG = diffG;
michael@0 1581 const int32_t reservedF = diffF;
michael@0 1582
michael@0 1583 // Read the buffer form the first aligned location.
michael@0 1584 ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double)));
michael@0 1585 ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(StackAlignment - 1)));
michael@0 1586
michael@0 1587 for (FloatRegisterForwardIterator iter(set.fpus()); iter.more(); iter++) {
michael@0 1588 // :TODO: (Bug 972836) Fix this once odd regs can be used as
michael@0 1589 // float32 only. For now we skip loading odd regs for O32 ABI.
michael@0 1590
michael@0 1591 // :TODO: (Bug 985881) Make a switch for N32 ABI.
michael@0 1592 if (!ignore.has(*iter) && ((*iter).code() % 2 == 0))
michael@0 1593 // Use assembly l.d because we have alligned the stack.
michael@0 1594 as_ld(*iter, SecondScratchReg, -diffF);
michael@0 1595 diffF -= sizeof(double);
michael@0 1596 }
michael@0 1597 freeStack(reservedF + sizeof(double));
michael@0 1598 MOZ_ASSERT(diffF == 0);
michael@0 1599
michael@0 1600 for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
michael@0 1601 diffG -= sizeof(intptr_t);
michael@0 1602 if (!ignore.has(*iter))
michael@0 1603 loadPtr(Address(StackPointer, diffG), *iter);
michael@0 1604 }
michael@0 1605 freeStack(reservedG);
michael@0 1606 MOZ_ASSERT(diffG == 0);
michael@0 1607 }
michael@0 1608
michael@0 1609 void
michael@0 1610 MacroAssemblerMIPSCompat::add32(Register src, Register dest)
michael@0 1611 {
michael@0 1612 as_addu(dest, dest, src);
michael@0 1613 }
michael@0 1614
michael@0 1615 void
michael@0 1616 MacroAssemblerMIPSCompat::add32(Imm32 imm, Register dest)
michael@0 1617 {
michael@0 1618 ma_addu(dest, dest, imm);
michael@0 1619 }
michael@0 1620
michael@0 1621 void
michael@0 1622
michael@0 1623 MacroAssemblerMIPSCompat::add32(Imm32 imm, const Address &dest)
michael@0 1624 {
michael@0 1625 load32(dest, SecondScratchReg);
michael@0 1626 ma_addu(SecondScratchReg, imm);
michael@0 1627 store32(SecondScratchReg, dest);
michael@0 1628 }
michael@0 1629
michael@0 1630 void
michael@0 1631 MacroAssemblerMIPSCompat::sub32(Imm32 imm, Register dest)
michael@0 1632 {
michael@0 1633 ma_subu(dest, dest, imm);
michael@0 1634 }
michael@0 1635
michael@0 1636 void
michael@0 1637 MacroAssemblerMIPSCompat::sub32(Register src, Register dest)
michael@0 1638 {
michael@0 1639 ma_subu(dest, dest, src);
michael@0 1640 }
michael@0 1641
michael@0 1642 void
michael@0 1643 MacroAssemblerMIPSCompat::addPtr(Register src, Register dest)
michael@0 1644 {
michael@0 1645 ma_addu(dest, src);
michael@0 1646 }
michael@0 1647
michael@0 1648 void
michael@0 1649 MacroAssemblerMIPSCompat::addPtr(const Address &src, Register dest)
michael@0 1650 {
michael@0 1651 loadPtr(src, ScratchRegister);
michael@0 1652 ma_addu(dest, ScratchRegister);
michael@0 1653 }
michael@0 1654
michael@0 1655 void
michael@0 1656 MacroAssemblerMIPSCompat::subPtr(Register src, Register dest)
michael@0 1657 {
michael@0 1658 ma_subu(dest, dest, src);
michael@0 1659 }
michael@0 1660
michael@0 1661 void
michael@0 1662 MacroAssemblerMIPSCompat::not32(Register reg)
michael@0 1663 {
michael@0 1664 ma_not(reg, reg);
michael@0 1665 }
michael@0 1666
michael@0 1667 // Logical operations
michael@0 1668 void
michael@0 1669 MacroAssemblerMIPSCompat::and32(Imm32 imm, Register dest)
michael@0 1670 {
michael@0 1671 ma_and(dest, imm);
michael@0 1672 }
michael@0 1673
michael@0 1674 void
michael@0 1675 MacroAssemblerMIPSCompat::and32(Imm32 imm, const Address &dest)
michael@0 1676 {
michael@0 1677 load32(dest, SecondScratchReg);
michael@0 1678 ma_and(SecondScratchReg, imm);
michael@0 1679 store32(SecondScratchReg, dest);
michael@0 1680 }
michael@0 1681
michael@0 1682 void
michael@0 1683 MacroAssemblerMIPSCompat::or32(Imm32 imm, const Address &dest)
michael@0 1684 {
michael@0 1685 load32(dest, SecondScratchReg);
michael@0 1686 ma_or(SecondScratchReg, imm);
michael@0 1687 store32(SecondScratchReg, dest);
michael@0 1688 }
michael@0 1689
michael@0 1690 void
michael@0 1691 MacroAssemblerMIPSCompat::xor32(Imm32 imm, Register dest)
michael@0 1692 {
michael@0 1693 ma_xor(dest, imm);
michael@0 1694 }
michael@0 1695
michael@0 1696 void
michael@0 1697 MacroAssemblerMIPSCompat::xorPtr(Imm32 imm, Register dest)
michael@0 1698 {
michael@0 1699 ma_xor(dest, imm);
michael@0 1700 }
michael@0 1701
michael@0 1702 void
michael@0 1703 MacroAssemblerMIPSCompat::xorPtr(Register src, Register dest)
michael@0 1704 {
michael@0 1705 ma_xor(dest, src);
michael@0 1706 }
michael@0 1707
michael@0 1708 void
michael@0 1709 MacroAssemblerMIPSCompat::orPtr(Imm32 imm, Register dest)
michael@0 1710 {
michael@0 1711 ma_or(dest, imm);
michael@0 1712 }
michael@0 1713
michael@0 1714 void
michael@0 1715 MacroAssemblerMIPSCompat::orPtr(Register src, Register dest)
michael@0 1716 {
michael@0 1717 ma_or(dest, src);
michael@0 1718 }
michael@0 1719
michael@0 1720 void
michael@0 1721 MacroAssemblerMIPSCompat::andPtr(Imm32 imm, Register dest)
michael@0 1722 {
michael@0 1723 ma_and(dest, imm);
michael@0 1724 }
michael@0 1725
michael@0 1726 void
michael@0 1727 MacroAssemblerMIPSCompat::andPtr(Register src, Register dest)
michael@0 1728 {
michael@0 1729 ma_and(dest, src);
michael@0 1730 }
michael@0 1731
michael@0 1732 void
michael@0 1733 MacroAssemblerMIPSCompat::move32(const Imm32 &imm, const Register &dest)
michael@0 1734 {
michael@0 1735 ma_li(dest, imm);
michael@0 1736 }
michael@0 1737
michael@0 1738 void
michael@0 1739 MacroAssemblerMIPSCompat::move32(const Register &src, const Register &dest)
michael@0 1740 {
michael@0 1741 ma_move(dest, src);
michael@0 1742 }
michael@0 1743
michael@0 1744 void
michael@0 1745 MacroAssemblerMIPSCompat::movePtr(const Register &src, const Register &dest)
michael@0 1746 {
michael@0 1747 ma_move(dest, src);
michael@0 1748 }
michael@0 1749 void
michael@0 1750 MacroAssemblerMIPSCompat::movePtr(const ImmWord &imm, const Register &dest)
michael@0 1751 {
michael@0 1752 ma_li(dest, Imm32(imm.value));
michael@0 1753 }
michael@0 1754
michael@0 1755 void
michael@0 1756 MacroAssemblerMIPSCompat::movePtr(const ImmGCPtr &imm, const Register &dest)
michael@0 1757 {
michael@0 1758 ma_li(dest, imm);
michael@0 1759 }
michael@0 1760 void
michael@0 1761 MacroAssemblerMIPSCompat::movePtr(const ImmPtr &imm, const Register &dest)
michael@0 1762 {
michael@0 1763 movePtr(ImmWord(uintptr_t(imm.value)), dest);
michael@0 1764 }
michael@0 1765 void
michael@0 1766 MacroAssemblerMIPSCompat::movePtr(const AsmJSImmPtr &imm, const Register &dest)
michael@0 1767 {
michael@0 1768 MOZ_ASSUME_UNREACHABLE("NYI");
michael@0 1769 }
michael@0 1770
michael@0 1771 void
michael@0 1772 MacroAssemblerMIPSCompat::load8ZeroExtend(const Address &address, const Register &dest)
michael@0 1773 {
michael@0 1774 ma_load(dest, address, SizeByte, ZeroExtend);
michael@0 1775 }
michael@0 1776
michael@0 1777 void
michael@0 1778 MacroAssemblerMIPSCompat::load8ZeroExtend(const BaseIndex &src, const Register &dest)
michael@0 1779 {
michael@0 1780 ma_load(dest, src, SizeByte, ZeroExtend);
michael@0 1781 }
michael@0 1782
michael@0 1783 void
michael@0 1784 MacroAssemblerMIPSCompat::load8SignExtend(const Address &address, const Register &dest)
michael@0 1785 {
michael@0 1786 ma_load(dest, address, SizeByte, SignExtend);
michael@0 1787 }
michael@0 1788
michael@0 1789 void
michael@0 1790 MacroAssemblerMIPSCompat::load8SignExtend(const BaseIndex &src, const Register &dest)
michael@0 1791 {
michael@0 1792 ma_load(dest, src, SizeByte, SignExtend);
michael@0 1793 }
michael@0 1794
michael@0 1795 void
michael@0 1796 MacroAssemblerMIPSCompat::load16ZeroExtend(const Address &address, const Register &dest)
michael@0 1797 {
michael@0 1798 ma_load(dest, address, SizeHalfWord, ZeroExtend);
michael@0 1799 }
michael@0 1800
michael@0 1801 void
michael@0 1802 MacroAssemblerMIPSCompat::load16ZeroExtend(const BaseIndex &src, const Register &dest)
michael@0 1803 {
michael@0 1804 ma_load(dest, src, SizeHalfWord, ZeroExtend);
michael@0 1805 }
michael@0 1806
michael@0 1807 void
michael@0 1808 MacroAssemblerMIPSCompat::load16SignExtend(const Address &address, const Register &dest)
michael@0 1809 {
michael@0 1810 ma_load(dest, address, SizeHalfWord, SignExtend);
michael@0 1811 }
michael@0 1812
michael@0 1813 void
michael@0 1814 MacroAssemblerMIPSCompat::load16SignExtend(const BaseIndex &src, const Register &dest)
michael@0 1815 {
michael@0 1816 ma_load(dest, src, SizeHalfWord, SignExtend);
michael@0 1817 }
michael@0 1818
michael@0 1819 void
michael@0 1820 MacroAssemblerMIPSCompat::load32(const Address &address, const Register &dest)
michael@0 1821 {
michael@0 1822 ma_lw(dest, address);
michael@0 1823 }
michael@0 1824
michael@0 1825 void
michael@0 1826 MacroAssemblerMIPSCompat::load32(const BaseIndex &address, const Register &dest)
michael@0 1827 {
michael@0 1828 ma_load(dest, address, SizeWord);
michael@0 1829 }
michael@0 1830
michael@0 1831 void
michael@0 1832 MacroAssemblerMIPSCompat::load32(const AbsoluteAddress &address, const Register &dest)
michael@0 1833 {
michael@0 1834 ma_li(ScratchRegister, Imm32((uint32_t)address.addr));
michael@0 1835 as_lw(dest, ScratchRegister, 0);
michael@0 1836 }
michael@0 1837
michael@0 1838 void
michael@0 1839 MacroAssemblerMIPSCompat::loadPtr(const Address &address, const Register &dest)
michael@0 1840 {
michael@0 1841 ma_lw(dest, address);
michael@0 1842 }
michael@0 1843
michael@0 1844 void
michael@0 1845 MacroAssemblerMIPSCompat::loadPtr(const BaseIndex &src, const Register &dest)
michael@0 1846 {
michael@0 1847 load32(src, dest);
michael@0 1848 }
michael@0 1849
michael@0 1850 void
michael@0 1851 MacroAssemblerMIPSCompat::loadPtr(const AbsoluteAddress &address, const Register &dest)
michael@0 1852 {
michael@0 1853 ma_li(ScratchRegister, Imm32((uint32_t)address.addr));
michael@0 1854 as_lw(dest, ScratchRegister, 0);
michael@0 1855 }
michael@0 1856 void
michael@0 1857 MacroAssemblerMIPSCompat::loadPtr(const AsmJSAbsoluteAddress &address, const Register &dest)
michael@0 1858 {
michael@0 1859 movePtr(AsmJSImmPtr(address.kind()), ScratchRegister);
michael@0 1860 loadPtr(Address(ScratchRegister, 0x0), dest);
michael@0 1861 }
michael@0 1862
michael@0 1863 void
michael@0 1864 MacroAssemblerMIPSCompat::loadPrivate(const Address &address, const Register &dest)
michael@0 1865 {
michael@0 1866 ma_lw(dest, Address(address.base, address.offset + PAYLOAD_OFFSET));
michael@0 1867 }
michael@0 1868
michael@0 1869 void
michael@0 1870 MacroAssemblerMIPSCompat::loadDouble(const Address &address, const FloatRegister &dest)
michael@0 1871 {
michael@0 1872 ma_ld(dest, address);
michael@0 1873 }
michael@0 1874
michael@0 1875 void
michael@0 1876 MacroAssemblerMIPSCompat::loadDouble(const BaseIndex &src, const FloatRegister &dest)
michael@0 1877 {
michael@0 1878 computeScaledAddress(src, SecondScratchReg);
michael@0 1879 ma_ld(dest, Address(SecondScratchReg, src.offset));
michael@0 1880 }
michael@0 1881
michael@0 1882 void
michael@0 1883 MacroAssemblerMIPSCompat::loadFloatAsDouble(const Address &address, const FloatRegister &dest)
michael@0 1884 {
michael@0 1885 ma_ls(dest, address);
michael@0 1886 as_cvtds(dest, dest);
michael@0 1887 }
michael@0 1888
michael@0 1889 void
michael@0 1890 MacroAssemblerMIPSCompat::loadFloatAsDouble(const BaseIndex &src, const FloatRegister &dest)
michael@0 1891 {
michael@0 1892 loadFloat32(src, dest);
michael@0 1893 as_cvtds(dest, dest);
michael@0 1894 }
michael@0 1895
michael@0 1896 void
michael@0 1897 MacroAssemblerMIPSCompat::loadFloat32(const Address &address, const FloatRegister &dest)
michael@0 1898 {
michael@0 1899 ma_ls(dest, address);
michael@0 1900 }
michael@0 1901
michael@0 1902 void
michael@0 1903 MacroAssemblerMIPSCompat::loadFloat32(const BaseIndex &src, const FloatRegister &dest)
michael@0 1904 {
michael@0 1905 computeScaledAddress(src, SecondScratchReg);
michael@0 1906 ma_ls(dest, Address(SecondScratchReg, src.offset));
michael@0 1907 }
michael@0 1908
michael@0 1909 void
michael@0 1910 MacroAssemblerMIPSCompat::store8(const Imm32 &imm, const Address &address)
michael@0 1911 {
michael@0 1912 ma_li(SecondScratchReg, imm);
michael@0 1913 ma_store(SecondScratchReg, address, SizeByte);
michael@0 1914 }
michael@0 1915
michael@0 1916 void
michael@0 1917 MacroAssemblerMIPSCompat::store8(const Register &src, const Address &address)
michael@0 1918 {
michael@0 1919 ma_store(src, address, SizeByte);
michael@0 1920 }
michael@0 1921
michael@0 1922 void
michael@0 1923 MacroAssemblerMIPSCompat::store8(const Imm32 &imm, const BaseIndex &dest)
michael@0 1924 {
michael@0 1925 ma_store(imm, dest, SizeByte);
michael@0 1926 }
michael@0 1927
michael@0 1928 void
michael@0 1929 MacroAssemblerMIPSCompat::store8(const Register &src, const BaseIndex &dest)
michael@0 1930 {
michael@0 1931 ma_store(src, dest, SizeByte);
michael@0 1932 }
michael@0 1933
michael@0 1934 void
michael@0 1935 MacroAssemblerMIPSCompat::store16(const Imm32 &imm, const Address &address)
michael@0 1936 {
michael@0 1937 ma_li(SecondScratchReg, imm);
michael@0 1938 ma_store(SecondScratchReg, address, SizeHalfWord);
michael@0 1939 }
michael@0 1940
michael@0 1941 void
michael@0 1942 MacroAssemblerMIPSCompat::store16(const Register &src, const Address &address)
michael@0 1943 {
michael@0 1944 ma_store(src, address, SizeHalfWord);
michael@0 1945 }
michael@0 1946
michael@0 1947 void
michael@0 1948 MacroAssemblerMIPSCompat::store16(const Imm32 &imm, const BaseIndex &dest)
michael@0 1949 {
michael@0 1950 ma_store(imm, dest, SizeHalfWord);
michael@0 1951 }
michael@0 1952
michael@0 1953 void
michael@0 1954 MacroAssemblerMIPSCompat::store16(const Register &src, const BaseIndex &address)
michael@0 1955 {
michael@0 1956 ma_store(src, address, SizeHalfWord);
michael@0 1957 }
michael@0 1958
michael@0 1959 void
michael@0 1960 MacroAssemblerMIPSCompat::store32(const Register &src, const AbsoluteAddress &address)
michael@0 1961 {
michael@0 1962 storePtr(src, address);
michael@0 1963 }
michael@0 1964
michael@0 1965 void
michael@0 1966 MacroAssemblerMIPSCompat::store32(const Register &src, const Address &address)
michael@0 1967 {
michael@0 1968 storePtr(src, address);
michael@0 1969 }
michael@0 1970
michael@0 1971 void
michael@0 1972 MacroAssemblerMIPSCompat::store32(const Imm32 &src, const Address &address)
michael@0 1973 {
michael@0 1974 move32(src, ScratchRegister);
michael@0 1975 storePtr(ScratchRegister, address);
michael@0 1976 }
michael@0 1977
michael@0 1978 void
michael@0 1979 MacroAssemblerMIPSCompat::store32(const Imm32 &imm, const BaseIndex &dest)
michael@0 1980 {
michael@0 1981 ma_store(imm, dest, SizeWord);
michael@0 1982 }
michael@0 1983
michael@0 1984 void
michael@0 1985 MacroAssemblerMIPSCompat::store32(const Register &src, const BaseIndex &dest)
michael@0 1986 {
michael@0 1987 ma_store(src, dest, SizeWord);
michael@0 1988 }
michael@0 1989
michael@0 1990 void
michael@0 1991 MacroAssemblerMIPSCompat::storePtr(ImmWord imm, const Address &address)
michael@0 1992 {
michael@0 1993 ma_li(ScratchRegister, Imm32(imm.value));
michael@0 1994 ma_sw(ScratchRegister, address);
michael@0 1995 }
michael@0 1996
michael@0 1997 void
michael@0 1998 MacroAssemblerMIPSCompat::storePtr(ImmPtr imm, const Address &address)
michael@0 1999 {
michael@0 2000 storePtr(ImmWord(uintptr_t(imm.value)), address);
michael@0 2001 }
michael@0 2002
michael@0 2003 void
michael@0 2004 MacroAssemblerMIPSCompat::storePtr(ImmGCPtr imm, const Address &address)
michael@0 2005 {
michael@0 2006 ma_li(ScratchRegister, imm);
michael@0 2007 ma_sw(ScratchRegister, address);
michael@0 2008 }
michael@0 2009
michael@0 2010 void
michael@0 2011 MacroAssemblerMIPSCompat::storePtr(Register src, const Address &address)
michael@0 2012 {
michael@0 2013 ma_sw(src, address);
michael@0 2014 }
michael@0 2015
michael@0 2016 void
michael@0 2017 MacroAssemblerMIPSCompat::storePtr(const Register &src, const AbsoluteAddress &dest)
michael@0 2018 {
michael@0 2019 ma_li(ScratchRegister, Imm32((uint32_t)dest.addr));
michael@0 2020 as_sw(src, ScratchRegister, 0);
michael@0 2021 }
michael@0 2022
michael@0 2023 void
michael@0 2024 MacroAssemblerMIPSCompat::subPtr(Imm32 imm, const Register dest)
michael@0 2025 {
michael@0 2026 ma_subu(dest, dest, imm);
michael@0 2027 }
michael@0 2028
michael@0 2029 void
michael@0 2030 MacroAssemblerMIPSCompat::addPtr(Imm32 imm, const Register dest)
michael@0 2031 {
michael@0 2032 ma_addu(dest, imm);
michael@0 2033 }
michael@0 2034
michael@0 2035 void
michael@0 2036 MacroAssemblerMIPSCompat::addPtr(Imm32 imm, const Address &dest)
michael@0 2037 {
michael@0 2038 loadPtr(dest, ScratchRegister);
michael@0 2039 addPtr(imm, ScratchRegister);
michael@0 2040 storePtr(ScratchRegister, dest);
michael@0 2041 }
michael@0 2042
michael@0 2043 void
michael@0 2044 MacroAssemblerMIPSCompat::branchDouble(DoubleCondition cond, const FloatRegister &lhs,
michael@0 2045 const FloatRegister &rhs, Label *label)
michael@0 2046 {
michael@0 2047 ma_bc1d(lhs, rhs, label, cond);
michael@0 2048 }
michael@0 2049
michael@0 2050 void
michael@0 2051 MacroAssemblerMIPSCompat::branchFloat(DoubleCondition cond, const FloatRegister &lhs,
michael@0 2052 const FloatRegister &rhs, Label *label)
michael@0 2053 {
michael@0 2054 ma_bc1s(lhs, rhs, label, cond);
michael@0 2055 }
michael@0 2056
michael@0 2057 // higher level tag testing code
michael@0 2058 Operand
michael@0 2059 ToPayload(Operand base)
michael@0 2060 {
michael@0 2061 return Operand(Register::FromCode(base.base()), base.disp() + PAYLOAD_OFFSET);
michael@0 2062 }
michael@0 2063
michael@0 2064 Operand
michael@0 2065 ToType(Operand base)
michael@0 2066 {
michael@0 2067 return Operand(Register::FromCode(base.base()), base.disp() + TAG_OFFSET);
michael@0 2068 }
michael@0 2069
michael@0 2070 void
michael@0 2071 MacroAssemblerMIPSCompat::branchTestGCThing(Condition cond, const Address &address, Label *label)
michael@0 2072 {
michael@0 2073 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2074 extractTag(address, SecondScratchReg);
michael@0 2075 ma_b(SecondScratchReg, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET), label,
michael@0 2076 (cond == Equal) ? AboveOrEqual : Below);
michael@0 2077 }
michael@0 2078 void
michael@0 2079 MacroAssemblerMIPSCompat::branchTestGCThing(Condition cond, const BaseIndex &src, Label *label)
michael@0 2080 {
michael@0 2081 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2082 extractTag(src, SecondScratchReg);
michael@0 2083 ma_b(SecondScratchReg, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET), label,
michael@0 2084 (cond == Equal) ? AboveOrEqual : Below);
michael@0 2085 }
michael@0 2086
michael@0 2087 void
michael@0 2088 MacroAssemblerMIPSCompat::branchTestPrimitive(Condition cond, const ValueOperand &value,
michael@0 2089 Label *label)
michael@0 2090 {
michael@0 2091 branchTestPrimitive(cond, value.typeReg(), label);
michael@0 2092 }
michael@0 2093 void
michael@0 2094 MacroAssemblerMIPSCompat::branchTestPrimitive(Condition cond, const Register &tag, Label *label)
michael@0 2095 {
michael@0 2096 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2097 ma_b(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET), label,
michael@0 2098 (cond == Equal) ? Below : AboveOrEqual);
michael@0 2099 }
michael@0 2100
michael@0 2101 void
michael@0 2102 MacroAssemblerMIPSCompat::branchTestInt32(Condition cond, const ValueOperand &value, Label *label)
michael@0 2103 {
michael@0 2104 MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
michael@0 2105 ma_b(value.typeReg(), ImmType(JSVAL_TYPE_INT32), label, cond);
michael@0 2106 }
michael@0 2107
michael@0 2108 void
michael@0 2109 MacroAssemblerMIPSCompat::branchTestInt32(Condition cond, const Register &tag, Label *label)
michael@0 2110 {
michael@0 2111 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2112 ma_b(tag, ImmTag(JSVAL_TAG_INT32), label, cond);
michael@0 2113 }
michael@0 2114
michael@0 2115 void
michael@0 2116 MacroAssemblerMIPSCompat::branchTestInt32(Condition cond, const Address &address, Label *label)
michael@0 2117 {
michael@0 2118 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2119 extractTag(address, SecondScratchReg);
michael@0 2120 ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_INT32), label, cond);
michael@0 2121 }
michael@0 2122
michael@0 2123 void
michael@0 2124 MacroAssemblerMIPSCompat::branchTestInt32(Condition cond, const BaseIndex &src, Label *label)
michael@0 2125 {
michael@0 2126 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2127 extractTag(src, SecondScratchReg);
michael@0 2128 ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_INT32), label, cond);
michael@0 2129 }
michael@0 2130
michael@0 2131 void
michael@0 2132 MacroAssemblerMIPSCompat:: branchTestBoolean(Condition cond, const ValueOperand &value,
michael@0 2133 Label *label)
michael@0 2134 {
michael@0 2135 MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
michael@0 2136 ma_b(value.typeReg(), ImmType(JSVAL_TYPE_BOOLEAN), label, cond);
michael@0 2137 }
michael@0 2138
michael@0 2139 void
michael@0 2140 MacroAssemblerMIPSCompat:: branchTestBoolean(Condition cond, const Register &tag, Label *label)
michael@0 2141 {
michael@0 2142 MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
michael@0 2143 ma_b(tag, ImmType(JSVAL_TYPE_BOOLEAN), label, cond);
michael@0 2144 }
michael@0 2145
michael@0 2146 void
michael@0 2147 MacroAssemblerMIPSCompat::branchTestBoolean(Condition cond, const BaseIndex &src, Label *label)
michael@0 2148 {
michael@0 2149 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2150 extractTag(src, SecondScratchReg);
michael@0 2151 ma_b(SecondScratchReg, ImmType(JSVAL_TYPE_BOOLEAN), label, cond);
michael@0 2152 }
michael@0 2153
michael@0 2154 void
michael@0 2155 MacroAssemblerMIPSCompat::branchTestDouble(Condition cond, const ValueOperand &value, Label *label)
michael@0 2156 {
michael@0 2157 MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
michael@0 2158 Assembler::Condition actual = (cond == Equal) ? Below : AboveOrEqual;
michael@0 2159 ma_b(value.typeReg(), ImmTag(JSVAL_TAG_CLEAR), label, actual);
michael@0 2160 }
michael@0 2161
michael@0 2162 void
michael@0 2163 MacroAssemblerMIPSCompat::branchTestDouble(Condition cond, const Register &tag, Label *label)
michael@0 2164 {
michael@0 2165 MOZ_ASSERT(cond == Assembler::Equal || cond == NotEqual);
michael@0 2166 Condition actual = (cond == Equal) ? Below : AboveOrEqual;
michael@0 2167 ma_b(tag, ImmTag(JSVAL_TAG_CLEAR), label, actual);
michael@0 2168 }
michael@0 2169
michael@0 2170 void
michael@0 2171 MacroAssemblerMIPSCompat::branchTestDouble(Condition cond, const Address &address, Label *label)
michael@0 2172 {
michael@0 2173 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2174 extractTag(address, SecondScratchReg);
michael@0 2175 ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_CLEAR), label, cond);
michael@0 2176 }
michael@0 2177
michael@0 2178 void
michael@0 2179 MacroAssemblerMIPSCompat::branchTestDouble(Condition cond, const BaseIndex &src, Label *label)
michael@0 2180 {
michael@0 2181 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2182 Condition actual = (cond == Equal) ? Below : AboveOrEqual;
michael@0 2183 extractTag(src, SecondScratchReg);
michael@0 2184 ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_CLEAR), label, actual);
michael@0 2185 }
michael@0 2186
michael@0 2187 void
michael@0 2188 MacroAssemblerMIPSCompat::branchTestNull(Condition cond, const ValueOperand &value, Label *label)
michael@0 2189 {
michael@0 2190 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2191 ma_b(value.typeReg(), ImmType(JSVAL_TYPE_NULL), label, cond);
michael@0 2192 }
michael@0 2193
michael@0 2194 void
michael@0 2195 MacroAssemblerMIPSCompat::branchTestNull(Condition cond, const Register &tag, Label *label)
michael@0 2196 {
michael@0 2197 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2198 ma_b(tag, ImmTag(JSVAL_TAG_NULL), label, cond);
michael@0 2199 }
michael@0 2200
michael@0 2201 void
michael@0 2202 MacroAssemblerMIPSCompat::branchTestNull(Condition cond, const BaseIndex &src, Label *label)
michael@0 2203 {
michael@0 2204 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2205 extractTag(src, SecondScratchReg);
michael@0 2206 ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_NULL), label, cond);
michael@0 2207 }
michael@0 2208
michael@0 2209
michael@0 2210 void
michael@0 2211 MacroAssemblerMIPSCompat::branchTestObject(Condition cond, const ValueOperand &value, Label *label)
michael@0 2212 {
michael@0 2213 branchTestObject(cond, value.typeReg(), label);
michael@0 2214 }
michael@0 2215
michael@0 2216 void
michael@0 2217 MacroAssemblerMIPSCompat::branchTestObject(Condition cond, const Register &tag, Label *label)
michael@0 2218 {
michael@0 2219 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2220 ma_b(tag, ImmTag(JSVAL_TAG_OBJECT), label, cond);
michael@0 2221 }
michael@0 2222
michael@0 2223 void
michael@0 2224 MacroAssemblerMIPSCompat::branchTestObject(Condition cond, const BaseIndex &src, Label *label)
michael@0 2225 {
michael@0 2226 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2227 extractTag(src, SecondScratchReg);
michael@0 2228 ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_OBJECT), label, cond);
michael@0 2229 }
michael@0 2230
michael@0 2231
michael@0 2232 void
michael@0 2233 MacroAssemblerMIPSCompat::branchTestString(Condition cond, const ValueOperand &value, Label *label)
michael@0 2234 {
michael@0 2235 branchTestString(cond, value.typeReg(), label);
michael@0 2236 }
michael@0 2237
michael@0 2238 void
michael@0 2239 MacroAssemblerMIPSCompat::branchTestString(Condition cond, const Register &tag, Label *label)
michael@0 2240 {
michael@0 2241 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2242 ma_b(tag, ImmTag(JSVAL_TAG_STRING), label, cond);
michael@0 2243 }
michael@0 2244
michael@0 2245 void
michael@0 2246 MacroAssemblerMIPSCompat::branchTestString(Condition cond, const BaseIndex &src, Label *label)
michael@0 2247 {
michael@0 2248 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2249 extractTag(src, SecondScratchReg);
michael@0 2250 ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_STRING), label, cond);
michael@0 2251 }
michael@0 2252
michael@0 2253 void
michael@0 2254 MacroAssemblerMIPSCompat::branchTestUndefined(Condition cond, const ValueOperand &value,
michael@0 2255 Label *label)
michael@0 2256 {
michael@0 2257 MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
michael@0 2258 ma_b(value.typeReg(), ImmType(JSVAL_TYPE_UNDEFINED), label, cond);
michael@0 2259 }
michael@0 2260
michael@0 2261 void
michael@0 2262 MacroAssemblerMIPSCompat::branchTestUndefined(Condition cond, const Register &tag, Label *label)
michael@0 2263 {
michael@0 2264 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2265 ma_b(tag, ImmTag(JSVAL_TAG_UNDEFINED), label, cond);
michael@0 2266 }
michael@0 2267
michael@0 2268 void
michael@0 2269 MacroAssemblerMIPSCompat::branchTestUndefined(Condition cond, const BaseIndex &src, Label *label)
michael@0 2270 {
michael@0 2271 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2272 extractTag(src, SecondScratchReg);
michael@0 2273 ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_UNDEFINED), label, cond);
michael@0 2274 }
michael@0 2275
michael@0 2276 void
michael@0 2277 MacroAssemblerMIPSCompat::branchTestUndefined(Condition cond, const Address &address, Label *label)
michael@0 2278 {
michael@0 2279 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2280 extractTag(address, SecondScratchReg);
michael@0 2281 ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_UNDEFINED), label, cond);
michael@0 2282 }
michael@0 2283
michael@0 2284
michael@0 2285 void
michael@0 2286 MacroAssemblerMIPSCompat::branchTestNumber(Condition cond, const ValueOperand &value, Label *label)
michael@0 2287 {
michael@0 2288 branchTestNumber(cond, value.typeReg(), label);
michael@0 2289 }
michael@0 2290
michael@0 2291 void
michael@0 2292 MacroAssemblerMIPSCompat::branchTestNumber(Condition cond, const Register &tag, Label *label)
michael@0 2293 {
michael@0 2294 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2295 ma_b(tag, ImmTag(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET), label,
michael@0 2296 cond == Equal ? BelowOrEqual : Above);
michael@0 2297 }
michael@0 2298
michael@0 2299 void
michael@0 2300 MacroAssemblerMIPSCompat::branchTestMagic(Condition cond, const ValueOperand &value, Label *label)
michael@0 2301 {
michael@0 2302 branchTestMagic(cond, value.typeReg(), label);
michael@0 2303 }
michael@0 2304
michael@0 2305 void
michael@0 2306 MacroAssemblerMIPSCompat::branchTestMagic(Condition cond, const Register &tag, Label *label)
michael@0 2307 {
michael@0 2308 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2309 ma_b(tag, ImmTag(JSVAL_TAG_MAGIC), label, cond);
michael@0 2310 }
michael@0 2311
michael@0 2312 void
michael@0 2313 MacroAssemblerMIPSCompat::branchTestMagic(Condition cond, const Address &address, Label *label)
michael@0 2314 {
michael@0 2315 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2316 extractTag(address, SecondScratchReg);
michael@0 2317 ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_MAGIC), label, cond);
michael@0 2318 }
michael@0 2319
michael@0 2320 void
michael@0 2321 MacroAssemblerMIPSCompat::branchTestMagic(Condition cond, const BaseIndex &src, Label *label)
michael@0 2322 {
michael@0 2323 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2324 extractTag(src, SecondScratchReg);
michael@0 2325 ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_MAGIC), label, cond);
michael@0 2326 }
michael@0 2327
michael@0 2328 void
michael@0 2329 MacroAssemblerMIPSCompat::branchTestValue(Condition cond, const ValueOperand &value,
michael@0 2330 const Value &v, Label *label)
michael@0 2331 {
michael@0 2332 moveData(v, ScratchRegister);
michael@0 2333
michael@0 2334 if (cond == Equal) {
michael@0 2335 Label done;
michael@0 2336 ma_b(value.payloadReg(), ScratchRegister, &done, NotEqual, ShortJump);
michael@0 2337 {
michael@0 2338 ma_b(value.typeReg(), Imm32(getType(v)), label, Equal);
michael@0 2339 }
michael@0 2340 bind(&done);
michael@0 2341 } else {
michael@0 2342 MOZ_ASSERT(cond == NotEqual);
michael@0 2343 ma_b(value.payloadReg(), ScratchRegister, label, NotEqual);
michael@0 2344
michael@0 2345 ma_b(value.typeReg(), Imm32(getType(v)), label, NotEqual);
michael@0 2346 }
michael@0 2347 }
michael@0 2348
michael@0 2349 void
michael@0 2350 MacroAssemblerMIPSCompat::branchTestValue(Condition cond, const Address &valaddr,
michael@0 2351 const ValueOperand &value, Label *label)
michael@0 2352 {
michael@0 2353 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 2354
michael@0 2355 // Load tag.
michael@0 2356 ma_lw(ScratchRegister, Address(valaddr.base, valaddr.offset + TAG_OFFSET));
michael@0 2357 branchPtr(cond, ScratchRegister, value.typeReg(), label);
michael@0 2358
michael@0 2359 // Load payload
michael@0 2360 ma_lw(ScratchRegister, Address(valaddr.base, valaddr.offset + PAYLOAD_OFFSET));
michael@0 2361 branchPtr(cond, ScratchRegister, value.payloadReg(), label);
michael@0 2362 }
michael@0 2363
michael@0 2364 // unboxing code
michael@0 2365 void
michael@0 2366 MacroAssemblerMIPSCompat::unboxInt32(const ValueOperand &operand, const Register &dest)
michael@0 2367 {
michael@0 2368 ma_move(dest, operand.payloadReg());
michael@0 2369 }
michael@0 2370
michael@0 2371 void
michael@0 2372 MacroAssemblerMIPSCompat::unboxInt32(const Address &src, const Register &dest)
michael@0 2373 {
michael@0 2374 ma_lw(dest, Address(src.base, src.offset + PAYLOAD_OFFSET));
michael@0 2375 }
michael@0 2376
michael@0 2377 void
michael@0 2378 MacroAssemblerMIPSCompat::unboxBoolean(const ValueOperand &operand, const Register &dest)
michael@0 2379 {
michael@0 2380 ma_move(dest, operand.payloadReg());
michael@0 2381 }
michael@0 2382
michael@0 2383 void
michael@0 2384 MacroAssemblerMIPSCompat::unboxBoolean(const Address &src, const Register &dest)
michael@0 2385 {
michael@0 2386 ma_lw(dest, Address(src.base, src.offset + PAYLOAD_OFFSET));
michael@0 2387 }
michael@0 2388
michael@0 2389 void
michael@0 2390 MacroAssemblerMIPSCompat::unboxDouble(const ValueOperand &operand, const FloatRegister &dest)
michael@0 2391 {
michael@0 2392 MOZ_ASSERT(dest != ScratchFloatReg);
michael@0 2393 moveToDoubleLo(operand.payloadReg(), dest);
michael@0 2394 moveToDoubleHi(operand.typeReg(), dest);
michael@0 2395 }
michael@0 2396
michael@0 2397 void
michael@0 2398 MacroAssemblerMIPSCompat::unboxDouble(const Address &src, const FloatRegister &dest)
michael@0 2399 {
michael@0 2400 ma_lw(ScratchRegister, Address(src.base, src.offset + PAYLOAD_OFFSET));
michael@0 2401 moveToDoubleLo(ScratchRegister, dest);
michael@0 2402 ma_lw(ScratchRegister, Address(src.base, src.offset + TAG_OFFSET));
michael@0 2403 moveToDoubleHi(ScratchRegister, dest);
michael@0 2404 }
michael@0 2405
michael@0 2406 void
michael@0 2407 MacroAssemblerMIPSCompat::unboxString(const ValueOperand &operand, const Register &dest)
michael@0 2408 {
michael@0 2409 ma_move(dest, operand.payloadReg());
michael@0 2410 }
michael@0 2411
michael@0 2412 void
michael@0 2413 MacroAssemblerMIPSCompat::unboxString(const Address &src, const Register &dest)
michael@0 2414 {
michael@0 2415 ma_lw(dest, Address(src.base, src.offset + PAYLOAD_OFFSET));
michael@0 2416 }
michael@0 2417
michael@0 2418 void
michael@0 2419 MacroAssemblerMIPSCompat::unboxObject(const ValueOperand &src, const Register &dest)
michael@0 2420 {
michael@0 2421 ma_move(dest, src.payloadReg());
michael@0 2422 }
michael@0 2423
michael@0 2424 void
michael@0 2425 MacroAssemblerMIPSCompat::unboxValue(const ValueOperand &src, AnyRegister dest)
michael@0 2426 {
michael@0 2427 if (dest.isFloat()) {
michael@0 2428 Label notInt32, end;
michael@0 2429 branchTestInt32(Assembler::NotEqual, src, &notInt32);
michael@0 2430 convertInt32ToDouble(src.payloadReg(), dest.fpu());
michael@0 2431 ma_b(&end, ShortJump);
michael@0 2432 bind(&notInt32);
michael@0 2433 unboxDouble(src, dest.fpu());
michael@0 2434 bind(&end);
michael@0 2435 } else if (src.payloadReg() != dest.gpr()) {
michael@0 2436 ma_move(dest.gpr(), src.payloadReg());
michael@0 2437 }
michael@0 2438 }
michael@0 2439
michael@0 2440 void
michael@0 2441 MacroAssemblerMIPSCompat::unboxPrivate(const ValueOperand &src, Register dest)
michael@0 2442 {
michael@0 2443 ma_move(dest, src.payloadReg());
michael@0 2444 }
michael@0 2445
michael@0 2446 void
michael@0 2447 MacroAssemblerMIPSCompat::boxDouble(const FloatRegister &src, const ValueOperand &dest)
michael@0 2448 {
michael@0 2449 moveFromDoubleLo(src, dest.payloadReg());
michael@0 2450 moveFromDoubleHi(src, dest.typeReg());
michael@0 2451 }
michael@0 2452
michael@0 2453 void
michael@0 2454 MacroAssemblerMIPSCompat::boxNonDouble(JSValueType type, const Register &src,
michael@0 2455 const ValueOperand &dest)
michael@0 2456 {
michael@0 2457 if (src != dest.payloadReg())
michael@0 2458 ma_move(dest.payloadReg(), src);
michael@0 2459 ma_li(dest.typeReg(), ImmType(type));
michael@0 2460 }
michael@0 2461
michael@0 2462 void
michael@0 2463 MacroAssemblerMIPSCompat::boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest)
michael@0 2464 {
michael@0 2465 convertBoolToInt32(ScratchRegister, operand.payloadReg());
michael@0 2466 convertInt32ToDouble(ScratchRegister, dest);
michael@0 2467 }
michael@0 2468
michael@0 2469 void
michael@0 2470 MacroAssemblerMIPSCompat::int32ValueToDouble(const ValueOperand &operand,
michael@0 2471 const FloatRegister &dest)
michael@0 2472 {
michael@0 2473 convertInt32ToDouble(operand.payloadReg(), dest);
michael@0 2474 }
michael@0 2475
michael@0 2476 void
michael@0 2477 MacroAssemblerMIPSCompat::boolValueToFloat32(const ValueOperand &operand,
michael@0 2478 const FloatRegister &dest)
michael@0 2479 {
michael@0 2480
michael@0 2481 convertBoolToInt32(ScratchRegister, operand.payloadReg());
michael@0 2482 convertInt32ToFloat32(ScratchRegister, dest);
michael@0 2483 }
michael@0 2484
michael@0 2485 void
michael@0 2486 MacroAssemblerMIPSCompat::int32ValueToFloat32(const ValueOperand &operand,
michael@0 2487 const FloatRegister &dest)
michael@0 2488 {
michael@0 2489 convertInt32ToFloat32(operand.payloadReg(), dest);
michael@0 2490 }
michael@0 2491
michael@0 2492 void
michael@0 2493 MacroAssemblerMIPSCompat::loadConstantFloat32(float f, const FloatRegister &dest)
michael@0 2494 {
michael@0 2495 ma_lis(dest, f);
michael@0 2496 }
michael@0 2497
michael@0 2498 void
michael@0 2499 MacroAssemblerMIPSCompat::loadInt32OrDouble(const Address &src, const FloatRegister &dest)
michael@0 2500 {
michael@0 2501 Label notInt32, end;
michael@0 2502 // If it's an int, convert it to double.
michael@0 2503 ma_lw(SecondScratchReg, Address(src.base, src.offset + TAG_OFFSET));
michael@0 2504 branchTestInt32(Assembler::NotEqual, SecondScratchReg, &notInt32);
michael@0 2505 ma_lw(SecondScratchReg, Address(src.base, src.offset + PAYLOAD_OFFSET));
michael@0 2506 convertInt32ToDouble(SecondScratchReg, dest);
michael@0 2507 ma_b(&end, ShortJump);
michael@0 2508
michael@0 2509 // Not an int, just load as double.
michael@0 2510 bind(&notInt32);
michael@0 2511 ma_ld(dest, src);
michael@0 2512 bind(&end);
michael@0 2513 }
michael@0 2514
michael@0 2515 void
michael@0 2516 MacroAssemblerMIPSCompat::loadInt32OrDouble(Register base, Register index,
michael@0 2517 const FloatRegister &dest, int32_t shift)
michael@0 2518 {
michael@0 2519 Label notInt32, end;
michael@0 2520
michael@0 2521 // If it's an int, convert it to double.
michael@0 2522
michael@0 2523 computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg);
michael@0 2524 // Since we only have one scratch, we need to stomp over it with the tag.
michael@0 2525 load32(Address(SecondScratchReg, TAG_OFFSET), SecondScratchReg);
michael@0 2526 branchTestInt32(Assembler::NotEqual, SecondScratchReg, &notInt32);
michael@0 2527
michael@0 2528 computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg);
michael@0 2529 load32(Address(SecondScratchReg, PAYLOAD_OFFSET), SecondScratchReg);
michael@0 2530 convertInt32ToDouble(SecondScratchReg, dest);
michael@0 2531 ma_b(&end, ShortJump);
michael@0 2532
michael@0 2533 // Not an int, just load as double.
michael@0 2534 bind(&notInt32);
michael@0 2535 // First, recompute the offset that had been stored in the scratch register
michael@0 2536 // since the scratch register was overwritten loading in the type.
michael@0 2537 computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg);
michael@0 2538 loadDouble(Address(SecondScratchReg, 0), dest);
michael@0 2539 bind(&end);
michael@0 2540 }
michael@0 2541
michael@0 2542 void
michael@0 2543 MacroAssemblerMIPSCompat::loadConstantDouble(double dp, const FloatRegister &dest)
michael@0 2544 {
michael@0 2545 ma_lid(dest, dp);
michael@0 2546 }
michael@0 2547
michael@0 2548 void
michael@0 2549 MacroAssemblerMIPSCompat::branchTestInt32Truthy(bool b, const ValueOperand &value, Label *label)
michael@0 2550 {
michael@0 2551 ma_and(ScratchRegister, value.payloadReg(), value.payloadReg());
michael@0 2552 ma_b(ScratchRegister, ScratchRegister, label, b ? NonZero : Zero);
michael@0 2553 }
michael@0 2554
michael@0 2555 void
michael@0 2556 MacroAssemblerMIPSCompat::branchTestStringTruthy(bool b, const ValueOperand &value, Label *label)
michael@0 2557 {
michael@0 2558 Register string = value.payloadReg();
michael@0 2559 size_t mask = (0xFFFFFFFF << JSString::LENGTH_SHIFT);
michael@0 2560 ma_lw(SecondScratchReg, Address(string, JSString::offsetOfLengthAndFlags()));
michael@0 2561
michael@0 2562 // Use SecondScratchReg because ma_and will clobber ScratchRegister
michael@0 2563 ma_and(ScratchRegister, SecondScratchReg, Imm32(mask));
michael@0 2564 ma_b(ScratchRegister, ScratchRegister, label, b ? NonZero : Zero);
michael@0 2565 }
michael@0 2566
michael@0 2567 void
michael@0 2568 MacroAssemblerMIPSCompat::branchTestDoubleTruthy(bool b, const FloatRegister &value, Label *label)
michael@0 2569 {
michael@0 2570 ma_lid(ScratchFloatReg, 0.0);
michael@0 2571 DoubleCondition cond = b ? DoubleNotEqual : DoubleEqualOrUnordered;
michael@0 2572 ma_bc1d(value, ScratchFloatReg, label, cond);
michael@0 2573 }
michael@0 2574
michael@0 2575 void
michael@0 2576 MacroAssemblerMIPSCompat::branchTestBooleanTruthy(bool b, const ValueOperand &operand,
michael@0 2577 Label *label)
michael@0 2578 {
michael@0 2579 ma_b(operand.payloadReg(), operand.payloadReg(), label, b ? NonZero : Zero);
michael@0 2580 }
michael@0 2581
michael@0 2582 Register
michael@0 2583 MacroAssemblerMIPSCompat::extractObject(const Address &address, Register scratch)
michael@0 2584 {
michael@0 2585 ma_lw(scratch, Address(address.base, address.offset + PAYLOAD_OFFSET));
michael@0 2586 return scratch;
michael@0 2587 }
michael@0 2588
michael@0 2589 Register
michael@0 2590 MacroAssemblerMIPSCompat::extractTag(const Address &address, Register scratch)
michael@0 2591 {
michael@0 2592 ma_lw(scratch, Address(address.base, address.offset + TAG_OFFSET));
michael@0 2593 return scratch;
michael@0 2594 }
michael@0 2595
michael@0 2596 Register
michael@0 2597 MacroAssemblerMIPSCompat::extractTag(const BaseIndex &address, Register scratch)
michael@0 2598 {
michael@0 2599 computeScaledAddress(address, scratch);
michael@0 2600 return extractTag(Address(scratch, address.offset), scratch);
michael@0 2601 }
michael@0 2602
michael@0 2603
michael@0 2604 uint32_t
michael@0 2605 MacroAssemblerMIPSCompat::getType(const Value &val)
michael@0 2606 {
michael@0 2607 jsval_layout jv = JSVAL_TO_IMPL(val);
michael@0 2608 return jv.s.tag;
michael@0 2609 }
michael@0 2610
michael@0 2611 void
michael@0 2612 MacroAssemblerMIPSCompat::moveData(const Value &val, Register data)
michael@0 2613 {
michael@0 2614 jsval_layout jv = JSVAL_TO_IMPL(val);
michael@0 2615 if (val.isMarkable())
michael@0 2616 ma_li(data, ImmGCPtr(reinterpret_cast<gc::Cell *>(val.toGCThing())));
michael@0 2617 else
michael@0 2618 ma_li(data, Imm32(jv.s.payload.i32));
michael@0 2619 }
michael@0 2620
michael@0 2621 void
michael@0 2622 MacroAssemblerMIPSCompat::moveValue(const Value &val, Register type, Register data)
michael@0 2623 {
michael@0 2624 MOZ_ASSERT(type != data);
michael@0 2625 ma_li(type, Imm32(getType(val)));
michael@0 2626 moveData(val, data);
michael@0 2627 }
michael@0 2628 void
michael@0 2629 MacroAssemblerMIPSCompat::moveValue(const Value &val, const ValueOperand &dest)
michael@0 2630 {
michael@0 2631 moveValue(val, dest.typeReg(), dest.payloadReg());
michael@0 2632 }
michael@0 2633
michael@0 2634 CodeOffsetJump
michael@0 2635 MacroAssemblerMIPSCompat::jumpWithPatch(RepatchLabel *label)
michael@0 2636 {
michael@0 2637 // Only one branch per label.
michael@0 2638 MOZ_ASSERT(!label->used());
michael@0 2639 uint32_t dest = label->bound() ? label->offset() : LabelBase::INVALID_OFFSET;
michael@0 2640
michael@0 2641 BufferOffset bo = nextOffset();
michael@0 2642 label->use(bo.getOffset());
michael@0 2643 addLongJump(bo);
michael@0 2644 ma_liPatchable(ScratchRegister, Imm32(dest));
michael@0 2645 as_jr(ScratchRegister);
michael@0 2646 as_nop();
michael@0 2647 return CodeOffsetJump(bo.getOffset());
michael@0 2648 }
michael@0 2649
michael@0 2650
michael@0 2651 /////////////////////////////////////////////////////////////////
michael@0 2652 // X86/X64-common/ARM/MIPS interface.
michael@0 2653 /////////////////////////////////////////////////////////////////
michael@0 2654 void
michael@0 2655 MacroAssemblerMIPSCompat::storeValue(ValueOperand val, Operand dst)
michael@0 2656 {
michael@0 2657 storeValue(val, Address(Register::FromCode(dst.base()), dst.disp()));
michael@0 2658 }
michael@0 2659
michael@0 2660 void
michael@0 2661 MacroAssemblerMIPSCompat::storeValue(ValueOperand val, const BaseIndex &dest)
michael@0 2662 {
michael@0 2663 computeScaledAddress(dest, SecondScratchReg);
michael@0 2664 storeValue(val, Address(SecondScratchReg, dest.offset));
michael@0 2665 }
michael@0 2666
michael@0 2667 void
michael@0 2668 MacroAssemblerMIPSCompat::storeValue(JSValueType type, Register reg, BaseIndex dest)
michael@0 2669 {
michael@0 2670 computeScaledAddress(dest, ScratchRegister);
michael@0 2671
michael@0 2672 // Make sure that ma_sw doesn't clobber ScratchRegister
michael@0 2673 int32_t offset = dest.offset;
michael@0 2674 if (!Imm16::isInSignedRange(offset)) {
michael@0 2675 ma_li(SecondScratchReg, Imm32(offset));
michael@0 2676 as_addu(ScratchRegister, ScratchRegister, SecondScratchReg);
michael@0 2677 offset = 0;
michael@0 2678 }
michael@0 2679
michael@0 2680 storeValue(type, reg, Address(ScratchRegister, offset));
michael@0 2681 }
michael@0 2682
michael@0 2683 void
michael@0 2684 MacroAssemblerMIPSCompat::storeValue(ValueOperand val, const Address &dest)
michael@0 2685 {
michael@0 2686 ma_sw(val.payloadReg(), Address(dest.base, dest.offset + PAYLOAD_OFFSET));
michael@0 2687 ma_sw(val.typeReg(), Address(dest.base, dest.offset + TAG_OFFSET));
michael@0 2688 }
michael@0 2689
michael@0 2690 void
michael@0 2691 MacroAssemblerMIPSCompat::storeValue(JSValueType type, Register reg, Address dest)
michael@0 2692 {
michael@0 2693 MOZ_ASSERT(dest.base != SecondScratchReg);
michael@0 2694
michael@0 2695 ma_sw(reg, Address(dest.base, dest.offset + PAYLOAD_OFFSET));
michael@0 2696 ma_li(SecondScratchReg, ImmTag(JSVAL_TYPE_TO_TAG(type)));
michael@0 2697 ma_sw(SecondScratchReg, Address(dest.base, dest.offset + TAG_OFFSET));
michael@0 2698 }
michael@0 2699
michael@0 2700 void
michael@0 2701 MacroAssemblerMIPSCompat::storeValue(const Value &val, Address dest)
michael@0 2702 {
michael@0 2703 MOZ_ASSERT(dest.base != SecondScratchReg);
michael@0 2704
michael@0 2705 ma_li(SecondScratchReg, Imm32(getType(val)));
michael@0 2706 ma_sw(SecondScratchReg, Address(dest.base, dest.offset + TAG_OFFSET));
michael@0 2707 moveData(val, SecondScratchReg);
michael@0 2708 ma_sw(SecondScratchReg, Address(dest.base, dest.offset + PAYLOAD_OFFSET));
michael@0 2709 }
michael@0 2710
michael@0 2711 void
michael@0 2712 MacroAssemblerMIPSCompat::storeValue(const Value &val, BaseIndex dest)
michael@0 2713 {
michael@0 2714 computeScaledAddress(dest, ScratchRegister);
michael@0 2715
michael@0 2716 // Make sure that ma_sw doesn't clobber ScratchRegister
michael@0 2717 int32_t offset = dest.offset;
michael@0 2718 if (!Imm16::isInSignedRange(offset)) {
michael@0 2719 ma_li(SecondScratchReg, Imm32(offset));
michael@0 2720 as_addu(ScratchRegister, ScratchRegister, SecondScratchReg);
michael@0 2721 offset = 0;
michael@0 2722 }
michael@0 2723 storeValue(val, Address(ScratchRegister, offset));
michael@0 2724 }
michael@0 2725
michael@0 2726 void
michael@0 2727 MacroAssemblerMIPSCompat::loadValue(const BaseIndex &addr, ValueOperand val)
michael@0 2728 {
michael@0 2729 computeScaledAddress(addr, SecondScratchReg);
michael@0 2730 loadValue(Address(SecondScratchReg, addr.offset), val);
michael@0 2731 }
michael@0 2732
michael@0 2733 void
michael@0 2734 MacroAssemblerMIPSCompat::loadValue(Address src, ValueOperand val)
michael@0 2735 {
michael@0 2736 // Ensure that loading the payload does not erase the pointer to the
michael@0 2737 // Value in memory.
michael@0 2738 if (src.base != val.payloadReg()) {
michael@0 2739 ma_lw(val.payloadReg(), Address(src.base, src.offset + PAYLOAD_OFFSET));
michael@0 2740 ma_lw(val.typeReg(), Address(src.base, src.offset + TAG_OFFSET));
michael@0 2741 } else {
michael@0 2742 ma_lw(val.typeReg(), Address(src.base, src.offset + TAG_OFFSET));
michael@0 2743 ma_lw(val.payloadReg(), Address(src.base, src.offset + PAYLOAD_OFFSET));
michael@0 2744 }
michael@0 2745 }
michael@0 2746
michael@0 2747 void
michael@0 2748 MacroAssemblerMIPSCompat::tagValue(JSValueType type, Register payload, ValueOperand dest)
michael@0 2749 {
michael@0 2750 MOZ_ASSERT(payload != dest.typeReg());
michael@0 2751 ma_li(dest.typeReg(), ImmType(type));
michael@0 2752 if (payload != dest.payloadReg())
michael@0 2753 ma_move(dest.payloadReg(), payload);
michael@0 2754 }
michael@0 2755
michael@0 2756 void
michael@0 2757 MacroAssemblerMIPSCompat::pushValue(ValueOperand val)
michael@0 2758 {
michael@0 2759 // Allocate stack slots for type and payload. One for each.
michael@0 2760 ma_subu(StackPointer, StackPointer, Imm32(sizeof(Value)));
michael@0 2761 // Store type and payload.
michael@0 2762 storeValue(val, Address(StackPointer, 0));
michael@0 2763 }
michael@0 2764
michael@0 2765 void
michael@0 2766 MacroAssemblerMIPSCompat::pushValue(const Address &addr)
michael@0 2767 {
michael@0 2768 // Allocate stack slots for type and payload. One for each.
michael@0 2769 ma_subu(StackPointer, StackPointer, Imm32(sizeof(Value)));
michael@0 2770 // Store type and payload.
michael@0 2771 ma_lw(ScratchRegister, Address(addr.base, addr.offset + TAG_OFFSET));
michael@0 2772 ma_sw(ScratchRegister, Address(StackPointer, TAG_OFFSET));
michael@0 2773 ma_lw(ScratchRegister, Address(addr.base, addr.offset + PAYLOAD_OFFSET));
michael@0 2774 ma_sw(ScratchRegister, Address(StackPointer, PAYLOAD_OFFSET));
michael@0 2775 }
michael@0 2776
michael@0 2777 void
michael@0 2778 MacroAssemblerMIPSCompat::popValue(ValueOperand val)
michael@0 2779 {
michael@0 2780 // Load payload and type.
michael@0 2781 as_lw(val.payloadReg(), StackPointer, PAYLOAD_OFFSET);
michael@0 2782 as_lw(val.typeReg(), StackPointer, TAG_OFFSET);
michael@0 2783 // Free stack.
michael@0 2784 as_addiu(StackPointer, StackPointer, sizeof(Value));
michael@0 2785 }
michael@0 2786
michael@0 2787 void
michael@0 2788 MacroAssemblerMIPSCompat::storePayload(const Value &val, Address dest)
michael@0 2789 {
michael@0 2790 moveData(val, SecondScratchReg);
michael@0 2791 ma_sw(SecondScratchReg, Address(dest.base, dest.offset + PAYLOAD_OFFSET));
michael@0 2792 }
michael@0 2793
michael@0 2794 void
michael@0 2795 MacroAssemblerMIPSCompat::storePayload(Register src, Address dest)
michael@0 2796 {
michael@0 2797 ma_sw(src, Address(dest.base, dest.offset + PAYLOAD_OFFSET));
michael@0 2798 return;
michael@0 2799 }
michael@0 2800
michael@0 2801 void
michael@0 2802 MacroAssemblerMIPSCompat::storePayload(const Value &val, Register base, Register index,
michael@0 2803 int32_t shift)
michael@0 2804 {
michael@0 2805 computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg);
michael@0 2806
michael@0 2807 moveData(val, ScratchRegister);
michael@0 2808
michael@0 2809 as_sw(ScratchRegister, SecondScratchReg, NUNBOX32_PAYLOAD_OFFSET);
michael@0 2810 }
michael@0 2811
michael@0 2812 void
michael@0 2813 MacroAssemblerMIPSCompat::storePayload(Register src, Register base, Register index, int32_t shift)
michael@0 2814 {
michael@0 2815 computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg);
michael@0 2816 as_sw(src, SecondScratchReg, NUNBOX32_PAYLOAD_OFFSET);
michael@0 2817 }
michael@0 2818
michael@0 2819 void
michael@0 2820 MacroAssemblerMIPSCompat::storeTypeTag(ImmTag tag, Address dest)
michael@0 2821 {
michael@0 2822 ma_li(SecondScratchReg, tag);
michael@0 2823 ma_sw(SecondScratchReg, Address(dest.base, dest.offset + TAG_OFFSET));
michael@0 2824 }
michael@0 2825
michael@0 2826 void
michael@0 2827 MacroAssemblerMIPSCompat::storeTypeTag(ImmTag tag, Register base, Register index, int32_t shift)
michael@0 2828 {
michael@0 2829 computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg);
michael@0 2830 ma_li(ScratchRegister, tag);
michael@0 2831 as_sw(ScratchRegister, SecondScratchReg, TAG_OFFSET);
michael@0 2832 }
michael@0 2833
michael@0 2834 void
michael@0 2835 MacroAssemblerMIPSCompat::linkExitFrame()
michael@0 2836 {
michael@0 2837 uint8_t *dest = (uint8_t*)GetIonContext()->runtime->addressOfIonTop();
michael@0 2838 movePtr(ImmPtr(dest), ScratchRegister);
michael@0 2839 ma_sw(StackPointer, Address(ScratchRegister, 0));
michael@0 2840 }
michael@0 2841
michael@0 2842 void
michael@0 2843 MacroAssemblerMIPSCompat::linkParallelExitFrame(const Register &pt)
michael@0 2844 {
michael@0 2845 ma_sw(StackPointer, Address(pt, offsetof(PerThreadData, ionTop)));
michael@0 2846 }
michael@0 2847
michael@0 2848 // This macrosintruction calls the ion code and pushes the return address to
michael@0 2849 // the stack in the case when stack is alligned.
michael@0 2850 void
michael@0 2851 MacroAssemblerMIPS::ma_callIon(const Register r)
michael@0 2852 {
michael@0 2853 // This is a MIPS hack to push return address during jalr delay slot.
michael@0 2854 as_addiu(StackPointer, StackPointer, -2 * sizeof(intptr_t));
michael@0 2855 as_jalr(r);
michael@0 2856 as_sw(ra, StackPointer, 0);
michael@0 2857 }
michael@0 2858
michael@0 2859 // This macrosintruction calls the ion code and pushes the return address to
michael@0 2860 // the stack in the case when stack is not alligned.
michael@0 2861 void
michael@0 2862 MacroAssemblerMIPS::ma_callIonHalfPush(const Register r)
michael@0 2863 {
michael@0 2864 // This is a MIPS hack to push return address during jalr delay slot.
michael@0 2865 as_addiu(StackPointer, StackPointer, -sizeof(intptr_t));
michael@0 2866 as_jalr(r);
michael@0 2867 as_sw(ra, StackPointer, 0);
michael@0 2868 }
michael@0 2869
michael@0 2870 void
michael@0 2871 MacroAssemblerMIPS::ma_call(ImmPtr dest)
michael@0 2872 {
michael@0 2873 ma_liPatchable(CallReg, dest);
michael@0 2874 as_jalr(CallReg);
michael@0 2875 as_nop();
michael@0 2876 }
michael@0 2877
michael@0 2878 void
michael@0 2879 MacroAssemblerMIPS::ma_jump(ImmPtr dest)
michael@0 2880 {
michael@0 2881 ma_liPatchable(ScratchRegister, dest);
michael@0 2882 as_jr(ScratchRegister);
michael@0 2883 as_nop();
michael@0 2884 }
michael@0 2885
michael@0 2886 void
michael@0 2887 MacroAssemblerMIPSCompat::breakpoint()
michael@0 2888 {
michael@0 2889 as_break(0);
michael@0 2890 }
michael@0 2891
michael@0 2892 void
michael@0 2893 MacroAssemblerMIPSCompat::ensureDouble(const ValueOperand &source, FloatRegister dest,
michael@0 2894 Label *failure)
michael@0 2895 {
michael@0 2896 Label isDouble, done;
michael@0 2897 branchTestDouble(Assembler::Equal, source.typeReg(), &isDouble);
michael@0 2898 branchTestInt32(Assembler::NotEqual, source.typeReg(), failure);
michael@0 2899
michael@0 2900 convertInt32ToDouble(source.payloadReg(), dest);
michael@0 2901 jump(&done);
michael@0 2902
michael@0 2903 bind(&isDouble);
michael@0 2904 unboxDouble(source, dest);
michael@0 2905
michael@0 2906 bind(&done);
michael@0 2907 }
michael@0 2908
michael@0 2909 void
michael@0 2910 MacroAssemblerMIPSCompat::setupABICall(uint32_t args)
michael@0 2911 {
michael@0 2912 MOZ_ASSERT(!inCall_);
michael@0 2913 inCall_ = true;
michael@0 2914 args_ = args;
michael@0 2915 passedArgs_ = 0;
michael@0 2916
michael@0 2917 usedArgSlots_ = 0;
michael@0 2918 firstArgType = MoveOp::GENERAL;
michael@0 2919 }
michael@0 2920
michael@0 2921 void
michael@0 2922 MacroAssemblerMIPSCompat::setupAlignedABICall(uint32_t args)
michael@0 2923 {
michael@0 2924 setupABICall(args);
michael@0 2925
michael@0 2926 dynamicAlignment_ = false;
michael@0 2927 }
michael@0 2928
michael@0 2929 void
michael@0 2930 MacroAssemblerMIPSCompat::setupUnalignedABICall(uint32_t args, const Register &scratch)
michael@0 2931 {
michael@0 2932 setupABICall(args);
michael@0 2933 dynamicAlignment_ = true;
michael@0 2934
michael@0 2935 ma_move(scratch, StackPointer);
michael@0 2936
michael@0 2937 // Force sp to be aligned
michael@0 2938 ma_subu(StackPointer, StackPointer, Imm32(sizeof(uint32_t)));
michael@0 2939 ma_and(StackPointer, StackPointer, Imm32(~(StackAlignment - 1)));
michael@0 2940 as_sw(scratch, StackPointer, 0);
michael@0 2941 }
michael@0 2942
michael@0 2943 void
michael@0 2944 MacroAssemblerMIPSCompat::passABIArg(const MoveOperand &from, MoveOp::Type type)
michael@0 2945 {
michael@0 2946 ++passedArgs_;
michael@0 2947 if (!enoughMemory_)
michael@0 2948 return;
michael@0 2949 switch (type) {
michael@0 2950 case MoveOp::FLOAT32:
michael@0 2951 if (!usedArgSlots_) {
michael@0 2952 if (from.floatReg() != f12)
michael@0 2953 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f12), type);
michael@0 2954 firstArgType = MoveOp::FLOAT32;
michael@0 2955 } else if ((usedArgSlots_ == 1 && firstArgType == MoveOp::FLOAT32) ||
michael@0 2956 (usedArgSlots_ == 2 && firstArgType == MoveOp::DOUBLE)) {
michael@0 2957 if (from.floatReg() != f14)
michael@0 2958 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f14), type);
michael@0 2959 } else {
michael@0 2960 Register destReg;
michael@0 2961 if (GetIntArgReg(usedArgSlots_, &destReg)) {
michael@0 2962 if (from.isGeneralReg() && from.reg() == destReg) {
michael@0 2963 // Nothing to do. Value is in the right register already
michael@0 2964 } else {
michael@0 2965 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(destReg), type);
michael@0 2966 }
michael@0 2967 } else {
michael@0 2968 uint32_t disp = GetArgStackDisp(usedArgSlots_);
michael@0 2969 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), type);
michael@0 2970 }
michael@0 2971 }
michael@0 2972 usedArgSlots_++;
michael@0 2973 break;
michael@0 2974 case MoveOp::DOUBLE:
michael@0 2975 if (!usedArgSlots_) {
michael@0 2976 if (from.floatReg() != f12)
michael@0 2977 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f12), type);
michael@0 2978 usedArgSlots_ = 2;
michael@0 2979 firstArgType = MoveOp::DOUBLE;
michael@0 2980 } else if (usedArgSlots_ <= 2) {
michael@0 2981 if ((usedArgSlots_ == 1 && firstArgType == MoveOp::FLOAT32) ||
michael@0 2982 (usedArgSlots_ == 2 && firstArgType == MoveOp::DOUBLE)) {
michael@0 2983 if (from.floatReg() != f14)
michael@0 2984 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f14), type);
michael@0 2985 } else {
michael@0 2986 // Create two moves so that cycles are found. Move emitter
michael@0 2987 // will have special case to handle this.
michael@0 2988 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(a2), type);
michael@0 2989 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(a3), type);
michael@0 2990 }
michael@0 2991 usedArgSlots_ = 4;
michael@0 2992 } else {
michael@0 2993 // Align if necessary
michael@0 2994 usedArgSlots_ += usedArgSlots_ % 2;
michael@0 2995
michael@0 2996 uint32_t disp = GetArgStackDisp(usedArgSlots_);
michael@0 2997 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), type);
michael@0 2998 usedArgSlots_ += 2;
michael@0 2999 }
michael@0 3000 break;
michael@0 3001 case MoveOp::GENERAL:
michael@0 3002 Register destReg;
michael@0 3003 if (GetIntArgReg(usedArgSlots_, &destReg)) {
michael@0 3004 if (from.isGeneralReg() && from.reg() == destReg) {
michael@0 3005 // Nothing to do. Value is in the right register already
michael@0 3006 } else {
michael@0 3007 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(destReg), type);
michael@0 3008 }
michael@0 3009 } else {
michael@0 3010 uint32_t disp = GetArgStackDisp(usedArgSlots_);
michael@0 3011 enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), type);
michael@0 3012 }
michael@0 3013 usedArgSlots_++;
michael@0 3014 break;
michael@0 3015 default:
michael@0 3016 MOZ_ASSUME_UNREACHABLE("Unexpected argument type");
michael@0 3017 }
michael@0 3018 }
michael@0 3019
michael@0 3020 void
michael@0 3021 MacroAssemblerMIPSCompat::passABIArg(const Register &reg)
michael@0 3022 {
michael@0 3023 passABIArg(MoveOperand(reg), MoveOp::GENERAL);
michael@0 3024 }
michael@0 3025
michael@0 3026 void
michael@0 3027 MacroAssemblerMIPSCompat::passABIArg(const FloatRegister &freg, MoveOp::Type type)
michael@0 3028 {
michael@0 3029 passABIArg(MoveOperand(freg), type);
michael@0 3030 }
michael@0 3031
michael@0 3032 void MacroAssemblerMIPSCompat::checkStackAlignment()
michael@0 3033 {
michael@0 3034 #ifdef DEBUG
michael@0 3035 Label aligned;
michael@0 3036 as_andi(ScratchRegister, sp, StackAlignment - 1);
michael@0 3037 ma_b(ScratchRegister, zero, &aligned, Equal, ShortJump);
michael@0 3038 as_break(MAX_BREAK_CODE);
michael@0 3039 bind(&aligned);
michael@0 3040 #endif
michael@0 3041 }
michael@0 3042
michael@0 3043 void
michael@0 3044 MacroAssemblerMIPSCompat::alignPointerUp(Register src, Register dest, uint32_t alignment)
michael@0 3045 {
michael@0 3046 MOZ_ASSERT(alignment > 1);
michael@0 3047 ma_addu(dest, src, Imm32(alignment - 1));
michael@0 3048 ma_and(dest, dest, Imm32(~(alignment - 1)));
michael@0 3049 }
michael@0 3050
michael@0 3051 void
michael@0 3052 MacroAssemblerMIPSCompat::callWithABIPre(uint32_t *stackAdjust)
michael@0 3053 {
michael@0 3054 MOZ_ASSERT(inCall_);
michael@0 3055
michael@0 3056 // Reserve place for $ra.
michael@0 3057 *stackAdjust = sizeof(intptr_t);
michael@0 3058
michael@0 3059 *stackAdjust += usedArgSlots_ > NumIntArgRegs ?
michael@0 3060 usedArgSlots_ * sizeof(intptr_t) :
michael@0 3061 NumIntArgRegs * sizeof(intptr_t);
michael@0 3062
michael@0 3063 if (dynamicAlignment_) {
michael@0 3064 *stackAdjust += ComputeByteAlignment(*stackAdjust, StackAlignment);
michael@0 3065 } else {
michael@0 3066 *stackAdjust += ComputeByteAlignment(framePushed_ + *stackAdjust, StackAlignment);
michael@0 3067 }
michael@0 3068
michael@0 3069 reserveStack(*stackAdjust);
michael@0 3070
michael@0 3071 // Save $ra because call is going to clobber it. Restore it in
michael@0 3072 // callWithABIPost. NOTE: This is needed for calls from BaselineIC.
michael@0 3073 // Maybe we can do this differently.
michael@0 3074 ma_sw(ra, Address(StackPointer, *stackAdjust - sizeof(intptr_t)));
michael@0 3075
michael@0 3076 // Position all arguments.
michael@0 3077 {
michael@0 3078 enoughMemory_ = enoughMemory_ && moveResolver_.resolve();
michael@0 3079 if (!enoughMemory_)
michael@0 3080 return;
michael@0 3081
michael@0 3082 MoveEmitter emitter(*this);
michael@0 3083 emitter.emit(moveResolver_);
michael@0 3084 emitter.finish();
michael@0 3085 }
michael@0 3086
michael@0 3087 checkStackAlignment();
michael@0 3088 }
michael@0 3089
michael@0 3090 void
michael@0 3091 MacroAssemblerMIPSCompat::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
michael@0 3092 {
michael@0 3093 // Restore ra value (as stored in callWithABIPre()).
michael@0 3094 ma_lw(ra, Address(StackPointer, stackAdjust - sizeof(intptr_t)));
michael@0 3095
michael@0 3096 if (dynamicAlignment_) {
michael@0 3097 // Restore sp value from stack (as stored in setupUnalignedABICall()).
michael@0 3098 ma_lw(StackPointer, Address(StackPointer, stackAdjust));
michael@0 3099 // Use adjustFrame instead of freeStack because we already restored sp.
michael@0 3100 adjustFrame(-stackAdjust);
michael@0 3101 } else {
michael@0 3102 freeStack(stackAdjust);
michael@0 3103 }
michael@0 3104
michael@0 3105 MOZ_ASSERT(inCall_);
michael@0 3106 inCall_ = false;
michael@0 3107 }
michael@0 3108
michael@0 3109 void
michael@0 3110 MacroAssemblerMIPSCompat::callWithABI(void *fun, MoveOp::Type result)
michael@0 3111 {
michael@0 3112 uint32_t stackAdjust;
michael@0 3113 callWithABIPre(&stackAdjust);
michael@0 3114 ma_call(ImmPtr(fun));
michael@0 3115 callWithABIPost(stackAdjust, result);
michael@0 3116 }
michael@0 3117
michael@0 3118 void
michael@0 3119 MacroAssemblerMIPSCompat::callWithABI(AsmJSImmPtr imm, MoveOp::Type result)
michael@0 3120 {
michael@0 3121 uint32_t stackAdjust;
michael@0 3122 callWithABIPre(&stackAdjust);
michael@0 3123 call(imm);
michael@0 3124 callWithABIPost(stackAdjust, result);
michael@0 3125 }
michael@0 3126
michael@0 3127 void
michael@0 3128 MacroAssemblerMIPSCompat::callWithABI(const Address &fun, MoveOp::Type result)
michael@0 3129 {
michael@0 3130 // Load the callee in t9, no instruction between the lw and call
michael@0 3131 // should clobber it. Note that we can't use fun.base because it may
michael@0 3132 // be one of the IntArg registers clobbered before the call.
michael@0 3133 ma_lw(t9, Address(fun.base, fun.offset));
michael@0 3134 uint32_t stackAdjust;
michael@0 3135 callWithABIPre(&stackAdjust);
michael@0 3136 call(t9);
michael@0 3137 callWithABIPost(stackAdjust, result);
michael@0 3138
michael@0 3139 }
michael@0 3140
michael@0 3141 void
michael@0 3142 MacroAssemblerMIPSCompat::handleFailureWithHandler(void *handler)
michael@0 3143 {
michael@0 3144 // Reserve space for exception information.
michael@0 3145 int size = (sizeof(ResumeFromException) + StackAlignment) & ~(StackAlignment - 1);
michael@0 3146 ma_subu(StackPointer, StackPointer, Imm32(size));
michael@0 3147 ma_move(a0, StackPointer); // Use a0 since it is a first function argument
michael@0 3148
michael@0 3149 // Ask for an exception handler.
michael@0 3150 setupUnalignedABICall(1, a1);
michael@0 3151 passABIArg(a0);
michael@0 3152 callWithABI(handler);
michael@0 3153
michael@0 3154 JitCode *excTail = GetIonContext()->runtime->jitRuntime()->getExceptionTail();
michael@0 3155 branch(excTail);
michael@0 3156 }
michael@0 3157
michael@0 3158 void
michael@0 3159 MacroAssemblerMIPSCompat::handleFailureWithHandlerTail()
michael@0 3160 {
michael@0 3161 Label entryFrame;
michael@0 3162 Label catch_;
michael@0 3163 Label finally;
michael@0 3164 Label return_;
michael@0 3165 Label bailout;
michael@0 3166
michael@0 3167 // Already clobbered a0, so use it...
michael@0 3168 ma_lw(a0, Address(StackPointer, offsetof(ResumeFromException, kind)));
michael@0 3169 branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_ENTRY_FRAME), &entryFrame);
michael@0 3170 branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_CATCH), &catch_);
michael@0 3171 branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_FINALLY), &finally);
michael@0 3172 branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_FORCED_RETURN), &return_);
michael@0 3173 branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_BAILOUT), &bailout);
michael@0 3174
michael@0 3175 breakpoint(); // Invalid kind.
michael@0 3176
michael@0 3177 // No exception handler. Load the error value, load the new stack pointer
michael@0 3178 // and return from the entry frame.
michael@0 3179 bind(&entryFrame);
michael@0 3180 moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
michael@0 3181 ma_lw(StackPointer, Address(StackPointer, offsetof(ResumeFromException, stackPointer)));
michael@0 3182
michael@0 3183 // We're going to be returning by the ion calling convention
michael@0 3184 ma_pop(ra);
michael@0 3185 as_jr(ra);
michael@0 3186 as_nop();
michael@0 3187
michael@0 3188 // If we found a catch handler, this must be a baseline frame. Restore
michael@0 3189 // state and jump to the catch block.
michael@0 3190 bind(&catch_);
michael@0 3191 ma_lw(a0, Address(StackPointer, offsetof(ResumeFromException, target)));
michael@0 3192 ma_lw(BaselineFrameReg, Address(StackPointer, offsetof(ResumeFromException, framePointer)));
michael@0 3193 ma_lw(StackPointer, Address(StackPointer, offsetof(ResumeFromException, stackPointer)));
michael@0 3194 jump(a0);
michael@0 3195
michael@0 3196 // If we found a finally block, this must be a baseline frame. Push
michael@0 3197 // two values expected by JSOP_RETSUB: BooleanValue(true) and the
michael@0 3198 // exception.
michael@0 3199 bind(&finally);
michael@0 3200 ValueOperand exception = ValueOperand(a1, a2);
michael@0 3201 loadValue(Address(sp, offsetof(ResumeFromException, exception)), exception);
michael@0 3202
michael@0 3203 ma_lw(a0, Address(sp, offsetof(ResumeFromException, target)));
michael@0 3204 ma_lw(BaselineFrameReg, Address(sp, offsetof(ResumeFromException, framePointer)));
michael@0 3205 ma_lw(sp, Address(sp, offsetof(ResumeFromException, stackPointer)));
michael@0 3206
michael@0 3207 pushValue(BooleanValue(true));
michael@0 3208 pushValue(exception);
michael@0 3209 jump(a0);
michael@0 3210
michael@0 3211 // Only used in debug mode. Return BaselineFrame->returnValue() to the
michael@0 3212 // caller.
michael@0 3213 bind(&return_);
michael@0 3214 ma_lw(BaselineFrameReg, Address(StackPointer, offsetof(ResumeFromException, framePointer)));
michael@0 3215 ma_lw(StackPointer, Address(StackPointer, offsetof(ResumeFromException, stackPointer)));
michael@0 3216 loadValue(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfReturnValue()),
michael@0 3217 JSReturnOperand);
michael@0 3218 ma_move(StackPointer, BaselineFrameReg);
michael@0 3219 pop(BaselineFrameReg);
michael@0 3220 ret();
michael@0 3221
michael@0 3222 // If we are bailing out to baseline to handle an exception, jump to
michael@0 3223 // the bailout tail stub.
michael@0 3224 bind(&bailout);
michael@0 3225 ma_lw(a2, Address(sp, offsetof(ResumeFromException, bailoutInfo)));
michael@0 3226 ma_li(ReturnReg, Imm32(BAILOUT_RETURN_OK));
michael@0 3227 ma_lw(a1, Address(sp, offsetof(ResumeFromException, target)));
michael@0 3228 jump(a1);
michael@0 3229 }
michael@0 3230
michael@0 3231 CodeOffsetLabel
michael@0 3232 MacroAssemblerMIPSCompat::toggledJump(Label *label)
michael@0 3233 {
michael@0 3234 CodeOffsetLabel ret(nextOffset().getOffset());
michael@0 3235 ma_b(label);
michael@0 3236 return ret;
michael@0 3237 }
michael@0 3238
michael@0 3239 CodeOffsetLabel
michael@0 3240 MacroAssemblerMIPSCompat::toggledCall(JitCode *target, bool enabled)
michael@0 3241 {
michael@0 3242 BufferOffset bo = nextOffset();
michael@0 3243 CodeOffsetLabel offset(bo.getOffset());
michael@0 3244 addPendingJump(bo, ImmPtr(target->raw()), Relocation::JITCODE);
michael@0 3245 ma_liPatchable(ScratchRegister, ImmPtr(target->raw()));
michael@0 3246 if (enabled) {
michael@0 3247 as_jalr(ScratchRegister);
michael@0 3248 as_nop();
michael@0 3249 } else {
michael@0 3250 as_nop();
michael@0 3251 as_nop();
michael@0 3252 }
michael@0 3253 MOZ_ASSERT(nextOffset().getOffset() - offset.offset() == ToggledCallSize());
michael@0 3254 return offset;
michael@0 3255 }
michael@0 3256
michael@0 3257 void
michael@0 3258 MacroAssemblerMIPSCompat::branchPtrInNurseryRange(Register ptr, Register temp, Label *label)
michael@0 3259 {
michael@0 3260 JS_ASSERT(temp != InvalidReg);
michael@0 3261 const Nursery &nursery = GetIonContext()->runtime->gcNursery();
michael@0 3262
michael@0 3263 // ptr and temp may be the same register, in which case we mustn't trash it
michael@0 3264 // before we use its contents.
michael@0 3265 if (ptr == temp) {
michael@0 3266 addPtr(ImmWord(-ptrdiff_t(nursery.start())), ptr);
michael@0 3267 branchPtr(Assembler::Below, ptr, Imm32(Nursery::NurserySize), label);
michael@0 3268 } else {
michael@0 3269 movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp);
michael@0 3270 addPtr(ptr, temp);
michael@0 3271 branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label);
michael@0 3272 }
michael@0 3273 }

mercurial