js/src/jit/mips/MacroAssembler-mips.h

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

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

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

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef jit_mips_MacroAssembler_mips_h
michael@0 8 #define jit_mips_MacroAssembler_mips_h
michael@0 9
michael@0 10 #include "jsopcode.h"
michael@0 11
michael@0 12 #include "jit/IonCaches.h"
michael@0 13 #include "jit/IonFrames.h"
michael@0 14 #include "jit/mips/Assembler-mips.h"
michael@0 15 #include "jit/MoveResolver.h"
michael@0 16
michael@0 17 namespace js {
michael@0 18 namespace jit {
michael@0 19
michael@0 20 enum LoadStoreSize
michael@0 21 {
michael@0 22 SizeByte = 8,
michael@0 23 SizeHalfWord = 16,
michael@0 24 SizeWord = 32,
michael@0 25 SizeDouble = 64
michael@0 26 };
michael@0 27
michael@0 28 enum LoadStoreExtension
michael@0 29 {
michael@0 30 ZeroExtend = 0,
michael@0 31 SignExtend = 1
michael@0 32 };
michael@0 33
michael@0 34 enum JumpKind
michael@0 35 {
michael@0 36 LongJump = 0,
michael@0 37 ShortJump = 1
michael@0 38 };
michael@0 39
michael@0 40 struct ImmTag : public Imm32
michael@0 41 {
michael@0 42 ImmTag(JSValueTag mask)
michael@0 43 : Imm32(int32_t(mask))
michael@0 44 { }
michael@0 45 };
michael@0 46
michael@0 47 struct ImmType : public ImmTag
michael@0 48 {
michael@0 49 ImmType(JSValueType type)
michael@0 50 : ImmTag(JSVAL_TYPE_TO_TAG(type))
michael@0 51 { }
michael@0 52 };
michael@0 53
michael@0 54 static const ValueOperand JSReturnOperand = ValueOperand(JSReturnReg_Type, JSReturnReg_Data);
michael@0 55 static const ValueOperand softfpReturnOperand = ValueOperand(v1, v0);
michael@0 56
michael@0 57 static Register CallReg = t9;
michael@0 58 static const int defaultShift = 3;
michael@0 59 static_assert(1 << defaultShift == sizeof(jsval), "The defaultShift is wrong");
michael@0 60
michael@0 61 class MacroAssemblerMIPS : public Assembler
michael@0 62 {
michael@0 63 public:
michael@0 64
michael@0 65 void convertBoolToInt32(Register source, Register dest);
michael@0 66 void convertInt32ToDouble(const Register &src, const FloatRegister &dest);
michael@0 67 void convertInt32ToDouble(const Address &src, FloatRegister dest);
michael@0 68 void convertUInt32ToDouble(const Register &src, const FloatRegister &dest);
michael@0 69 void convertUInt32ToFloat32(const Register &src, const FloatRegister &dest);
michael@0 70 void convertDoubleToFloat32(const FloatRegister &src, const FloatRegister &dest);
michael@0 71 void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail);
michael@0 72 void convertDoubleToInt32(const FloatRegister &src, const Register &dest, Label *fail,
michael@0 73 bool negativeZeroCheck = true);
michael@0 74 void convertFloat32ToInt32(const FloatRegister &src, const Register &dest, Label *fail,
michael@0 75 bool negativeZeroCheck = true);
michael@0 76
michael@0 77 void convertFloat32ToDouble(const FloatRegister &src, const FloatRegister &dest);
michael@0 78 void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail);
michael@0 79 void convertInt32ToFloat32(const Register &src, const FloatRegister &dest);
michael@0 80 void convertInt32ToFloat32(const Address &src, FloatRegister dest);
michael@0 81
michael@0 82
michael@0 83 void addDouble(FloatRegister src, FloatRegister dest);
michael@0 84 void subDouble(FloatRegister src, FloatRegister dest);
michael@0 85 void mulDouble(FloatRegister src, FloatRegister dest);
michael@0 86 void divDouble(FloatRegister src, FloatRegister dest);
michael@0 87
michael@0 88 void negateDouble(FloatRegister reg);
michael@0 89 void inc64(AbsoluteAddress dest);
michael@0 90
michael@0 91 public:
michael@0 92
michael@0 93 void ma_move(Register rd, Register rs);
michael@0 94
michael@0 95 void ma_li(Register dest, const ImmGCPtr &ptr);
michael@0 96
michael@0 97 void ma_li(const Register &dest, AbsoluteLabel *label);
michael@0 98
michael@0 99 void ma_li(Register dest, Imm32 imm);
michael@0 100 void ma_liPatchable(Register dest, Imm32 imm);
michael@0 101 void ma_liPatchable(Register dest, ImmPtr imm);
michael@0 102
michael@0 103 // Shift operations
michael@0 104 void ma_sll(Register rd, Register rt, Imm32 shift);
michael@0 105 void ma_srl(Register rd, Register rt, Imm32 shift);
michael@0 106 void ma_sra(Register rd, Register rt, Imm32 shift);
michael@0 107 void ma_ror(Register rd, Register rt, Imm32 shift);
michael@0 108 void ma_rol(Register rd, Register rt, Imm32 shift);
michael@0 109
michael@0 110 void ma_sll(Register rd, Register rt, Register shift);
michael@0 111 void ma_srl(Register rd, Register rt, Register shift);
michael@0 112 void ma_sra(Register rd, Register rt, Register shift);
michael@0 113 void ma_ror(Register rd, Register rt, Register shift);
michael@0 114 void ma_rol(Register rd, Register rt, Register shift);
michael@0 115
michael@0 116 // Negate
michael@0 117 void ma_negu(Register rd, Register rs);
michael@0 118
michael@0 119 void ma_not(Register rd, Register rs);
michael@0 120
michael@0 121 // and
michael@0 122 void ma_and(Register rd, Register rs);
michael@0 123 void ma_and(Register rd, Register rs, Register rt);
michael@0 124 void ma_and(Register rd, Imm32 imm);
michael@0 125 void ma_and(Register rd, Register rs, Imm32 imm);
michael@0 126
michael@0 127 // or
michael@0 128 void ma_or(Register rd, Register rs);
michael@0 129 void ma_or(Register rd, Register rs, Register rt);
michael@0 130 void ma_or(Register rd, Imm32 imm);
michael@0 131 void ma_or(Register rd, Register rs, Imm32 imm);
michael@0 132
michael@0 133 // xor
michael@0 134 void ma_xor(Register rd, Register rs);
michael@0 135 void ma_xor(Register rd, Register rs, Register rt);
michael@0 136 void ma_xor(Register rd, Imm32 imm);
michael@0 137 void ma_xor(Register rd, Register rs, Imm32 imm);
michael@0 138
michael@0 139 // load
michael@0 140 void ma_load(const Register &dest, Address address, LoadStoreSize size = SizeWord,
michael@0 141 LoadStoreExtension extension = SignExtend);
michael@0 142 void ma_load(const Register &dest, const BaseIndex &src, LoadStoreSize size = SizeWord,
michael@0 143 LoadStoreExtension extension = SignExtend);
michael@0 144
michael@0 145 // store
michael@0 146 void ma_store(const Register &data, Address address, LoadStoreSize size = SizeWord,
michael@0 147 LoadStoreExtension extension = SignExtend);
michael@0 148 void ma_store(const Register &data, const BaseIndex &dest, LoadStoreSize size = SizeWord,
michael@0 149 LoadStoreExtension extension = SignExtend);
michael@0 150 void ma_store(const Imm32 &imm, const BaseIndex &dest, LoadStoreSize size = SizeWord,
michael@0 151 LoadStoreExtension extension = SignExtend);
michael@0 152
michael@0 153 void computeScaledAddress(const BaseIndex &address, Register dest);
michael@0 154
michael@0 155 void computeEffectiveAddress(const Address &address, Register dest) {
michael@0 156 ma_addu(dest, address.base, Imm32(address.offset));
michael@0 157 }
michael@0 158
michael@0 159 void computeEffectiveAddress(const BaseIndex &address, Register dest) {
michael@0 160 computeScaledAddress(address, dest);
michael@0 161 if (address.offset) {
michael@0 162 ma_addu(dest, dest, Imm32(address.offset));
michael@0 163 }
michael@0 164 }
michael@0 165
michael@0 166 // arithmetic based ops
michael@0 167 // add
michael@0 168 void ma_addu(Register rd, Register rs, Imm32 imm);
michael@0 169 void ma_addu(Register rd, Register rs);
michael@0 170 void ma_addu(Register rd, Imm32 imm);
michael@0 171 void ma_addTestOverflow(Register rd, Register rs, Register rt, Label *overflow);
michael@0 172 void ma_addTestOverflow(Register rd, Register rs, Imm32 imm, Label *overflow);
michael@0 173
michael@0 174 // subtract
michael@0 175 void ma_subu(Register rd, Register rs, Register rt);
michael@0 176 void ma_subu(Register rd, Register rs, Imm32 imm);
michael@0 177 void ma_subu(Register rd, Imm32 imm);
michael@0 178 void ma_subTestOverflow(Register rd, Register rs, Register rt, Label *overflow);
michael@0 179 void ma_subTestOverflow(Register rd, Register rs, Imm32 imm, Label *overflow);
michael@0 180
michael@0 181 // multiplies. For now, there are only few that we care about.
michael@0 182 void ma_mult(Register rs, Imm32 imm);
michael@0 183 void ma_mul_branch_overflow(Register rd, Register rs, Register rt, Label *overflow);
michael@0 184 void ma_mul_branch_overflow(Register rd, Register rs, Imm32 imm, Label *overflow);
michael@0 185
michael@0 186 // divisions
michael@0 187 void ma_div_branch_overflow(Register rd, Register rs, Register rt, Label *overflow);
michael@0 188 void ma_div_branch_overflow(Register rd, Register rs, Imm32 imm, Label *overflow);
michael@0 189
michael@0 190 // fast mod, uses scratch registers, and thus needs to be in the assembler
michael@0 191 // implicitly assumes that we can overwrite dest at the beginning of the sequence
michael@0 192 void ma_mod_mask(Register src, Register dest, Register hold, int32_t shift,
michael@0 193 Label *negZero = nullptr);
michael@0 194
michael@0 195 // memory
michael@0 196 // shortcut for when we know we're transferring 32 bits of data
michael@0 197 void ma_lw(Register data, Address address);
michael@0 198
michael@0 199 void ma_sw(Register data, Address address);
michael@0 200 void ma_sw(Imm32 imm, Address address);
michael@0 201
michael@0 202 void ma_pop(Register r);
michael@0 203 void ma_push(Register r);
michael@0 204
michael@0 205 // branches when done from within mips-specific code
michael@0 206 void ma_b(Register lhs, Register rhs, Label *l, Condition c, JumpKind jumpKind = LongJump);
michael@0 207 void ma_b(Register lhs, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump);
michael@0 208 void ma_b(Register lhs, Address addr, Label *l, Condition c, JumpKind jumpKind = LongJump);
michael@0 209 void ma_b(Address addr, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump);
michael@0 210 void ma_b(Label *l, JumpKind jumpKind = LongJump);
michael@0 211 void ma_bal(Label *l, JumpKind jumpKind = LongJump);
michael@0 212
michael@0 213 // fp instructions
michael@0 214 void ma_lis(FloatRegister dest, float value);
michael@0 215 void ma_lid(FloatRegister dest, double value);
michael@0 216 void ma_liNegZero(FloatRegister dest);
michael@0 217
michael@0 218 void ma_mv(FloatRegister src, ValueOperand dest);
michael@0 219 void ma_mv(ValueOperand src, FloatRegister dest);
michael@0 220
michael@0 221 void ma_ls(FloatRegister fd, Address address);
michael@0 222 void ma_ld(FloatRegister fd, Address address);
michael@0 223 void ma_sd(FloatRegister fd, Address address);
michael@0 224 void ma_sd(FloatRegister fd, BaseIndex address);
michael@0 225 void ma_ss(FloatRegister fd, Address address);
michael@0 226 void ma_ss(FloatRegister fd, BaseIndex address);
michael@0 227
michael@0 228 void ma_pop(FloatRegister fs);
michael@0 229 void ma_push(FloatRegister fs);
michael@0 230
michael@0 231 //FP branches
michael@0 232 void ma_bc1s(FloatRegister lhs, FloatRegister rhs, Label *label, DoubleCondition c,
michael@0 233 JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0);
michael@0 234 void ma_bc1d(FloatRegister lhs, FloatRegister rhs, Label *label, DoubleCondition c,
michael@0 235 JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0);
michael@0 236
michael@0 237
michael@0 238 // These fuctions abstract the access to high part of the double precision
michael@0 239 // float register. It is intended to work on both 32 bit and 64 bit
michael@0 240 // floating point coprocessor.
michael@0 241 // :TODO: (Bug 985881) Modify this for N32 ABI to use mthc1 and mfhc1
michael@0 242 void moveToDoubleHi(Register src, FloatRegister dest) {
michael@0 243 as_mtc1(src, getOddPair(dest));
michael@0 244 }
michael@0 245 void moveFromDoubleHi(FloatRegister src, Register dest) {
michael@0 246 as_mfc1(dest, getOddPair(src));
michael@0 247 }
michael@0 248
michael@0 249 void moveToDoubleLo(Register src, FloatRegister dest) {
michael@0 250 as_mtc1(src, dest);
michael@0 251 }
michael@0 252 void moveFromDoubleLo(FloatRegister src, Register dest) {
michael@0 253 as_mfc1(dest, src);
michael@0 254 }
michael@0 255
michael@0 256 void moveToFloat32(Register src, FloatRegister dest) {
michael@0 257 as_mtc1(src, dest);
michael@0 258 }
michael@0 259 void moveFromFloat32(FloatRegister src, Register dest) {
michael@0 260 as_mfc1(dest, src);
michael@0 261 }
michael@0 262
michael@0 263 protected:
michael@0 264 void branchWithCode(InstImm code, Label *label, JumpKind jumpKind);
michael@0 265 Condition ma_cmp(Register rd, Register lhs, Register rhs, Condition c);
michael@0 266
michael@0 267 void compareFloatingPoint(FloatFormat fmt, FloatRegister lhs, FloatRegister rhs,
michael@0 268 DoubleCondition c, FloatTestKind *testKind,
michael@0 269 FPConditionBit fcc = FCC0);
michael@0 270
michael@0 271 public:
michael@0 272 // calls an Ion function, assumes that the stack is untouched (8 byte alinged)
michael@0 273 void ma_callIon(const Register reg);
michael@0 274 // callso an Ion function, assuming that sp has already been decremented
michael@0 275 void ma_callIonNoPush(const Register reg);
michael@0 276 // calls an ion function, assuming that the stack is currently not 8 byte aligned
michael@0 277 void ma_callIonHalfPush(const Register reg);
michael@0 278
michael@0 279 void ma_call(ImmPtr dest);
michael@0 280
michael@0 281 void ma_jump(ImmPtr dest);
michael@0 282
michael@0 283 void ma_cmp_set(Register dst, Register lhs, Register rhs, Condition c);
michael@0 284 void ma_cmp_set(Register dst, Register lhs, Imm32 imm, Condition c);
michael@0 285 void ma_cmp_set(Register rd, Register rs, Address addr, Condition c);
michael@0 286 void ma_cmp_set(Register dst, Address lhs, Register imm, Condition c);
michael@0 287 void ma_cmp_set_double(Register dst, FloatRegister lhs, FloatRegister rhs, DoubleCondition c);
michael@0 288 void ma_cmp_set_float32(Register dst, FloatRegister lhs, FloatRegister rhs, DoubleCondition c);
michael@0 289 };
michael@0 290
michael@0 291 class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
michael@0 292 {
michael@0 293 // Number of bytes the stack is adjusted inside a call to C. Calls to C may
michael@0 294 // not be nested.
michael@0 295 bool inCall_;
michael@0 296 uint32_t args_;
michael@0 297 // The actual number of arguments that were passed, used to assert that
michael@0 298 // the initial number of arguments declared was correct.
michael@0 299 uint32_t passedArgs_;
michael@0 300
michael@0 301 uint32_t usedArgSlots_;
michael@0 302 MoveOp::Type firstArgType;
michael@0 303
michael@0 304 bool dynamicAlignment_;
michael@0 305
michael@0 306 bool enoughMemory_;
michael@0 307 // Compute space needed for the function call and set the properties of the
michael@0 308 // callee. It returns the space which has to be allocated for calling the
michael@0 309 // function.
michael@0 310 //
michael@0 311 // arg Number of arguments of the function.
michael@0 312 void setupABICall(uint32_t arg);
michael@0 313
michael@0 314 protected:
michael@0 315 MoveResolver moveResolver_;
michael@0 316
michael@0 317 // Extra bytes currently pushed onto the frame beyond frameDepth_. This is
michael@0 318 // needed to compute offsets to stack slots while temporary space has been
michael@0 319 // reserved for unexpected spills or C++ function calls. It is maintained
michael@0 320 // by functions which track stack alignment, which for clear distinction
michael@0 321 // use StudlyCaps (for example, Push, Pop).
michael@0 322 uint32_t framePushed_;
michael@0 323 void adjustFrame(int value) {
michael@0 324 setFramePushed(framePushed_ + value);
michael@0 325 }
michael@0 326 public:
michael@0 327 MacroAssemblerMIPSCompat()
michael@0 328 : inCall_(false),
michael@0 329 enoughMemory_(true),
michael@0 330 framePushed_(0)
michael@0 331 { }
michael@0 332 bool oom() const {
michael@0 333 return Assembler::oom();
michael@0 334 }
michael@0 335
michael@0 336 public:
michael@0 337 using MacroAssemblerMIPS::call;
michael@0 338
michael@0 339 void j(Label *dest) {
michael@0 340 ma_b(dest);
michael@0 341 }
michael@0 342
michael@0 343 void mov(Register src, Register dest) {
michael@0 344 as_or(dest, src, zero);
michael@0 345 }
michael@0 346 void mov(ImmWord imm, Register dest) {
michael@0 347 ma_li(dest, Imm32(imm.value));
michael@0 348 }
michael@0 349 void mov(ImmPtr imm, Register dest) {
michael@0 350 mov(ImmWord(uintptr_t(imm.value)), dest);
michael@0 351 }
michael@0 352 void mov(Register src, Address dest) {
michael@0 353 MOZ_ASSUME_UNREACHABLE("NYI-IC");
michael@0 354 }
michael@0 355 void mov(Address src, Register dest) {
michael@0 356 MOZ_ASSUME_UNREACHABLE("NYI-IC");
michael@0 357 }
michael@0 358
michael@0 359 void call(const Register reg) {
michael@0 360 as_jalr(reg);
michael@0 361 as_nop();
michael@0 362 }
michael@0 363
michael@0 364 void call(Label *label) {
michael@0 365 // for now, assume that it'll be nearby?
michael@0 366 ma_bal(label);
michael@0 367 }
michael@0 368
michael@0 369 void call(ImmWord imm) {
michael@0 370 call(ImmPtr((void*)imm.value));
michael@0 371 }
michael@0 372 void call(ImmPtr imm) {
michael@0 373 BufferOffset bo = m_buffer.nextOffset();
michael@0 374 addPendingJump(bo, imm, Relocation::HARDCODED);
michael@0 375 ma_call(imm);
michael@0 376 }
michael@0 377 void call(AsmJSImmPtr imm) {
michael@0 378 movePtr(imm, CallReg);
michael@0 379 call(CallReg);
michael@0 380 }
michael@0 381 void call(JitCode *c) {
michael@0 382 BufferOffset bo = m_buffer.nextOffset();
michael@0 383 addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
michael@0 384 ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
michael@0 385 ma_callIonHalfPush(ScratchRegister);
michael@0 386 }
michael@0 387 void branch(JitCode *c) {
michael@0 388 BufferOffset bo = m_buffer.nextOffset();
michael@0 389 addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
michael@0 390 ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
michael@0 391 as_jr(ScratchRegister);
michael@0 392 as_nop();
michael@0 393 }
michael@0 394 void branch(const Register reg) {
michael@0 395 as_jr(reg);
michael@0 396 as_nop();
michael@0 397 }
michael@0 398 void nop() {
michael@0 399 as_nop();
michael@0 400 }
michael@0 401 void ret() {
michael@0 402 ma_pop(ra);
michael@0 403 as_jr(ra);
michael@0 404 as_nop();
michael@0 405 }
michael@0 406 void retn(Imm32 n) {
michael@0 407 // pc <- [sp]; sp += n
michael@0 408 ma_lw(ra, Address(StackPointer, 0));
michael@0 409 ma_addu(StackPointer, StackPointer, n);
michael@0 410 as_jr(ra);
michael@0 411 as_nop();
michael@0 412 }
michael@0 413 void push(Imm32 imm) {
michael@0 414 ma_li(ScratchRegister, imm);
michael@0 415 ma_push(ScratchRegister);
michael@0 416 }
michael@0 417 void push(ImmWord imm) {
michael@0 418 ma_li(ScratchRegister, Imm32(imm.value));
michael@0 419 ma_push(ScratchRegister);
michael@0 420 }
michael@0 421 void push(ImmGCPtr imm) {
michael@0 422 ma_li(ScratchRegister, imm);
michael@0 423 ma_push(ScratchRegister);
michael@0 424 }
michael@0 425 void push(const Address &address) {
michael@0 426 ma_lw(ScratchRegister, address);
michael@0 427 ma_push(ScratchRegister);
michael@0 428 }
michael@0 429 void push(const Register &reg) {
michael@0 430 ma_push(reg);
michael@0 431 }
michael@0 432 void push(const FloatRegister &reg) {
michael@0 433 ma_push(reg);
michael@0 434 }
michael@0 435 void pop(const Register &reg) {
michael@0 436 ma_pop(reg);
michael@0 437 }
michael@0 438 void pop(const FloatRegister &reg) {
michael@0 439 ma_pop(reg);
michael@0 440 }
michael@0 441
michael@0 442 // Emit a branch that can be toggled to a non-operation. On MIPS we use
michael@0 443 // "andi" instruction to toggle the branch.
michael@0 444 // See ToggleToJmp(), ToggleToCmp().
michael@0 445 CodeOffsetLabel toggledJump(Label *label);
michael@0 446
michael@0 447 // Emit a "jalr" or "nop" instruction. ToggleCall can be used to patch
michael@0 448 // this instruction.
michael@0 449 CodeOffsetLabel toggledCall(JitCode *target, bool enabled);
michael@0 450
michael@0 451 static size_t ToggledCallSize() {
michael@0 452 // Four instructions used in: MacroAssemblerMIPSCompat::toggledCall
michael@0 453 return 4 * sizeof(uint32_t);
michael@0 454 }
michael@0 455
michael@0 456 CodeOffsetLabel pushWithPatch(ImmWord imm) {
michael@0 457 CodeOffsetLabel label = movWithPatch(imm, ScratchRegister);
michael@0 458 ma_push(ScratchRegister);
michael@0 459 return label;
michael@0 460 }
michael@0 461
michael@0 462 CodeOffsetLabel movWithPatch(ImmWord imm, Register dest) {
michael@0 463 CodeOffsetLabel label = currentOffset();
michael@0 464 ma_liPatchable(dest, Imm32(imm.value));
michael@0 465 return label;
michael@0 466 }
michael@0 467 CodeOffsetLabel movWithPatch(ImmPtr imm, Register dest) {
michael@0 468 return movWithPatch(ImmWord(uintptr_t(imm.value)), dest);
michael@0 469 }
michael@0 470
michael@0 471 void jump(Label *label) {
michael@0 472 ma_b(label);
michael@0 473 }
michael@0 474 void jump(Register reg) {
michael@0 475 as_jr(reg);
michael@0 476 as_nop();
michael@0 477 }
michael@0 478 void jump(const Address &address) {
michael@0 479 ma_lw(ScratchRegister, address);
michael@0 480 as_jr(ScratchRegister);
michael@0 481 as_nop();
michael@0 482 }
michael@0 483
michael@0 484 void neg32(Register reg) {
michael@0 485 ma_negu(reg, reg);
michael@0 486 }
michael@0 487 void negl(Register reg) {
michael@0 488 ma_negu(reg, reg);
michael@0 489 }
michael@0 490
michael@0 491 // Returns the register containing the type tag.
michael@0 492 Register splitTagForTest(const ValueOperand &value) {
michael@0 493 return value.typeReg();
michael@0 494 }
michael@0 495
michael@0 496 void branchTestGCThing(Condition cond, const Address &address, Label *label);
michael@0 497 void branchTestGCThing(Condition cond, const BaseIndex &src, Label *label);
michael@0 498
michael@0 499 void branchTestPrimitive(Condition cond, const ValueOperand &value, Label *label);
michael@0 500 void branchTestPrimitive(Condition cond, const Register &tag, Label *label);
michael@0 501
michael@0 502 void branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label);
michael@0 503 void branchTestValue(Condition cond, const Address &valaddr, const ValueOperand &value,
michael@0 504 Label *label);
michael@0 505
michael@0 506 // unboxing code
michael@0 507 void unboxInt32(const ValueOperand &operand, const Register &dest);
michael@0 508 void unboxInt32(const Address &src, const Register &dest);
michael@0 509 void unboxBoolean(const ValueOperand &operand, const Register &dest);
michael@0 510 void unboxBoolean(const Address &src, const Register &dest);
michael@0 511 void unboxDouble(const ValueOperand &operand, const FloatRegister &dest);
michael@0 512 void unboxDouble(const Address &src, const FloatRegister &dest);
michael@0 513 void unboxString(const ValueOperand &operand, const Register &dest);
michael@0 514 void unboxString(const Address &src, const Register &dest);
michael@0 515 void unboxObject(const ValueOperand &src, const Register &dest);
michael@0 516 void unboxValue(const ValueOperand &src, AnyRegister dest);
michael@0 517 void unboxPrivate(const ValueOperand &src, Register dest);
michael@0 518
michael@0 519 void notBoolean(const ValueOperand &val) {
michael@0 520 as_xori(val.payloadReg(), val.payloadReg(), 1);
michael@0 521 }
michael@0 522
michael@0 523 // boxing code
michael@0 524 void boxDouble(const FloatRegister &src, const ValueOperand &dest);
michael@0 525 void boxNonDouble(JSValueType type, const Register &src, const ValueOperand &dest);
michael@0 526
michael@0 527 // Extended unboxing API. If the payload is already in a register, returns
michael@0 528 // that register. Otherwise, provides a move to the given scratch register,
michael@0 529 // and returns that.
michael@0 530 Register extractObject(const Address &address, Register scratch);
michael@0 531 Register extractObject(const ValueOperand &value, Register scratch) {
michael@0 532 return value.payloadReg();
michael@0 533 }
michael@0 534 Register extractInt32(const ValueOperand &value, Register scratch) {
michael@0 535 return value.payloadReg();
michael@0 536 }
michael@0 537 Register extractBoolean(const ValueOperand &value, Register scratch) {
michael@0 538 return value.payloadReg();
michael@0 539 }
michael@0 540 Register extractTag(const Address &address, Register scratch);
michael@0 541 Register extractTag(const BaseIndex &address, Register scratch);
michael@0 542 Register extractTag(const ValueOperand &value, Register scratch) {
michael@0 543 return value.typeReg();
michael@0 544 }
michael@0 545
michael@0 546 void boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest);
michael@0 547 void int32ValueToDouble(const ValueOperand &operand, const FloatRegister &dest);
michael@0 548 void loadInt32OrDouble(const Address &address, const FloatRegister &dest);
michael@0 549 void loadInt32OrDouble(Register base, Register index,
michael@0 550 const FloatRegister &dest, int32_t shift = defaultShift);
michael@0 551 void loadConstantDouble(double dp, const FloatRegister &dest);
michael@0 552
michael@0 553 void boolValueToFloat32(const ValueOperand &operand, const FloatRegister &dest);
michael@0 554 void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest);
michael@0 555 void loadConstantFloat32(float f, const FloatRegister &dest);
michael@0 556
michael@0 557 void branchTestInt32(Condition cond, const ValueOperand &value, Label *label);
michael@0 558 void branchTestInt32(Condition cond, const Register &tag, Label *label);
michael@0 559 void branchTestInt32(Condition cond, const Address &address, Label *label);
michael@0 560 void branchTestInt32(Condition cond, const BaseIndex &src, Label *label);
michael@0 561
michael@0 562 void branchTestBoolean(Condition cond, const ValueOperand &value, Label *label);
michael@0 563 void branchTestBoolean(Condition cond, const Register &tag, Label *label);
michael@0 564 void branchTestBoolean(Condition cond, const BaseIndex &src, Label *label);
michael@0 565
michael@0 566 void branch32(Condition cond, Register lhs, Register rhs, Label *label) {
michael@0 567 ma_b(lhs, rhs, label, cond);
michael@0 568 }
michael@0 569 void branch32(Condition cond, Register lhs, Imm32 imm, Label *label) {
michael@0 570 ma_b(lhs, imm, label, cond);
michael@0 571 }
michael@0 572 void branch32(Condition cond, const Operand &lhs, Register rhs, Label *label) {
michael@0 573 if (lhs.getTag() == Operand::REG) {
michael@0 574 ma_b(lhs.toReg(), rhs, label, cond);
michael@0 575 } else {
michael@0 576 branch32(cond, lhs.toAddress(), rhs, label);
michael@0 577 }
michael@0 578 }
michael@0 579 void branch32(Condition cond, const Operand &lhs, Imm32 rhs, Label *label) {
michael@0 580 if (lhs.getTag() == Operand::REG) {
michael@0 581 ma_b(lhs.toReg(), rhs, label, cond);
michael@0 582 } else {
michael@0 583 branch32(cond, lhs.toAddress(), rhs, label);
michael@0 584 }
michael@0 585 }
michael@0 586 void branch32(Condition cond, const Address &lhs, Register rhs, Label *label) {
michael@0 587 ma_lw(ScratchRegister, lhs);
michael@0 588 ma_b(ScratchRegister, rhs, label, cond);
michael@0 589 }
michael@0 590 void branch32(Condition cond, const Address &lhs, Imm32 rhs, Label *label) {
michael@0 591 ma_lw(SecondScratchReg, lhs);
michael@0 592 ma_b(SecondScratchReg, rhs, label, cond);
michael@0 593 }
michael@0 594 void branchPtr(Condition cond, const Address &lhs, Register rhs, Label *label) {
michael@0 595 branch32(cond, lhs, rhs, label);
michael@0 596 }
michael@0 597
michael@0 598 void branchPrivatePtr(Condition cond, const Address &lhs, ImmPtr ptr, Label *label) {
michael@0 599 branchPtr(cond, lhs, ptr, label);
michael@0 600 }
michael@0 601
michael@0 602 void branchPrivatePtr(Condition cond, const Address &lhs, Register ptr, Label *label) {
michael@0 603 branchPtr(cond, lhs, ptr, label);
michael@0 604 }
michael@0 605
michael@0 606 void branchPrivatePtr(Condition cond, Register lhs, ImmWord ptr, Label *label) {
michael@0 607 branchPtr(cond, lhs, ptr, label);
michael@0 608 }
michael@0 609
michael@0 610 void branchTestDouble(Condition cond, const ValueOperand &value, Label *label);
michael@0 611 void branchTestDouble(Condition cond, const Register &tag, Label *label);
michael@0 612 void branchTestDouble(Condition cond, const Address &address, Label *label);
michael@0 613 void branchTestDouble(Condition cond, const BaseIndex &src, Label *label);
michael@0 614
michael@0 615 void branchTestNull(Condition cond, const ValueOperand &value, Label *label);
michael@0 616 void branchTestNull(Condition cond, const Register &tag, Label *label);
michael@0 617 void branchTestNull(Condition cond, const BaseIndex &src, Label *label);
michael@0 618
michael@0 619 void branchTestObject(Condition cond, const ValueOperand &value, Label *label);
michael@0 620 void branchTestObject(Condition cond, const Register &tag, Label *label);
michael@0 621 void branchTestObject(Condition cond, const BaseIndex &src, Label *label);
michael@0 622
michael@0 623 void branchTestString(Condition cond, const ValueOperand &value, Label *label);
michael@0 624 void branchTestString(Condition cond, const Register &tag, Label *label);
michael@0 625 void branchTestString(Condition cond, const BaseIndex &src, Label *label);
michael@0 626
michael@0 627 void branchTestUndefined(Condition cond, const ValueOperand &value, Label *label);
michael@0 628 void branchTestUndefined(Condition cond, const Register &tag, Label *label);
michael@0 629 void branchTestUndefined(Condition cond, const BaseIndex &src, Label *label);
michael@0 630 void branchTestUndefined(Condition cond, const Address &address, Label *label);
michael@0 631
michael@0 632 void branchTestNumber(Condition cond, const ValueOperand &value, Label *label);
michael@0 633 void branchTestNumber(Condition cond, const Register &tag, Label *label);
michael@0 634
michael@0 635 void branchTestMagic(Condition cond, const ValueOperand &value, Label *label);
michael@0 636 void branchTestMagic(Condition cond, const Register &tag, Label *label);
michael@0 637 void branchTestMagic(Condition cond, const Address &address, Label *label);
michael@0 638 void branchTestMagic(Condition cond, const BaseIndex &src, Label *label);
michael@0 639
michael@0 640 void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why,
michael@0 641 Label *label) {
michael@0 642 MOZ_ASSERT(cond == Equal || cond == NotEqual);
michael@0 643 // Test for magic
michael@0 644 Label notmagic;
michael@0 645 branchTestMagic(cond, val, &notmagic);
michael@0 646 // Test magic value
michael@0 647 branch32(cond, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label);
michael@0 648 bind(&notmagic);
michael@0 649 }
michael@0 650
michael@0 651 void branchTestInt32Truthy(bool b, const ValueOperand &value, Label *label);
michael@0 652
michael@0 653 void branchTestStringTruthy(bool b, const ValueOperand &value, Label *label);
michael@0 654
michael@0 655 void branchTestDoubleTruthy(bool b, const FloatRegister &value, Label *label);
michael@0 656
michael@0 657 void branchTestBooleanTruthy(bool b, const ValueOperand &operand, Label *label);
michael@0 658
michael@0 659 void branchTest32(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
michael@0 660 MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
michael@0 661 if (lhs == rhs) {
michael@0 662 ma_b(lhs, rhs, label, cond);
michael@0 663 } else {
michael@0 664 as_and(ScratchRegister, lhs, rhs);
michael@0 665 ma_b(ScratchRegister, ScratchRegister, label, cond);
michael@0 666 }
michael@0 667 }
michael@0 668 void branchTest32(Condition cond, const Register &lhs, Imm32 imm, Label *label) {
michael@0 669 ma_li(ScratchRegister, imm);
michael@0 670 branchTest32(cond, lhs, ScratchRegister, label);
michael@0 671 }
michael@0 672 void branchTest32(Condition cond, const Address &address, Imm32 imm, Label *label) {
michael@0 673 ma_lw(SecondScratchReg, address);
michael@0 674 branchTest32(cond, SecondScratchReg, imm, label);
michael@0 675 }
michael@0 676 void branchTestPtr(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
michael@0 677 branchTest32(cond, lhs, rhs, label);
michael@0 678 }
michael@0 679 void branchTestPtr(Condition cond, const Register &lhs, const Imm32 rhs, Label *label) {
michael@0 680 branchTest32(cond, lhs, rhs, label);
michael@0 681 }
michael@0 682 void branchTestPtr(Condition cond, const Address &lhs, Imm32 imm, Label *label) {
michael@0 683 branchTest32(cond, lhs, imm, label);
michael@0 684 }
michael@0 685 void branchPtr(Condition cond, Register lhs, Register rhs, Label *label) {
michael@0 686 ma_b(lhs, rhs, label, cond);
michael@0 687 }
michael@0 688 void branchPtr(Condition cond, Register lhs, ImmGCPtr ptr, Label *label) {
michael@0 689 ma_li(ScratchRegister, ptr);
michael@0 690 ma_b(lhs, ScratchRegister, label, cond);
michael@0 691 }
michael@0 692 void branchPtr(Condition cond, Register lhs, ImmWord imm, Label *label) {
michael@0 693 ma_b(lhs, Imm32(imm.value), label, cond);
michael@0 694 }
michael@0 695 void branchPtr(Condition cond, Register lhs, ImmPtr imm, Label *label) {
michael@0 696 branchPtr(cond, lhs, ImmWord(uintptr_t(imm.value)), label);
michael@0 697 }
michael@0 698 void branchPtr(Condition cond, Register lhs, AsmJSImmPtr imm, Label *label) {
michael@0 699 movePtr(imm, ScratchRegister);
michael@0 700 branchPtr(cond, lhs, ScratchRegister, label);
michael@0 701 }
michael@0 702 void branchPtr(Condition cond, Register lhs, Imm32 imm, Label *label) {
michael@0 703 ma_b(lhs, imm, label, cond);
michael@0 704 }
michael@0 705 void decBranchPtr(Condition cond, const Register &lhs, Imm32 imm, Label *label) {
michael@0 706 subPtr(imm, lhs);
michael@0 707 branch32(cond, lhs, Imm32(0), label);
michael@0 708 }
michael@0 709
michael@0 710 protected:
michael@0 711 uint32_t getType(const Value &val);
michael@0 712 void moveData(const Value &val, Register data);
michael@0 713 public:
michael@0 714 void moveValue(const Value &val, Register type, Register data);
michael@0 715
michael@0 716 CodeOffsetJump jumpWithPatch(RepatchLabel *label);
michael@0 717
michael@0 718 template <typename T>
michael@0 719 CodeOffsetJump branchPtrWithPatch(Condition cond, Register reg, T ptr, RepatchLabel *label) {
michael@0 720 movePtr(ptr, ScratchRegister);
michael@0 721 Label skipJump;
michael@0 722 ma_b(reg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump);
michael@0 723 CodeOffsetJump off = jumpWithPatch(label);
michael@0 724 bind(&skipJump);
michael@0 725 return off;
michael@0 726 }
michael@0 727
michael@0 728 template <typename T>
michael@0 729 CodeOffsetJump branchPtrWithPatch(Condition cond, Address addr, T ptr, RepatchLabel *label) {
michael@0 730 loadPtr(addr, SecondScratchReg);
michael@0 731 movePtr(ptr, ScratchRegister);
michael@0 732 Label skipJump;
michael@0 733 ma_b(SecondScratchReg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump);
michael@0 734 CodeOffsetJump off = jumpWithPatch(label);
michael@0 735 bind(&skipJump);
michael@0 736 return off;
michael@0 737 }
michael@0 738 void branchPtr(Condition cond, Address addr, ImmGCPtr ptr, Label *label) {
michael@0 739 ma_lw(SecondScratchReg, addr);
michael@0 740 ma_li(ScratchRegister, ptr);
michael@0 741 ma_b(SecondScratchReg, ScratchRegister, label, cond);
michael@0 742 }
michael@0 743 void branchPtr(Condition cond, Address addr, ImmWord ptr, Label *label) {
michael@0 744 ma_lw(SecondScratchReg, addr);
michael@0 745 ma_b(SecondScratchReg, Imm32(ptr.value), label, cond);
michael@0 746 }
michael@0 747 void branchPtr(Condition cond, Address addr, ImmPtr ptr, Label *label) {
michael@0 748 branchPtr(cond, addr, ImmWord(uintptr_t(ptr.value)), label);
michael@0 749 }
michael@0 750 void branchPtr(Condition cond, const AbsoluteAddress &addr, const Register &ptr, Label *label) {
michael@0 751 loadPtr(addr, ScratchRegister);
michael@0 752 ma_b(ScratchRegister, ptr, label, cond);
michael@0 753 }
michael@0 754 void branchPtr(Condition cond, const AsmJSAbsoluteAddress &addr, const Register &ptr,
michael@0 755 Label *label) {
michael@0 756 loadPtr(addr, ScratchRegister);
michael@0 757 ma_b(ScratchRegister, ptr, label, cond);
michael@0 758 }
michael@0 759 void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) {
michael@0 760 loadPtr(lhs, SecondScratchReg); // ma_b might use scratch
michael@0 761 ma_b(SecondScratchReg, rhs, label, cond);
michael@0 762 }
michael@0 763 void branch32(Condition cond, const AbsoluteAddress &lhs, const Register &rhs, Label *label) {
michael@0 764 loadPtr(lhs, ScratchRegister);
michael@0 765 ma_b(ScratchRegister, rhs, label, cond);
michael@0 766 }
michael@0 767
michael@0 768 void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) {
michael@0 769 if (dest.isFloat())
michael@0 770 loadInt32OrDouble(address, dest.fpu());
michael@0 771 else
michael@0 772 ma_lw(dest.gpr(), address);
michael@0 773 }
michael@0 774
michael@0 775 void loadUnboxedValue(BaseIndex address, MIRType type, AnyRegister dest) {
michael@0 776 if (dest.isFloat())
michael@0 777 loadInt32OrDouble(address.base, address.index, dest.fpu(), address.scale);
michael@0 778 else
michael@0 779 load32(address, dest.gpr());
michael@0 780 }
michael@0 781
michael@0 782 void moveValue(const Value &val, const ValueOperand &dest);
michael@0 783
michael@0 784 void moveValue(const ValueOperand &src, const ValueOperand &dest) {
michael@0 785 MOZ_ASSERT(src.typeReg() != dest.payloadReg());
michael@0 786 MOZ_ASSERT(src.payloadReg() != dest.typeReg());
michael@0 787 if (src.typeReg() != dest.typeReg())
michael@0 788 ma_move(dest.typeReg(), src.typeReg());
michael@0 789 if (src.payloadReg() != dest.payloadReg())
michael@0 790 ma_move(dest.payloadReg(), src.payloadReg());
michael@0 791 }
michael@0 792
michael@0 793 void storeValue(ValueOperand val, Operand dst);
michael@0 794 void storeValue(ValueOperand val, const BaseIndex &dest);
michael@0 795 void storeValue(JSValueType type, Register reg, BaseIndex dest);
michael@0 796 void storeValue(ValueOperand val, const Address &dest);
michael@0 797 void storeValue(JSValueType type, Register reg, Address dest);
michael@0 798 void storeValue(const Value &val, Address dest);
michael@0 799 void storeValue(const Value &val, BaseIndex dest);
michael@0 800
michael@0 801 void loadValue(Address src, ValueOperand val);
michael@0 802 void loadValue(Operand dest, ValueOperand val) {
michael@0 803 loadValue(dest.toAddress(), val);
michael@0 804 }
michael@0 805 void loadValue(const BaseIndex &addr, ValueOperand val);
michael@0 806 void tagValue(JSValueType type, Register payload, ValueOperand dest);
michael@0 807
michael@0 808 void pushValue(ValueOperand val);
michael@0 809 void popValue(ValueOperand val);
michael@0 810 void pushValue(const Value &val) {
michael@0 811 jsval_layout jv = JSVAL_TO_IMPL(val);
michael@0 812 push(Imm32(jv.s.tag));
michael@0 813 if (val.isMarkable())
michael@0 814 push(ImmGCPtr(reinterpret_cast<gc::Cell *>(val.toGCThing())));
michael@0 815 else
michael@0 816 push(Imm32(jv.s.payload.i32));
michael@0 817 }
michael@0 818 void pushValue(JSValueType type, Register reg) {
michael@0 819 push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
michael@0 820 ma_push(reg);
michael@0 821 }
michael@0 822 void pushValue(const Address &addr);
michael@0 823 void Push(const ValueOperand &val) {
michael@0 824 pushValue(val);
michael@0 825 framePushed_ += sizeof(Value);
michael@0 826 }
michael@0 827 void Pop(const ValueOperand &val) {
michael@0 828 popValue(val);
michael@0 829 framePushed_ -= sizeof(Value);
michael@0 830 }
michael@0 831 void storePayload(const Value &val, Address dest);
michael@0 832 void storePayload(Register src, Address dest);
michael@0 833 void storePayload(const Value &val, Register base, Register index, int32_t shift = defaultShift);
michael@0 834 void storePayload(Register src, Register base, Register index, int32_t shift = defaultShift);
michael@0 835 void storeTypeTag(ImmTag tag, Address dest);
michael@0 836 void storeTypeTag(ImmTag tag, Register base, Register index, int32_t shift = defaultShift);
michael@0 837
michael@0 838 void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
michael@0 839 ma_sll(frameSizeReg, frameSizeReg, Imm32(FRAMESIZE_SHIFT));
michael@0 840 ma_or(frameSizeReg, frameSizeReg, Imm32(type));
michael@0 841 }
michael@0 842
michael@0 843 void linkExitFrame();
michael@0 844 void linkParallelExitFrame(const Register &pt);
michael@0 845 void handleFailureWithHandler(void *handler);
michael@0 846 void handleFailureWithHandlerTail();
michael@0 847
michael@0 848 /////////////////////////////////////////////////////////////////
michael@0 849 // Common interface.
michael@0 850 /////////////////////////////////////////////////////////////////
michael@0 851 public:
michael@0 852 // The following functions are exposed for use in platform-shared code.
michael@0 853 void Push(const Register &reg) {
michael@0 854 ma_push(reg);
michael@0 855 adjustFrame(sizeof(intptr_t));
michael@0 856 }
michael@0 857 void Push(const Imm32 imm) {
michael@0 858 ma_li(ScratchRegister, imm);
michael@0 859 ma_push(ScratchRegister);
michael@0 860 adjustFrame(sizeof(intptr_t));
michael@0 861 }
michael@0 862 void Push(const ImmWord imm) {
michael@0 863 ma_li(ScratchRegister, Imm32(imm.value));
michael@0 864 ma_push(ScratchRegister);
michael@0 865 adjustFrame(sizeof(intptr_t));
michael@0 866 }
michael@0 867 void Push(const ImmPtr imm) {
michael@0 868 Push(ImmWord(uintptr_t(imm.value)));
michael@0 869 }
michael@0 870 void Push(const ImmGCPtr ptr) {
michael@0 871 ma_li(ScratchRegister, ptr);
michael@0 872 ma_push(ScratchRegister);
michael@0 873 adjustFrame(sizeof(intptr_t));
michael@0 874 }
michael@0 875 void Push(const FloatRegister &f) {
michael@0 876 ma_push(f);
michael@0 877 adjustFrame(sizeof(double));
michael@0 878 }
michael@0 879
michael@0 880 CodeOffsetLabel PushWithPatch(const ImmWord &word) {
michael@0 881 framePushed_ += sizeof(word.value);
michael@0 882 return pushWithPatch(word);
michael@0 883 }
michael@0 884 CodeOffsetLabel PushWithPatch(const ImmPtr &imm) {
michael@0 885 return PushWithPatch(ImmWord(uintptr_t(imm.value)));
michael@0 886 }
michael@0 887
michael@0 888 void Pop(const Register &reg) {
michael@0 889 ma_pop(reg);
michael@0 890 adjustFrame(-sizeof(intptr_t));
michael@0 891 }
michael@0 892 void implicitPop(uint32_t args) {
michael@0 893 MOZ_ASSERT(args % sizeof(intptr_t) == 0);
michael@0 894 adjustFrame(-args);
michael@0 895 }
michael@0 896 uint32_t framePushed() const {
michael@0 897 return framePushed_;
michael@0 898 }
michael@0 899 void setFramePushed(uint32_t framePushed) {
michael@0 900 framePushed_ = framePushed;
michael@0 901 }
michael@0 902
michael@0 903 // Builds an exit frame on the stack, with a return address to an internal
michael@0 904 // non-function. Returns offset to be passed to markSafepointAt().
michael@0 905 bool buildFakeExitFrame(const Register &scratch, uint32_t *offset);
michael@0 906
michael@0 907 void callWithExitFrame(JitCode *target);
michael@0 908 void callWithExitFrame(JitCode *target, Register dynStack);
michael@0 909
michael@0 910 // Makes an Ion call using the only two methods that it is sane for
michael@0 911 // indep code to make a call
michael@0 912 void callIon(const Register &callee);
michael@0 913
michael@0 914 void reserveStack(uint32_t amount);
michael@0 915 void freeStack(uint32_t amount);
michael@0 916 void freeStack(Register amount);
michael@0 917
michael@0 918 void add32(Register src, Register dest);
michael@0 919 void add32(Imm32 imm, Register dest);
michael@0 920 void add32(Imm32 imm, const Address &dest);
michael@0 921 void sub32(Imm32 imm, Register dest);
michael@0 922 void sub32(Register src, Register dest);
michael@0 923
michael@0 924 void and32(Imm32 imm, Register dest);
michael@0 925 void and32(Imm32 imm, const Address &dest);
michael@0 926 void or32(Imm32 imm, const Address &dest);
michael@0 927 void xor32(Imm32 imm, Register dest);
michael@0 928 void xorPtr(Imm32 imm, Register dest);
michael@0 929 void xorPtr(Register src, Register dest);
michael@0 930 void orPtr(Imm32 imm, Register dest);
michael@0 931 void orPtr(Register src, Register dest);
michael@0 932 void andPtr(Imm32 imm, Register dest);
michael@0 933 void andPtr(Register src, Register dest);
michael@0 934 void addPtr(Register src, Register dest);
michael@0 935 void subPtr(Register src, Register dest);
michael@0 936 void addPtr(const Address &src, Register dest);
michael@0 937 void not32(Register reg);
michael@0 938
michael@0 939 void move32(const Imm32 &imm, const Register &dest);
michael@0 940 void move32(const Register &src, const Register &dest);
michael@0 941
michael@0 942 void movePtr(const Register &src, const Register &dest);
michael@0 943 void movePtr(const ImmWord &imm, const Register &dest);
michael@0 944 void movePtr(const ImmPtr &imm, const Register &dest);
michael@0 945 void movePtr(const AsmJSImmPtr &imm, const Register &dest);
michael@0 946 void movePtr(const ImmGCPtr &imm, const Register &dest);
michael@0 947
michael@0 948 void load8SignExtend(const Address &address, const Register &dest);
michael@0 949 void load8SignExtend(const BaseIndex &src, const Register &dest);
michael@0 950
michael@0 951 void load8ZeroExtend(const Address &address, const Register &dest);
michael@0 952 void load8ZeroExtend(const BaseIndex &src, const Register &dest);
michael@0 953
michael@0 954 void load16SignExtend(const Address &address, const Register &dest);
michael@0 955 void load16SignExtend(const BaseIndex &src, const Register &dest);
michael@0 956
michael@0 957 void load16ZeroExtend(const Address &address, const Register &dest);
michael@0 958 void load16ZeroExtend(const BaseIndex &src, const Register &dest);
michael@0 959
michael@0 960 void load32(const Address &address, const Register &dest);
michael@0 961 void load32(const BaseIndex &address, const Register &dest);
michael@0 962 void load32(const AbsoluteAddress &address, const Register &dest);
michael@0 963
michael@0 964 void loadPtr(const Address &address, const Register &dest);
michael@0 965 void loadPtr(const BaseIndex &src, const Register &dest);
michael@0 966 void loadPtr(const AbsoluteAddress &address, const Register &dest);
michael@0 967 void loadPtr(const AsmJSAbsoluteAddress &address, const Register &dest);
michael@0 968
michael@0 969 void loadPrivate(const Address &address, const Register &dest);
michael@0 970
michael@0 971 void loadDouble(const Address &addr, const FloatRegister &dest);
michael@0 972 void loadDouble(const BaseIndex &src, const FloatRegister &dest);
michael@0 973
michael@0 974 // Load a float value into a register, then expand it to a double.
michael@0 975 void loadFloatAsDouble(const Address &addr, const FloatRegister &dest);
michael@0 976 void loadFloatAsDouble(const BaseIndex &src, const FloatRegister &dest);
michael@0 977
michael@0 978 void loadFloat32(const Address &addr, const FloatRegister &dest);
michael@0 979 void loadFloat32(const BaseIndex &src, const FloatRegister &dest);
michael@0 980
michael@0 981 void store8(const Register &src, const Address &address);
michael@0 982 void store8(const Imm32 &imm, const Address &address);
michael@0 983 void store8(const Register &src, const BaseIndex &address);
michael@0 984 void store8(const Imm32 &imm, const BaseIndex &address);
michael@0 985
michael@0 986 void store16(const Register &src, const Address &address);
michael@0 987 void store16(const Imm32 &imm, const Address &address);
michael@0 988 void store16(const Register &src, const BaseIndex &address);
michael@0 989 void store16(const Imm32 &imm, const BaseIndex &address);
michael@0 990
michael@0 991 void store32(const Register &src, const AbsoluteAddress &address);
michael@0 992 void store32(const Register &src, const Address &address);
michael@0 993 void store32(const Register &src, const BaseIndex &address);
michael@0 994 void store32(const Imm32 &src, const Address &address);
michael@0 995 void store32(const Imm32 &src, const BaseIndex &address);
michael@0 996
michael@0 997 void storePtr(ImmWord imm, const Address &address);
michael@0 998 void storePtr(ImmPtr imm, const Address &address);
michael@0 999 void storePtr(ImmGCPtr imm, const Address &address);
michael@0 1000 void storePtr(Register src, const Address &address);
michael@0 1001 void storePtr(const Register &src, const AbsoluteAddress &dest);
michael@0 1002 void storeDouble(FloatRegister src, Address addr) {
michael@0 1003 ma_sd(src, addr);
michael@0 1004 }
michael@0 1005 void storeDouble(FloatRegister src, BaseIndex addr) {
michael@0 1006 MOZ_ASSERT(addr.offset == 0);
michael@0 1007 ma_sd(src, addr);
michael@0 1008 }
michael@0 1009 void moveDouble(FloatRegister src, FloatRegister dest) {
michael@0 1010 as_movd(dest, src);
michael@0 1011 }
michael@0 1012
michael@0 1013 void storeFloat32(FloatRegister src, Address addr) {
michael@0 1014 ma_ss(src, addr);
michael@0 1015 }
michael@0 1016 void storeFloat32(FloatRegister src, BaseIndex addr) {
michael@0 1017 MOZ_ASSERT(addr.offset == 0);
michael@0 1018 ma_ss(src, addr);
michael@0 1019 }
michael@0 1020
michael@0 1021 void zeroDouble(FloatRegister reg) {
michael@0 1022 moveToDoubleLo(zero, reg);
michael@0 1023 moveToDoubleHi(zero, reg);
michael@0 1024 }
michael@0 1025
michael@0 1026 void clampIntToUint8(Register reg) {
michael@0 1027 // look at (reg >> 8) if it is 0, then src shouldn't be clamped
michael@0 1028 // if it is <0, then we want to clamp to 0,
michael@0 1029 // otherwise, we wish to clamp to 255
michael@0 1030 Label done;
michael@0 1031 ma_move(ScratchRegister, reg);
michael@0 1032 as_sra(ScratchRegister, ScratchRegister, 8);
michael@0 1033 ma_b(ScratchRegister, ScratchRegister, &done, Assembler::Zero, ShortJump);
michael@0 1034 {
michael@0 1035 Label negative;
michael@0 1036 ma_b(ScratchRegister, ScratchRegister, &negative, Assembler::Signed, ShortJump);
michael@0 1037 {
michael@0 1038 ma_li(reg, Imm32(255));
michael@0 1039 ma_b(&done, ShortJump);
michael@0 1040 }
michael@0 1041 bind(&negative);
michael@0 1042 {
michael@0 1043 ma_move(reg, zero);
michael@0 1044 }
michael@0 1045 }
michael@0 1046 bind(&done);
michael@0 1047 }
michael@0 1048
michael@0 1049 void subPtr(Imm32 imm, const Register dest);
michael@0 1050 void addPtr(Imm32 imm, const Register dest);
michael@0 1051 void addPtr(Imm32 imm, const Address &dest);
michael@0 1052 void addPtr(ImmWord imm, const Register dest) {
michael@0 1053 addPtr(Imm32(imm.value), dest);
michael@0 1054 }
michael@0 1055 void addPtr(ImmPtr imm, const Register dest) {
michael@0 1056 addPtr(ImmWord(uintptr_t(imm.value)), dest);
michael@0 1057 }
michael@0 1058
michael@0 1059 void breakpoint();
michael@0 1060
michael@0 1061 void branchDouble(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs,
michael@0 1062 Label *label);
michael@0 1063
michael@0 1064 void branchFloat(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs,
michael@0 1065 Label *label);
michael@0 1066
michael@0 1067 void checkStackAlignment();
michael@0 1068
michael@0 1069 void alignPointerUp(Register src, Register dest, uint32_t alignment);
michael@0 1070
michael@0 1071 void rshiftPtr(Imm32 imm, Register dest) {
michael@0 1072 ma_srl(dest, dest, imm);
michael@0 1073 }
michael@0 1074 void lshiftPtr(Imm32 imm, Register dest) {
michael@0 1075 ma_sll(dest, dest, imm);
michael@0 1076 }
michael@0 1077
michael@0 1078 // If source is a double, load it into dest. If source is int32,
michael@0 1079 // convert it to double. Else, branch to failure.
michael@0 1080 void ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure);
michael@0 1081
michael@0 1082 // Setup a call to C/C++ code, given the number of general arguments it
michael@0 1083 // takes. Note that this only supports cdecl.
michael@0 1084 //
michael@0 1085 // In order for alignment to work correctly, the MacroAssembler must have a
michael@0 1086 // consistent view of the stack displacement. It is okay to call "push"
michael@0 1087 // manually, however, if the stack alignment were to change, the macro
michael@0 1088 // assembler should be notified before starting a call.
michael@0 1089 void setupAlignedABICall(uint32_t args);
michael@0 1090
michael@0 1091 // Sets up an ABI call for when the alignment is not known. This may need a
michael@0 1092 // scratch register.
michael@0 1093 void setupUnalignedABICall(uint32_t args, const Register &scratch);
michael@0 1094
michael@0 1095 // Arguments must be assigned in a left-to-right order. This process may
michael@0 1096 // temporarily use more stack, in which case sp-relative addresses will be
michael@0 1097 // automatically adjusted. It is extremely important that sp-relative
michael@0 1098 // addresses are computed *after* setupABICall(). Furthermore, no
michael@0 1099 // operations should be emitted while setting arguments.
michael@0 1100 void passABIArg(const MoveOperand &from, MoveOp::Type type);
michael@0 1101 void passABIArg(const Register &reg);
michael@0 1102 void passABIArg(const FloatRegister &reg, MoveOp::Type type);
michael@0 1103 void passABIArg(const ValueOperand &regs);
michael@0 1104
michael@0 1105 protected:
michael@0 1106 bool buildOOLFakeExitFrame(void *fakeReturnAddr);
michael@0 1107
michael@0 1108 private:
michael@0 1109 void callWithABIPre(uint32_t *stackAdjust);
michael@0 1110 void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result);
michael@0 1111
michael@0 1112 public:
michael@0 1113 // Emits a call to a C/C++ function, resolving all argument moves.
michael@0 1114 void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL);
michael@0 1115 void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL);
michael@0 1116 void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL);
michael@0 1117
michael@0 1118 CodeOffsetLabel labelForPatch() {
michael@0 1119 return CodeOffsetLabel(nextOffset().getOffset());
michael@0 1120 }
michael@0 1121
michael@0 1122 void memIntToValue(Address Source, Address Dest) {
michael@0 1123 MOZ_ASSUME_UNREACHABLE("NYI");
michael@0 1124 }
michael@0 1125
michael@0 1126 void lea(Operand addr, Register dest) {
michael@0 1127 MOZ_ASSUME_UNREACHABLE("NYI");
michael@0 1128 }
michael@0 1129
michael@0 1130 void abiret() {
michael@0 1131 MOZ_ASSUME_UNREACHABLE("NYI");
michael@0 1132 }
michael@0 1133
michael@0 1134 void ma_storeImm(Imm32 imm, const Address &addr) {
michael@0 1135 ma_sw(imm, addr);
michael@0 1136 }
michael@0 1137
michael@0 1138 BufferOffset ma_BoundsCheck(Register bounded) {
michael@0 1139 BufferOffset bo = m_buffer.nextOffset();
michael@0 1140 ma_liPatchable(bounded, Imm32(0));
michael@0 1141 return bo;
michael@0 1142 }
michael@0 1143
michael@0 1144 void moveFloat32(FloatRegister src, FloatRegister dest) {
michael@0 1145 as_movs(dest, src);
michael@0 1146 }
michael@0 1147
michael@0 1148 void branchPtrInNurseryRange(Register ptr, Register temp, Label *label);
michael@0 1149 };
michael@0 1150
michael@0 1151 typedef MacroAssemblerMIPSCompat MacroAssemblerSpecific;
michael@0 1152
michael@0 1153 } // namespace jit
michael@0 1154 } // namespace js
michael@0 1155
michael@0 1156 #endif /* jit_mips_MacroAssembler_mips_h */

mercurial