Wed, 31 Dec 2014 06:09:35 +0100
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), ¬Zero, 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(¬Zero); |
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), ¬Zero, 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(¬Zero); |
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, ¬Int32); |
michael@0 | 2430 | convertInt32ToDouble(src.payloadReg(), dest.fpu()); |
michael@0 | 2431 | ma_b(&end, ShortJump); |
michael@0 | 2432 | bind(¬Int32); |
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, ¬Int32); |
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(¬Int32); |
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, ¬Int32); |
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(¬Int32); |
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 ®) |
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 | } |