js/src/jit/shared/Assembler-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_Assembler_x86_shared_h
michael@0 8 #define jit_shared_Assembler_x86_shared_h
michael@0 9
michael@0 10 #include <cstddef>
michael@0 11
michael@0 12 #include "assembler/assembler/X86Assembler.h"
michael@0 13 #include "jit/shared/Assembler-shared.h"
michael@0 14
michael@0 15 namespace js {
michael@0 16 namespace jit {
michael@0 17
michael@0 18 class Operand
michael@0 19 {
michael@0 20 public:
michael@0 21 enum Kind {
michael@0 22 REG,
michael@0 23 MEM_REG_DISP,
michael@0 24 FPREG,
michael@0 25 MEM_SCALE,
michael@0 26 MEM_ADDRESS32
michael@0 27 };
michael@0 28
michael@0 29 private:
michael@0 30 Kind kind_ : 4;
michael@0 31 int32_t base_ : 5;
michael@0 32 Scale scale_ : 3;
michael@0 33 int32_t index_ : 5;
michael@0 34 int32_t disp_;
michael@0 35
michael@0 36 public:
michael@0 37 explicit Operand(Register reg)
michael@0 38 : kind_(REG),
michael@0 39 base_(reg.code())
michael@0 40 { }
michael@0 41 explicit Operand(FloatRegister reg)
michael@0 42 : kind_(FPREG),
michael@0 43 base_(reg.code())
michael@0 44 { }
michael@0 45 explicit Operand(const Address &address)
michael@0 46 : kind_(MEM_REG_DISP),
michael@0 47 base_(address.base.code()),
michael@0 48 disp_(address.offset)
michael@0 49 { }
michael@0 50 explicit Operand(const BaseIndex &address)
michael@0 51 : kind_(MEM_SCALE),
michael@0 52 base_(address.base.code()),
michael@0 53 scale_(address.scale),
michael@0 54 index_(address.index.code()),
michael@0 55 disp_(address.offset)
michael@0 56 { }
michael@0 57 Operand(Register base, Register index, Scale scale, int32_t disp = 0)
michael@0 58 : kind_(MEM_SCALE),
michael@0 59 base_(base.code()),
michael@0 60 scale_(scale),
michael@0 61 index_(index.code()),
michael@0 62 disp_(disp)
michael@0 63 { }
michael@0 64 Operand(Register reg, int32_t disp)
michael@0 65 : kind_(MEM_REG_DISP),
michael@0 66 base_(reg.code()),
michael@0 67 disp_(disp)
michael@0 68 { }
michael@0 69 explicit Operand(const AbsoluteAddress &address)
michael@0 70 : kind_(MEM_ADDRESS32),
michael@0 71 disp_(JSC::X86Assembler::addressImmediate(address.addr))
michael@0 72 { }
michael@0 73
michael@0 74 Address toAddress() const {
michael@0 75 JS_ASSERT(kind() == MEM_REG_DISP);
michael@0 76 return Address(Register::FromCode(base()), disp());
michael@0 77 }
michael@0 78
michael@0 79 BaseIndex toBaseIndex() const {
michael@0 80 JS_ASSERT(kind() == MEM_SCALE);
michael@0 81 return BaseIndex(Register::FromCode(base()), Register::FromCode(index()), scale(), disp());
michael@0 82 }
michael@0 83
michael@0 84 Kind kind() const {
michael@0 85 return kind_;
michael@0 86 }
michael@0 87 Registers::Code reg() const {
michael@0 88 JS_ASSERT(kind() == REG);
michael@0 89 return (Registers::Code)base_;
michael@0 90 }
michael@0 91 Registers::Code base() const {
michael@0 92 JS_ASSERT(kind() == MEM_REG_DISP || kind() == MEM_SCALE);
michael@0 93 return (Registers::Code)base_;
michael@0 94 }
michael@0 95 Registers::Code index() const {
michael@0 96 JS_ASSERT(kind() == MEM_SCALE);
michael@0 97 return (Registers::Code)index_;
michael@0 98 }
michael@0 99 Scale scale() const {
michael@0 100 JS_ASSERT(kind() == MEM_SCALE);
michael@0 101 return scale_;
michael@0 102 }
michael@0 103 FloatRegisters::Code fpu() const {
michael@0 104 JS_ASSERT(kind() == FPREG);
michael@0 105 return (FloatRegisters::Code)base_;
michael@0 106 }
michael@0 107 int32_t disp() const {
michael@0 108 JS_ASSERT(kind() == MEM_REG_DISP || kind() == MEM_SCALE);
michael@0 109 return disp_;
michael@0 110 }
michael@0 111 void *address() const {
michael@0 112 JS_ASSERT(kind() == MEM_ADDRESS32);
michael@0 113 return reinterpret_cast<void *>(disp_);
michael@0 114 }
michael@0 115 };
michael@0 116
michael@0 117 class AssemblerX86Shared : public AssemblerShared
michael@0 118 {
michael@0 119 protected:
michael@0 120 struct RelativePatch {
michael@0 121 int32_t offset;
michael@0 122 void *target;
michael@0 123 Relocation::Kind kind;
michael@0 124
michael@0 125 RelativePatch(int32_t offset, void *target, Relocation::Kind kind)
michael@0 126 : offset(offset),
michael@0 127 target(target),
michael@0 128 kind(kind)
michael@0 129 { }
michael@0 130 };
michael@0 131
michael@0 132 Vector<CodeLabel, 0, SystemAllocPolicy> codeLabels_;
michael@0 133 Vector<RelativePatch, 8, SystemAllocPolicy> jumps_;
michael@0 134 CompactBufferWriter jumpRelocations_;
michael@0 135 CompactBufferWriter dataRelocations_;
michael@0 136 CompactBufferWriter preBarriers_;
michael@0 137 bool enoughMemory_;
michael@0 138
michael@0 139 void writeDataRelocation(const Value &val) {
michael@0 140 if (val.isMarkable()) {
michael@0 141 JS_ASSERT(static_cast<gc::Cell*>(val.toGCThing())->isTenured());
michael@0 142 dataRelocations_.writeUnsigned(masm.currentOffset());
michael@0 143 }
michael@0 144 }
michael@0 145 void writeDataRelocation(const ImmGCPtr &ptr) {
michael@0 146 if (ptr.value)
michael@0 147 dataRelocations_.writeUnsigned(masm.currentOffset());
michael@0 148 }
michael@0 149 void writePrebarrierOffset(CodeOffsetLabel label) {
michael@0 150 preBarriers_.writeUnsigned(label.offset());
michael@0 151 }
michael@0 152
michael@0 153 protected:
michael@0 154 JSC::X86Assembler masm;
michael@0 155
michael@0 156 typedef JSC::X86Assembler::JmpSrc JmpSrc;
michael@0 157 typedef JSC::X86Assembler::JmpDst JmpDst;
michael@0 158
michael@0 159 public:
michael@0 160 enum Condition {
michael@0 161 Equal = JSC::X86Assembler::ConditionE,
michael@0 162 NotEqual = JSC::X86Assembler::ConditionNE,
michael@0 163 Above = JSC::X86Assembler::ConditionA,
michael@0 164 AboveOrEqual = JSC::X86Assembler::ConditionAE,
michael@0 165 Below = JSC::X86Assembler::ConditionB,
michael@0 166 BelowOrEqual = JSC::X86Assembler::ConditionBE,
michael@0 167 GreaterThan = JSC::X86Assembler::ConditionG,
michael@0 168 GreaterThanOrEqual = JSC::X86Assembler::ConditionGE,
michael@0 169 LessThan = JSC::X86Assembler::ConditionL,
michael@0 170 LessThanOrEqual = JSC::X86Assembler::ConditionLE,
michael@0 171 Overflow = JSC::X86Assembler::ConditionO,
michael@0 172 Signed = JSC::X86Assembler::ConditionS,
michael@0 173 NotSigned = JSC::X86Assembler::ConditionNS,
michael@0 174 Zero = JSC::X86Assembler::ConditionE,
michael@0 175 NonZero = JSC::X86Assembler::ConditionNE,
michael@0 176 Parity = JSC::X86Assembler::ConditionP,
michael@0 177 NoParity = JSC::X86Assembler::ConditionNP
michael@0 178 };
michael@0 179
michael@0 180 // If this bit is set, the ucomisd operands have to be inverted.
michael@0 181 static const int DoubleConditionBitInvert = 0x10;
michael@0 182
michael@0 183 // Bit set when a DoubleCondition does not map to a single x86 condition.
michael@0 184 // The macro assembler has to special-case these conditions.
michael@0 185 static const int DoubleConditionBitSpecial = 0x20;
michael@0 186 static const int DoubleConditionBits = DoubleConditionBitInvert | DoubleConditionBitSpecial;
michael@0 187
michael@0 188 enum DoubleCondition {
michael@0 189 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
michael@0 190 DoubleOrdered = NoParity,
michael@0 191 DoubleEqual = Equal | DoubleConditionBitSpecial,
michael@0 192 DoubleNotEqual = NotEqual,
michael@0 193 DoubleGreaterThan = Above,
michael@0 194 DoubleGreaterThanOrEqual = AboveOrEqual,
michael@0 195 DoubleLessThan = Above | DoubleConditionBitInvert,
michael@0 196 DoubleLessThanOrEqual = AboveOrEqual | DoubleConditionBitInvert,
michael@0 197 // If either operand is NaN, these conditions always evaluate to true.
michael@0 198 DoubleUnordered = Parity,
michael@0 199 DoubleEqualOrUnordered = Equal,
michael@0 200 DoubleNotEqualOrUnordered = NotEqual | DoubleConditionBitSpecial,
michael@0 201 DoubleGreaterThanOrUnordered = Below | DoubleConditionBitInvert,
michael@0 202 DoubleGreaterThanOrEqualOrUnordered = BelowOrEqual | DoubleConditionBitInvert,
michael@0 203 DoubleLessThanOrUnordered = Below,
michael@0 204 DoubleLessThanOrEqualOrUnordered = BelowOrEqual
michael@0 205 };
michael@0 206
michael@0 207 enum NaNCond {
michael@0 208 NaN_HandledByCond,
michael@0 209 NaN_IsTrue,
michael@0 210 NaN_IsFalse
michael@0 211 };
michael@0 212
michael@0 213 // If the primary condition returned by ConditionFromDoubleCondition doesn't
michael@0 214 // handle NaNs properly, return NaN_IsFalse if the comparison should be
michael@0 215 // overridden to return false on NaN, NaN_IsTrue if it should be overridden
michael@0 216 // to return true on NaN, or NaN_HandledByCond if no secondary check is
michael@0 217 // needed.
michael@0 218 static inline NaNCond NaNCondFromDoubleCondition(DoubleCondition cond) {
michael@0 219 switch (cond) {
michael@0 220 case DoubleOrdered:
michael@0 221 case DoubleNotEqual:
michael@0 222 case DoubleGreaterThan:
michael@0 223 case DoubleGreaterThanOrEqual:
michael@0 224 case DoubleLessThan:
michael@0 225 case DoubleLessThanOrEqual:
michael@0 226 case DoubleUnordered:
michael@0 227 case DoubleEqualOrUnordered:
michael@0 228 case DoubleGreaterThanOrUnordered:
michael@0 229 case DoubleGreaterThanOrEqualOrUnordered:
michael@0 230 case DoubleLessThanOrUnordered:
michael@0 231 case DoubleLessThanOrEqualOrUnordered:
michael@0 232 return NaN_HandledByCond;
michael@0 233 case DoubleEqual:
michael@0 234 return NaN_IsFalse;
michael@0 235 case DoubleNotEqualOrUnordered:
michael@0 236 return NaN_IsTrue;
michael@0 237 }
michael@0 238
michael@0 239 MOZ_ASSUME_UNREACHABLE("Unknown double condition");
michael@0 240 }
michael@0 241
michael@0 242 static void staticAsserts() {
michael@0 243 // DoubleConditionBits should not interfere with x86 condition codes.
michael@0 244 JS_STATIC_ASSERT(!((Equal | NotEqual | Above | AboveOrEqual | Below |
michael@0 245 BelowOrEqual | Parity | NoParity) & DoubleConditionBits));
michael@0 246 }
michael@0 247
michael@0 248 AssemblerX86Shared()
michael@0 249 : enoughMemory_(true)
michael@0 250 {
michael@0 251 }
michael@0 252
michael@0 253 static Condition InvertCondition(Condition cond);
michael@0 254
michael@0 255 // Return the primary condition to test. Some primary conditions may not
michael@0 256 // handle NaNs properly and may therefore require a secondary condition.
michael@0 257 // Use NaNCondFromDoubleCondition to determine what else is needed.
michael@0 258 static inline Condition ConditionFromDoubleCondition(DoubleCondition cond) {
michael@0 259 return static_cast<Condition>(cond & ~DoubleConditionBits);
michael@0 260 }
michael@0 261
michael@0 262 static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
michael@0 263
michael@0 264 // MacroAssemblers hold onto gcthings, so they are traced by the GC.
michael@0 265 void trace(JSTracer *trc);
michael@0 266
michael@0 267 bool oom() const {
michael@0 268 return masm.oom() ||
michael@0 269 !enoughMemory_ ||
michael@0 270 jumpRelocations_.oom() ||
michael@0 271 dataRelocations_.oom() ||
michael@0 272 preBarriers_.oom();
michael@0 273 }
michael@0 274
michael@0 275 void setPrinter(Sprinter *sp) {
michael@0 276 masm.setPrinter(sp);
michael@0 277 }
michael@0 278
michael@0 279 void executableCopy(void *buffer);
michael@0 280 void processCodeLabels(uint8_t *rawCode);
michael@0 281 void copyJumpRelocationTable(uint8_t *dest);
michael@0 282 void copyDataRelocationTable(uint8_t *dest);
michael@0 283 void copyPreBarrierTable(uint8_t *dest);
michael@0 284
michael@0 285 bool addCodeLabel(CodeLabel label) {
michael@0 286 return codeLabels_.append(label);
michael@0 287 }
michael@0 288 size_t numCodeLabels() const {
michael@0 289 return codeLabels_.length();
michael@0 290 }
michael@0 291 CodeLabel codeLabel(size_t i) {
michael@0 292 return codeLabels_[i];
michael@0 293 }
michael@0 294
michael@0 295 // Size of the instruction stream, in bytes.
michael@0 296 size_t size() const {
michael@0 297 return masm.size();
michael@0 298 }
michael@0 299 // Size of the jump relocation table, in bytes.
michael@0 300 size_t jumpRelocationTableBytes() const {
michael@0 301 return jumpRelocations_.length();
michael@0 302 }
michael@0 303 size_t dataRelocationTableBytes() const {
michael@0 304 return dataRelocations_.length();
michael@0 305 }
michael@0 306 size_t preBarrierTableBytes() const {
michael@0 307 return preBarriers_.length();
michael@0 308 }
michael@0 309 // Size of the data table, in bytes.
michael@0 310 size_t bytesNeeded() const {
michael@0 311 return size() +
michael@0 312 jumpRelocationTableBytes() +
michael@0 313 dataRelocationTableBytes() +
michael@0 314 preBarrierTableBytes();
michael@0 315 }
michael@0 316
michael@0 317 public:
michael@0 318 void align(int alignment) {
michael@0 319 masm.align(alignment);
michael@0 320 }
michael@0 321 void writeCodePointer(AbsoluteLabel *label) {
michael@0 322 JS_ASSERT(!label->bound());
michael@0 323 // Thread the patch list through the unpatched address word in the
michael@0 324 // instruction stream.
michael@0 325 masm.jumpTablePointer(label->prev());
michael@0 326 label->setPrev(masm.size());
michael@0 327 }
michael@0 328 void writeDoubleConstant(double d, Label *label) {
michael@0 329 label->bind(masm.size());
michael@0 330 masm.doubleConstant(d);
michael@0 331 }
michael@0 332 void writeFloatConstant(float f, Label *label) {
michael@0 333 label->bind(masm.size());
michael@0 334 masm.floatConstant(f);
michael@0 335 }
michael@0 336 void movl(const Imm32 &imm32, const Register &dest) {
michael@0 337 masm.movl_i32r(imm32.value, dest.code());
michael@0 338 }
michael@0 339 void movl(const Register &src, const Register &dest) {
michael@0 340 masm.movl_rr(src.code(), dest.code());
michael@0 341 }
michael@0 342 void movl(const Operand &src, const Register &dest) {
michael@0 343 switch (src.kind()) {
michael@0 344 case Operand::REG:
michael@0 345 masm.movl_rr(src.reg(), dest.code());
michael@0 346 break;
michael@0 347 case Operand::MEM_REG_DISP:
michael@0 348 masm.movl_mr(src.disp(), src.base(), dest.code());
michael@0 349 break;
michael@0 350 case Operand::MEM_SCALE:
michael@0 351 masm.movl_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
michael@0 352 break;
michael@0 353 case Operand::MEM_ADDRESS32:
michael@0 354 masm.movl_mr(src.address(), dest.code());
michael@0 355 break;
michael@0 356 default:
michael@0 357 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 358 }
michael@0 359 }
michael@0 360 void movl(const Register &src, const Operand &dest) {
michael@0 361 switch (dest.kind()) {
michael@0 362 case Operand::REG:
michael@0 363 masm.movl_rr(src.code(), dest.reg());
michael@0 364 break;
michael@0 365 case Operand::MEM_REG_DISP:
michael@0 366 masm.movl_rm(src.code(), dest.disp(), dest.base());
michael@0 367 break;
michael@0 368 case Operand::MEM_SCALE:
michael@0 369 masm.movl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
michael@0 370 break;
michael@0 371 case Operand::MEM_ADDRESS32:
michael@0 372 masm.movl_rm(src.code(), dest.address());
michael@0 373 break;
michael@0 374 default:
michael@0 375 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 376 }
michael@0 377 }
michael@0 378 void movl(const Imm32 &imm32, const Operand &dest) {
michael@0 379 switch (dest.kind()) {
michael@0 380 case Operand::REG:
michael@0 381 masm.movl_i32r(imm32.value, dest.reg());
michael@0 382 break;
michael@0 383 case Operand::MEM_REG_DISP:
michael@0 384 masm.movl_i32m(imm32.value, dest.disp(), dest.base());
michael@0 385 break;
michael@0 386 case Operand::MEM_SCALE:
michael@0 387 masm.movl_i32m(imm32.value, dest.disp(), dest.base(), dest.index(), dest.scale());
michael@0 388 break;
michael@0 389 default:
michael@0 390 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 391 }
michael@0 392 }
michael@0 393
michael@0 394 void xchgl(const Register &src, const Register &dest) {
michael@0 395 masm.xchgl_rr(src.code(), dest.code());
michael@0 396 }
michael@0 397
michael@0 398 // Eventually movapd and movaps should be overloaded to support loads and
michael@0 399 // stores too.
michael@0 400 void movapd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 401 JS_ASSERT(HasSSE2());
michael@0 402 masm.movapd_rr(src.code(), dest.code());
michael@0 403 }
michael@0 404 void movaps(const FloatRegister &src, const FloatRegister &dest) {
michael@0 405 JS_ASSERT(HasSSE2());
michael@0 406 masm.movaps_rr(src.code(), dest.code());
michael@0 407 }
michael@0 408
michael@0 409 // movsd and movss are only provided in load/store form since the
michael@0 410 // register-to-register form has different semantics (it doesn't clobber
michael@0 411 // the whole output register) and isn't needed currently.
michael@0 412 void movsd(const Address &src, const FloatRegister &dest) {
michael@0 413 masm.movsd_mr(src.offset, src.base.code(), dest.code());
michael@0 414 }
michael@0 415 void movsd(const BaseIndex &src, const FloatRegister &dest) {
michael@0 416 masm.movsd_mr(src.offset, src.base.code(), src.index.code(), src.scale, dest.code());
michael@0 417 }
michael@0 418 void movsd(const FloatRegister &src, const Address &dest) {
michael@0 419 masm.movsd_rm(src.code(), dest.offset, dest.base.code());
michael@0 420 }
michael@0 421 void movsd(const FloatRegister &src, const BaseIndex &dest) {
michael@0 422 masm.movsd_rm(src.code(), dest.offset, dest.base.code(), dest.index.code(), dest.scale);
michael@0 423 }
michael@0 424 void movss(const Address &src, const FloatRegister &dest) {
michael@0 425 masm.movss_mr(src.offset, src.base.code(), dest.code());
michael@0 426 }
michael@0 427 void movss(const BaseIndex &src, const FloatRegister &dest) {
michael@0 428 masm.movss_mr(src.offset, src.base.code(), src.index.code(), src.scale, dest.code());
michael@0 429 }
michael@0 430 void movss(const FloatRegister &src, const Address &dest) {
michael@0 431 masm.movss_rm(src.code(), dest.offset, dest.base.code());
michael@0 432 }
michael@0 433 void movss(const FloatRegister &src, const BaseIndex &dest) {
michael@0 434 masm.movss_rm(src.code(), dest.offset, dest.base.code(), dest.index.code(), dest.scale);
michael@0 435 }
michael@0 436 void movdqa(const Operand &src, const FloatRegister &dest) {
michael@0 437 JS_ASSERT(HasSSE2());
michael@0 438 switch (src.kind()) {
michael@0 439 case Operand::MEM_REG_DISP:
michael@0 440 masm.movdqa_mr(src.disp(), src.base(), dest.code());
michael@0 441 break;
michael@0 442 case Operand::MEM_SCALE:
michael@0 443 masm.movdqa_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
michael@0 444 break;
michael@0 445 default:
michael@0 446 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 447 }
michael@0 448 }
michael@0 449 void movdqa(const FloatRegister &src, const Operand &dest) {
michael@0 450 JS_ASSERT(HasSSE2());
michael@0 451 switch (dest.kind()) {
michael@0 452 case Operand::MEM_REG_DISP:
michael@0 453 masm.movdqa_rm(src.code(), dest.disp(), dest.base());
michael@0 454 break;
michael@0 455 case Operand::MEM_SCALE:
michael@0 456 masm.movdqa_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
michael@0 457 break;
michael@0 458 default:
michael@0 459 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 460 }
michael@0 461 }
michael@0 462 void cvtss2sd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 463 JS_ASSERT(HasSSE2());
michael@0 464 masm.cvtss2sd_rr(src.code(), dest.code());
michael@0 465 }
michael@0 466 void cvtsd2ss(const FloatRegister &src, const FloatRegister &dest) {
michael@0 467 JS_ASSERT(HasSSE2());
michael@0 468 masm.cvtsd2ss_rr(src.code(), dest.code());
michael@0 469 }
michael@0 470 void movzbl(const Operand &src, const Register &dest) {
michael@0 471 switch (src.kind()) {
michael@0 472 case Operand::MEM_REG_DISP:
michael@0 473 masm.movzbl_mr(src.disp(), src.base(), dest.code());
michael@0 474 break;
michael@0 475 case Operand::MEM_SCALE:
michael@0 476 masm.movzbl_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
michael@0 477 break;
michael@0 478 default:
michael@0 479 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 480 }
michael@0 481 }
michael@0 482 void movsbl(const Operand &src, const Register &dest) {
michael@0 483 switch (src.kind()) {
michael@0 484 case Operand::MEM_REG_DISP:
michael@0 485 masm.movsbl_mr(src.disp(), src.base(), dest.code());
michael@0 486 break;
michael@0 487 case Operand::MEM_SCALE:
michael@0 488 masm.movsbl_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
michael@0 489 break;
michael@0 490 default:
michael@0 491 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 492 }
michael@0 493 }
michael@0 494 void movb(const Register &src, const Operand &dest) {
michael@0 495 switch (dest.kind()) {
michael@0 496 case Operand::MEM_REG_DISP:
michael@0 497 masm.movb_rm(src.code(), dest.disp(), dest.base());
michael@0 498 break;
michael@0 499 case Operand::MEM_SCALE:
michael@0 500 masm.movb_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
michael@0 501 break;
michael@0 502 default:
michael@0 503 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 504 }
michael@0 505 }
michael@0 506 void movb(const Imm32 &src, const Operand &dest) {
michael@0 507 switch (dest.kind()) {
michael@0 508 case Operand::MEM_REG_DISP:
michael@0 509 masm.movb_i8m(src.value, dest.disp(), dest.base());
michael@0 510 break;
michael@0 511 case Operand::MEM_SCALE:
michael@0 512 masm.movb_i8m(src.value, dest.disp(), dest.base(), dest.index(), dest.scale());
michael@0 513 break;
michael@0 514 default:
michael@0 515 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 516 }
michael@0 517 }
michael@0 518 void movzwl(const Operand &src, const Register &dest) {
michael@0 519 switch (src.kind()) {
michael@0 520 case Operand::REG:
michael@0 521 masm.movzwl_rr(src.reg(), dest.code());
michael@0 522 break;
michael@0 523 case Operand::MEM_REG_DISP:
michael@0 524 masm.movzwl_mr(src.disp(), src.base(), dest.code());
michael@0 525 break;
michael@0 526 case Operand::MEM_SCALE:
michael@0 527 masm.movzwl_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
michael@0 528 break;
michael@0 529 default:
michael@0 530 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 531 }
michael@0 532 }
michael@0 533 void movzwl(const Register &src, const Register &dest) {
michael@0 534 masm.movzwl_rr(src.code(), dest.code());
michael@0 535 }
michael@0 536 void movw(const Register &src, const Operand &dest) {
michael@0 537 switch (dest.kind()) {
michael@0 538 case Operand::MEM_REG_DISP:
michael@0 539 masm.movw_rm(src.code(), dest.disp(), dest.base());
michael@0 540 break;
michael@0 541 case Operand::MEM_SCALE:
michael@0 542 masm.movw_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
michael@0 543 break;
michael@0 544 default:
michael@0 545 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 546 }
michael@0 547 }
michael@0 548 void movw(const Imm32 &src, const Operand &dest) {
michael@0 549 switch (dest.kind()) {
michael@0 550 case Operand::MEM_REG_DISP:
michael@0 551 masm.movw_i16m(src.value, dest.disp(), dest.base());
michael@0 552 break;
michael@0 553 case Operand::MEM_SCALE:
michael@0 554 masm.movw_i16m(src.value, dest.disp(), dest.base(), dest.index(), dest.scale());
michael@0 555 break;
michael@0 556 default:
michael@0 557 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 558 }
michael@0 559 }
michael@0 560 void movswl(const Operand &src, const Register &dest) {
michael@0 561 switch (src.kind()) {
michael@0 562 case Operand::MEM_REG_DISP:
michael@0 563 masm.movswl_mr(src.disp(), src.base(), dest.code());
michael@0 564 break;
michael@0 565 case Operand::MEM_SCALE:
michael@0 566 masm.movswl_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
michael@0 567 break;
michael@0 568 default:
michael@0 569 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 570 }
michael@0 571 }
michael@0 572 void leal(const Operand &src, const Register &dest) {
michael@0 573 switch (src.kind()) {
michael@0 574 case Operand::MEM_REG_DISP:
michael@0 575 masm.leal_mr(src.disp(), src.base(), dest.code());
michael@0 576 break;
michael@0 577 case Operand::MEM_SCALE:
michael@0 578 masm.leal_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
michael@0 579 break;
michael@0 580 default:
michael@0 581 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 582 }
michael@0 583 }
michael@0 584
michael@0 585 protected:
michael@0 586 JmpSrc jSrc(Condition cond, Label *label) {
michael@0 587 JmpSrc j = masm.jCC(static_cast<JSC::X86Assembler::Condition>(cond));
michael@0 588 if (label->bound()) {
michael@0 589 // The jump can be immediately patched to the correct destination.
michael@0 590 masm.linkJump(j, JmpDst(label->offset()));
michael@0 591 } else {
michael@0 592 // Thread the jump list through the unpatched jump targets.
michael@0 593 JmpSrc prev = JmpSrc(label->use(j.offset()));
michael@0 594 masm.setNextJump(j, prev);
michael@0 595 }
michael@0 596 return j;
michael@0 597 }
michael@0 598 JmpSrc jmpSrc(Label *label) {
michael@0 599 JmpSrc j = masm.jmp();
michael@0 600 if (label->bound()) {
michael@0 601 // The jump can be immediately patched to the correct destination.
michael@0 602 masm.linkJump(j, JmpDst(label->offset()));
michael@0 603 } else {
michael@0 604 // Thread the jump list through the unpatched jump targets.
michael@0 605 JmpSrc prev = JmpSrc(label->use(j.offset()));
michael@0 606 masm.setNextJump(j, prev);
michael@0 607 }
michael@0 608 return j;
michael@0 609 }
michael@0 610
michael@0 611 // Comparison of EAX against the address given by a Label.
michael@0 612 JmpSrc cmpSrc(Label *label) {
michael@0 613 JmpSrc j = masm.cmp_eax();
michael@0 614 if (label->bound()) {
michael@0 615 // The jump can be immediately patched to the correct destination.
michael@0 616 masm.linkJump(j, JmpDst(label->offset()));
michael@0 617 } else {
michael@0 618 // Thread the jump list through the unpatched jump targets.
michael@0 619 JmpSrc prev = JmpSrc(label->use(j.offset()));
michael@0 620 masm.setNextJump(j, prev);
michael@0 621 }
michael@0 622 return j;
michael@0 623 }
michael@0 624
michael@0 625 JmpSrc jSrc(Condition cond, RepatchLabel *label) {
michael@0 626 JmpSrc j = masm.jCC(static_cast<JSC::X86Assembler::Condition>(cond));
michael@0 627 if (label->bound()) {
michael@0 628 // The jump can be immediately patched to the correct destination.
michael@0 629 masm.linkJump(j, JmpDst(label->offset()));
michael@0 630 } else {
michael@0 631 label->use(j.offset());
michael@0 632 }
michael@0 633 return j;
michael@0 634 }
michael@0 635 JmpSrc jmpSrc(RepatchLabel *label) {
michael@0 636 JmpSrc j = masm.jmp();
michael@0 637 if (label->bound()) {
michael@0 638 // The jump can be immediately patched to the correct destination.
michael@0 639 masm.linkJump(j, JmpDst(label->offset()));
michael@0 640 } else {
michael@0 641 // Thread the jump list through the unpatched jump targets.
michael@0 642 label->use(j.offset());
michael@0 643 }
michael@0 644 return j;
michael@0 645 }
michael@0 646
michael@0 647 public:
michael@0 648 void nop() { masm.nop(); }
michael@0 649 void j(Condition cond, Label *label) { jSrc(cond, label); }
michael@0 650 void jmp(Label *label) { jmpSrc(label); }
michael@0 651 void j(Condition cond, RepatchLabel *label) { jSrc(cond, label); }
michael@0 652 void jmp(RepatchLabel *label) { jmpSrc(label); }
michael@0 653
michael@0 654 void jmp(const Operand &op) {
michael@0 655 switch (op.kind()) {
michael@0 656 case Operand::MEM_REG_DISP:
michael@0 657 masm.jmp_m(op.disp(), op.base());
michael@0 658 break;
michael@0 659 case Operand::MEM_SCALE:
michael@0 660 masm.jmp_m(op.disp(), op.base(), op.index(), op.scale());
michael@0 661 break;
michael@0 662 case Operand::REG:
michael@0 663 masm.jmp_r(op.reg());
michael@0 664 break;
michael@0 665 default:
michael@0 666 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 667 }
michael@0 668 }
michael@0 669 void cmpEAX(Label *label) { cmpSrc(label); }
michael@0 670 void bind(Label *label) {
michael@0 671 JSC::MacroAssembler::Label jsclabel;
michael@0 672 JSC::X86Assembler::JmpDst dst(masm.label());
michael@0 673 if (label->used()) {
michael@0 674 bool more;
michael@0 675 JSC::X86Assembler::JmpSrc jmp(label->offset());
michael@0 676 do {
michael@0 677 JSC::X86Assembler::JmpSrc next;
michael@0 678 more = masm.nextJump(jmp, &next);
michael@0 679 masm.linkJump(jmp, dst);
michael@0 680 jmp = next;
michael@0 681 } while (more);
michael@0 682 }
michael@0 683 label->bind(dst.offset());
michael@0 684 }
michael@0 685 void bind(RepatchLabel *label) {
michael@0 686 JSC::MacroAssembler::Label jsclabel;
michael@0 687 JSC::X86Assembler::JmpDst dst(masm.label());
michael@0 688 if (label->used()) {
michael@0 689 JSC::X86Assembler::JmpSrc jmp(label->offset());
michael@0 690 masm.linkJump(jmp, dst);
michael@0 691 }
michael@0 692 label->bind(dst.offset());
michael@0 693 }
michael@0 694 uint32_t currentOffset() {
michael@0 695 return masm.label().offset();
michael@0 696 }
michael@0 697
michael@0 698 // Re-routes pending jumps to a new label.
michael@0 699 void retarget(Label *label, Label *target) {
michael@0 700 JSC::MacroAssembler::Label jsclabel;
michael@0 701 if (label->used()) {
michael@0 702 bool more;
michael@0 703 JSC::X86Assembler::JmpSrc jmp(label->offset());
michael@0 704 do {
michael@0 705 JSC::X86Assembler::JmpSrc next;
michael@0 706 more = masm.nextJump(jmp, &next);
michael@0 707
michael@0 708 if (target->bound()) {
michael@0 709 // The jump can be immediately patched to the correct destination.
michael@0 710 masm.linkJump(jmp, JmpDst(target->offset()));
michael@0 711 } else {
michael@0 712 // Thread the jump list through the unpatched jump targets.
michael@0 713 JmpSrc prev = JmpSrc(target->use(jmp.offset()));
michael@0 714 masm.setNextJump(jmp, prev);
michael@0 715 }
michael@0 716
michael@0 717 jmp = next;
michael@0 718 } while (more);
michael@0 719 }
michael@0 720 label->reset();
michael@0 721 }
michael@0 722
michael@0 723 static void Bind(uint8_t *raw, AbsoluteLabel *label, const void *address) {
michael@0 724 if (label->used()) {
michael@0 725 intptr_t src = label->offset();
michael@0 726 do {
michael@0 727 intptr_t next = reinterpret_cast<intptr_t>(JSC::X86Assembler::getPointer(raw + src));
michael@0 728 JSC::X86Assembler::setPointer(raw + src, address);
michael@0 729 src = next;
michael@0 730 } while (src != AbsoluteLabel::INVALID_OFFSET);
michael@0 731 }
michael@0 732 label->bind();
michael@0 733 }
michael@0 734
michael@0 735 // See Bind and JSC::X86Assembler::setPointer.
michael@0 736 size_t labelOffsetToPatchOffset(size_t offset) {
michael@0 737 return offset - sizeof(void*);
michael@0 738 }
michael@0 739
michael@0 740 void ret() {
michael@0 741 masm.ret();
michael@0 742 }
michael@0 743 void retn(Imm32 n) {
michael@0 744 // Remove the size of the return address which is included in the frame.
michael@0 745 masm.ret(n.value - sizeof(void *));
michael@0 746 }
michael@0 747 void call(Label *label) {
michael@0 748 if (label->bound()) {
michael@0 749 masm.linkJump(masm.call(), JmpDst(label->offset()));
michael@0 750 } else {
michael@0 751 JmpSrc j = masm.call();
michael@0 752 JmpSrc prev = JmpSrc(label->use(j.offset()));
michael@0 753 masm.setNextJump(j, prev);
michael@0 754 }
michael@0 755 }
michael@0 756 void call(const Register &reg) {
michael@0 757 masm.call(reg.code());
michael@0 758 }
michael@0 759 void call(const Operand &op) {
michael@0 760 switch (op.kind()) {
michael@0 761 case Operand::REG:
michael@0 762 masm.call(op.reg());
michael@0 763 break;
michael@0 764 case Operand::MEM_REG_DISP:
michael@0 765 masm.call_m(op.disp(), op.base());
michael@0 766 break;
michael@0 767 default:
michael@0 768 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 769 }
michael@0 770 }
michael@0 771
michael@0 772 void breakpoint() {
michael@0 773 masm.int3();
michael@0 774 }
michael@0 775
michael@0 776 #ifdef DEBUG
michael@0 777 static bool HasSSE2() {
michael@0 778 return JSC::MacroAssembler::isSSE2Present();
michael@0 779 }
michael@0 780 #endif
michael@0 781 static bool HasSSE3() {
michael@0 782 return JSC::MacroAssembler::isSSE3Present();
michael@0 783 }
michael@0 784 static bool HasSSE41() {
michael@0 785 return JSC::MacroAssembler::isSSE41Present();
michael@0 786 }
michael@0 787
michael@0 788 // The below cmpl methods switch the lhs and rhs when it invokes the
michael@0 789 // macroassembler to conform with intel standard. When calling this
michael@0 790 // function put the left operand on the left as you would expect.
michael@0 791 void cmpl(const Register &lhs, const Register &rhs) {
michael@0 792 masm.cmpl_rr(rhs.code(), lhs.code());
michael@0 793 }
michael@0 794 void cmpl(const Register &lhs, const Operand &rhs) {
michael@0 795 switch (rhs.kind()) {
michael@0 796 case Operand::REG:
michael@0 797 masm.cmpl_rr(rhs.reg(), lhs.code());
michael@0 798 break;
michael@0 799 case Operand::MEM_REG_DISP:
michael@0 800 masm.cmpl_mr(rhs.disp(), rhs.base(), lhs.code());
michael@0 801 break;
michael@0 802 default:
michael@0 803 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 804 }
michael@0 805 }
michael@0 806 void cmpl(const Register &src, Imm32 imm) {
michael@0 807 masm.cmpl_ir(imm.value, src.code());
michael@0 808 }
michael@0 809 void cmpl(const Operand &op, Imm32 imm) {
michael@0 810 switch (op.kind()) {
michael@0 811 case Operand::REG:
michael@0 812 masm.cmpl_ir(imm.value, op.reg());
michael@0 813 break;
michael@0 814 case Operand::MEM_REG_DISP:
michael@0 815 masm.cmpl_im(imm.value, op.disp(), op.base());
michael@0 816 break;
michael@0 817 case Operand::MEM_SCALE:
michael@0 818 masm.cmpl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
michael@0 819 break;
michael@0 820 case Operand::MEM_ADDRESS32:
michael@0 821 masm.cmpl_im(imm.value, op.address());
michael@0 822 break;
michael@0 823 default:
michael@0 824 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 825 }
michael@0 826 }
michael@0 827 void cmpl(const Operand &lhs, const Register &rhs) {
michael@0 828 switch (lhs.kind()) {
michael@0 829 case Operand::REG:
michael@0 830 masm.cmpl_rr(rhs.code(), lhs.reg());
michael@0 831 break;
michael@0 832 case Operand::MEM_REG_DISP:
michael@0 833 masm.cmpl_rm(rhs.code(), lhs.disp(), lhs.base());
michael@0 834 break;
michael@0 835 case Operand::MEM_ADDRESS32:
michael@0 836 masm.cmpl_rm(rhs.code(), lhs.address());
michael@0 837 break;
michael@0 838 default:
michael@0 839 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 840 }
michael@0 841 }
michael@0 842 void cmpl(const Operand &op, ImmWord imm) {
michael@0 843 switch (op.kind()) {
michael@0 844 case Operand::REG:
michael@0 845 masm.cmpl_ir(imm.value, op.reg());
michael@0 846 break;
michael@0 847 case Operand::MEM_REG_DISP:
michael@0 848 masm.cmpl_im(imm.value, op.disp(), op.base());
michael@0 849 break;
michael@0 850 case Operand::MEM_ADDRESS32:
michael@0 851 masm.cmpl_im(imm.value, op.address());
michael@0 852 break;
michael@0 853 default:
michael@0 854 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 855 }
michael@0 856 }
michael@0 857 void cmpl(const Operand &op, ImmPtr imm) {
michael@0 858 cmpl(op, ImmWord(uintptr_t(imm.value)));
michael@0 859 }
michael@0 860 void cmpw(const Register &lhs, const Register &rhs) {
michael@0 861 masm.cmpw_rr(lhs.code(), rhs.code());
michael@0 862 }
michael@0 863 void setCC(Condition cond, const Register &r) {
michael@0 864 masm.setCC_r(static_cast<JSC::X86Assembler::Condition>(cond), r.code());
michael@0 865 }
michael@0 866 void testb(const Register &lhs, const Register &rhs) {
michael@0 867 JS_ASSERT(GeneralRegisterSet(Registers::SingleByteRegs).has(lhs));
michael@0 868 JS_ASSERT(GeneralRegisterSet(Registers::SingleByteRegs).has(rhs));
michael@0 869 masm.testb_rr(rhs.code(), lhs.code());
michael@0 870 }
michael@0 871 void testw(const Register &lhs, const Register &rhs) {
michael@0 872 masm.testw_rr(rhs.code(), lhs.code());
michael@0 873 }
michael@0 874 void testl(const Register &lhs, const Register &rhs) {
michael@0 875 masm.testl_rr(rhs.code(), lhs.code());
michael@0 876 }
michael@0 877 void testl(const Register &lhs, Imm32 rhs) {
michael@0 878 masm.testl_i32r(rhs.value, lhs.code());
michael@0 879 }
michael@0 880 void testl(const Operand &lhs, Imm32 rhs) {
michael@0 881 switch (lhs.kind()) {
michael@0 882 case Operand::REG:
michael@0 883 masm.testl_i32r(rhs.value, lhs.reg());
michael@0 884 break;
michael@0 885 case Operand::MEM_REG_DISP:
michael@0 886 masm.testl_i32m(rhs.value, lhs.disp(), lhs.base());
michael@0 887 break;
michael@0 888 default:
michael@0 889 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 890 break;
michael@0 891 }
michael@0 892 }
michael@0 893
michael@0 894 void addl(Imm32 imm, const Register &dest) {
michael@0 895 masm.addl_ir(imm.value, dest.code());
michael@0 896 }
michael@0 897 void addl(Imm32 imm, const Operand &op) {
michael@0 898 switch (op.kind()) {
michael@0 899 case Operand::REG:
michael@0 900 masm.addl_ir(imm.value, op.reg());
michael@0 901 break;
michael@0 902 case Operand::MEM_REG_DISP:
michael@0 903 masm.addl_im(imm.value, op.disp(), op.base());
michael@0 904 break;
michael@0 905 case Operand::MEM_ADDRESS32:
michael@0 906 masm.addl_im(imm.value, op.address());
michael@0 907 break;
michael@0 908 default:
michael@0 909 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 910 }
michael@0 911 }
michael@0 912 void subl(Imm32 imm, const Register &dest) {
michael@0 913 masm.subl_ir(imm.value, dest.code());
michael@0 914 }
michael@0 915 void subl(Imm32 imm, const Operand &op) {
michael@0 916 switch (op.kind()) {
michael@0 917 case Operand::REG:
michael@0 918 masm.subl_ir(imm.value, op.reg());
michael@0 919 break;
michael@0 920 case Operand::MEM_REG_DISP:
michael@0 921 masm.subl_im(imm.value, op.disp(), op.base());
michael@0 922 break;
michael@0 923 default:
michael@0 924 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 925 }
michael@0 926 }
michael@0 927 void addl(const Register &src, const Register &dest) {
michael@0 928 masm.addl_rr(src.code(), dest.code());
michael@0 929 }
michael@0 930 void subl(const Register &src, const Register &dest) {
michael@0 931 masm.subl_rr(src.code(), dest.code());
michael@0 932 }
michael@0 933 void subl(const Operand &src, const Register &dest) {
michael@0 934 switch (src.kind()) {
michael@0 935 case Operand::REG:
michael@0 936 masm.subl_rr(src.reg(), dest.code());
michael@0 937 break;
michael@0 938 case Operand::MEM_REG_DISP:
michael@0 939 masm.subl_mr(src.disp(), src.base(), dest.code());
michael@0 940 break;
michael@0 941 default:
michael@0 942 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 943 }
michael@0 944 }
michael@0 945 void subl(const Register &src, const Operand &dest) {
michael@0 946 switch (dest.kind()) {
michael@0 947 case Operand::REG:
michael@0 948 masm.subl_rr(src.code(), dest.reg());
michael@0 949 break;
michael@0 950 case Operand::MEM_REG_DISP:
michael@0 951 masm.subl_rm(src.code(), dest.disp(), dest.base());
michael@0 952 break;
michael@0 953 default:
michael@0 954 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 955 }
michael@0 956 }
michael@0 957 void orl(const Register &reg, const Register &dest) {
michael@0 958 masm.orl_rr(reg.code(), dest.code());
michael@0 959 }
michael@0 960 void orl(Imm32 imm, const Register &reg) {
michael@0 961 masm.orl_ir(imm.value, reg.code());
michael@0 962 }
michael@0 963 void orl(Imm32 imm, const Operand &op) {
michael@0 964 switch (op.kind()) {
michael@0 965 case Operand::REG:
michael@0 966 masm.orl_ir(imm.value, op.reg());
michael@0 967 break;
michael@0 968 case Operand::MEM_REG_DISP:
michael@0 969 masm.orl_im(imm.value, op.disp(), op.base());
michael@0 970 break;
michael@0 971 default:
michael@0 972 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 973 }
michael@0 974 }
michael@0 975 void xorl(const Register &src, const Register &dest) {
michael@0 976 masm.xorl_rr(src.code(), dest.code());
michael@0 977 }
michael@0 978 void xorl(Imm32 imm, const Register &reg) {
michael@0 979 masm.xorl_ir(imm.value, reg.code());
michael@0 980 }
michael@0 981 void xorl(Imm32 imm, const Operand &op) {
michael@0 982 switch (op.kind()) {
michael@0 983 case Operand::REG:
michael@0 984 masm.xorl_ir(imm.value, op.reg());
michael@0 985 break;
michael@0 986 case Operand::MEM_REG_DISP:
michael@0 987 masm.xorl_im(imm.value, op.disp(), op.base());
michael@0 988 break;
michael@0 989 default:
michael@0 990 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 991 }
michael@0 992 }
michael@0 993 void andl(const Register &src, const Register &dest) {
michael@0 994 masm.andl_rr(src.code(), dest.code());
michael@0 995 }
michael@0 996 void andl(Imm32 imm, const Register &dest) {
michael@0 997 masm.andl_ir(imm.value, dest.code());
michael@0 998 }
michael@0 999 void andl(Imm32 imm, const Operand &op) {
michael@0 1000 switch (op.kind()) {
michael@0 1001 case Operand::REG:
michael@0 1002 masm.andl_ir(imm.value, op.reg());
michael@0 1003 break;
michael@0 1004 case Operand::MEM_REG_DISP:
michael@0 1005 masm.andl_im(imm.value, op.disp(), op.base());
michael@0 1006 break;
michael@0 1007 default:
michael@0 1008 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1009 }
michael@0 1010 }
michael@0 1011 void addl(const Operand &src, const Register &dest) {
michael@0 1012 switch (src.kind()) {
michael@0 1013 case Operand::REG:
michael@0 1014 masm.addl_rr(src.reg(), dest.code());
michael@0 1015 break;
michael@0 1016 case Operand::MEM_REG_DISP:
michael@0 1017 masm.addl_mr(src.disp(), src.base(), dest.code());
michael@0 1018 break;
michael@0 1019 default:
michael@0 1020 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1021 }
michael@0 1022 }
michael@0 1023 void orl(const Operand &src, const Register &dest) {
michael@0 1024 switch (src.kind()) {
michael@0 1025 case Operand::REG:
michael@0 1026 masm.orl_rr(src.reg(), dest.code());
michael@0 1027 break;
michael@0 1028 case Operand::MEM_REG_DISP:
michael@0 1029 masm.orl_mr(src.disp(), src.base(), dest.code());
michael@0 1030 break;
michael@0 1031 default:
michael@0 1032 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1033 }
michael@0 1034 }
michael@0 1035 void xorl(const Operand &src, const Register &dest) {
michael@0 1036 switch (src.kind()) {
michael@0 1037 case Operand::REG:
michael@0 1038 masm.xorl_rr(src.reg(), dest.code());
michael@0 1039 break;
michael@0 1040 case Operand::MEM_REG_DISP:
michael@0 1041 masm.xorl_mr(src.disp(), src.base(), dest.code());
michael@0 1042 break;
michael@0 1043 default:
michael@0 1044 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1045 }
michael@0 1046 }
michael@0 1047 void andl(const Operand &src, const Register &dest) {
michael@0 1048 switch (src.kind()) {
michael@0 1049 case Operand::REG:
michael@0 1050 masm.andl_rr(src.reg(), dest.code());
michael@0 1051 break;
michael@0 1052 case Operand::MEM_REG_DISP:
michael@0 1053 masm.andl_mr(src.disp(), src.base(), dest.code());
michael@0 1054 break;
michael@0 1055 default:
michael@0 1056 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1057 }
michael@0 1058 }
michael@0 1059 void imull(const Register &multiplier) {
michael@0 1060 masm.imull_r(multiplier.code());
michael@0 1061 }
michael@0 1062 void imull(Imm32 imm, const Register &dest) {
michael@0 1063 masm.imull_i32r(dest.code(), imm.value, dest.code());
michael@0 1064 }
michael@0 1065 void imull(const Register &src, const Register &dest) {
michael@0 1066 masm.imull_rr(src.code(), dest.code());
michael@0 1067 }
michael@0 1068 void imull(Imm32 imm, const Register &src, const Register &dest) {
michael@0 1069 masm.imull_i32r(src.code(), imm.value, dest.code());
michael@0 1070 }
michael@0 1071 void imull(const Operand &src, const Register &dest) {
michael@0 1072 switch (src.kind()) {
michael@0 1073 case Operand::REG:
michael@0 1074 masm.imull_rr(src.reg(), dest.code());
michael@0 1075 break;
michael@0 1076 case Operand::MEM_REG_DISP:
michael@0 1077 masm.imull_mr(src.disp(), src.base(), dest.code());
michael@0 1078 break;
michael@0 1079 default:
michael@0 1080 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1081 }
michael@0 1082 }
michael@0 1083 void negl(const Operand &src) {
michael@0 1084 switch (src.kind()) {
michael@0 1085 case Operand::REG:
michael@0 1086 masm.negl_r(src.reg());
michael@0 1087 break;
michael@0 1088 case Operand::MEM_REG_DISP:
michael@0 1089 masm.negl_m(src.disp(), src.base());
michael@0 1090 break;
michael@0 1091 default:
michael@0 1092 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1093 }
michael@0 1094 }
michael@0 1095 void negl(const Register &reg) {
michael@0 1096 masm.negl_r(reg.code());
michael@0 1097 }
michael@0 1098 void notl(const Operand &src) {
michael@0 1099 switch (src.kind()) {
michael@0 1100 case Operand::REG:
michael@0 1101 masm.notl_r(src.reg());
michael@0 1102 break;
michael@0 1103 case Operand::MEM_REG_DISP:
michael@0 1104 masm.notl_m(src.disp(), src.base());
michael@0 1105 break;
michael@0 1106 default:
michael@0 1107 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1108 }
michael@0 1109 }
michael@0 1110 void notl(const Register &reg) {
michael@0 1111 masm.notl_r(reg.code());
michael@0 1112 }
michael@0 1113 void shrl(const Imm32 imm, const Register &dest) {
michael@0 1114 masm.shrl_i8r(imm.value, dest.code());
michael@0 1115 }
michael@0 1116 void shll(const Imm32 imm, const Register &dest) {
michael@0 1117 masm.shll_i8r(imm.value, dest.code());
michael@0 1118 }
michael@0 1119 void sarl(const Imm32 imm, const Register &dest) {
michael@0 1120 masm.sarl_i8r(imm.value, dest.code());
michael@0 1121 }
michael@0 1122 void shrl_cl(const Register &dest) {
michael@0 1123 masm.shrl_CLr(dest.code());
michael@0 1124 }
michael@0 1125 void shll_cl(const Register &dest) {
michael@0 1126 masm.shll_CLr(dest.code());
michael@0 1127 }
michael@0 1128 void sarl_cl(const Register &dest) {
michael@0 1129 masm.sarl_CLr(dest.code());
michael@0 1130 }
michael@0 1131
michael@0 1132 void incl(const Operand &op) {
michael@0 1133 switch (op.kind()) {
michael@0 1134 case Operand::MEM_REG_DISP:
michael@0 1135 masm.incl_m32(op.disp(), op.base());
michael@0 1136 break;
michael@0 1137 default:
michael@0 1138 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1139 }
michael@0 1140 }
michael@0 1141 void lock_incl(const Operand &op) {
michael@0 1142 masm.prefix_lock();
michael@0 1143 incl(op);
michael@0 1144 }
michael@0 1145
michael@0 1146 void decl(const Operand &op) {
michael@0 1147 switch (op.kind()) {
michael@0 1148 case Operand::MEM_REG_DISP:
michael@0 1149 masm.decl_m32(op.disp(), op.base());
michael@0 1150 break;
michael@0 1151 default:
michael@0 1152 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1153 }
michael@0 1154 }
michael@0 1155 void lock_decl(const Operand &op) {
michael@0 1156 masm.prefix_lock();
michael@0 1157 decl(op);
michael@0 1158 }
michael@0 1159
michael@0 1160 void lock_cmpxchg32(const Register &src, const Operand &op) {
michael@0 1161 masm.prefix_lock();
michael@0 1162 switch (op.kind()) {
michael@0 1163 case Operand::MEM_REG_DISP:
michael@0 1164 masm.cmpxchg32(src.code(), op.disp(), op.base());
michael@0 1165 break;
michael@0 1166 default:
michael@0 1167 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1168 }
michael@0 1169 }
michael@0 1170
michael@0 1171 void xaddl(const Register &srcdest, const Operand &mem) {
michael@0 1172 switch (mem.kind()) {
michael@0 1173 case Operand::MEM_REG_DISP:
michael@0 1174 masm.xaddl_rm(srcdest.code(), mem.disp(), mem.base());
michael@0 1175 break;
michael@0 1176 case Operand::MEM_SCALE:
michael@0 1177 masm.xaddl_rm(srcdest.code(), mem.disp(), mem.base(), mem.index(), mem.scale());
michael@0 1178 break;
michael@0 1179 default:
michael@0 1180 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1181 }
michael@0 1182 }
michael@0 1183
michael@0 1184 void push(const Imm32 imm) {
michael@0 1185 masm.push_i32(imm.value);
michael@0 1186 }
michael@0 1187
michael@0 1188 void push(const Operand &src) {
michael@0 1189 switch (src.kind()) {
michael@0 1190 case Operand::REG:
michael@0 1191 masm.push_r(src.reg());
michael@0 1192 break;
michael@0 1193 case Operand::MEM_REG_DISP:
michael@0 1194 masm.push_m(src.disp(), src.base());
michael@0 1195 break;
michael@0 1196 default:
michael@0 1197 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1198 }
michael@0 1199 }
michael@0 1200 void push(const Register &src) {
michael@0 1201 masm.push_r(src.code());
michael@0 1202 }
michael@0 1203 void push(const Address &src) {
michael@0 1204 masm.push_m(src.offset, src.base.code());
michael@0 1205 }
michael@0 1206
michael@0 1207 void pop(const Operand &src) {
michael@0 1208 switch (src.kind()) {
michael@0 1209 case Operand::REG:
michael@0 1210 masm.pop_r(src.reg());
michael@0 1211 break;
michael@0 1212 case Operand::MEM_REG_DISP:
michael@0 1213 masm.pop_m(src.disp(), src.base());
michael@0 1214 break;
michael@0 1215 default:
michael@0 1216 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1217 }
michael@0 1218 }
michael@0 1219 void pop(const Register &src) {
michael@0 1220 masm.pop_r(src.code());
michael@0 1221 }
michael@0 1222
michael@0 1223 void pushFlags() {
michael@0 1224 masm.push_flags();
michael@0 1225 }
michael@0 1226 void popFlags() {
michael@0 1227 masm.pop_flags();
michael@0 1228 }
michael@0 1229
michael@0 1230 #ifdef JS_CODEGEN_X86
michael@0 1231 void pushAllRegs() {
michael@0 1232 masm.pusha();
michael@0 1233 }
michael@0 1234 void popAllRegs() {
michael@0 1235 masm.popa();
michael@0 1236 }
michael@0 1237 #endif
michael@0 1238
michael@0 1239 // Zero-extend byte to 32-bit integer.
michael@0 1240 void movzbl(const Register &src, const Register &dest) {
michael@0 1241 masm.movzbl_rr(src.code(), dest.code());
michael@0 1242 }
michael@0 1243
michael@0 1244 void cdq() {
michael@0 1245 masm.cdq();
michael@0 1246 }
michael@0 1247 void idiv(Register divisor) {
michael@0 1248 masm.idivl_r(divisor.code());
michael@0 1249 }
michael@0 1250 void udiv(Register divisor) {
michael@0 1251 masm.divl_r(divisor.code());
michael@0 1252 }
michael@0 1253
michael@0 1254 void unpcklps(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1255 JS_ASSERT(HasSSE2());
michael@0 1256 masm.unpcklps_rr(src.code(), dest.code());
michael@0 1257 }
michael@0 1258 void pinsrd(const Register &src, const FloatRegister &dest) {
michael@0 1259 JS_ASSERT(HasSSE2());
michael@0 1260 masm.pinsrd_rr(src.code(), dest.code());
michael@0 1261 }
michael@0 1262 void pinsrd(const Operand &src, const FloatRegister &dest) {
michael@0 1263 JS_ASSERT(HasSSE2());
michael@0 1264 switch (src.kind()) {
michael@0 1265 case Operand::REG:
michael@0 1266 masm.pinsrd_rr(src.reg(), dest.code());
michael@0 1267 break;
michael@0 1268 case Operand::MEM_REG_DISP:
michael@0 1269 masm.pinsrd_mr(src.disp(), src.base(), dest.code());
michael@0 1270 break;
michael@0 1271 default:
michael@0 1272 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1273 }
michael@0 1274 }
michael@0 1275 void psrldq(Imm32 shift, const FloatRegister &dest) {
michael@0 1276 JS_ASSERT(HasSSE2());
michael@0 1277 masm.psrldq_ir(shift.value, dest.code());
michael@0 1278 }
michael@0 1279 void psllq(Imm32 shift, const FloatRegister &dest) {
michael@0 1280 JS_ASSERT(HasSSE2());
michael@0 1281 masm.psllq_ir(shift.value, dest.code());
michael@0 1282 }
michael@0 1283 void psrlq(Imm32 shift, const FloatRegister &dest) {
michael@0 1284 JS_ASSERT(HasSSE2());
michael@0 1285 masm.psrlq_ir(shift.value, dest.code());
michael@0 1286 }
michael@0 1287
michael@0 1288 void cvtsi2sd(const Operand &src, const FloatRegister &dest) {
michael@0 1289 JS_ASSERT(HasSSE2());
michael@0 1290 switch (src.kind()) {
michael@0 1291 case Operand::REG:
michael@0 1292 masm.cvtsi2sd_rr(src.reg(), dest.code());
michael@0 1293 break;
michael@0 1294 case Operand::MEM_REG_DISP:
michael@0 1295 masm.cvtsi2sd_mr(src.disp(), src.base(), dest.code());
michael@0 1296 break;
michael@0 1297 case Operand::MEM_SCALE:
michael@0 1298 masm.cvtsi2sd_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
michael@0 1299 break;
michael@0 1300 default:
michael@0 1301 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1302 }
michael@0 1303 }
michael@0 1304 void cvttsd2si(const FloatRegister &src, const Register &dest) {
michael@0 1305 JS_ASSERT(HasSSE2());
michael@0 1306 masm.cvttsd2si_rr(src.code(), dest.code());
michael@0 1307 }
michael@0 1308 void cvttss2si(const FloatRegister &src, const Register &dest) {
michael@0 1309 JS_ASSERT(HasSSE2());
michael@0 1310 masm.cvttss2si_rr(src.code(), dest.code());
michael@0 1311 }
michael@0 1312 void cvtsi2ss(const Operand &src, const FloatRegister &dest) {
michael@0 1313 JS_ASSERT(HasSSE2());
michael@0 1314 switch (src.kind()) {
michael@0 1315 case Operand::REG:
michael@0 1316 masm.cvtsi2ss_rr(src.reg(), dest.code());
michael@0 1317 break;
michael@0 1318 case Operand::MEM_REG_DISP:
michael@0 1319 masm.cvtsi2ss_mr(src.disp(), src.base(), dest.code());
michael@0 1320 break;
michael@0 1321 case Operand::MEM_SCALE:
michael@0 1322 masm.cvtsi2ss_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
michael@0 1323 break;
michael@0 1324 default:
michael@0 1325 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1326 }
michael@0 1327 }
michael@0 1328 void cvtsi2ss(const Register &src, const FloatRegister &dest) {
michael@0 1329 JS_ASSERT(HasSSE2());
michael@0 1330 masm.cvtsi2ss_rr(src.code(), dest.code());
michael@0 1331 }
michael@0 1332 void cvtsi2sd(const Register &src, const FloatRegister &dest) {
michael@0 1333 JS_ASSERT(HasSSE2());
michael@0 1334 masm.cvtsi2sd_rr(src.code(), dest.code());
michael@0 1335 }
michael@0 1336 void movmskpd(const FloatRegister &src, const Register &dest) {
michael@0 1337 JS_ASSERT(HasSSE2());
michael@0 1338 masm.movmskpd_rr(src.code(), dest.code());
michael@0 1339 }
michael@0 1340 void movmskps(const FloatRegister &src, const Register &dest) {
michael@0 1341 JS_ASSERT(HasSSE2());
michael@0 1342 masm.movmskps_rr(src.code(), dest.code());
michael@0 1343 }
michael@0 1344 void ptest(const FloatRegister &lhs, const FloatRegister &rhs) {
michael@0 1345 JS_ASSERT(HasSSE41());
michael@0 1346 masm.ptest_rr(rhs.code(), lhs.code());
michael@0 1347 }
michael@0 1348 void ucomisd(const FloatRegister &lhs, const FloatRegister &rhs) {
michael@0 1349 JS_ASSERT(HasSSE2());
michael@0 1350 masm.ucomisd_rr(rhs.code(), lhs.code());
michael@0 1351 }
michael@0 1352 void ucomiss(const FloatRegister &lhs, const FloatRegister &rhs) {
michael@0 1353 JS_ASSERT(HasSSE2());
michael@0 1354 masm.ucomiss_rr(rhs.code(), lhs.code());
michael@0 1355 }
michael@0 1356 void pcmpeqw(const FloatRegister &lhs, const FloatRegister &rhs) {
michael@0 1357 JS_ASSERT(HasSSE2());
michael@0 1358 masm.pcmpeqw_rr(rhs.code(), lhs.code());
michael@0 1359 }
michael@0 1360 void movd(const Register &src, const FloatRegister &dest) {
michael@0 1361 JS_ASSERT(HasSSE2());
michael@0 1362 masm.movd_rr(src.code(), dest.code());
michael@0 1363 }
michael@0 1364 void movd(const FloatRegister &src, const Register &dest) {
michael@0 1365 JS_ASSERT(HasSSE2());
michael@0 1366 masm.movd_rr(src.code(), dest.code());
michael@0 1367 }
michael@0 1368 void addsd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1369 JS_ASSERT(HasSSE2());
michael@0 1370 masm.addsd_rr(src.code(), dest.code());
michael@0 1371 }
michael@0 1372 void addss(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1373 JS_ASSERT(HasSSE2());
michael@0 1374 masm.addss_rr(src.code(), dest.code());
michael@0 1375 }
michael@0 1376 void addsd(const Operand &src, const FloatRegister &dest) {
michael@0 1377 JS_ASSERT(HasSSE2());
michael@0 1378 switch (src.kind()) {
michael@0 1379 case Operand::FPREG:
michael@0 1380 masm.addsd_rr(src.fpu(), dest.code());
michael@0 1381 break;
michael@0 1382 case Operand::MEM_REG_DISP:
michael@0 1383 masm.addsd_mr(src.disp(), src.base(), dest.code());
michael@0 1384 break;
michael@0 1385 case Operand::MEM_ADDRESS32:
michael@0 1386 masm.addsd_mr(src.address(), dest.code());
michael@0 1387 break;
michael@0 1388 default:
michael@0 1389 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1390 }
michael@0 1391 }
michael@0 1392 void addss(const Operand &src, const FloatRegister &dest) {
michael@0 1393 JS_ASSERT(HasSSE2());
michael@0 1394 switch (src.kind()) {
michael@0 1395 case Operand::FPREG:
michael@0 1396 masm.addss_rr(src.fpu(), dest.code());
michael@0 1397 break;
michael@0 1398 case Operand::MEM_REG_DISP:
michael@0 1399 masm.addss_mr(src.disp(), src.base(), dest.code());
michael@0 1400 break;
michael@0 1401 case Operand::MEM_ADDRESS32:
michael@0 1402 masm.addss_mr(src.address(), dest.code());
michael@0 1403 break;
michael@0 1404 default:
michael@0 1405 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1406 }
michael@0 1407 }
michael@0 1408 void subsd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1409 JS_ASSERT(HasSSE2());
michael@0 1410 masm.subsd_rr(src.code(), dest.code());
michael@0 1411 }
michael@0 1412 void subss(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1413 JS_ASSERT(HasSSE2());
michael@0 1414 masm.subss_rr(src.code(), dest.code());
michael@0 1415 }
michael@0 1416 void subsd(const Operand &src, const FloatRegister &dest) {
michael@0 1417 JS_ASSERT(HasSSE2());
michael@0 1418 switch (src.kind()) {
michael@0 1419 case Operand::FPREG:
michael@0 1420 masm.subsd_rr(src.fpu(), dest.code());
michael@0 1421 break;
michael@0 1422 case Operand::MEM_REG_DISP:
michael@0 1423 masm.subsd_mr(src.disp(), src.base(), dest.code());
michael@0 1424 break;
michael@0 1425 default:
michael@0 1426 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1427 }
michael@0 1428 }
michael@0 1429 void subss(const Operand &src, const FloatRegister &dest) {
michael@0 1430 JS_ASSERT(HasSSE2());
michael@0 1431 switch (src.kind()) {
michael@0 1432 case Operand::FPREG:
michael@0 1433 masm.subss_rr(src.fpu(), dest.code());
michael@0 1434 break;
michael@0 1435 case Operand::MEM_REG_DISP:
michael@0 1436 masm.subss_mr(src.disp(), src.base(), dest.code());
michael@0 1437 break;
michael@0 1438 default:
michael@0 1439 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1440 }
michael@0 1441 }
michael@0 1442 void mulsd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1443 JS_ASSERT(HasSSE2());
michael@0 1444 masm.mulsd_rr(src.code(), dest.code());
michael@0 1445 }
michael@0 1446 void mulsd(const Operand &src, const FloatRegister &dest) {
michael@0 1447 JS_ASSERT(HasSSE2());
michael@0 1448 switch (src.kind()) {
michael@0 1449 case Operand::FPREG:
michael@0 1450 masm.mulsd_rr(src.fpu(), dest.code());
michael@0 1451 break;
michael@0 1452 case Operand::MEM_REG_DISP:
michael@0 1453 masm.mulsd_mr(src.disp(), src.base(), dest.code());
michael@0 1454 break;
michael@0 1455 default:
michael@0 1456 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1457 }
michael@0 1458 }
michael@0 1459 void mulss(const Operand &src, const FloatRegister &dest) {
michael@0 1460 JS_ASSERT(HasSSE2());
michael@0 1461 switch (src.kind()) {
michael@0 1462 case Operand::FPREG:
michael@0 1463 masm.mulss_rr(src.fpu(), dest.code());
michael@0 1464 break;
michael@0 1465 case Operand::MEM_REG_DISP:
michael@0 1466 masm.mulss_mr(src.disp(), src.base(), dest.code());
michael@0 1467 break;
michael@0 1468 default:
michael@0 1469 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1470 }
michael@0 1471 }
michael@0 1472 void mulss(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1473 JS_ASSERT(HasSSE2());
michael@0 1474 masm.mulss_rr(src.code(), dest.code());
michael@0 1475 }
michael@0 1476 void divsd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1477 JS_ASSERT(HasSSE2());
michael@0 1478 masm.divsd_rr(src.code(), dest.code());
michael@0 1479 }
michael@0 1480 void divss(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1481 JS_ASSERT(HasSSE2());
michael@0 1482 masm.divss_rr(src.code(), dest.code());
michael@0 1483 }
michael@0 1484 void divsd(const Operand &src, const FloatRegister &dest) {
michael@0 1485 JS_ASSERT(HasSSE2());
michael@0 1486 switch (src.kind()) {
michael@0 1487 case Operand::FPREG:
michael@0 1488 masm.divsd_rr(src.fpu(), dest.code());
michael@0 1489 break;
michael@0 1490 case Operand::MEM_REG_DISP:
michael@0 1491 masm.divsd_mr(src.disp(), src.base(), dest.code());
michael@0 1492 break;
michael@0 1493 default:
michael@0 1494 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1495 }
michael@0 1496 }
michael@0 1497 void divss(const Operand &src, const FloatRegister &dest) {
michael@0 1498 JS_ASSERT(HasSSE2());
michael@0 1499 switch (src.kind()) {
michael@0 1500 case Operand::FPREG:
michael@0 1501 masm.divss_rr(src.fpu(), dest.code());
michael@0 1502 break;
michael@0 1503 case Operand::MEM_REG_DISP:
michael@0 1504 masm.divss_mr(src.disp(), src.base(), dest.code());
michael@0 1505 break;
michael@0 1506 default:
michael@0 1507 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1508 }
michael@0 1509 }
michael@0 1510 void xorpd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1511 JS_ASSERT(HasSSE2());
michael@0 1512 masm.xorpd_rr(src.code(), dest.code());
michael@0 1513 }
michael@0 1514 void xorps(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1515 JS_ASSERT(HasSSE2());
michael@0 1516 masm.xorps_rr(src.code(), dest.code());
michael@0 1517 }
michael@0 1518 void orpd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1519 JS_ASSERT(HasSSE2());
michael@0 1520 masm.orpd_rr(src.code(), dest.code());
michael@0 1521 }
michael@0 1522 void andpd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1523 JS_ASSERT(HasSSE2());
michael@0 1524 masm.andpd_rr(src.code(), dest.code());
michael@0 1525 }
michael@0 1526 void andps(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1527 JS_ASSERT(HasSSE2());
michael@0 1528 masm.andps_rr(src.code(), dest.code());
michael@0 1529 }
michael@0 1530 void sqrtsd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1531 JS_ASSERT(HasSSE2());
michael@0 1532 masm.sqrtsd_rr(src.code(), dest.code());
michael@0 1533 }
michael@0 1534 void sqrtss(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1535 JS_ASSERT(HasSSE2());
michael@0 1536 masm.sqrtss_rr(src.code(), dest.code());
michael@0 1537 }
michael@0 1538 void roundsd(const FloatRegister &src, const FloatRegister &dest,
michael@0 1539 JSC::X86Assembler::RoundingMode mode)
michael@0 1540 {
michael@0 1541 JS_ASSERT(HasSSE41());
michael@0 1542 masm.roundsd_rr(src.code(), dest.code(), mode);
michael@0 1543 }
michael@0 1544 void roundss(const FloatRegister &src, const FloatRegister &dest,
michael@0 1545 JSC::X86Assembler::RoundingMode mode)
michael@0 1546 {
michael@0 1547 JS_ASSERT(HasSSE41());
michael@0 1548 masm.roundss_rr(src.code(), dest.code(), mode);
michael@0 1549 }
michael@0 1550 void minsd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1551 JS_ASSERT(HasSSE2());
michael@0 1552 masm.minsd_rr(src.code(), dest.code());
michael@0 1553 }
michael@0 1554 void minsd(const Operand &src, const FloatRegister &dest) {
michael@0 1555 JS_ASSERT(HasSSE2());
michael@0 1556 switch (src.kind()) {
michael@0 1557 case Operand::FPREG:
michael@0 1558 masm.minsd_rr(src.fpu(), dest.code());
michael@0 1559 break;
michael@0 1560 case Operand::MEM_REG_DISP:
michael@0 1561 masm.minsd_mr(src.disp(), src.base(), dest.code());
michael@0 1562 break;
michael@0 1563 default:
michael@0 1564 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1565 }
michael@0 1566 }
michael@0 1567 void maxsd(const FloatRegister &src, const FloatRegister &dest) {
michael@0 1568 JS_ASSERT(HasSSE2());
michael@0 1569 masm.maxsd_rr(src.code(), dest.code());
michael@0 1570 }
michael@0 1571 void maxsd(const Operand &src, const FloatRegister &dest) {
michael@0 1572 JS_ASSERT(HasSSE2());
michael@0 1573 switch (src.kind()) {
michael@0 1574 case Operand::FPREG:
michael@0 1575 masm.maxsd_rr(src.fpu(), dest.code());
michael@0 1576 break;
michael@0 1577 case Operand::MEM_REG_DISP:
michael@0 1578 masm.maxsd_mr(src.disp(), src.base(), dest.code());
michael@0 1579 break;
michael@0 1580 default:
michael@0 1581 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1582 }
michael@0 1583 }
michael@0 1584 void fisttp(const Operand &dest) {
michael@0 1585 JS_ASSERT(HasSSE3());
michael@0 1586 switch (dest.kind()) {
michael@0 1587 case Operand::MEM_REG_DISP:
michael@0 1588 masm.fisttp_m(dest.disp(), dest.base());
michael@0 1589 break;
michael@0 1590 default:
michael@0 1591 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1592 }
michael@0 1593 }
michael@0 1594 void fld(const Operand &dest) {
michael@0 1595 switch (dest.kind()) {
michael@0 1596 case Operand::MEM_REG_DISP:
michael@0 1597 masm.fld_m(dest.disp(), dest.base());
michael@0 1598 break;
michael@0 1599 default:
michael@0 1600 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1601 }
michael@0 1602 }
michael@0 1603 void fstp(const Operand &src) {
michael@0 1604 switch (src.kind()) {
michael@0 1605 case Operand::MEM_REG_DISP:
michael@0 1606 masm.fstp_m(src.disp(), src.base());
michael@0 1607 break;
michael@0 1608 default:
michael@0 1609 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1610 }
michael@0 1611 }
michael@0 1612 void fstp32(const Operand &src) {
michael@0 1613 switch (src.kind()) {
michael@0 1614 case Operand::MEM_REG_DISP:
michael@0 1615 masm.fstp32_m(src.disp(), src.base());
michael@0 1616 break;
michael@0 1617 default:
michael@0 1618 MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
michael@0 1619 }
michael@0 1620 }
michael@0 1621
michael@0 1622 // Defined for compatibility with ARM's assembler
michael@0 1623 uint32_t actualOffset(uint32_t x) {
michael@0 1624 return x;
michael@0 1625 }
michael@0 1626
michael@0 1627 uint32_t actualIndex(uint32_t x) {
michael@0 1628 return x;
michael@0 1629 }
michael@0 1630
michael@0 1631 void flushBuffer() {
michael@0 1632 }
michael@0 1633
michael@0 1634 // Patching.
michael@0 1635
michael@0 1636 static size_t patchWrite_NearCallSize() {
michael@0 1637 return 5;
michael@0 1638 }
michael@0 1639 static uintptr_t getPointer(uint8_t *instPtr) {
michael@0 1640 uintptr_t *ptr = ((uintptr_t *) instPtr) - 1;
michael@0 1641 return *ptr;
michael@0 1642 }
michael@0 1643 // Write a relative call at the start location |dataLabel|.
michael@0 1644 // Note that this DOES NOT patch data that comes before |label|.
michael@0 1645 static void patchWrite_NearCall(CodeLocationLabel startLabel, CodeLocationLabel target) {
michael@0 1646 uint8_t *start = startLabel.raw();
michael@0 1647 *start = 0xE8;
michael@0 1648 ptrdiff_t offset = target - startLabel - patchWrite_NearCallSize();
michael@0 1649 JS_ASSERT(int32_t(offset) == offset);
michael@0 1650 *((int32_t *) (start + 1)) = offset;
michael@0 1651 }
michael@0 1652
michael@0 1653 static void patchWrite_Imm32(CodeLocationLabel dataLabel, Imm32 toWrite) {
michael@0 1654 *((int32_t *) dataLabel.raw() - 1) = toWrite.value;
michael@0 1655 }
michael@0 1656
michael@0 1657 static void patchDataWithValueCheck(CodeLocationLabel data, PatchedImmPtr newData,
michael@0 1658 PatchedImmPtr expectedData) {
michael@0 1659 // The pointer given is a pointer to *after* the data.
michael@0 1660 uintptr_t *ptr = ((uintptr_t *) data.raw()) - 1;
michael@0 1661 JS_ASSERT(*ptr == (uintptr_t)expectedData.value);
michael@0 1662 *ptr = (uintptr_t)newData.value;
michael@0 1663 }
michael@0 1664 static void patchDataWithValueCheck(CodeLocationLabel data, ImmPtr newData, ImmPtr expectedData) {
michael@0 1665 patchDataWithValueCheck(data, PatchedImmPtr(newData.value), PatchedImmPtr(expectedData.value));
michael@0 1666 }
michael@0 1667 static uint32_t nopSize() {
michael@0 1668 return 1;
michael@0 1669 }
michael@0 1670 static uint8_t *nextInstruction(uint8_t *cur, uint32_t *count) {
michael@0 1671 MOZ_ASSUME_UNREACHABLE("nextInstruction NYI on x86");
michael@0 1672 }
michael@0 1673
michael@0 1674 // Toggle a jmp or cmp emitted by toggledJump().
michael@0 1675 static void ToggleToJmp(CodeLocationLabel inst) {
michael@0 1676 uint8_t *ptr = (uint8_t *)inst.raw();
michael@0 1677 JS_ASSERT(*ptr == 0x3D);
michael@0 1678 *ptr = 0xE9;
michael@0 1679 }
michael@0 1680 static void ToggleToCmp(CodeLocationLabel inst) {
michael@0 1681 uint8_t *ptr = (uint8_t *)inst.raw();
michael@0 1682 JS_ASSERT(*ptr == 0xE9);
michael@0 1683 *ptr = 0x3D;
michael@0 1684 }
michael@0 1685 static void ToggleCall(CodeLocationLabel inst, bool enabled) {
michael@0 1686 uint8_t *ptr = (uint8_t *)inst.raw();
michael@0 1687 JS_ASSERT(*ptr == 0x3D || // CMP
michael@0 1688 *ptr == 0xE8); // CALL
michael@0 1689 *ptr = enabled ? 0xE8 : 0x3D;
michael@0 1690 }
michael@0 1691 };
michael@0 1692
michael@0 1693 } // namespace jit
michael@0 1694 } // namespace js
michael@0 1695
michael@0 1696 #endif /* jit_shared_Assembler_x86_shared_h */

mercurial