js/src/jit/arm/MacroAssembler-arm.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_arm_MacroAssembler_arm_h
michael@0 8 #define jit_arm_MacroAssembler_arm_h
michael@0 9
michael@0 10 #include "mozilla/DebugOnly.h"
michael@0 11
michael@0 12 #include "jsopcode.h"
michael@0 13
michael@0 14 #include "jit/arm/Assembler-arm.h"
michael@0 15 #include "jit/IonCaches.h"
michael@0 16 #include "jit/IonFrames.h"
michael@0 17 #include "jit/MoveResolver.h"
michael@0 18
michael@0 19 using mozilla::DebugOnly;
michael@0 20
michael@0 21 namespace js {
michael@0 22 namespace jit {
michael@0 23
michael@0 24 static Register CallReg = ip;
michael@0 25 static const int defaultShift = 3;
michael@0 26 JS_STATIC_ASSERT(1 << defaultShift == sizeof(jsval));
michael@0 27
michael@0 28 // MacroAssemblerARM is inheriting form Assembler defined in Assembler-arm.{h,cpp}
michael@0 29 class MacroAssemblerARM : public Assembler
michael@0 30 {
michael@0 31 protected:
michael@0 32 // On ARM, some instructions require a second scratch register. This register
michael@0 33 // defaults to lr, since it's non-allocatable (as it can be clobbered by some
michael@0 34 // instructions). Allow the baseline compiler to override this though, since
michael@0 35 // baseline IC stubs rely on lr holding the return address.
michael@0 36 Register secondScratchReg_;
michael@0 37
michael@0 38 // higher level tag testing code
michael@0 39 Operand ToPayload(Operand base) {
michael@0 40 return Operand(Register::FromCode(base.base()), base.disp());
michael@0 41 }
michael@0 42 Address ToPayload(Address base) {
michael@0 43 return ToPayload(Operand(base)).toAddress();
michael@0 44 }
michael@0 45 Operand ToType(Operand base) {
michael@0 46 return Operand(Register::FromCode(base.base()), base.disp() + sizeof(void *));
michael@0 47 }
michael@0 48 Address ToType(Address base) {
michael@0 49 return ToType(Operand(base)).toAddress();
michael@0 50 }
michael@0 51
michael@0 52 public:
michael@0 53 MacroAssemblerARM()
michael@0 54 : secondScratchReg_(lr)
michael@0 55 { }
michael@0 56
michael@0 57 void setSecondScratchReg(Register reg) {
michael@0 58 JS_ASSERT(reg != ScratchRegister);
michael@0 59 secondScratchReg_ = reg;
michael@0 60 }
michael@0 61
michael@0 62 void convertBoolToInt32(Register source, Register dest);
michael@0 63 void convertInt32ToDouble(const Register &src, const FloatRegister &dest);
michael@0 64 void convertInt32ToDouble(const Address &src, FloatRegister dest);
michael@0 65 void convertUInt32ToFloat32(const Register &src, const FloatRegister &dest);
michael@0 66 void convertUInt32ToDouble(const Register &src, const FloatRegister &dest);
michael@0 67 void convertDoubleToFloat32(const FloatRegister &src, const FloatRegister &dest,
michael@0 68 Condition c = Always);
michael@0 69 void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail);
michael@0 70 void convertDoubleToInt32(const FloatRegister &src, const Register &dest, Label *fail,
michael@0 71 bool negativeZeroCheck = true);
michael@0 72 void convertFloat32ToInt32(const FloatRegister &src, const Register &dest, Label *fail,
michael@0 73 bool negativeZeroCheck = true);
michael@0 74
michael@0 75 void convertFloat32ToDouble(const FloatRegister &src, const FloatRegister &dest);
michael@0 76 void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail);
michael@0 77 void convertInt32ToFloat32(const Register &src, const FloatRegister &dest);
michael@0 78 void convertInt32ToFloat32(const Address &src, FloatRegister dest);
michael@0 79
michael@0 80 void addDouble(FloatRegister src, FloatRegister dest);
michael@0 81 void subDouble(FloatRegister src, FloatRegister dest);
michael@0 82 void mulDouble(FloatRegister src, FloatRegister dest);
michael@0 83 void divDouble(FloatRegister src, FloatRegister dest);
michael@0 84
michael@0 85 void negateDouble(FloatRegister reg);
michael@0 86 void inc64(AbsoluteAddress dest);
michael@0 87
michael@0 88 // somewhat direct wrappers for the low-level assembler funcitons
michael@0 89 // bitops
michael@0 90 // attempt to encode a virtual alu instruction using
michael@0 91 // two real instructions.
michael@0 92 private:
michael@0 93 bool alu_dbl(Register src1, Imm32 imm, Register dest, ALUOp op,
michael@0 94 SetCond_ sc, Condition c);
michael@0 95
michael@0 96 public:
michael@0 97 void ma_alu(Register src1, Operand2 op2, Register dest, ALUOp op,
michael@0 98 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 99 void ma_alu(Register src1, Imm32 imm, Register dest,
michael@0 100 ALUOp op,
michael@0 101 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 102
michael@0 103 void ma_alu(Register src1, Operand op2, Register dest, ALUOp op,
michael@0 104 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 105 void ma_nop();
michael@0 106 void ma_movPatchable(Imm32 imm, Register dest, Assembler::Condition c,
michael@0 107 RelocStyle rs, Instruction *i = nullptr);
michael@0 108 void ma_movPatchable(ImmPtr imm, Register dest, Assembler::Condition c,
michael@0 109 RelocStyle rs, Instruction *i = nullptr);
michael@0 110 // These should likely be wrapped up as a set of macros
michael@0 111 // or something like that. I cannot think of a good reason
michael@0 112 // to explicitly have all of this code.
michael@0 113 // ALU based ops
michael@0 114 // mov
michael@0 115 void ma_mov(Register src, Register dest,
michael@0 116 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 117
michael@0 118 void ma_mov(Imm32 imm, Register dest,
michael@0 119 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 120 void ma_mov(ImmWord imm, Register dest,
michael@0 121 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 122
michael@0 123 void ma_mov(const ImmGCPtr &ptr, Register dest);
michael@0 124
michael@0 125 // Shifts (just a move with a shifting op2)
michael@0 126 void ma_lsl(Imm32 shift, Register src, Register dst);
michael@0 127 void ma_lsr(Imm32 shift, Register src, Register dst);
michael@0 128 void ma_asr(Imm32 shift, Register src, Register dst);
michael@0 129 void ma_ror(Imm32 shift, Register src, Register dst);
michael@0 130 void ma_rol(Imm32 shift, Register src, Register dst);
michael@0 131 // Shifts (just a move with a shifting op2)
michael@0 132 void ma_lsl(Register shift, Register src, Register dst);
michael@0 133 void ma_lsr(Register shift, Register src, Register dst);
michael@0 134 void ma_asr(Register shift, Register src, Register dst);
michael@0 135 void ma_ror(Register shift, Register src, Register dst);
michael@0 136 void ma_rol(Register shift, Register src, Register dst);
michael@0 137
michael@0 138 // Move not (dest <- ~src)
michael@0 139 void ma_mvn(Imm32 imm, Register dest,
michael@0 140 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 141
michael@0 142
michael@0 143 void ma_mvn(Register src1, Register dest,
michael@0 144 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 145
michael@0 146 // Negate (dest <- -src) implemented as rsb dest, src, 0
michael@0 147 void ma_neg(Register src, Register dest,
michael@0 148 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 149
michael@0 150 // and
michael@0 151 void ma_and(Register src, Register dest,
michael@0 152 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 153
michael@0 154 void ma_and(Register src1, Register src2, Register dest,
michael@0 155 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 156
michael@0 157 void ma_and(Imm32 imm, Register dest,
michael@0 158 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 159
michael@0 160 void ma_and(Imm32 imm, Register src1, Register dest,
michael@0 161 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 162
michael@0 163
michael@0 164
michael@0 165 // bit clear (dest <- dest & ~imm) or (dest <- src1 & ~src2)
michael@0 166 void ma_bic(Imm32 imm, Register dest,
michael@0 167 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 168
michael@0 169 // exclusive or
michael@0 170 void ma_eor(Register src, Register dest,
michael@0 171 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 172
michael@0 173 void ma_eor(Register src1, Register src2, Register dest,
michael@0 174 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 175
michael@0 176 void ma_eor(Imm32 imm, Register dest,
michael@0 177 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 178
michael@0 179 void ma_eor(Imm32 imm, Register src1, Register dest,
michael@0 180 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 181
michael@0 182
michael@0 183 // or
michael@0 184 void ma_orr(Register src, Register dest,
michael@0 185 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 186
michael@0 187 void ma_orr(Register src1, Register src2, Register dest,
michael@0 188 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 189
michael@0 190 void ma_orr(Imm32 imm, Register dest,
michael@0 191 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 192
michael@0 193 void ma_orr(Imm32 imm, Register src1, Register dest,
michael@0 194 SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 195
michael@0 196
michael@0 197 // arithmetic based ops
michael@0 198 // add with carry
michael@0 199 void ma_adc(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 200 void ma_adc(Register src, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 201 void ma_adc(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 202
michael@0 203 // add
michael@0 204 void ma_add(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 205 void ma_add(Register src1, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 206 void ma_add(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 207 void ma_add(Register src1, Operand op, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 208 void ma_add(Register src1, Imm32 op, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 209
michael@0 210 // subtract with carry
michael@0 211 void ma_sbc(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 212 void ma_sbc(Register src1, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 213 void ma_sbc(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 214
michael@0 215 // subtract
michael@0 216 void ma_sub(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 217 void ma_sub(Register src1, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 218 void ma_sub(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 219 void ma_sub(Register src1, Operand op, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 220 void ma_sub(Register src1, Imm32 op, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 221
michael@0 222 // reverse subtract
michael@0 223 void ma_rsb(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 224 void ma_rsb(Register src1, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 225 void ma_rsb(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 226 void ma_rsb(Register src1, Imm32 op2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 227
michael@0 228 // reverse subtract with carry
michael@0 229 void ma_rsc(Imm32 imm, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 230 void ma_rsc(Register src1, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 231 void ma_rsc(Register src1, Register src2, Register dest, SetCond_ sc = NoSetCond, Condition c = Always);
michael@0 232
michael@0 233 // compares/tests
michael@0 234 // compare negative (sets condition codes as src1 + src2 would)
michael@0 235 void ma_cmn(Register src1, Imm32 imm, Condition c = Always);
michael@0 236 void ma_cmn(Register src1, Register src2, Condition c = Always);
michael@0 237 void ma_cmn(Register src1, Operand op, Condition c = Always);
michael@0 238
michael@0 239 // compare (src - src2)
michael@0 240 void ma_cmp(Register src1, Imm32 imm, Condition c = Always);
michael@0 241 void ma_cmp(Register src1, ImmWord ptr, Condition c = Always);
michael@0 242 void ma_cmp(Register src1, ImmGCPtr ptr, Condition c = Always);
michael@0 243 void ma_cmp(Register src1, Operand op, Condition c = Always);
michael@0 244 void ma_cmp(Register src1, Register src2, Condition c = Always);
michael@0 245
michael@0 246
michael@0 247 // test for equality, (src1^src2)
michael@0 248 void ma_teq(Register src1, Imm32 imm, Condition c = Always);
michael@0 249 void ma_teq(Register src1, Register src2, Condition c = Always);
michael@0 250 void ma_teq(Register src1, Operand op, Condition c = Always);
michael@0 251
michael@0 252
michael@0 253 // test (src1 & src2)
michael@0 254 void ma_tst(Register src1, Imm32 imm, Condition c = Always);
michael@0 255 void ma_tst(Register src1, Register src2, Condition c = Always);
michael@0 256 void ma_tst(Register src1, Operand op, Condition c = Always);
michael@0 257
michael@0 258 // multiplies. For now, there are only two that we care about.
michael@0 259 void ma_mul(Register src1, Register src2, Register dest);
michael@0 260 void ma_mul(Register src1, Imm32 imm, Register dest);
michael@0 261 Condition ma_check_mul(Register src1, Register src2, Register dest, Condition cond);
michael@0 262 Condition ma_check_mul(Register src1, Imm32 imm, Register dest, Condition cond);
michael@0 263
michael@0 264 // fast mod, uses scratch registers, and thus needs to be in the assembler
michael@0 265 // implicitly assumes that we can overwrite dest at the beginning of the sequence
michael@0 266 void ma_mod_mask(Register src, Register dest, Register hold, Register tmp,
michael@0 267 int32_t shift);
michael@0 268
michael@0 269 // mod, depends on integer divide instructions being supported
michael@0 270 void ma_smod(Register num, Register div, Register dest);
michael@0 271 void ma_umod(Register num, Register div, Register dest);
michael@0 272
michael@0 273 // division, depends on integer divide instructions being supported
michael@0 274 void ma_sdiv(Register num, Register div, Register dest, Condition cond = Always);
michael@0 275 void ma_udiv(Register num, Register div, Register dest, Condition cond = Always);
michael@0 276
michael@0 277 // memory
michael@0 278 // shortcut for when we know we're transferring 32 bits of data
michael@0 279 void ma_dtr(LoadStore ls, Register rn, Imm32 offset, Register rt,
michael@0 280 Index mode = Offset, Condition cc = Always);
michael@0 281
michael@0 282 void ma_dtr(LoadStore ls, Register rn, Register rm, Register rt,
michael@0 283 Index mode = Offset, Condition cc = Always);
michael@0 284
michael@0 285
michael@0 286 void ma_str(Register rt, DTRAddr addr, Index mode = Offset, Condition cc = Always);
michael@0 287 void ma_str(Register rt, const Operand &addr, Index mode = Offset, Condition cc = Always);
michael@0 288 void ma_dtr(LoadStore ls, Register rt, const Operand &addr, Index mode, Condition cc);
michael@0 289
michael@0 290 void ma_ldr(DTRAddr addr, Register rt, Index mode = Offset, Condition cc = Always);
michael@0 291 void ma_ldr(const Operand &addr, Register rt, Index mode = Offset, Condition cc = Always);
michael@0 292
michael@0 293 void ma_ldrb(DTRAddr addr, Register rt, Index mode = Offset, Condition cc = Always);
michael@0 294 void ma_ldrh(EDtrAddr addr, Register rt, Index mode = Offset, Condition cc = Always);
michael@0 295 void ma_ldrsh(EDtrAddr addr, Register rt, Index mode = Offset, Condition cc = Always);
michael@0 296 void ma_ldrsb(EDtrAddr addr, Register rt, Index mode = Offset, Condition cc = Always);
michael@0 297 void ma_ldrd(EDtrAddr addr, Register rt, DebugOnly<Register> rt2, Index mode = Offset, Condition cc = Always);
michael@0 298 void ma_strb(Register rt, DTRAddr addr, Index mode = Offset, Condition cc = Always);
michael@0 299 void ma_strh(Register rt, EDtrAddr addr, Index mode = Offset, Condition cc = Always);
michael@0 300 void ma_strd(Register rt, DebugOnly<Register> rt2, EDtrAddr addr, Index mode = Offset, Condition cc = Always);
michael@0 301 // specialty for moving N bits of data, where n == 8,16,32,64
michael@0 302 BufferOffset ma_dataTransferN(LoadStore ls, int size, bool IsSigned,
michael@0 303 Register rn, Register rm, Register rt,
michael@0 304 Index mode = Offset, Condition cc = Always, unsigned scale = TimesOne);
michael@0 305
michael@0 306 BufferOffset ma_dataTransferN(LoadStore ls, int size, bool IsSigned,
michael@0 307 Register rn, Imm32 offset, Register rt,
michael@0 308 Index mode = Offset, Condition cc = Always);
michael@0 309 void ma_pop(Register r);
michael@0 310 void ma_push(Register r);
michael@0 311
michael@0 312 void ma_vpop(VFPRegister r);
michael@0 313 void ma_vpush(VFPRegister r);
michael@0 314
michael@0 315 // branches when done from within arm-specific code
michael@0 316 BufferOffset ma_b(Label *dest, Condition c = Always, bool isPatchable = false);
michael@0 317 void ma_bx(Register dest, Condition c = Always);
michael@0 318
michael@0 319 void ma_b(void *target, Relocation::Kind reloc, Condition c = Always);
michael@0 320
michael@0 321 // this is almost NEVER necessary, we'll basically never be calling a label
michael@0 322 // except, possibly in the crazy bailout-table case.
michael@0 323 void ma_bl(Label *dest, Condition c = Always);
michael@0 324
michael@0 325 void ma_blx(Register dest, Condition c = Always);
michael@0 326
michael@0 327 //VFP/ALU
michael@0 328 void ma_vadd(FloatRegister src1, FloatRegister src2, FloatRegister dst);
michael@0 329 void ma_vsub(FloatRegister src1, FloatRegister src2, FloatRegister dst);
michael@0 330
michael@0 331 void ma_vmul(FloatRegister src1, FloatRegister src2, FloatRegister dst);
michael@0 332 void ma_vdiv(FloatRegister src1, FloatRegister src2, FloatRegister dst);
michael@0 333
michael@0 334 void ma_vneg(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 335 void ma_vmov(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 336 void ma_vmov_f32(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 337 void ma_vabs(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 338 void ma_vabs_f32(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 339
michael@0 340 void ma_vsqrt(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 341 void ma_vsqrt_f32(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 342
michael@0 343 void ma_vimm(double value, FloatRegister dest, Condition cc = Always);
michael@0 344 void ma_vimm_f32(float value, FloatRegister dest, Condition cc = Always);
michael@0 345
michael@0 346 void ma_vcmp(FloatRegister src1, FloatRegister src2, Condition cc = Always);
michael@0 347 void ma_vcmp_f32(FloatRegister src1, FloatRegister src2, Condition cc = Always);
michael@0 348 void ma_vcmpz(FloatRegister src1, Condition cc = Always);
michael@0 349 void ma_vcmpz_f32(FloatRegister src1, Condition cc = Always);
michael@0 350
michael@0 351 void ma_vadd_f32(FloatRegister src1, FloatRegister src2, FloatRegister dst);
michael@0 352 void ma_vsub_f32(FloatRegister src1, FloatRegister src2, FloatRegister dst);
michael@0 353
michael@0 354 void ma_vmul_f32(FloatRegister src1, FloatRegister src2, FloatRegister dst);
michael@0 355 void ma_vdiv_f32(FloatRegister src1, FloatRegister src2, FloatRegister dst);
michael@0 356
michael@0 357 void ma_vneg_f32(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 358
michael@0 359 // source is F64, dest is I32
michael@0 360 void ma_vcvt_F64_I32(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 361 void ma_vcvt_F64_U32(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 362
michael@0 363 // source is I32, dest is F64
michael@0 364 void ma_vcvt_I32_F64(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 365 void ma_vcvt_U32_F64(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 366
michael@0 367 // source is F32, dest is I32
michael@0 368 void ma_vcvt_F32_I32(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 369 void ma_vcvt_F32_U32(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 370
michael@0 371 // source is I32, dest is F32
michael@0 372 void ma_vcvt_I32_F32(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 373 void ma_vcvt_U32_F32(FloatRegister src, FloatRegister dest, Condition cc = Always);
michael@0 374
michael@0 375 void ma_vxfer(FloatRegister src, Register dest, Condition cc = Always);
michael@0 376 void ma_vxfer(FloatRegister src, Register dest1, Register dest2, Condition cc = Always);
michael@0 377
michael@0 378 void ma_vxfer(VFPRegister src, Register dest, Condition cc = Always);
michael@0 379 void ma_vxfer(VFPRegister src, Register dest1, Register dest2, Condition cc = Always);
michael@0 380
michael@0 381 void ma_vxfer(Register src1, Register src2, FloatRegister dest, Condition cc = Always);
michael@0 382
michael@0 383 BufferOffset ma_vdtr(LoadStore ls, const Operand &addr, VFPRegister dest, Condition cc = Always);
michael@0 384
michael@0 385
michael@0 386 BufferOffset ma_vldr(VFPAddr addr, VFPRegister dest, Condition cc = Always);
michael@0 387 BufferOffset ma_vldr(const Operand &addr, VFPRegister dest, Condition cc = Always);
michael@0 388 BufferOffset ma_vldr(VFPRegister src, Register base, Register index, int32_t shift = defaultShift, Condition cc = Always);
michael@0 389
michael@0 390 BufferOffset ma_vstr(VFPRegister src, VFPAddr addr, Condition cc = Always);
michael@0 391 BufferOffset ma_vstr(VFPRegister src, const Operand &addr, Condition cc = Always);
michael@0 392
michael@0 393 BufferOffset ma_vstr(VFPRegister src, Register base, Register index, int32_t shift = defaultShift, Condition cc = Always);
michael@0 394 // calls an Ion function, assumes that the stack is untouched (8 byte alinged)
michael@0 395 void ma_callIon(const Register reg);
michael@0 396 // callso an Ion function, assuming that sp has already been decremented
michael@0 397 void ma_callIonNoPush(const Register reg);
michael@0 398 // calls an ion function, assuming that the stack is currently not 8 byte aligned
michael@0 399 void ma_callIonHalfPush(const Register reg);
michael@0 400
michael@0 401 void ma_call(ImmPtr dest);
michael@0 402
michael@0 403 // calls reg, storing the return address into sp[0]
michael@0 404 void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes);
michael@0 405
michael@0 406 // Float registers can only be loaded/stored in continuous runs
michael@0 407 // when using vstm/vldm.
michael@0 408 // This function breaks set into continuous runs and loads/stores
michael@0 409 // them at [rm]. rm will be modified and left in a state logically
michael@0 410 // suitable for the next load/store.
michael@0 411 // Returns the offset from [dm] for the logical next load/store.
michael@0 412 int32_t transferMultipleByRuns(FloatRegisterSet set, LoadStore ls,
michael@0 413 Register rm, DTMMode mode)
michael@0 414 {
michael@0 415 if (mode == IA) {
michael@0 416 return transferMultipleByRunsImpl
michael@0 417 <FloatRegisterForwardIterator>(set, ls, rm, mode, 1);
michael@0 418 }
michael@0 419 if (mode == DB) {
michael@0 420 return transferMultipleByRunsImpl
michael@0 421 <FloatRegisterBackwardIterator>(set, ls, rm, mode, -1);
michael@0 422 }
michael@0 423 MOZ_ASSUME_UNREACHABLE("Invalid data transfer addressing mode");
michael@0 424 }
michael@0 425
michael@0 426 private:
michael@0 427 // Implementation for transferMultipleByRuns so we can use different
michael@0 428 // iterators for forward/backward traversals.
michael@0 429 // The sign argument should be 1 if we traverse forwards, -1 if we
michael@0 430 // traverse backwards.
michael@0 431 template<typename RegisterIterator> int32_t
michael@0 432 transferMultipleByRunsImpl(FloatRegisterSet set, LoadStore ls,
michael@0 433 Register rm, DTMMode mode, int32_t sign)
michael@0 434 {
michael@0 435 JS_ASSERT(sign == 1 || sign == -1);
michael@0 436
michael@0 437 int32_t delta = sign * sizeof(double);
michael@0 438 int32_t offset = 0;
michael@0 439 RegisterIterator iter(set);
michael@0 440 while (iter.more()) {
michael@0 441 startFloatTransferM(ls, rm, mode, WriteBack);
michael@0 442 int32_t reg = (*iter).code_;
michael@0 443 do {
michael@0 444 offset += delta;
michael@0 445 transferFloatReg(*iter);
michael@0 446 } while ((++iter).more() && (*iter).code_ == (reg += sign));
michael@0 447 finishFloatTransfer();
michael@0 448 }
michael@0 449
michael@0 450 JS_ASSERT(offset == static_cast<int32_t>(set.size() * sizeof(double)) * sign);
michael@0 451 return offset;
michael@0 452 }
michael@0 453 };
michael@0 454
michael@0 455 class MacroAssemblerARMCompat : public MacroAssemblerARM
michael@0 456 {
michael@0 457 // Number of bytes the stack is adjusted inside a call to C. Calls to C may
michael@0 458 // not be nested.
michael@0 459 bool inCall_;
michael@0 460 uint32_t args_;
michael@0 461 // The actual number of arguments that were passed, used to assert that
michael@0 462 // the initial number of arguments declared was correct.
michael@0 463 uint32_t passedArgs_;
michael@0 464 uint32_t passedArgTypes_;
michael@0 465
michael@0 466 // ARM treats arguments as a vector in registers/memory, that looks like:
michael@0 467 // { r0, r1, r2, r3, [sp], [sp,+4], [sp,+8] ... }
michael@0 468 // usedIntSlots_ keeps track of how many of these have been used.
michael@0 469 // It bears a passing resemblance to passedArgs_, but a single argument
michael@0 470 // can effectively use between one and three slots depending on its size and
michael@0 471 // alignment requirements
michael@0 472 uint32_t usedIntSlots_;
michael@0 473 #if defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_ARM_SIMULATOR)
michael@0 474 uint32_t usedFloatSlots_;
michael@0 475 bool usedFloat32_;
michael@0 476 uint32_t padding_;
michael@0 477 #endif
michael@0 478 bool dynamicAlignment_;
michael@0 479
michael@0 480 bool enoughMemory_;
michael@0 481
michael@0 482 // Used to work around the move resolver's lack of support for
michael@0 483 // moving into register pairs, which the softfp ABI needs.
michael@0 484 mozilla::Array<MoveOperand, 2> floatArgsInGPR;
michael@0 485 mozilla::Array<bool, 2> floatArgsInGPRValid;
michael@0 486
michael@0 487 // Compute space needed for the function call and set the properties of the
michael@0 488 // callee. It returns the space which has to be allocated for calling the
michael@0 489 // function.
michael@0 490 //
michael@0 491 // arg Number of arguments of the function.
michael@0 492 void setupABICall(uint32_t arg);
michael@0 493
michael@0 494 protected:
michael@0 495 MoveResolver moveResolver_;
michael@0 496
michael@0 497 // Extra bytes currently pushed onto the frame beyond frameDepth_. This is
michael@0 498 // needed to compute offsets to stack slots while temporary space has been
michael@0 499 // reserved for unexpected spills or C++ function calls. It is maintained
michael@0 500 // by functions which track stack alignment, which for clear distinction
michael@0 501 // use StudlyCaps (for example, Push, Pop).
michael@0 502 uint32_t framePushed_;
michael@0 503 void adjustFrame(int value) {
michael@0 504 setFramePushed(framePushed_ + value);
michael@0 505 }
michael@0 506 public:
michael@0 507 MacroAssemblerARMCompat()
michael@0 508 : inCall_(false),
michael@0 509 enoughMemory_(true),
michael@0 510 framePushed_(0)
michael@0 511 { }
michael@0 512 bool oom() const {
michael@0 513 return Assembler::oom() || !enoughMemory_;
michael@0 514 }
michael@0 515
michael@0 516 public:
michael@0 517 using MacroAssemblerARM::call;
michael@0 518
michael@0 519 // jumps + other functions that should be called from
michael@0 520 // non-arm specific code...
michael@0 521 // basically, an x86 front end on top of the ARM code.
michael@0 522 void j(Condition code , Label *dest)
michael@0 523 {
michael@0 524 as_b(dest, code);
michael@0 525 }
michael@0 526 void j(Label *dest)
michael@0 527 {
michael@0 528 as_b(dest, Always);
michael@0 529 }
michael@0 530
michael@0 531 void mov(Register src, Register dest) {
michael@0 532 ma_mov(src, dest);
michael@0 533 }
michael@0 534 void mov(ImmWord imm, Register dest) {
michael@0 535 ma_mov(Imm32(imm.value), dest);
michael@0 536 }
michael@0 537 void mov(ImmPtr imm, Register dest) {
michael@0 538 mov(ImmWord(uintptr_t(imm.value)), dest);
michael@0 539 }
michael@0 540 void mov(Register src, Address dest) {
michael@0 541 MOZ_ASSUME_UNREACHABLE("NYI-IC");
michael@0 542 }
michael@0 543 void mov(Address src, Register dest) {
michael@0 544 MOZ_ASSUME_UNREACHABLE("NYI-IC");
michael@0 545 }
michael@0 546
michael@0 547 void call(const Register reg) {
michael@0 548 as_blx(reg);
michael@0 549 }
michael@0 550 void call(Label *label) {
michael@0 551 // for now, assume that it'll be nearby?
michael@0 552 as_bl(label, Always);
michael@0 553 }
michael@0 554 void call(ImmWord imm) {
michael@0 555 call(ImmPtr((void*)imm.value));
michael@0 556 }
michael@0 557 void call(ImmPtr imm) {
michael@0 558 BufferOffset bo = m_buffer.nextOffset();
michael@0 559 addPendingJump(bo, imm, Relocation::HARDCODED);
michael@0 560 ma_call(imm);
michael@0 561 }
michael@0 562 void call(AsmJSImmPtr imm) {
michael@0 563 movePtr(imm, CallReg);
michael@0 564 call(CallReg);
michael@0 565 }
michael@0 566 void call(JitCode *c) {
michael@0 567 BufferOffset bo = m_buffer.nextOffset();
michael@0 568 addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
michael@0 569 RelocStyle rs;
michael@0 570 if (hasMOVWT())
michael@0 571 rs = L_MOVWT;
michael@0 572 else
michael@0 573 rs = L_LDR;
michael@0 574
michael@0 575 ma_movPatchable(ImmPtr(c->raw()), ScratchRegister, Always, rs);
michael@0 576 ma_callIonHalfPush(ScratchRegister);
michael@0 577 }
michael@0 578
michael@0 579 void appendCallSite(const CallSiteDesc &desc) {
michael@0 580 enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_));
michael@0 581 }
michael@0 582
michael@0 583 void call(const CallSiteDesc &desc, const Register reg) {
michael@0 584 call(reg);
michael@0 585 appendCallSite(desc);
michael@0 586 }
michael@0 587 void call(const CallSiteDesc &desc, Label *label) {
michael@0 588 call(label);
michael@0 589 appendCallSite(desc);
michael@0 590 }
michael@0 591 void call(const CallSiteDesc &desc, AsmJSImmPtr imm) {
michael@0 592 call(imm);
michael@0 593 appendCallSite(desc);
michael@0 594 }
michael@0 595 void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) {
michael@0 596 movePtr(imm, CallReg);
michael@0 597 ma_callAndStoreRet(CallReg, stackArgBytes);
michael@0 598 appendCallSite(CallSiteDesc::Exit());
michael@0 599 }
michael@0 600 void callIonFromAsmJS(const Register reg) {
michael@0 601 ma_callIonNoPush(reg);
michael@0 602 appendCallSite(CallSiteDesc::Exit());
michael@0 603
michael@0 604 // The Ion ABI has the callee pop the return address off the stack.
michael@0 605 // The asm.js caller assumes that the call leaves sp unchanged, so bump
michael@0 606 // the stack.
michael@0 607 subPtr(Imm32(sizeof(void*)), sp);
michael@0 608 }
michael@0 609
michael@0 610 void branch(JitCode *c) {
michael@0 611 BufferOffset bo = m_buffer.nextOffset();
michael@0 612 addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
michael@0 613 RelocStyle rs;
michael@0 614 if (hasMOVWT())
michael@0 615 rs = L_MOVWT;
michael@0 616 else
michael@0 617 rs = L_LDR;
michael@0 618
michael@0 619 ma_movPatchable(ImmPtr(c->raw()), ScratchRegister, Always, rs);
michael@0 620 ma_bx(ScratchRegister);
michael@0 621 }
michael@0 622 void branch(const Register reg) {
michael@0 623 ma_bx(reg);
michael@0 624 }
michael@0 625 void nop() {
michael@0 626 ma_nop();
michael@0 627 }
michael@0 628 void ret() {
michael@0 629 ma_pop(pc);
michael@0 630 m_buffer.markGuard();
michael@0 631 }
michael@0 632 void retn(Imm32 n) {
michael@0 633 // pc <- [sp]; sp += n
michael@0 634 ma_dtr(IsLoad, sp, n, pc, PostIndex);
michael@0 635 m_buffer.markGuard();
michael@0 636 }
michael@0 637 void push(Imm32 imm) {
michael@0 638 ma_mov(imm, ScratchRegister);
michael@0 639 ma_push(ScratchRegister);
michael@0 640 }
michael@0 641 void push(ImmWord imm) {
michael@0 642 push(Imm32(imm.value));
michael@0 643 }
michael@0 644 void push(ImmGCPtr imm) {
michael@0 645 ma_mov(imm, ScratchRegister);
michael@0 646 ma_push(ScratchRegister);
michael@0 647 }
michael@0 648 void push(const Address &address) {
michael@0 649 ma_ldr(Operand(address.base, address.offset), ScratchRegister);
michael@0 650 ma_push(ScratchRegister);
michael@0 651 }
michael@0 652 void push(const Register &reg) {
michael@0 653 ma_push(reg);
michael@0 654 }
michael@0 655 void push(const FloatRegister &reg) {
michael@0 656 ma_vpush(VFPRegister(reg));
michael@0 657 }
michael@0 658 void pushWithPadding(const Register &reg, const Imm32 extraSpace) {
michael@0 659 Imm32 totSpace = Imm32(extraSpace.value + 4);
michael@0 660 ma_dtr(IsStore, sp, totSpace, reg, PreIndex);
michael@0 661 }
michael@0 662 void pushWithPadding(const Imm32 &imm, const Imm32 extraSpace) {
michael@0 663 Imm32 totSpace = Imm32(extraSpace.value + 4);
michael@0 664 // ma_dtr may need the scratch register to adjust the stack, so use the
michael@0 665 // second scratch register.
michael@0 666 ma_mov(imm, secondScratchReg_);
michael@0 667 ma_dtr(IsStore, sp, totSpace, secondScratchReg_, PreIndex);
michael@0 668 }
michael@0 669
michael@0 670 void pop(const Register &reg) {
michael@0 671 ma_pop(reg);
michael@0 672 }
michael@0 673 void pop(const FloatRegister &reg) {
michael@0 674 ma_vpop(VFPRegister(reg));
michael@0 675 }
michael@0 676
michael@0 677 void popN(const Register &reg, Imm32 extraSpace) {
michael@0 678 Imm32 totSpace = Imm32(extraSpace.value + 4);
michael@0 679 ma_dtr(IsLoad, sp, totSpace, reg, PostIndex);
michael@0 680 }
michael@0 681
michael@0 682 CodeOffsetLabel toggledJump(Label *label);
michael@0 683
michael@0 684 // Emit a BLX or NOP instruction. ToggleCall can be used to patch
michael@0 685 // this instruction.
michael@0 686 CodeOffsetLabel toggledCall(JitCode *target, bool enabled);
michael@0 687
michael@0 688 static size_t ToggledCallSize() {
michael@0 689 if (hasMOVWT())
michael@0 690 // Size of a movw, movt, nop/blx instruction.
michael@0 691 return 12;
michael@0 692 // Size of a ldr, nop/blx instruction
michael@0 693 return 8;
michael@0 694 }
michael@0 695
michael@0 696 CodeOffsetLabel pushWithPatch(ImmWord imm) {
michael@0 697 CodeOffsetLabel label = movWithPatch(imm, ScratchRegister);
michael@0 698 ma_push(ScratchRegister);
michael@0 699 return label;
michael@0 700 }
michael@0 701
michael@0 702 CodeOffsetLabel movWithPatch(ImmWord imm, Register dest) {
michael@0 703 CodeOffsetLabel label = currentOffset();
michael@0 704 ma_movPatchable(Imm32(imm.value), dest, Always, hasMOVWT() ? L_MOVWT : L_LDR);
michael@0 705 return label;
michael@0 706 }
michael@0 707 CodeOffsetLabel movWithPatch(ImmPtr imm, Register dest) {
michael@0 708 return movWithPatch(ImmWord(uintptr_t(imm.value)), dest);
michael@0 709 }
michael@0 710
michael@0 711 void jump(Label *label) {
michael@0 712 as_b(label);
michael@0 713 }
michael@0 714 void jump(Register reg) {
michael@0 715 ma_bx(reg);
michael@0 716 }
michael@0 717 void jump(const Address &address) {
michael@0 718 ma_ldr(Operand(address.base, address.offset), ScratchRegister);
michael@0 719 ma_bx(ScratchRegister);
michael@0 720 }
michael@0 721
michael@0 722 void neg32(Register reg) {
michael@0 723 ma_neg(reg, reg, SetCond);
michael@0 724 }
michael@0 725 void negl(Register reg) {
michael@0 726 ma_neg(reg, reg, SetCond);
michael@0 727 }
michael@0 728 void test32(Register lhs, Register rhs) {
michael@0 729 ma_tst(lhs, rhs);
michael@0 730 }
michael@0 731 void test32(Register lhs, Imm32 imm) {
michael@0 732 ma_tst(lhs, imm);
michael@0 733 }
michael@0 734 void test32(const Address &address, Imm32 imm) {
michael@0 735 ma_ldr(Operand(address.base, address.offset), ScratchRegister);
michael@0 736 ma_tst(ScratchRegister, imm);
michael@0 737 }
michael@0 738 void testPtr(Register lhs, Register rhs) {
michael@0 739 test32(lhs, rhs);
michael@0 740 }
michael@0 741
michael@0 742 // Returns the register containing the type tag.
michael@0 743 Register splitTagForTest(const ValueOperand &value) {
michael@0 744 return value.typeReg();
michael@0 745 }
michael@0 746
michael@0 747 // higher level tag testing code
michael@0 748 Condition testInt32(Condition cond, const ValueOperand &value);
michael@0 749 Condition testBoolean(Condition cond, const ValueOperand &value);
michael@0 750 Condition testDouble(Condition cond, const ValueOperand &value);
michael@0 751 Condition testNull(Condition cond, const ValueOperand &value);
michael@0 752 Condition testUndefined(Condition cond, const ValueOperand &value);
michael@0 753 Condition testString(Condition cond, const ValueOperand &value);
michael@0 754 Condition testObject(Condition cond, const ValueOperand &value);
michael@0 755 Condition testNumber(Condition cond, const ValueOperand &value);
michael@0 756 Condition testMagic(Condition cond, const ValueOperand &value);
michael@0 757
michael@0 758 Condition testPrimitive(Condition cond, const ValueOperand &value);
michael@0 759
michael@0 760 // register-based tests
michael@0 761 Condition testInt32(Condition cond, const Register &tag);
michael@0 762 Condition testBoolean(Condition cond, const Register &tag);
michael@0 763 Condition testNull(Condition cond, const Register &tag);
michael@0 764 Condition testUndefined(Condition cond, const Register &tag);
michael@0 765 Condition testString(Condition cond, const Register &tag);
michael@0 766 Condition testObject(Condition cond, const Register &tag);
michael@0 767 Condition testDouble(Condition cond, const Register &tag);
michael@0 768 Condition testNumber(Condition cond, const Register &tag);
michael@0 769 Condition testMagic(Condition cond, const Register &tag);
michael@0 770 Condition testPrimitive(Condition cond, const Register &tag);
michael@0 771
michael@0 772 Condition testGCThing(Condition cond, const Address &address);
michael@0 773 Condition testMagic(Condition cond, const Address &address);
michael@0 774 Condition testInt32(Condition cond, const Address &address);
michael@0 775 Condition testDouble(Condition cond, const Address &address);
michael@0 776 Condition testBoolean(Condition cond, const Address &address);
michael@0 777 Condition testNull(Condition cond, const Address &address);
michael@0 778 Condition testUndefined(Condition cond, const Address &address);
michael@0 779 Condition testString(Condition cond, const Address &address);
michael@0 780 Condition testObject(Condition cond, const Address &address);
michael@0 781 Condition testNumber(Condition cond, const Address &address);
michael@0 782
michael@0 783 Condition testUndefined(Condition cond, const BaseIndex &src);
michael@0 784 Condition testNull(Condition cond, const BaseIndex &src);
michael@0 785 Condition testBoolean(Condition cond, const BaseIndex &src);
michael@0 786 Condition testString(Condition cond, const BaseIndex &src);
michael@0 787 Condition testInt32(Condition cond, const BaseIndex &src);
michael@0 788 Condition testObject(Condition cond, const BaseIndex &src);
michael@0 789 Condition testDouble(Condition cond, const BaseIndex &src);
michael@0 790 Condition testMagic(Condition cond, const BaseIndex &src);
michael@0 791 Condition testGCThing(Condition cond, const BaseIndex &src);
michael@0 792
michael@0 793 template <typename T>
michael@0 794 void branchTestGCThing(Condition cond, const T &t, Label *label) {
michael@0 795 Condition c = testGCThing(cond, t);
michael@0 796 ma_b(label, c);
michael@0 797 }
michael@0 798 template <typename T>
michael@0 799 void branchTestPrimitive(Condition cond, const T &t, Label *label) {
michael@0 800 Condition c = testPrimitive(cond, t);
michael@0 801 ma_b(label, c);
michael@0 802 }
michael@0 803
michael@0 804 void branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label);
michael@0 805 void branchTestValue(Condition cond, const Address &valaddr, const ValueOperand &value,
michael@0 806 Label *label);
michael@0 807
michael@0 808 // unboxing code
michael@0 809 void unboxInt32(const ValueOperand &operand, const Register &dest);
michael@0 810 void unboxInt32(const Address &src, const Register &dest);
michael@0 811 void unboxBoolean(const ValueOperand &operand, const Register &dest);
michael@0 812 void unboxBoolean(const Address &src, const Register &dest);
michael@0 813 void unboxDouble(const ValueOperand &operand, const FloatRegister &dest);
michael@0 814 void unboxDouble(const Address &src, const FloatRegister &dest);
michael@0 815 void unboxString(const ValueOperand &operand, const Register &dest);
michael@0 816 void unboxString(const Address &src, const Register &dest);
michael@0 817 void unboxObject(const ValueOperand &src, const Register &dest);
michael@0 818 void unboxValue(const ValueOperand &src, AnyRegister dest);
michael@0 819 void unboxPrivate(const ValueOperand &src, Register dest);
michael@0 820
michael@0 821 void notBoolean(const ValueOperand &val) {
michael@0 822 ma_eor(Imm32(1), val.payloadReg());
michael@0 823 }
michael@0 824
michael@0 825 // boxing code
michael@0 826 void boxDouble(const FloatRegister &src, const ValueOperand &dest);
michael@0 827 void boxNonDouble(JSValueType type, const Register &src, const ValueOperand &dest);
michael@0 828
michael@0 829 // Extended unboxing API. If the payload is already in a register, returns
michael@0 830 // that register. Otherwise, provides a move to the given scratch register,
michael@0 831 // and returns that.
michael@0 832 Register extractObject(const Address &address, Register scratch);
michael@0 833 Register extractObject(const ValueOperand &value, Register scratch) {
michael@0 834 return value.payloadReg();
michael@0 835 }
michael@0 836 Register extractInt32(const ValueOperand &value, Register scratch) {
michael@0 837 return value.payloadReg();
michael@0 838 }
michael@0 839 Register extractBoolean(const ValueOperand &value, Register scratch) {
michael@0 840 return value.payloadReg();
michael@0 841 }
michael@0 842 Register extractTag(const Address &address, Register scratch);
michael@0 843 Register extractTag(const BaseIndex &address, Register scratch);
michael@0 844 Register extractTag(const ValueOperand &value, Register scratch) {
michael@0 845 return value.typeReg();
michael@0 846 }
michael@0 847
michael@0 848 void boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest);
michael@0 849 void int32ValueToDouble(const ValueOperand &operand, const FloatRegister &dest);
michael@0 850 void loadInt32OrDouble(const Operand &src, const FloatRegister &dest);
michael@0 851 void loadInt32OrDouble(Register base, Register index,
michael@0 852 const FloatRegister &dest, int32_t shift = defaultShift);
michael@0 853 void loadConstantDouble(double dp, const FloatRegister &dest);
michael@0 854 // treat the value as a boolean, and set condition codes accordingly
michael@0 855 Condition testInt32Truthy(bool truthy, const ValueOperand &operand);
michael@0 856 Condition testBooleanTruthy(bool truthy, const ValueOperand &operand);
michael@0 857 Condition testDoubleTruthy(bool truthy, const FloatRegister &reg);
michael@0 858 Condition testStringTruthy(bool truthy, const ValueOperand &value);
michael@0 859
michael@0 860 void boolValueToFloat32(const ValueOperand &operand, const FloatRegister &dest);
michael@0 861 void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest);
michael@0 862 void loadConstantFloat32(float f, const FloatRegister &dest);
michael@0 863
michael@0 864 template<typename T>
michael@0 865 void branchTestInt32(Condition cond, const T & t, Label *label) {
michael@0 866 Condition c = testInt32(cond, t);
michael@0 867 ma_b(label, c);
michael@0 868 }
michael@0 869 template<typename T>
michael@0 870 void branchTestBoolean(Condition cond, const T & t, Label *label) {
michael@0 871 Condition c = testBoolean(cond, t);
michael@0 872 ma_b(label, c);
michael@0 873 }
michael@0 874 void branch32(Condition cond, Register lhs, Register rhs, Label *label) {
michael@0 875 ma_cmp(lhs, rhs);
michael@0 876 ma_b(label, cond);
michael@0 877 }
michael@0 878 void branch32(Condition cond, Register lhs, Imm32 imm, Label *label) {
michael@0 879 ma_cmp(lhs, imm);
michael@0 880 ma_b(label, cond);
michael@0 881 }
michael@0 882 void branch32(Condition cond, const Operand &lhs, Register rhs, Label *label) {
michael@0 883 if (lhs.getTag() == Operand::OP2) {
michael@0 884 branch32(cond, lhs.toReg(), rhs, label);
michael@0 885 } else {
michael@0 886 ma_ldr(lhs, ScratchRegister);
michael@0 887 branch32(cond, ScratchRegister, rhs, label);
michael@0 888 }
michael@0 889 }
michael@0 890 void branch32(Condition cond, const Operand &lhs, Imm32 rhs, Label *label) {
michael@0 891 if (lhs.getTag() == Operand::OP2) {
michael@0 892 branch32(cond, lhs.toReg(), rhs, label);
michael@0 893 } else {
michael@0 894 // branch32 will use ScratchRegister.
michael@0 895 ma_ldr(lhs, secondScratchReg_);
michael@0 896 branch32(cond, secondScratchReg_, rhs, label);
michael@0 897 }
michael@0 898 }
michael@0 899 void branch32(Condition cond, const Address &lhs, Register rhs, Label *label) {
michael@0 900 load32(lhs, ScratchRegister);
michael@0 901 branch32(cond, ScratchRegister, rhs, label);
michael@0 902 }
michael@0 903 void branch32(Condition cond, const Address &lhs, Imm32 rhs, Label *label) {
michael@0 904 // branch32 will use ScratchRegister.
michael@0 905 load32(lhs, secondScratchReg_);
michael@0 906 branch32(cond, secondScratchReg_, rhs, label);
michael@0 907 }
michael@0 908 void branchPtr(Condition cond, const Address &lhs, Register rhs, Label *label) {
michael@0 909 branch32(cond, lhs, rhs, label);
michael@0 910 }
michael@0 911
michael@0 912 void branchPrivatePtr(Condition cond, const Address &lhs, ImmPtr ptr, Label *label) {
michael@0 913 branchPtr(cond, lhs, ptr, label);
michael@0 914 }
michael@0 915
michael@0 916 void branchPrivatePtr(Condition cond, const Address &lhs, Register ptr, Label *label) {
michael@0 917 branchPtr(cond, lhs, ptr, label);
michael@0 918 }
michael@0 919
michael@0 920 void branchPrivatePtr(Condition cond, Register lhs, ImmWord ptr, Label *label) {
michael@0 921 branchPtr(cond, lhs, ptr, label);
michael@0 922 }
michael@0 923
michael@0 924 template<typename T>
michael@0 925 void branchTestDouble(Condition cond, const T & t, Label *label) {
michael@0 926 Condition c = testDouble(cond, t);
michael@0 927 ma_b(label, c);
michael@0 928 }
michael@0 929 template<typename T>
michael@0 930 void branchTestNull(Condition cond, const T & t, Label *label) {
michael@0 931 Condition c = testNull(cond, t);
michael@0 932 ma_b(label, c);
michael@0 933 }
michael@0 934 template<typename T>
michael@0 935 void branchTestObject(Condition cond, const T & t, Label *label) {
michael@0 936 Condition c = testObject(cond, t);
michael@0 937 ma_b(label, c);
michael@0 938 }
michael@0 939 template<typename T>
michael@0 940 void branchTestString(Condition cond, const T & t, Label *label) {
michael@0 941 Condition c = testString(cond, t);
michael@0 942 ma_b(label, c);
michael@0 943 }
michael@0 944 template<typename T>
michael@0 945 void branchTestUndefined(Condition cond, const T & t, Label *label) {
michael@0 946 Condition c = testUndefined(cond, t);
michael@0 947 ma_b(label, c);
michael@0 948 }
michael@0 949 template <typename T>
michael@0 950 void branchTestNumber(Condition cond, const T &t, Label *label) {
michael@0 951 cond = testNumber(cond, t);
michael@0 952 ma_b(label, cond);
michael@0 953 }
michael@0 954 template <typename T>
michael@0 955 void branchTestMagic(Condition cond, const T &t, Label *label) {
michael@0 956 cond = testMagic(cond, t);
michael@0 957 ma_b(label, cond);
michael@0 958 }
michael@0 959 void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why,
michael@0 960 Label *label) {
michael@0 961 JS_ASSERT(cond == Equal || cond == NotEqual);
michael@0 962 // Test for magic
michael@0 963 Label notmagic;
michael@0 964 Condition testCond = testMagic(cond, val);
michael@0 965 ma_b(&notmagic, InvertCondition(testCond));
michael@0 966 // Test magic value
michael@0 967 branch32(cond, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label);
michael@0 968 bind(&notmagic);
michael@0 969 }
michael@0 970 void branchTestInt32Truthy(bool truthy, const ValueOperand &operand, Label *label) {
michael@0 971 Condition c = testInt32Truthy(truthy, operand);
michael@0 972 ma_b(label, c);
michael@0 973 }
michael@0 974 void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) {
michael@0 975 Condition c = testBooleanTruthy(truthy, operand);
michael@0 976 ma_b(label, c);
michael@0 977 }
michael@0 978 void branchTestDoubleTruthy(bool truthy, const FloatRegister &reg, Label *label) {
michael@0 979 Condition c = testDoubleTruthy(truthy, reg);
michael@0 980 ma_b(label, c);
michael@0 981 }
michael@0 982 void branchTestStringTruthy(bool truthy, const ValueOperand &value, Label *label) {
michael@0 983 Condition c = testStringTruthy(truthy, value);
michael@0 984 ma_b(label, c);
michael@0 985 }
michael@0 986 void branchTest32(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
michael@0 987 // x86 likes test foo, foo rather than cmp foo, #0.
michael@0 988 // Convert the former into the latter.
michael@0 989 if (lhs == rhs && (cond == Zero || cond == NonZero))
michael@0 990 ma_cmp(lhs, Imm32(0));
michael@0 991 else
michael@0 992 ma_tst(lhs, rhs);
michael@0 993 ma_b(label, cond);
michael@0 994 }
michael@0 995 void branchTest32(Condition cond, const Register &lhs, Imm32 imm, Label *label) {
michael@0 996 ma_tst(lhs, imm);
michael@0 997 ma_b(label, cond);
michael@0 998 }
michael@0 999 void branchTest32(Condition cond, const Address &address, Imm32 imm, Label *label) {
michael@0 1000 // branchTest32 will use ScratchRegister.
michael@0 1001 load32(address, secondScratchReg_);
michael@0 1002 branchTest32(cond, secondScratchReg_, imm, label);
michael@0 1003 }
michael@0 1004 void branchTestPtr(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
michael@0 1005 branchTest32(cond, lhs, rhs, label);
michael@0 1006 }
michael@0 1007 void branchTestPtr(Condition cond, const Register &lhs, const Imm32 rhs, Label *label) {
michael@0 1008 branchTest32(cond, lhs, rhs, label);
michael@0 1009 }
michael@0 1010 void branchTestPtr(Condition cond, const Address &lhs, Imm32 imm, Label *label) {
michael@0 1011 branchTest32(cond, lhs, imm, label);
michael@0 1012 }
michael@0 1013 void branchPtr(Condition cond, Register lhs, Register rhs, Label *label) {
michael@0 1014 branch32(cond, lhs, rhs, label);
michael@0 1015 }
michael@0 1016 void branchPtr(Condition cond, Register lhs, ImmGCPtr ptr, Label *label) {
michael@0 1017 movePtr(ptr, ScratchRegister);
michael@0 1018 branchPtr(cond, lhs, ScratchRegister, label);
michael@0 1019 }
michael@0 1020 void branchPtr(Condition cond, Register lhs, ImmWord imm, Label *label) {
michael@0 1021 branch32(cond, lhs, Imm32(imm.value), label);
michael@0 1022 }
michael@0 1023 void branchPtr(Condition cond, Register lhs, ImmPtr imm, Label *label) {
michael@0 1024 branchPtr(cond, lhs, ImmWord(uintptr_t(imm.value)), label);
michael@0 1025 }
michael@0 1026 void branchPtr(Condition cond, Register lhs, AsmJSImmPtr imm, Label *label) {
michael@0 1027 movePtr(imm, ScratchRegister);
michael@0 1028 branchPtr(cond, lhs, ScratchRegister, label);
michael@0 1029 }
michael@0 1030 void branchPtr(Condition cond, Register lhs, Imm32 imm, Label *label) {
michael@0 1031 branch32(cond, lhs, imm, label);
michael@0 1032 }
michael@0 1033 void decBranchPtr(Condition cond, const Register &lhs, Imm32 imm, Label *label) {
michael@0 1034 subPtr(imm, lhs);
michael@0 1035 branch32(cond, lhs, Imm32(0), label);
michael@0 1036 }
michael@0 1037 void moveValue(const Value &val, Register type, Register data);
michael@0 1038
michael@0 1039 CodeOffsetJump jumpWithPatch(RepatchLabel *label, Condition cond = Always);
michael@0 1040 template <typename T>
michael@0 1041 CodeOffsetJump branchPtrWithPatch(Condition cond, Register reg, T ptr, RepatchLabel *label) {
michael@0 1042 ma_cmp(reg, ptr);
michael@0 1043 return jumpWithPatch(label, cond);
michael@0 1044 }
michael@0 1045 template <typename T>
michael@0 1046 CodeOffsetJump branchPtrWithPatch(Condition cond, Address addr, T ptr, RepatchLabel *label) {
michael@0 1047 ma_ldr(addr, secondScratchReg_);
michael@0 1048 ma_cmp(secondScratchReg_, ptr);
michael@0 1049 return jumpWithPatch(label, cond);
michael@0 1050 }
michael@0 1051 void branchPtr(Condition cond, Address addr, ImmGCPtr ptr, Label *label) {
michael@0 1052 ma_ldr(addr, secondScratchReg_);
michael@0 1053 ma_cmp(secondScratchReg_, ptr);
michael@0 1054 ma_b(label, cond);
michael@0 1055 }
michael@0 1056 void branchPtr(Condition cond, Address addr, ImmWord ptr, Label *label) {
michael@0 1057 ma_ldr(addr, secondScratchReg_);
michael@0 1058 ma_cmp(secondScratchReg_, ptr);
michael@0 1059 ma_b(label, cond);
michael@0 1060 }
michael@0 1061 void branchPtr(Condition cond, Address addr, ImmPtr ptr, Label *label) {
michael@0 1062 branchPtr(cond, addr, ImmWord(uintptr_t(ptr.value)), label);
michael@0 1063 }
michael@0 1064 void branchPtr(Condition cond, const AbsoluteAddress &addr, const Register &ptr, Label *label) {
michael@0 1065 loadPtr(addr, ScratchRegister);
michael@0 1066 ma_cmp(ScratchRegister, ptr);
michael@0 1067 ma_b(label, cond);
michael@0 1068 }
michael@0 1069 void branchPtr(Condition cond, const AsmJSAbsoluteAddress &addr, const Register &ptr, Label *label) {
michael@0 1070 loadPtr(addr, ScratchRegister);
michael@0 1071 ma_cmp(ScratchRegister, ptr);
michael@0 1072 ma_b(label, cond);
michael@0 1073 }
michael@0 1074 void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) {
michael@0 1075 loadPtr(lhs, secondScratchReg_); // ma_cmp will use the scratch register.
michael@0 1076 ma_cmp(secondScratchReg_, rhs);
michael@0 1077 ma_b(label, cond);
michael@0 1078 }
michael@0 1079 void branch32(Condition cond, const AbsoluteAddress &lhs, const Register &rhs, Label *label) {
michael@0 1080 loadPtr(lhs, secondScratchReg_); // ma_cmp will use the scratch register.
michael@0 1081 ma_cmp(secondScratchReg_, rhs);
michael@0 1082 ma_b(label, cond);
michael@0 1083 }
michael@0 1084
michael@0 1085 void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) {
michael@0 1086 if (dest.isFloat())
michael@0 1087 loadInt32OrDouble(Operand(address), dest.fpu());
michael@0 1088 else
michael@0 1089 ma_ldr(address, dest.gpr());
michael@0 1090 }
michael@0 1091
michael@0 1092 void loadUnboxedValue(BaseIndex address, MIRType type, AnyRegister dest) {
michael@0 1093 if (dest.isFloat())
michael@0 1094 loadInt32OrDouble(address.base, address.index, dest.fpu(), address.scale);
michael@0 1095 else
michael@0 1096 load32(address, dest.gpr());
michael@0 1097 }
michael@0 1098
michael@0 1099 void moveValue(const Value &val, const ValueOperand &dest);
michael@0 1100
michael@0 1101 void moveValue(const ValueOperand &src, const ValueOperand &dest) {
michael@0 1102 Register s0 = src.typeReg(), d0 = dest.typeReg(),
michael@0 1103 s1 = src.payloadReg(), d1 = dest.payloadReg();
michael@0 1104
michael@0 1105 // Either one or both of the source registers could be the same as a
michael@0 1106 // destination register.
michael@0 1107 if (s1 == d0) {
michael@0 1108 if (s0 == d1) {
michael@0 1109 // If both are, this is just a swap of two registers.
michael@0 1110 JS_ASSERT(d1 != ScratchRegister);
michael@0 1111 JS_ASSERT(d0 != ScratchRegister);
michael@0 1112 ma_mov(d1, ScratchRegister);
michael@0 1113 ma_mov(d0, d1);
michael@0 1114 ma_mov(ScratchRegister, d0);
michael@0 1115 return;
michael@0 1116 }
michael@0 1117 // If only one is, copy that source first.
michael@0 1118 mozilla::Swap(s0, s1);
michael@0 1119 mozilla::Swap(d0, d1);
michael@0 1120 }
michael@0 1121
michael@0 1122 if (s0 != d0)
michael@0 1123 ma_mov(s0, d0);
michael@0 1124 if (s1 != d1)
michael@0 1125 ma_mov(s1, d1);
michael@0 1126 }
michael@0 1127
michael@0 1128 void storeValue(ValueOperand val, Operand dst);
michael@0 1129 void storeValue(ValueOperand val, const BaseIndex &dest);
michael@0 1130 void storeValue(JSValueType type, Register reg, BaseIndex dest) {
michael@0 1131 // Harder cases not handled yet.
michael@0 1132 JS_ASSERT(dest.offset == 0);
michael@0 1133 ma_alu(dest.base, lsl(dest.index, dest.scale), ScratchRegister, op_add);
michael@0 1134 storeValue(type, reg, Address(ScratchRegister, 0));
michael@0 1135 }
michael@0 1136 void storeValue(ValueOperand val, const Address &dest) {
michael@0 1137 storeValue(val, Operand(dest));
michael@0 1138 }
michael@0 1139 void storeValue(JSValueType type, Register reg, Address dest) {
michael@0 1140 ma_str(reg, dest);
michael@0 1141 ma_mov(ImmTag(JSVAL_TYPE_TO_TAG(type)), secondScratchReg_);
michael@0 1142 ma_str(secondScratchReg_, Address(dest.base, dest.offset + 4));
michael@0 1143 }
michael@0 1144 void storeValue(const Value &val, Address dest) {
michael@0 1145 jsval_layout jv = JSVAL_TO_IMPL(val);
michael@0 1146 ma_mov(Imm32(jv.s.tag), secondScratchReg_);
michael@0 1147 ma_str(secondScratchReg_, Address(dest.base, dest.offset + 4));
michael@0 1148 if (val.isMarkable())
michael@0 1149 ma_mov(ImmGCPtr(reinterpret_cast<gc::Cell *>(val.toGCThing())), secondScratchReg_);
michael@0 1150 else
michael@0 1151 ma_mov(Imm32(jv.s.payload.i32), secondScratchReg_);
michael@0 1152 ma_str(secondScratchReg_, dest);
michael@0 1153 }
michael@0 1154 void storeValue(const Value &val, BaseIndex dest) {
michael@0 1155 // Harder cases not handled yet.
michael@0 1156 JS_ASSERT(dest.offset == 0);
michael@0 1157 ma_alu(dest.base, lsl(dest.index, dest.scale), ScratchRegister, op_add);
michael@0 1158 storeValue(val, Address(ScratchRegister, 0));
michael@0 1159 }
michael@0 1160
michael@0 1161 void loadValue(Address src, ValueOperand val);
michael@0 1162 void loadValue(Operand dest, ValueOperand val) {
michael@0 1163 loadValue(dest.toAddress(), val);
michael@0 1164 }
michael@0 1165 void loadValue(const BaseIndex &addr, ValueOperand val);
michael@0 1166 void tagValue(JSValueType type, Register payload, ValueOperand dest);
michael@0 1167
michael@0 1168 void pushValue(ValueOperand val);
michael@0 1169 void popValue(ValueOperand val);
michael@0 1170 void pushValue(const Value &val) {
michael@0 1171 jsval_layout jv = JSVAL_TO_IMPL(val);
michael@0 1172 push(Imm32(jv.s.tag));
michael@0 1173 if (val.isMarkable())
michael@0 1174 push(ImmGCPtr(reinterpret_cast<gc::Cell *>(val.toGCThing())));
michael@0 1175 else
michael@0 1176 push(Imm32(jv.s.payload.i32));
michael@0 1177 }
michael@0 1178 void pushValue(JSValueType type, Register reg) {
michael@0 1179 push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
michael@0 1180 ma_push(reg);
michael@0 1181 }
michael@0 1182 void pushValue(const Address &addr);
michael@0 1183 void Push(const ValueOperand &val) {
michael@0 1184 pushValue(val);
michael@0 1185 framePushed_ += sizeof(Value);
michael@0 1186 }
michael@0 1187 void Pop(const ValueOperand &val) {
michael@0 1188 popValue(val);
michael@0 1189 framePushed_ -= sizeof(Value);
michael@0 1190 }
michael@0 1191 void storePayload(const Value &val, Operand dest);
michael@0 1192 void storePayload(Register src, Operand dest);
michael@0 1193 void storePayload(const Value &val, Register base, Register index, int32_t shift = defaultShift);
michael@0 1194 void storePayload(Register src, Register base, Register index, int32_t shift = defaultShift);
michael@0 1195 void storeTypeTag(ImmTag tag, Operand dest);
michael@0 1196 void storeTypeTag(ImmTag tag, Register base, Register index, int32_t shift = defaultShift);
michael@0 1197
michael@0 1198 void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
michael@0 1199 ma_lsl(Imm32(FRAMESIZE_SHIFT), frameSizeReg, frameSizeReg);
michael@0 1200 ma_orr(Imm32(type), frameSizeReg);
michael@0 1201 }
michael@0 1202
michael@0 1203 void linkExitFrame();
michael@0 1204 void linkParallelExitFrame(const Register &pt);
michael@0 1205 void handleFailureWithHandler(void *handler);
michael@0 1206 void handleFailureWithHandlerTail();
michael@0 1207
michael@0 1208 /////////////////////////////////////////////////////////////////
michael@0 1209 // Common interface.
michael@0 1210 /////////////////////////////////////////////////////////////////
michael@0 1211 public:
michael@0 1212 // The following functions are exposed for use in platform-shared code.
michael@0 1213 void Push(const Register &reg) {
michael@0 1214 ma_push(reg);
michael@0 1215 adjustFrame(sizeof(intptr_t));
michael@0 1216 }
michael@0 1217 void Push(const Imm32 imm) {
michael@0 1218 push(imm);
michael@0 1219 adjustFrame(sizeof(intptr_t));
michael@0 1220 }
michael@0 1221 void Push(const ImmWord imm) {
michael@0 1222 push(imm);
michael@0 1223 adjustFrame(sizeof(intptr_t));
michael@0 1224 }
michael@0 1225 void Push(const ImmPtr imm) {
michael@0 1226 Push(ImmWord(uintptr_t(imm.value)));
michael@0 1227 }
michael@0 1228 void Push(const ImmGCPtr ptr) {
michael@0 1229 push(ptr);
michael@0 1230 adjustFrame(sizeof(intptr_t));
michael@0 1231 }
michael@0 1232 void Push(const FloatRegister &t) {
michael@0 1233 VFPRegister r = VFPRegister(t);
michael@0 1234 ma_vpush(VFPRegister(t));
michael@0 1235 adjustFrame(r.size());
michael@0 1236 }
michael@0 1237
michael@0 1238 CodeOffsetLabel PushWithPatch(const ImmWord &word) {
michael@0 1239 framePushed_ += sizeof(word.value);
michael@0 1240 return pushWithPatch(word);
michael@0 1241 }
michael@0 1242 CodeOffsetLabel PushWithPatch(const ImmPtr &imm) {
michael@0 1243 return PushWithPatch(ImmWord(uintptr_t(imm.value)));
michael@0 1244 }
michael@0 1245
michael@0 1246 void PushWithPadding(const Register &reg, const Imm32 extraSpace) {
michael@0 1247 pushWithPadding(reg, extraSpace);
michael@0 1248 adjustFrame(sizeof(intptr_t) + extraSpace.value);
michael@0 1249 }
michael@0 1250 void PushWithPadding(const Imm32 imm, const Imm32 extraSpace) {
michael@0 1251 pushWithPadding(imm, extraSpace);
michael@0 1252 adjustFrame(sizeof(intptr_t) + extraSpace.value);
michael@0 1253 }
michael@0 1254
michael@0 1255 void Pop(const Register &reg) {
michael@0 1256 ma_pop(reg);
michael@0 1257 adjustFrame(-sizeof(intptr_t));
michael@0 1258 }
michael@0 1259 void implicitPop(uint32_t args) {
michael@0 1260 JS_ASSERT(args % sizeof(intptr_t) == 0);
michael@0 1261 adjustFrame(-args);
michael@0 1262 }
michael@0 1263 uint32_t framePushed() const {
michael@0 1264 return framePushed_;
michael@0 1265 }
michael@0 1266 void setFramePushed(uint32_t framePushed) {
michael@0 1267 framePushed_ = framePushed;
michael@0 1268 }
michael@0 1269
michael@0 1270 // Builds an exit frame on the stack, with a return address to an internal
michael@0 1271 // non-function. Returns offset to be passed to markSafepointAt().
michael@0 1272 bool buildFakeExitFrame(const Register &scratch, uint32_t *offset);
michael@0 1273
michael@0 1274 void callWithExitFrame(JitCode *target);
michael@0 1275 void callWithExitFrame(JitCode *target, Register dynStack);
michael@0 1276
michael@0 1277 // Makes an Ion call using the only two methods that it is sane for
michael@0 1278 // indep code to make a call
michael@0 1279 void callIon(const Register &callee);
michael@0 1280
michael@0 1281 void reserveStack(uint32_t amount);
michael@0 1282 void freeStack(uint32_t amount);
michael@0 1283 void freeStack(Register amount);
michael@0 1284
michael@0 1285 void add32(Register src, Register dest);
michael@0 1286 void add32(Imm32 imm, Register dest);
michael@0 1287 void add32(Imm32 imm, const Address &dest);
michael@0 1288 void sub32(Imm32 imm, Register dest);
michael@0 1289 void sub32(Register src, Register dest);
michael@0 1290 template <typename T>
michael@0 1291 void branchAdd32(Condition cond, T src, Register dest, Label *label) {
michael@0 1292 add32(src, dest);
michael@0 1293 j(cond, label);
michael@0 1294 }
michael@0 1295 template <typename T>
michael@0 1296 void branchSub32(Condition cond, T src, Register dest, Label *label) {
michael@0 1297 sub32(src, dest);
michael@0 1298 j(cond, label);
michael@0 1299 }
michael@0 1300 void xor32(Imm32 imm, Register dest);
michael@0 1301
michael@0 1302 void and32(Imm32 imm, Register dest);
michael@0 1303 void and32(Imm32 imm, const Address &dest);
michael@0 1304 void or32(Imm32 imm, const Address &dest);
michael@0 1305 void xorPtr(Imm32 imm, Register dest);
michael@0 1306 void xorPtr(Register src, Register dest);
michael@0 1307 void orPtr(Imm32 imm, Register dest);
michael@0 1308 void orPtr(Register src, Register dest);
michael@0 1309 void andPtr(Imm32 imm, Register dest);
michael@0 1310 void andPtr(Register src, Register dest);
michael@0 1311 void addPtr(Register src, Register dest);
michael@0 1312 void addPtr(const Address &src, Register dest);
michael@0 1313 void not32(Register reg);
michael@0 1314
michael@0 1315 void move32(const Imm32 &imm, const Register &dest);
michael@0 1316 void move32(const Register &src, const Register &dest);
michael@0 1317
michael@0 1318 void movePtr(const Register &src, const Register &dest);
michael@0 1319 void movePtr(const ImmWord &imm, const Register &dest);
michael@0 1320 void movePtr(const ImmPtr &imm, const Register &dest);
michael@0 1321 void movePtr(const AsmJSImmPtr &imm, const Register &dest);
michael@0 1322 void movePtr(const ImmGCPtr &imm, const Register &dest);
michael@0 1323
michael@0 1324 void load8SignExtend(const Address &address, const Register &dest);
michael@0 1325 void load8SignExtend(const BaseIndex &src, const Register &dest);
michael@0 1326
michael@0 1327 void load8ZeroExtend(const Address &address, const Register &dest);
michael@0 1328 void load8ZeroExtend(const BaseIndex &src, const Register &dest);
michael@0 1329
michael@0 1330 void load16SignExtend(const Address &address, const Register &dest);
michael@0 1331 void load16SignExtend(const BaseIndex &src, const Register &dest);
michael@0 1332
michael@0 1333 void load16ZeroExtend(const Address &address, const Register &dest);
michael@0 1334 void load16ZeroExtend(const BaseIndex &src, const Register &dest);
michael@0 1335
michael@0 1336 void load32(const Address &address, const Register &dest);
michael@0 1337 void load32(const BaseIndex &address, const Register &dest);
michael@0 1338 void load32(const AbsoluteAddress &address, const Register &dest);
michael@0 1339
michael@0 1340 void loadPtr(const Address &address, const Register &dest);
michael@0 1341 void loadPtr(const BaseIndex &src, const Register &dest);
michael@0 1342 void loadPtr(const AbsoluteAddress &address, const Register &dest);
michael@0 1343 void loadPtr(const AsmJSAbsoluteAddress &address, const Register &dest);
michael@0 1344
michael@0 1345 void loadPrivate(const Address &address, const Register &dest);
michael@0 1346
michael@0 1347 void loadDouble(const Address &addr, const FloatRegister &dest);
michael@0 1348 void loadDouble(const BaseIndex &src, const FloatRegister &dest);
michael@0 1349
michael@0 1350 // Load a float value into a register, then expand it to a double.
michael@0 1351 void loadFloatAsDouble(const Address &addr, const FloatRegister &dest);
michael@0 1352 void loadFloatAsDouble(const BaseIndex &src, const FloatRegister &dest);
michael@0 1353
michael@0 1354 void loadFloat32(const Address &addr, const FloatRegister &dest);
michael@0 1355 void loadFloat32(const BaseIndex &src, const FloatRegister &dest);
michael@0 1356
michael@0 1357 void store8(const Register &src, const Address &address);
michael@0 1358 void store8(const Imm32 &imm, const Address &address);
michael@0 1359 void store8(const Register &src, const BaseIndex &address);
michael@0 1360 void store8(const Imm32 &imm, const BaseIndex &address);
michael@0 1361
michael@0 1362 void store16(const Register &src, const Address &address);
michael@0 1363 void store16(const Imm32 &imm, const Address &address);
michael@0 1364 void store16(const Register &src, const BaseIndex &address);
michael@0 1365 void store16(const Imm32 &imm, const BaseIndex &address);
michael@0 1366
michael@0 1367 void store32(const Register &src, const AbsoluteAddress &address);
michael@0 1368 void store32(const Register &src, const Address &address);
michael@0 1369 void store32(const Register &src, const BaseIndex &address);
michael@0 1370 void store32(const Imm32 &src, const Address &address);
michael@0 1371 void store32(const Imm32 &src, const BaseIndex &address);
michael@0 1372
michael@0 1373 void storePtr(ImmWord imm, const Address &address);
michael@0 1374 void storePtr(ImmPtr imm, const Address &address);
michael@0 1375 void storePtr(ImmGCPtr imm, const Address &address);
michael@0 1376 void storePtr(Register src, const Address &address);
michael@0 1377 void storePtr(const Register &src, const AbsoluteAddress &dest);
michael@0 1378 void storeDouble(FloatRegister src, Address addr) {
michael@0 1379 ma_vstr(src, Operand(addr));
michael@0 1380 }
michael@0 1381 void storeDouble(FloatRegister src, BaseIndex addr) {
michael@0 1382 // Harder cases not handled yet.
michael@0 1383 JS_ASSERT(addr.offset == 0);
michael@0 1384 uint32_t scale = Imm32::ShiftOf(addr.scale).value;
michael@0 1385 ma_vstr(src, addr.base, addr.index, scale);
michael@0 1386 }
michael@0 1387 void moveDouble(FloatRegister src, FloatRegister dest) {
michael@0 1388 ma_vmov(src, dest);
michael@0 1389 }
michael@0 1390
michael@0 1391 void storeFloat32(FloatRegister src, Address addr) {
michael@0 1392 ma_vstr(VFPRegister(src).singleOverlay(), Operand(addr));
michael@0 1393 }
michael@0 1394 void storeFloat32(FloatRegister src, BaseIndex addr) {
michael@0 1395 // Harder cases not handled yet.
michael@0 1396 JS_ASSERT(addr.offset == 0);
michael@0 1397 uint32_t scale = Imm32::ShiftOf(addr.scale).value;
michael@0 1398 ma_vstr(VFPRegister(src).singleOverlay(), addr.base, addr.index, scale);
michael@0 1399 }
michael@0 1400
michael@0 1401 void clampIntToUint8(Register reg) {
michael@0 1402 // look at (reg >> 8) if it is 0, then reg shouldn't be clamped
michael@0 1403 // if it is <0, then we want to clamp to 0, otherwise, we wish to clamp to 255
michael@0 1404 as_mov(ScratchRegister, asr(reg, 8), SetCond);
michael@0 1405 ma_mov(Imm32(0xff), reg, NoSetCond, NotEqual);
michael@0 1406 ma_mov(Imm32(0), reg, NoSetCond, Signed);
michael@0 1407 }
michael@0 1408
michael@0 1409 void cmp32(const Register &lhs, const Imm32 &rhs);
michael@0 1410 void cmp32(const Register &lhs, const Register &rhs);
michael@0 1411 void cmp32(const Operand &lhs, const Imm32 &rhs);
michael@0 1412 void cmp32(const Operand &lhs, const Register &rhs);
michael@0 1413
michael@0 1414 void cmpPtr(const Register &lhs, const ImmWord &rhs);
michael@0 1415 void cmpPtr(const Register &lhs, const ImmPtr &rhs);
michael@0 1416 void cmpPtr(const Register &lhs, const Register &rhs);
michael@0 1417 void cmpPtr(const Register &lhs, const ImmGCPtr &rhs);
michael@0 1418 void cmpPtr(const Register &lhs, const Imm32 &rhs);
michael@0 1419 void cmpPtr(const Address &lhs, const Register &rhs);
michael@0 1420 void cmpPtr(const Address &lhs, const ImmWord &rhs);
michael@0 1421 void cmpPtr(const Address &lhs, const ImmPtr &rhs);
michael@0 1422
michael@0 1423 void subPtr(Imm32 imm, const Register dest);
michael@0 1424 void subPtr(const Address &addr, const Register dest);
michael@0 1425 void subPtr(const Register &src, const Register &dest);
michael@0 1426 void subPtr(const Register &src, const Address &dest);
michael@0 1427 void addPtr(Imm32 imm, const Register dest);
michael@0 1428 void addPtr(Imm32 imm, const Address &dest);
michael@0 1429 void addPtr(ImmWord imm, const Register dest) {
michael@0 1430 addPtr(Imm32(imm.value), dest);
michael@0 1431 }
michael@0 1432 void addPtr(ImmPtr imm, const Register dest) {
michael@0 1433 addPtr(ImmWord(uintptr_t(imm.value)), dest);
michael@0 1434 }
michael@0 1435
michael@0 1436 void setStackArg(const Register &reg, uint32_t arg);
michael@0 1437
michael@0 1438 void breakpoint();
michael@0 1439 // conditional breakpoint
michael@0 1440 void breakpoint(Condition cc);
michael@0 1441
michael@0 1442 void compareDouble(FloatRegister lhs, FloatRegister rhs);
michael@0 1443 void branchDouble(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs,
michael@0 1444 Label *label);
michael@0 1445
michael@0 1446 void compareFloat(FloatRegister lhs, FloatRegister rhs);
michael@0 1447 void branchFloat(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs,
michael@0 1448 Label *label);
michael@0 1449
michael@0 1450 void checkStackAlignment();
michael@0 1451
michael@0 1452 void rshiftPtr(Imm32 imm, Register dest) {
michael@0 1453 ma_lsr(imm, dest, dest);
michael@0 1454 }
michael@0 1455 void lshiftPtr(Imm32 imm, Register dest) {
michael@0 1456 ma_lsl(imm, dest, dest);
michael@0 1457 }
michael@0 1458
michael@0 1459 // If source is a double, load it into dest. If source is int32,
michael@0 1460 // convert it to double. Else, branch to failure.
michael@0 1461 void ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure);
michael@0 1462
michael@0 1463 void
michael@0 1464 emitSet(Assembler::Condition cond, const Register &dest)
michael@0 1465 {
michael@0 1466 ma_mov(Imm32(0), dest);
michael@0 1467 ma_mov(Imm32(1), dest, NoSetCond, cond);
michael@0 1468 }
michael@0 1469
michael@0 1470 template <typename T1, typename T2>
michael@0 1471 void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, const Register &dest)
michael@0 1472 {
michael@0 1473 cmpPtr(lhs, rhs);
michael@0 1474 emitSet(cond, dest);
michael@0 1475 }
michael@0 1476 template <typename T1, typename T2>
michael@0 1477 void cmp32Set(Assembler::Condition cond, T1 lhs, T2 rhs, const Register &dest)
michael@0 1478 {
michael@0 1479 cmp32(lhs, rhs);
michael@0 1480 emitSet(cond, dest);
michael@0 1481 }
michael@0 1482
michael@0 1483 void testNullSet(Condition cond, const ValueOperand &value, Register dest) {
michael@0 1484 cond = testNull(cond, value);
michael@0 1485 emitSet(cond, dest);
michael@0 1486 }
michael@0 1487 void testUndefinedSet(Condition cond, const ValueOperand &value, Register dest) {
michael@0 1488 cond = testUndefined(cond, value);
michael@0 1489 emitSet(cond, dest);
michael@0 1490 }
michael@0 1491
michael@0 1492 // Setup a call to C/C++ code, given the number of general arguments it
michael@0 1493 // takes. Note that this only supports cdecl.
michael@0 1494 //
michael@0 1495 // In order for alignment to work correctly, the MacroAssembler must have a
michael@0 1496 // consistent view of the stack displacement. It is okay to call "push"
michael@0 1497 // manually, however, if the stack alignment were to change, the macro
michael@0 1498 // assembler should be notified before starting a call.
michael@0 1499 void setupAlignedABICall(uint32_t args);
michael@0 1500
michael@0 1501 // Sets up an ABI call for when the alignment is not known. This may need a
michael@0 1502 // scratch register.
michael@0 1503 void setupUnalignedABICall(uint32_t args, const Register &scratch);
michael@0 1504
michael@0 1505 // Arguments must be assigned in a left-to-right order. This process may
michael@0 1506 // temporarily use more stack, in which case esp-relative addresses will be
michael@0 1507 // automatically adjusted. It is extremely important that esp-relative
michael@0 1508 // addresses are computed *after* setupABICall(). Furthermore, no
michael@0 1509 // operations should be emitted while setting arguments.
michael@0 1510 void passABIArg(const MoveOperand &from, MoveOp::Type type);
michael@0 1511 void passABIArg(const Register &reg);
michael@0 1512 void passABIArg(const FloatRegister &reg, MoveOp::Type type);
michael@0 1513 void passABIArg(const ValueOperand &regs);
michael@0 1514
michael@0 1515 private:
michael@0 1516 void passHardFpABIArg(const MoveOperand &from, MoveOp::Type type);
michael@0 1517 void passSoftFpABIArg(const MoveOperand &from, MoveOp::Type type);
michael@0 1518
michael@0 1519 protected:
michael@0 1520 bool buildOOLFakeExitFrame(void *fakeReturnAddr);
michael@0 1521
michael@0 1522 private:
michael@0 1523 void callWithABIPre(uint32_t *stackAdjust);
michael@0 1524 void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result);
michael@0 1525
michael@0 1526 public:
michael@0 1527 // Emits a call to a C/C++ function, resolving all argument moves.
michael@0 1528 void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL);
michael@0 1529 void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL);
michael@0 1530 void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL);
michael@0 1531
michael@0 1532 CodeOffsetLabel labelForPatch() {
michael@0 1533 return CodeOffsetLabel(nextOffset().getOffset());
michael@0 1534 }
michael@0 1535
michael@0 1536 void computeEffectiveAddress(const Address &address, Register dest) {
michael@0 1537 ma_add(address.base, Imm32(address.offset), dest, NoSetCond);
michael@0 1538 }
michael@0 1539 void computeEffectiveAddress(const BaseIndex &address, Register dest) {
michael@0 1540 ma_alu(address.base, lsl(address.index, address.scale), dest, op_add, NoSetCond);
michael@0 1541 if (address.offset)
michael@0 1542 ma_add(dest, Imm32(address.offset), dest, NoSetCond);
michael@0 1543 }
michael@0 1544 void floor(FloatRegister input, Register output, Label *handleNotAnInt);
michael@0 1545 void floorf(FloatRegister input, Register output, Label *handleNotAnInt);
michael@0 1546 void round(FloatRegister input, Register output, Label *handleNotAnInt, FloatRegister tmp);
michael@0 1547 void roundf(FloatRegister input, Register output, Label *handleNotAnInt, FloatRegister tmp);
michael@0 1548
michael@0 1549 void clampCheck(Register r, Label *handleNotAnInt) {
michael@0 1550 // check explicitly for r == INT_MIN || r == INT_MAX
michael@0 1551 // this is the instruction sequence that gcc generated for this
michael@0 1552 // operation.
michael@0 1553 ma_sub(r, Imm32(0x80000001), ScratchRegister);
michael@0 1554 ma_cmn(ScratchRegister, Imm32(3));
michael@0 1555 ma_b(handleNotAnInt, Above);
michael@0 1556 }
michael@0 1557
michael@0 1558 void memIntToValue(Address Source, Address Dest) {
michael@0 1559 load32(Source, lr);
michael@0 1560 storeValue(JSVAL_TYPE_INT32, lr, Dest);
michael@0 1561 }
michael@0 1562 void memMove32(Address Source, Address Dest) {
michael@0 1563 loadPtr(Source, lr);
michael@0 1564 storePtr(lr, Dest);
michael@0 1565 }
michael@0 1566 void memMove64(Address Source, Address Dest) {
michael@0 1567 loadPtr(Source, lr);
michael@0 1568 storePtr(lr, Dest);
michael@0 1569 loadPtr(Address(Source.base, Source.offset+4), lr);
michael@0 1570 storePtr(lr, Address(Dest.base, Dest.offset+4));
michael@0 1571 }
michael@0 1572
michael@0 1573 void lea(Operand addr, Register dest) {
michael@0 1574 ma_add(addr.baseReg(), Imm32(addr.disp()), dest);
michael@0 1575 }
michael@0 1576
michael@0 1577 void stackCheck(ImmWord limitAddr, Label *label) {
michael@0 1578 int *foo = 0;
michael@0 1579 *foo = 5;
michael@0 1580 movePtr(limitAddr, ScratchRegister);
michael@0 1581 ma_ldr(Address(ScratchRegister, 0), ScratchRegister);
michael@0 1582 ma_cmp(ScratchRegister, StackPointer);
michael@0 1583 ma_b(label, Assembler::AboveOrEqual);
michael@0 1584 }
michael@0 1585 void abiret() {
michael@0 1586 as_bx(lr);
michael@0 1587 }
michael@0 1588
michael@0 1589 void ma_storeImm(Imm32 c, const Operand &dest) {
michael@0 1590 ma_mov(c, lr);
michael@0 1591 ma_str(lr, dest);
michael@0 1592 }
michael@0 1593 BufferOffset ma_BoundsCheck(Register bounded) {
michael@0 1594 return as_cmp(bounded, Imm8(0));
michael@0 1595 }
michael@0 1596
michael@0 1597 void moveFloat32(FloatRegister src, FloatRegister dest) {
michael@0 1598 as_vmov(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay());
michael@0 1599 }
michael@0 1600
michael@0 1601 #ifdef JSGC_GENERATIONAL
michael@0 1602 void branchPtrInNurseryRange(Register ptr, Register temp, Label *label);
michael@0 1603 void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label);
michael@0 1604 #endif
michael@0 1605 };
michael@0 1606
michael@0 1607 typedef MacroAssemblerARMCompat MacroAssemblerSpecific;
michael@0 1608
michael@0 1609 } // namespace jit
michael@0 1610 } // namespace js
michael@0 1611
michael@0 1612 #endif /* jit_arm_MacroAssembler_arm_h */

mercurial