js/src/jit/shared/MacroAssembler-x86-shared.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_shared_MacroAssembler_x86_shared_h
michael@0 8 #define jit_shared_MacroAssembler_x86_shared_h
michael@0 9
michael@0 10 #include "mozilla/Casting.h"
michael@0 11 #include "mozilla/DebugOnly.h"
michael@0 12
michael@0 13 #if defined(JS_CODEGEN_X86)
michael@0 14 # include "jit/x86/Assembler-x86.h"
michael@0 15 #elif defined(JS_CODEGEN_X64)
michael@0 16 # include "jit/x64/Assembler-x64.h"
michael@0 17 #endif
michael@0 18
michael@0 19 namespace js {
michael@0 20 namespace jit {
michael@0 21
michael@0 22 class MacroAssemblerX86Shared : public Assembler
michael@0 23 {
michael@0 24 protected:
michael@0 25 // Bytes pushed onto the frame by the callee; includes frameDepth_. This is
michael@0 26 // needed to compute offsets to stack slots while temporary space has been
michael@0 27 // reserved for unexpected spills or C++ function calls. It is maintained
michael@0 28 // by functions which track stack alignment, which for clear distinction
michael@0 29 // use StudlyCaps (for example, Push, Pop).
michael@0 30 uint32_t framePushed_;
michael@0 31
michael@0 32 public:
michael@0 33 using Assembler::call;
michael@0 34
michael@0 35 MacroAssemblerX86Shared()
michael@0 36 : framePushed_(0)
michael@0 37 { }
michael@0 38
michael@0 39 void compareDouble(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs) {
michael@0 40 if (cond & DoubleConditionBitInvert)
michael@0 41 ucomisd(rhs, lhs);
michael@0 42 else
michael@0 43 ucomisd(lhs, rhs);
michael@0 44 }
michael@0 45 void branchDouble(DoubleCondition cond, const FloatRegister &lhs,
michael@0 46 const FloatRegister &rhs, Label *label)
michael@0 47 {
michael@0 48 compareDouble(cond, lhs, rhs);
michael@0 49
michael@0 50 if (cond == DoubleEqual) {
michael@0 51 Label unordered;
michael@0 52 j(Parity, &unordered);
michael@0 53 j(Equal, label);
michael@0 54 bind(&unordered);
michael@0 55 return;
michael@0 56 }
michael@0 57 if (cond == DoubleNotEqualOrUnordered) {
michael@0 58 j(NotEqual, label);
michael@0 59 j(Parity, label);
michael@0 60 return;
michael@0 61 }
michael@0 62
michael@0 63 JS_ASSERT(!(cond & DoubleConditionBitSpecial));
michael@0 64 j(ConditionFromDoubleCondition(cond), label);
michael@0 65 }
michael@0 66
michael@0 67 void compareFloat(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs) {
michael@0 68 if (cond & DoubleConditionBitInvert)
michael@0 69 ucomiss(rhs, lhs);
michael@0 70 else
michael@0 71 ucomiss(lhs, rhs);
michael@0 72 }
michael@0 73 void branchFloat(DoubleCondition cond, const FloatRegister &lhs,
michael@0 74 const FloatRegister &rhs, Label *label)
michael@0 75 {
michael@0 76 compareFloat(cond, lhs, rhs);
michael@0 77
michael@0 78 if (cond == DoubleEqual) {
michael@0 79 Label unordered;
michael@0 80 j(Parity, &unordered);
michael@0 81 j(Equal, label);
michael@0 82 bind(&unordered);
michael@0 83 return;
michael@0 84 }
michael@0 85 if (cond == DoubleNotEqualOrUnordered) {
michael@0 86 j(NotEqual, label);
michael@0 87 j(Parity, label);
michael@0 88 return;
michael@0 89 }
michael@0 90
michael@0 91 JS_ASSERT(!(cond & DoubleConditionBitSpecial));
michael@0 92 j(ConditionFromDoubleCondition(cond), label);
michael@0 93 }
michael@0 94
michael@0 95 void branchNegativeZero(const FloatRegister &reg, const Register &scratch, Label *label);
michael@0 96 void branchNegativeZeroFloat32(const FloatRegister &reg, const Register &scratch, Label *label);
michael@0 97
michael@0 98 void move32(const Imm32 &imm, const Register &dest) {
michael@0 99 // Use the ImmWord version of mov to register, which has special
michael@0 100 // optimizations. Casting to uint32_t here ensures that the value
michael@0 101 // is zero-extended.
michael@0 102 mov(ImmWord(uint32_t(imm.value)), dest);
michael@0 103 }
michael@0 104 void move32(const Imm32 &imm, const Operand &dest) {
michael@0 105 movl(imm, dest);
michael@0 106 }
michael@0 107 void move32(const Register &src, const Register &dest) {
michael@0 108 movl(src, dest);
michael@0 109 }
michael@0 110 void move32(const Register &src, const Operand &dest) {
michael@0 111 movl(src, dest);
michael@0 112 }
michael@0 113 void and32(const Imm32 &imm, const Register &dest) {
michael@0 114 andl(imm, dest);
michael@0 115 }
michael@0 116 void and32(const Imm32 &imm, const Address &dest) {
michael@0 117 andl(imm, Operand(dest));
michael@0 118 }
michael@0 119 void or32(const Register &src, const Register &dest) {
michael@0 120 orl(src, dest);
michael@0 121 }
michael@0 122 void or32(const Imm32 &imm, const Register &dest) {
michael@0 123 orl(imm, dest);
michael@0 124 }
michael@0 125 void or32(const Imm32 &imm, const Address &dest) {
michael@0 126 orl(imm, Operand(dest));
michael@0 127 }
michael@0 128 void neg32(const Register &reg) {
michael@0 129 negl(reg);
michael@0 130 }
michael@0 131 void test32(const Register &lhs, const Register &rhs) {
michael@0 132 testl(lhs, rhs);
michael@0 133 }
michael@0 134 void test32(const Address &addr, Imm32 imm) {
michael@0 135 testl(Operand(addr), imm);
michael@0 136 }
michael@0 137 void test32(const Register &lhs, const Imm32 &rhs) {
michael@0 138 testl(lhs, rhs);
michael@0 139 }
michael@0 140 void cmp32(const Register &lhs, const Imm32 &rhs) {
michael@0 141 cmpl(lhs, rhs);
michael@0 142 }
michael@0 143 void cmp32(Register a, Register b) {
michael@0 144 cmpl(a, b);
michael@0 145 }
michael@0 146 void cmp32(const Operand &lhs, const Imm32 &rhs) {
michael@0 147 cmpl(lhs, rhs);
michael@0 148 }
michael@0 149 void cmp32(const Operand &lhs, const Register &rhs) {
michael@0 150 cmpl(lhs, rhs);
michael@0 151 }
michael@0 152 void add32(Register src, Register dest) {
michael@0 153 addl(src, dest);
michael@0 154 }
michael@0 155 void add32(Imm32 imm, Register dest) {
michael@0 156 addl(imm, dest);
michael@0 157 }
michael@0 158 void add32(Imm32 imm, const Address &dest) {
michael@0 159 addl(imm, Operand(dest));
michael@0 160 }
michael@0 161 void sub32(Imm32 imm, Register dest) {
michael@0 162 subl(imm, dest);
michael@0 163 }
michael@0 164 void sub32(Register src, Register dest) {
michael@0 165 subl(src, dest);
michael@0 166 }
michael@0 167 template <typename T>
michael@0 168 void branchAdd32(Condition cond, T src, Register dest, Label *label) {
michael@0 169 add32(src, dest);
michael@0 170 j(cond, label);
michael@0 171 }
michael@0 172 template <typename T>
michael@0 173 void branchSub32(Condition cond, T src, Register dest, Label *label) {
michael@0 174 sub32(src, dest);
michael@0 175 j(cond, label);
michael@0 176 }
michael@0 177 void xor32(Imm32 imm, Register dest) {
michael@0 178 xorl(imm, dest);
michael@0 179 }
michael@0 180 void xor32(Register src, Register dest) {
michael@0 181 xorl(src, dest);
michael@0 182 }
michael@0 183 void not32(Register reg) {
michael@0 184 notl(reg);
michael@0 185 }
michael@0 186 void inc32(const Operand &addr) {
michael@0 187 incl(addr);
michael@0 188 }
michael@0 189 void atomic_inc32(const Operand &addr) {
michael@0 190 lock_incl(addr);
michael@0 191 }
michael@0 192 void dec32(const Operand &addr) {
michael@0 193 decl(addr);
michael@0 194 }
michael@0 195 void atomic_dec32(const Operand &addr) {
michael@0 196 lock_decl(addr);
michael@0 197 }
michael@0 198 void atomic_cmpxchg32(const Register &src, const Operand &addr, const Register &dest) {
michael@0 199 // %eax must be explicitly provided for calling clarity.
michael@0 200 MOZ_ASSERT(dest.code() == JSC::X86Registers::eax);
michael@0 201 lock_cmpxchg32(src, addr);
michael@0 202 }
michael@0 203
michael@0 204 void branch16(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
michael@0 205 cmpw(lhs, rhs);
michael@0 206 j(cond, label);
michael@0 207 }
michael@0 208 void branch32(Condition cond, const Operand &lhs, const Register &rhs, Label *label) {
michael@0 209 cmpl(lhs, rhs);
michael@0 210 j(cond, label);
michael@0 211 }
michael@0 212 void branch32(Condition cond, const Operand &lhs, Imm32 rhs, Label *label) {
michael@0 213 cmpl(lhs, rhs);
michael@0 214 j(cond, label);
michael@0 215 }
michael@0 216 void branch32(Condition cond, const Address &lhs, const Register &rhs, Label *label) {
michael@0 217 cmpl(Operand(lhs), rhs);
michael@0 218 j(cond, label);
michael@0 219 }
michael@0 220 void branch32(Condition cond, const Address &lhs, Imm32 imm, Label *label) {
michael@0 221 cmpl(Operand(lhs), imm);
michael@0 222 j(cond, label);
michael@0 223 }
michael@0 224 void branch32(Condition cond, const Register &lhs, Imm32 imm, Label *label) {
michael@0 225 cmpl(lhs, imm);
michael@0 226 j(cond, label);
michael@0 227 }
michael@0 228 void branch32(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
michael@0 229 cmpl(lhs, rhs);
michael@0 230 j(cond, label);
michael@0 231 }
michael@0 232 void branchTest16(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
michael@0 233 testw(lhs, rhs);
michael@0 234 j(cond, label);
michael@0 235 }
michael@0 236 void branchTest32(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
michael@0 237 testl(lhs, rhs);
michael@0 238 j(cond, label);
michael@0 239 }
michael@0 240 void branchTest32(Condition cond, const Register &lhs, Imm32 imm, Label *label) {
michael@0 241 testl(lhs, imm);
michael@0 242 j(cond, label);
michael@0 243 }
michael@0 244 void branchTest32(Condition cond, const Address &address, Imm32 imm, Label *label) {
michael@0 245 testl(Operand(address), imm);
michael@0 246 j(cond, label);
michael@0 247 }
michael@0 248
michael@0 249 // The following functions are exposed for use in platform-shared code.
michael@0 250 template <typename T>
michael@0 251 void Push(const T &t) {
michael@0 252 push(t);
michael@0 253 framePushed_ += sizeof(intptr_t);
michael@0 254 }
michael@0 255 void Push(const FloatRegister &t) {
michael@0 256 push(t);
michael@0 257 framePushed_ += sizeof(double);
michael@0 258 }
michael@0 259 CodeOffsetLabel PushWithPatch(const ImmWord &word) {
michael@0 260 framePushed_ += sizeof(word.value);
michael@0 261 return pushWithPatch(word);
michael@0 262 }
michael@0 263 CodeOffsetLabel PushWithPatch(const ImmPtr &imm) {
michael@0 264 return PushWithPatch(ImmWord(uintptr_t(imm.value)));
michael@0 265 }
michael@0 266
michael@0 267 template <typename T>
michael@0 268 void Pop(const T &t) {
michael@0 269 pop(t);
michael@0 270 framePushed_ -= sizeof(intptr_t);
michael@0 271 }
michael@0 272 void Pop(const FloatRegister &t) {
michael@0 273 pop(t);
michael@0 274 framePushed_ -= sizeof(double);
michael@0 275 }
michael@0 276 void implicitPop(uint32_t args) {
michael@0 277 JS_ASSERT(args % sizeof(intptr_t) == 0);
michael@0 278 framePushed_ -= args;
michael@0 279 }
michael@0 280 uint32_t framePushed() const {
michael@0 281 return framePushed_;
michael@0 282 }
michael@0 283 void setFramePushed(uint32_t framePushed) {
michael@0 284 framePushed_ = framePushed;
michael@0 285 }
michael@0 286
michael@0 287 void jump(Label *label) {
michael@0 288 jmp(label);
michael@0 289 }
michael@0 290 void jump(RepatchLabel *label) {
michael@0 291 jmp(label);
michael@0 292 }
michael@0 293 void jump(Register reg) {
michael@0 294 jmp(Operand(reg));
michael@0 295 }
michael@0 296 void jump(const Address &addr) {
michael@0 297 jmp(Operand(addr));
michael@0 298 }
michael@0 299
michael@0 300 void convertInt32ToDouble(const Register &src, const FloatRegister &dest) {
michael@0 301 // cvtsi2sd and friends write only part of their output register, which
michael@0 302 // causes slowdowns on out-of-order processors. Explicitly break
michael@0 303 // dependencies with xorpd (and xorps elsewhere), which are handled
michael@0 304 // specially in modern CPUs, for this purpose. See sections 8.14, 9.8,
michael@0 305 // 10.8, 12.9, 13.16, 14.14, and 15.8 of Agner's Microarchitecture
michael@0 306 // document.
michael@0 307 zeroDouble(dest);
michael@0 308 cvtsi2sd(src, dest);
michael@0 309 }
michael@0 310 void convertInt32ToDouble(const Address &src, FloatRegister dest) {
michael@0 311 convertInt32ToDouble(Operand(src), dest);
michael@0 312 }
michael@0 313 void convertInt32ToDouble(const Operand &src, FloatRegister dest) {
michael@0 314 // Clear the output register first to break dependencies; see above;
michael@0 315 zeroDouble(dest);
michael@0 316 cvtsi2sd(Operand(src), dest);
michael@0 317 }
michael@0 318 void convertInt32ToFloat32(const Register &src, const FloatRegister &dest) {
michael@0 319 // Clear the output register first to break dependencies; see above;
michael@0 320 zeroFloat32(dest);
michael@0 321 cvtsi2ss(src, dest);
michael@0 322 }
michael@0 323 void convertInt32ToFloat32(const Address &src, FloatRegister dest) {
michael@0 324 convertInt32ToFloat32(Operand(src), dest);
michael@0 325 }
michael@0 326 void convertInt32ToFloat32(const Operand &src, FloatRegister dest) {
michael@0 327 // Clear the output register first to break dependencies; see above;
michael@0 328 zeroFloat32(dest);
michael@0 329 cvtsi2ss(src, dest);
michael@0 330 }
michael@0 331 Condition testDoubleTruthy(bool truthy, const FloatRegister &reg) {
michael@0 332 zeroDouble(ScratchFloatReg);
michael@0 333 ucomisd(ScratchFloatReg, reg);
michael@0 334 return truthy ? NonZero : Zero;
michael@0 335 }
michael@0 336 void branchTestDoubleTruthy(bool truthy, const FloatRegister &reg, Label *label) {
michael@0 337 Condition cond = testDoubleTruthy(truthy, reg);
michael@0 338 j(cond, label);
michael@0 339 }
michael@0 340 void load8ZeroExtend(const Address &src, const Register &dest) {
michael@0 341 movzbl(Operand(src), dest);
michael@0 342 }
michael@0 343 void load8ZeroExtend(const BaseIndex &src, const Register &dest) {
michael@0 344 movzbl(Operand(src), dest);
michael@0 345 }
michael@0 346 void load8SignExtend(const Address &src, const Register &dest) {
michael@0 347 movsbl(Operand(src), dest);
michael@0 348 }
michael@0 349 void load8SignExtend(const BaseIndex &src, const Register &dest) {
michael@0 350 movsbl(Operand(src), dest);
michael@0 351 }
michael@0 352 template <typename S, typename T>
michael@0 353 void store8(const S &src, const T &dest) {
michael@0 354 movb(src, Operand(dest));
michael@0 355 }
michael@0 356 void load16ZeroExtend(const Address &src, const Register &dest) {
michael@0 357 movzwl(Operand(src), dest);
michael@0 358 }
michael@0 359 void load16ZeroExtend(const BaseIndex &src, const Register &dest) {
michael@0 360 movzwl(Operand(src), dest);
michael@0 361 }
michael@0 362 template <typename S, typename T>
michael@0 363 void store16(const S &src, const T &dest) {
michael@0 364 movw(src, Operand(dest));
michael@0 365 }
michael@0 366 void load16SignExtend(const Address &src, const Register &dest) {
michael@0 367 movswl(Operand(src), dest);
michael@0 368 }
michael@0 369 void load16SignExtend(const BaseIndex &src, const Register &dest) {
michael@0 370 movswl(Operand(src), dest);
michael@0 371 }
michael@0 372 void load32(const Address &address, Register dest) {
michael@0 373 movl(Operand(address), dest);
michael@0 374 }
michael@0 375 void load32(const BaseIndex &src, Register dest) {
michael@0 376 movl(Operand(src), dest);
michael@0 377 }
michael@0 378 void load32(const Operand &src, Register dest) {
michael@0 379 movl(src, dest);
michael@0 380 }
michael@0 381 template <typename S, typename T>
michael@0 382 void store32(const S &src, const T &dest) {
michael@0 383 movl(src, Operand(dest));
michael@0 384 }
michael@0 385 void loadDouble(const Address &src, FloatRegister dest) {
michael@0 386 movsd(src, dest);
michael@0 387 }
michael@0 388 void loadDouble(const BaseIndex &src, FloatRegister dest) {
michael@0 389 movsd(src, dest);
michael@0 390 }
michael@0 391 void loadDouble(const Operand &src, FloatRegister dest) {
michael@0 392 switch (src.kind()) {
michael@0 393 case Operand::MEM_REG_DISP:
michael@0 394 loadDouble(src.toAddress(), dest);
michael@0 395 break;
michael@0 396 case Operand::MEM_SCALE:
michael@0 397 loadDouble(src.toBaseIndex(), dest);
michael@0 398 break;
michael@0 399 default:
michael@0 400 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 401 }
michael@0 402 }
michael@0 403 void storeDouble(FloatRegister src, const Address &dest) {
michael@0 404 movsd(src, dest);
michael@0 405 }
michael@0 406 void storeDouble(FloatRegister src, const BaseIndex &dest) {
michael@0 407 movsd(src, dest);
michael@0 408 }
michael@0 409 void storeDouble(FloatRegister src, const Operand &dest) {
michael@0 410 switch (dest.kind()) {
michael@0 411 case Operand::MEM_REG_DISP:
michael@0 412 storeDouble(src, dest.toAddress());
michael@0 413 break;
michael@0 414 case Operand::MEM_SCALE:
michael@0 415 storeDouble(src, dest.toBaseIndex());
michael@0 416 break;
michael@0 417 default:
michael@0 418 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 419 }
michael@0 420 }
michael@0 421 void moveDouble(FloatRegister src, FloatRegister dest) {
michael@0 422 // Use movapd instead of movsd to avoid dependencies.
michael@0 423 movapd(src, dest);
michael@0 424 }
michael@0 425 void zeroDouble(FloatRegister reg) {
michael@0 426 xorpd(reg, reg);
michael@0 427 }
michael@0 428 void zeroFloat32(FloatRegister reg) {
michael@0 429 xorps(reg, reg);
michael@0 430 }
michael@0 431 void negateDouble(FloatRegister reg) {
michael@0 432 // From MacroAssemblerX86Shared::maybeInlineDouble
michael@0 433 pcmpeqw(ScratchFloatReg, ScratchFloatReg);
michael@0 434 psllq(Imm32(63), ScratchFloatReg);
michael@0 435
michael@0 436 // XOR the float in a float register with -0.0.
michael@0 437 xorpd(ScratchFloatReg, reg); // s ^ 0x80000000000000
michael@0 438 }
michael@0 439 void negateFloat(FloatRegister reg) {
michael@0 440 pcmpeqw(ScratchFloatReg, ScratchFloatReg);
michael@0 441 psllq(Imm32(31), ScratchFloatReg);
michael@0 442
michael@0 443 // XOR the float in a float register with -0.0.
michael@0 444 xorps(ScratchFloatReg, reg); // s ^ 0x80000000
michael@0 445 }
michael@0 446 void addDouble(FloatRegister src, FloatRegister dest) {
michael@0 447 addsd(src, dest);
michael@0 448 }
michael@0 449 void subDouble(FloatRegister src, FloatRegister dest) {
michael@0 450 subsd(src, dest);
michael@0 451 }
michael@0 452 void mulDouble(FloatRegister src, FloatRegister dest) {
michael@0 453 mulsd(src, dest);
michael@0 454 }
michael@0 455 void divDouble(FloatRegister src, FloatRegister dest) {
michael@0 456 divsd(src, dest);
michael@0 457 }
michael@0 458 void convertFloat32ToDouble(const FloatRegister &src, const FloatRegister &dest) {
michael@0 459 cvtss2sd(src, dest);
michael@0 460 }
michael@0 461 void convertDoubleToFloat32(const FloatRegister &src, const FloatRegister &dest) {
michael@0 462 cvtsd2ss(src, dest);
michael@0 463 }
michael@0 464 void moveFloatAsDouble(const Register &src, FloatRegister dest) {
michael@0 465 movd(src, dest);
michael@0 466 cvtss2sd(dest, dest);
michael@0 467 }
michael@0 468 void loadFloatAsDouble(const Address &src, FloatRegister dest) {
michael@0 469 movss(src, dest);
michael@0 470 cvtss2sd(dest, dest);
michael@0 471 }
michael@0 472 void loadFloatAsDouble(const BaseIndex &src, FloatRegister dest) {
michael@0 473 movss(src, dest);
michael@0 474 cvtss2sd(dest, dest);
michael@0 475 }
michael@0 476 void loadFloatAsDouble(const Operand &src, FloatRegister dest) {
michael@0 477 loadFloat32(src, dest);
michael@0 478 cvtss2sd(dest, dest);
michael@0 479 }
michael@0 480 void loadFloat32(const Address &src, FloatRegister dest) {
michael@0 481 movss(src, dest);
michael@0 482 }
michael@0 483 void loadFloat32(const BaseIndex &src, FloatRegister dest) {
michael@0 484 movss(src, dest);
michael@0 485 }
michael@0 486 void loadFloat32(const Operand &src, FloatRegister dest) {
michael@0 487 switch (src.kind()) {
michael@0 488 case Operand::MEM_REG_DISP:
michael@0 489 loadFloat32(src.toAddress(), dest);
michael@0 490 break;
michael@0 491 case Operand::MEM_SCALE:
michael@0 492 loadFloat32(src.toBaseIndex(), dest);
michael@0 493 break;
michael@0 494 default:
michael@0 495 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 496 }
michael@0 497 }
michael@0 498 void storeFloat32(FloatRegister src, const Address &dest) {
michael@0 499 movss(src, dest);
michael@0 500 }
michael@0 501 void storeFloat32(FloatRegister src, const BaseIndex &dest) {
michael@0 502 movss(src, dest);
michael@0 503 }
michael@0 504 void storeFloat32(FloatRegister src, const Operand &dest) {
michael@0 505 switch (dest.kind()) {
michael@0 506 case Operand::MEM_REG_DISP:
michael@0 507 storeFloat32(src, dest.toAddress());
michael@0 508 break;
michael@0 509 case Operand::MEM_SCALE:
michael@0 510 storeFloat32(src, dest.toBaseIndex());
michael@0 511 break;
michael@0 512 default:
michael@0 513 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 514 }
michael@0 515 }
michael@0 516 void moveFloat32(FloatRegister src, FloatRegister dest) {
michael@0 517 // Use movaps instead of movss to avoid dependencies.
michael@0 518 movaps(src, dest);
michael@0 519 }
michael@0 520
michael@0 521 // Checks whether a double is representable as a 32-bit integer. If so, the
michael@0 522 // integer is written to the output register. Otherwise, a bailout is taken to
michael@0 523 // the given snapshot. This function overwrites the scratch float register.
michael@0 524 void convertDoubleToInt32(FloatRegister src, Register dest, Label *fail,
michael@0 525 bool negativeZeroCheck = true)
michael@0 526 {
michael@0 527 // Check for -0.0
michael@0 528 if (negativeZeroCheck)
michael@0 529 branchNegativeZero(src, dest, fail);
michael@0 530
michael@0 531 cvttsd2si(src, dest);
michael@0 532 cvtsi2sd(dest, ScratchFloatReg);
michael@0 533 ucomisd(src, ScratchFloatReg);
michael@0 534 j(Assembler::Parity, fail);
michael@0 535 j(Assembler::NotEqual, fail);
michael@0 536
michael@0 537 }
michael@0 538
michael@0 539 // Checks whether a float32 is representable as a 32-bit integer. If so, the
michael@0 540 // integer is written to the output register. Otherwise, a bailout is taken to
michael@0 541 // the given snapshot. This function overwrites the scratch float register.
michael@0 542 void convertFloat32ToInt32(FloatRegister src, Register dest, Label *fail,
michael@0 543 bool negativeZeroCheck = true)
michael@0 544 {
michael@0 545 // Check for -0.0
michael@0 546 if (negativeZeroCheck)
michael@0 547 branchNegativeZeroFloat32(src, dest, fail);
michael@0 548
michael@0 549 cvttss2si(src, dest);
michael@0 550 convertInt32ToFloat32(dest, ScratchFloatReg);
michael@0 551 ucomiss(src, ScratchFloatReg);
michael@0 552 j(Assembler::Parity, fail);
michael@0 553 j(Assembler::NotEqual, fail);
michael@0 554 }
michael@0 555
michael@0 556 void clampIntToUint8(Register reg) {
michael@0 557 Label inRange;
michael@0 558 branchTest32(Assembler::Zero, reg, Imm32(0xffffff00), &inRange);
michael@0 559 {
michael@0 560 sarl(Imm32(31), reg);
michael@0 561 notl(reg);
michael@0 562 andl(Imm32(255), reg);
michael@0 563 }
michael@0 564 bind(&inRange);
michael@0 565 }
michael@0 566
michael@0 567 bool maybeInlineDouble(double d, const FloatRegister &dest) {
michael@0 568 uint64_t u = mozilla::BitwiseCast<uint64_t>(d);
michael@0 569
michael@0 570 // Loading zero with xor is specially optimized in hardware.
michael@0 571 if (u == 0) {
michael@0 572 xorpd(dest, dest);
michael@0 573 return true;
michael@0 574 }
michael@0 575
michael@0 576 // It is also possible to load several common constants using pcmpeqw
michael@0 577 // to get all ones and then psllq and psrlq to get zeros at the ends,
michael@0 578 // as described in "13.4 Generating constants" of
michael@0 579 // "2. Optimizing subroutines in assembly language" by Agner Fog, and as
michael@0 580 // previously implemented here. However, with x86 and x64 both using
michael@0 581 // constant pool loads for double constants, this is probably only
michael@0 582 // worthwhile in cases where a load is likely to be delayed.
michael@0 583
michael@0 584 return false;
michael@0 585 }
michael@0 586
michael@0 587 bool maybeInlineFloat(float f, const FloatRegister &dest) {
michael@0 588 uint32_t u = mozilla::BitwiseCast<uint32_t>(f);
michael@0 589
michael@0 590 // See comment above
michael@0 591 if (u == 0) {
michael@0 592 xorps(dest, dest);
michael@0 593 return true;
michael@0 594 }
michael@0 595 return false;
michael@0 596 }
michael@0 597
michael@0 598 void convertBoolToInt32(Register source, Register dest) {
michael@0 599 // Note that C++ bool is only 1 byte, so zero extend it to clear the
michael@0 600 // higher-order bits.
michael@0 601 movzbl(source, dest);
michael@0 602 }
michael@0 603
michael@0 604 void emitSet(Assembler::Condition cond, const Register &dest,
michael@0 605 Assembler::NaNCond ifNaN = Assembler::NaN_HandledByCond) {
michael@0 606 if (GeneralRegisterSet(Registers::SingleByteRegs).has(dest)) {
michael@0 607 // If the register we're defining is a single byte register,
michael@0 608 // take advantage of the setCC instruction
michael@0 609 setCC(cond, dest);
michael@0 610 movzbl(dest, dest);
michael@0 611
michael@0 612 if (ifNaN != Assembler::NaN_HandledByCond) {
michael@0 613 Label noNaN;
michael@0 614 j(Assembler::NoParity, &noNaN);
michael@0 615 mov(ImmWord(ifNaN == Assembler::NaN_IsTrue), dest);
michael@0 616 bind(&noNaN);
michael@0 617 }
michael@0 618 } else {
michael@0 619 Label end;
michael@0 620 Label ifFalse;
michael@0 621
michael@0 622 if (ifNaN == Assembler::NaN_IsFalse)
michael@0 623 j(Assembler::Parity, &ifFalse);
michael@0 624 // Note a subtlety here: FLAGS is live at this point, and the
michael@0 625 // mov interface doesn't guarantee to preserve FLAGS. Use
michael@0 626 // movl instead of mov, because the movl instruction
michael@0 627 // preserves FLAGS.
michael@0 628 movl(Imm32(1), dest);
michael@0 629 j(cond, &end);
michael@0 630 if (ifNaN == Assembler::NaN_IsTrue)
michael@0 631 j(Assembler::Parity, &end);
michael@0 632 bind(&ifFalse);
michael@0 633 mov(ImmWord(0), dest);
michael@0 634
michael@0 635 bind(&end);
michael@0 636 }
michael@0 637 }
michael@0 638
michael@0 639 template <typename T1, typename T2>
michael@0 640 void cmp32Set(Assembler::Condition cond, T1 lhs, T2 rhs, const Register &dest)
michael@0 641 {
michael@0 642 cmp32(lhs, rhs);
michael@0 643 emitSet(cond, dest);
michael@0 644 }
michael@0 645
michael@0 646 // Emit a JMP that can be toggled to a CMP. See ToggleToJmp(), ToggleToCmp().
michael@0 647 CodeOffsetLabel toggledJump(Label *label) {
michael@0 648 CodeOffsetLabel offset(size());
michael@0 649 jump(label);
michael@0 650 return offset;
michael@0 651 }
michael@0 652
michael@0 653 template <typename T>
michael@0 654 void computeEffectiveAddress(const T &address, Register dest) {
michael@0 655 lea(Operand(address), dest);
michael@0 656 }
michael@0 657
michael@0 658 // Builds an exit frame on the stack, with a return address to an internal
michael@0 659 // non-function. Returns offset to be passed to markSafepointAt().
michael@0 660 bool buildFakeExitFrame(const Register &scratch, uint32_t *offset);
michael@0 661 void callWithExitFrame(JitCode *target);
michael@0 662
michael@0 663 void callIon(const Register &callee) {
michael@0 664 call(callee);
michael@0 665 }
michael@0 666
michael@0 667 void appendCallSite(const CallSiteDesc &desc) {
michael@0 668 // Add an extra sizeof(void*) to include the return address that was
michael@0 669 // pushed by the call instruction (see CallSite::stackDepth).
michael@0 670 enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + sizeof(void*)));
michael@0 671 }
michael@0 672
michael@0 673 void call(const CallSiteDesc &desc, Label *label) {
michael@0 674 call(label);
michael@0 675 appendCallSite(desc);
michael@0 676 }
michael@0 677 void call(const CallSiteDesc &desc, const Register &reg) {
michael@0 678 call(reg);
michael@0 679 appendCallSite(desc);
michael@0 680 }
michael@0 681 void callIonFromAsmJS(const Register &reg) {
michael@0 682 call(CallSiteDesc::Exit(), reg);
michael@0 683 }
michael@0 684
michael@0 685 void checkStackAlignment() {
michael@0 686 // Exists for ARM compatibility.
michael@0 687 }
michael@0 688
michael@0 689 CodeOffsetLabel labelForPatch() {
michael@0 690 return CodeOffsetLabel(size());
michael@0 691 }
michael@0 692
michael@0 693 void abiret() {
michael@0 694 ret();
michael@0 695 }
michael@0 696
michael@0 697 protected:
michael@0 698 bool buildOOLFakeExitFrame(void *fakeReturnAddr);
michael@0 699 };
michael@0 700
michael@0 701 } // namespace jit
michael@0 702 } // namespace js
michael@0 703
michael@0 704 #endif /* jit_shared_MacroAssembler_x86_shared_h */

mercurial