--- a/js/src/jit/MacroAssembler-inl.h
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -377,16 +377,23 @@ MacroAssembler::branchTestProxyHandlerFa
Address familyAddr(scratch, BaseProxyHandler::offsetOfFamily());
branchPtr(cond, familyAddr, ImmPtr(handlerp), label);
}
#ifndef JS_CODEGEN_ARM64
template <typename T>
void
+MacroAssembler::branchTestStackPtr(Condition cond, T t, Label* label)
+{
+ branchTestPtr(cond, getStackPointer(), t, label);
+}
+
+template <typename T>
+void
MacroAssembler::branchStackPtr(Condition cond, T rhs, Label* label)
{
branchPtr(cond, getStackPointer(), rhs, label);
}
template <typename T>
void
MacroAssembler::branchStackPtrRhs(Condition cond, T lhs, Label* label)
@@ -403,21 +410,63 @@ MacroAssembler::addToStackPtr(T t)
template <typename T> void
MacroAssembler::addStackPtrTo(T t)
{
addPtr(getStackPointer(), t);
}
#endif // !JS_CODEGEN_ARM64
+template <typename T>
+void
+MacroAssembler::storeObjectOrNull(Register src, const T& dest)
+{
+ Label notNull, done;
+ branchTestPtr(Assembler::NonZero, src, src, ¬Null);
+ storeValue(NullValue(), dest);
+ jump(&done);
+ bind(¬Null);
+ storeValue(JSVAL_TYPE_OBJECT, src, dest);
+ bind(&done);
+}
+
void
MacroAssembler::bumpKey(Int32Key* key, int diff)
{
if (key->isRegister())
add32(Imm32(diff), key->reg());
else
key->bumpConstant(diff);
}
+void
+MacroAssembler::assertStackAlignment(uint32_t alignment, int32_t offset /* = 0 */)
+{
+#ifdef DEBUG
+ Label ok, bad;
+ MOZ_ASSERT(IsPowerOfTwo(alignment));
+
+ // Wrap around the offset to be a non-negative number.
+ offset %= alignment;
+ if (offset < 0)
+ offset += alignment;
+
+ // Test if each bit from offset is set.
+ uint32_t off = offset;
+ while (off) {
+ uint32_t lowestBit = 1 << mozilla::CountTrailingZeroes32(off);
+ branchTestStackPtr(Assembler::Zero, Imm32(lowestBit), &bad);
+ off ^= lowestBit;
+ }
+
+ // Check that all remaining bits are zero.
+ branchTestStackPtr(Assembler::Zero, Imm32((alignment - 1) ^ offset), &ok);
+
+ bind(&bad);
+ breakpoint();
+ bind(&ok);
+#endif
+}
+
} // namespace jit
} // namespace js
#endif /* jit_MacroAssembler_inl_h */
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -836,16 +836,20 @@ class MacroAssembler : public MacroAssem
inline void branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rhs, Label* label)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
// This function compares a Value (lhs) which is having a private pointer
// boxed inside a js::Value, with a raw pointer (rhs).
inline void branchPrivatePtr(Condition cond, const Address& lhs, Register rhs, Label* label) PER_ARCH;
+ inline void branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label) PER_SHARED_ARCH;
+ inline void branchTestPtr(Condition cond, Register lhs, Imm32 rhs, Label* label) PER_SHARED_ARCH;
+ inline void branchTestPtr(Condition cond, const Address& lhs, Imm32 rhs, Label* label) PER_SHARED_ARCH;
+
inline void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
Label* label) PER_ARCH;
//}}} check_macroassembler_style
public:
// Emits a test of a value against all types in a TypeSet. A scratch
// register is required.
@@ -984,25 +988,17 @@ class MacroAssembler : public MacroAssem
}
storeDouble(reg, dest);
} else {
storeValue(ValueTypeFromMIRType(src.type()), src.typedReg().gpr(), dest);
}
}
template <typename T>
- void storeObjectOrNull(Register src, const T& dest) {
- Label notNull, done;
- branchTestPtr(Assembler::NonZero, src, src, ¬Null);
- storeValue(NullValue(), dest);
- jump(&done);
- bind(¬Null);
- storeValue(JSVAL_TYPE_OBJECT, src, dest);
- bind(&done);
- }
+ inline void storeObjectOrNull(Register src, const T& dest);
template <typename T>
void storeConstantOrRegister(ConstantOrRegister src, const T& dest) {
if (src.constant())
storeValue(src.value(), dest);
else
storeTypedOrValue(src.reg(), dest);
}
@@ -1358,19 +1354,17 @@ class MacroAssembler : public MacroAssem
void loadStackPtr(T t) { loadPtr(t, getStackPointer()); }
template <typename T>
void storeStackPtr(T t) { storePtr(getStackPointer(), t); }
// StackPointer testing functions.
// On ARM64, sp can function as the zero register depending on context.
// Code shared across platforms must use these functions to be valid.
template <typename T>
- void branchTestStackPtr(Condition cond, T t, Label* label) {
- branchTestPtr(cond, getStackPointer(), t, label);
- }
+ inline void branchTestStackPtr(Condition cond, T t, Label* label);
template <typename T>
inline void branchStackPtr(Condition cond, T rhs, Label* label);
template <typename T>
inline void branchStackPtrRhs(Condition cond, T lhs, Label* label);
#endif // !JS_CODEGEN_ARM64
public:
void enableProfilingInstrumentation() {
@@ -1692,42 +1686,17 @@ class MacroAssembler : public MacroAssem
void icRestoreLive(LiveRegisterSet& liveRegs, AfterICSaveLive& aic);
// Align the stack pointer based on the number of arguments which are pushed
// on the stack, such that the JitFrameLayout would be correctly aligned on
// the JitStackAlignment.
void alignJitStackBasedOnNArgs(Register nargs);
void alignJitStackBasedOnNArgs(uint32_t nargs);
- void assertStackAlignment(uint32_t alignment, int32_t offset = 0) {
-#ifdef DEBUG
- Label ok, bad;
- MOZ_ASSERT(IsPowerOfTwo(alignment));
-
- // Wrap around the offset to be a non-negative number.
- offset %= alignment;
- if (offset < 0)
- offset += alignment;
-
- // Test if each bit from offset is set.
- uint32_t off = offset;
- while (off) {
- uint32_t lowestBit = 1 << mozilla::CountTrailingZeroes32(off);
- branchTestStackPtr(Assembler::Zero, Imm32(lowestBit), &bad);
- off ^= lowestBit;
- }
-
- // Check that all remaining bits are zero.
- branchTestStackPtr(Assembler::Zero, Imm32((alignment - 1) ^ offset), &ok);
-
- bind(&bad);
- breakpoint();
- bind(&ok);
-#endif
- }
+ inline void assertStackAlignment(uint32_t alignment, int32_t offset = 0);
};
static inline Assembler::DoubleCondition
JSOpToDoubleCondition(JSOp op)
{
switch (op) {
case JSOP_EQ:
case JSOP_STRICTEQ:
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -571,16 +571,34 @@ MacroAssembler::branchPtr(Condition cond
void
MacroAssembler::branchPrivatePtr(Condition cond, const Address& lhs, Register rhs, Label* label)
{
branchPtr(cond, lhs, rhs, label);
}
void
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label)
+{
+ branchTest32(cond, lhs, rhs, label);
+}
+
+void
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Imm32 rhs, Label* label)
+{
+ branchTest32(cond, lhs, rhs, label);
+}
+
+void
+MacroAssembler::branchTestPtr(Condition cond, const Address& lhs, Imm32 rhs, Label* label)
+{
+ branchTest32(cond, lhs, rhs, label);
+}
+
+void
MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
Label* label)
{
if (cond == Assembler::Zero) {
MOZ_ASSERT(lhs.low == rhs.low);
MOZ_ASSERT(lhs.high == rhs.high);
ma_orr(lhs.low, lhs.high, ScratchRegister);
branchTestPtr(cond, ScratchRegister, ScratchRegister, label);
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -860,25 +860,16 @@ class MacroAssemblerARMCompat : public M
branchTest32(cond, scratch2, imm, label);
}
void branchTest32(Condition cond, AbsoluteAddress address, Imm32 imm, Label* label) {
// branchTest32 will use ScratchRegister.
AutoRegisterScope scratch2(asMasm(), secondScratchReg_);
load32(address, scratch2);
branchTest32(cond, scratch2, imm, label);
}
- void branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label) {
- branchTest32(cond, lhs, rhs, label);
- }
- void branchTestPtr(Condition cond, Register lhs, const Imm32 rhs, Label* label) {
- branchTest32(cond, lhs, rhs, label);
- }
- void branchTestPtr(Condition cond, const Address& lhs, Imm32 imm, Label* label) {
- branchTest32(cond, lhs, imm, label);
- }
void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
ma_sub(imm, lhs, SetCC);
as_b(label, cond);
}
void moveValue(const Value& val, Register type, Register data);
CodeOffsetJump jumpWithPatch(RepatchLabel* label, Condition cond = Always,
Label* documentation = nullptr);
--- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h
@@ -648,16 +648,40 @@ MacroAssembler::branchPrivatePtr(Conditi
if (rhs != scratch)
movePtr(rhs, scratch);
// Instead of unboxing lhs, box rhs and do direct comparison with lhs.
rshiftPtr(Imm32(1), scratch);
branchPtr(cond, lhs, scratch, label);
}
void
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label)
+{
+ Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64)));
+ B(label, cond);
+}
+
+void
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Imm32 rhs, Label* label)
+{
+ Tst(ARMRegister(lhs, 64), Operand(rhs.value));
+ B(label, cond);
+}
+
+void
+MacroAssembler::branchTestPtr(Condition cond, const Address& lhs, Imm32 rhs, Label* label)
+{
+ vixl::UseScratchRegisterScope temps(this);
+ const Register scratch = temps.AcquireX().asUnsized();
+ MOZ_ASSERT(scratch != lhs.base);
+ loadPtr(lhs, scratch);
+ branchTestPtr(cond, scratch, rhs, label);
+}
+
+void
MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
Label* label)
{
branchTestPtr(cond, lhs.reg, rhs.reg, label);
}
//}}} check_macroassembler_style
// ===============================================================
@@ -714,12 +738,19 @@ MacroAssemblerCompat::branchStackPtr(Con
template <typename T>
void
MacroAssemblerCompat::branchStackPtrRhs(Condition cond, T lhs, Label* label)
{
asMasm().branchPtr(cond, lhs, getStackPointer(), label);
}
+template <typename T>
+void
+MacroAssemblerCompat::branchTestStackPtr(Condition cond, T t, Label* label)
+{
+ asMasm().branchTestPtr(cond, getStackPointer(), t, label);
+}
+
} // namespace jit
} // namespace js
#endif /* jit_arm64_MacroAssembler_arm64_inl_h */
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -1052,19 +1052,17 @@ class MacroAssemblerCompat : public vixl
template <typename T>
void loadStackPtr(T t) { loadPtr(t, getStackPointer()); syncStackPtr(); }
template <typename T>
void storeStackPtr(T t) { storePtr(getStackPointer(), t); }
// StackPointer testing functions.
template <typename T>
- void branchTestStackPtr(Condition cond, T t, Label* label) {
- branchTestPtr(cond, getStackPointer(), t, label);
- }
+ inline void branchTestStackPtr(Condition cond, T t, Label* label);
template <typename T>
void branchStackPtr(Condition cond, T rhs, Label* label);
template <typename T>
void branchStackPtrRhs(Condition cond, T lhs, Label* label);
void testPtr(Register lhs, Register rhs) {
Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64)));
}
@@ -1430,32 +1428,16 @@ class MacroAssemblerCompat : public vixl
const Register scratch = temps.AcquireX().asUnsized();
MOZ_ASSERT(scratch != addr.base);
loadPtr(addr, scratch);
cmpPtr(scratch, ptr);
}
return jumpWithPatch(label, cond);
}
- void branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label) {
- Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64)));
- B(label, cond);
- }
- void branchTestPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
- Tst(ARMRegister(lhs, 64), Operand(imm.value));
- B(label, cond);
- }
- void branchTestPtr(Condition cond, const Address& lhs, Imm32 imm, Label* label) {
- vixl::UseScratchRegisterScope temps(this);
- const Register scratch = temps.AcquireX().asUnsized();
- MOZ_ASSERT(scratch != lhs.base);
- loadPtr(lhs, scratch);
- branchTestPtr(cond, scratch, imm, label);
- }
-
void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
Subs(ARMRegister(lhs, 64), ARMRegister(lhs, 64), Operand(imm.value));
B(cond, label);
}
void branchTestUndefined(Condition cond, Register tag, Label* label) {
Condition c = testUndefined(cond, tag);
B(label, c);
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
@@ -340,15 +340,41 @@ MacroAssembler::branchPtr(Condition cond
void
MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rhs, Label* label)
{
loadPtr(lhs, SecondScratchReg);
branchPtr(cond, SecondScratchReg, rhs, label);
}
+void
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label)
+{
+ MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
+ if (lhs == rhs) {
+ ma_b(lhs, rhs, label, cond);
+ } else {
+ as_and(ScratchRegister, lhs, rhs);
+ ma_b(ScratchRegister, ScratchRegister, label, cond);
+ }
+}
+
+void
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Imm32 rhs, Label* label)
+{
+ ma_li(ScratchRegister, rhs);
+ branchTestPtr(cond, lhs, ScratchRegister, label);
+}
+
+void
+MacroAssembler::branchTestPtr(Condition cond, const Address& lhs, Imm32 rhs, Label* label)
+{
+ loadPtr(lhs, SecondScratchReg);
+ branchTestPtr(cond, SecondScratchReg, rhs, label);
+}
+
//}}} check_macroassembler_style
// ===============================================================
} // namespace jit
} // namespace js
#endif /* jit_mips_shared_MacroAssembler_mips_shared_inl_h */
--- a/js/src/jit/mips32/MacroAssembler-mips32.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32.h
@@ -453,33 +453,16 @@ class MacroAssemblerMIPSCompat : public
void branchTest32(Condition cond, const Address& address, Imm32 imm, Label* label) {
load32(address, SecondScratchReg);
branchTest32(cond, SecondScratchReg, imm, label);
}
void branchTest32(Condition cond, AbsoluteAddress address, Imm32 imm, Label* label) {
load32(address, ScratchRegister);
branchTest32(cond, ScratchRegister, imm, label);
}
- void branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label) {
- MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
- if (lhs == rhs) {
- ma_b(lhs, rhs, label, cond);
- } else {
- as_and(ScratchRegister, lhs, rhs);
- ma_b(ScratchRegister, ScratchRegister, label, cond);
- }
- }
- void branchTestPtr(Condition cond, Register lhs, const Imm32 rhs, Label* label) {
- ma_li(ScratchRegister, rhs);
- branchTestPtr(cond, lhs, ScratchRegister, label);
- }
- void branchTestPtr(Condition cond, const Address& lhs, Imm32 imm, Label* label) {
- loadPtr(lhs, SecondScratchReg);
- branchTestPtr(cond, SecondScratchReg, imm, label);
- }
inline void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label);
// higher level tag testing code
Operand ToPayload(Operand base);
Address ToPayload(Address base) {
return ToPayload(Operand(base)).toAddress();
}
--- a/js/src/jit/mips64/MacroAssembler-mips64.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64.h
@@ -494,33 +494,16 @@ class MacroAssemblerMIPS64Compat : publi
void branchTest32(Condition cond, const Address& address, Imm32 imm, Label* label) {
load32(address, SecondScratchReg);
branchTest32(cond, SecondScratchReg, imm, label);
}
void branchTest32(Condition cond, AbsoluteAddress address, Imm32 imm, Label* label) {
load32(address, ScratchRegister);
branchTest32(cond, ScratchRegister, imm, label);
}
- void branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label) {
- MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
- if (lhs == rhs) {
- ma_b(lhs, rhs, label, cond);
- } else {
- as_and(ScratchRegister, lhs, rhs);
- ma_b(ScratchRegister, ScratchRegister, label, cond);
- }
- }
- void branchTestPtr(Condition cond, Register lhs, const Imm32 rhs, Label* label) {
- ma_li(ScratchRegister, rhs);
- branchTestPtr(cond, lhs, ScratchRegister, label);
- }
- void branchTestPtr(Condition cond, const Address& lhs, Imm32 imm, Label* label) {
- loadPtr(lhs, SecondScratchReg);
- branchTestPtr(cond, SecondScratchReg, imm, label);
- }
inline void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label);
// higher level tag testing code
Address ToPayload(Address value) {
return value;
}
void moveValue(const Value& val, Register dest);
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -242,17 +242,16 @@ class MacroAssemblerNone : public Assemb
void testUndefinedSet(Condition, ValueOperand, Register) { MOZ_CRASH(); }
template <typename T, typename S> void cmpPtrSet(Condition, T, S, Register) { MOZ_CRASH(); }
template <typename T, typename S> void cmp32Set(Condition, T, S, Register) { MOZ_CRASH(); }
template <typename T, typename S, typename L> void branchTest32(Condition, T, S, L) { MOZ_CRASH(); }
template <typename T, typename S> void branchAdd32(Condition, T, S, Label*) { MOZ_CRASH(); }
template <typename T, typename S> void branchSub32(Condition, T, S, Label*) { MOZ_CRASH(); }
- template <typename T, typename S> void branchTestPtr(Condition, T, S, Label*) { MOZ_CRASH(); }
template <typename T, typename S> void branchDouble(DoubleCondition, T, S, Label*) { MOZ_CRASH(); }
template <typename T, typename S> void branchFloat(DoubleCondition, T, S, Label*) { MOZ_CRASH(); }
template <typename T, typename S> void decBranchPtr(Condition, T, S, Label*) { MOZ_CRASH(); }
template <typename T, typename S> void mov(T, S) { MOZ_CRASH(); }
template <typename T, typename S> void movq(T, S) { MOZ_CRASH(); }
template <typename T, typename S> void movePtr(T, S) { MOZ_CRASH(); }
template <typename T, typename S> void move32(T, S) { MOZ_CRASH(); }
template <typename T, typename S> void moveFloat32(T, S) { MOZ_CRASH(); }
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -557,28 +557,16 @@ class MacroAssemblerX64 : public MacroAs
return jumpWithPatch(label);
}
template <typename S, typename T>
CodeOffsetJump branchPtrWithPatch(Condition cond, S lhs, T ptr, RepatchLabel* label) {
cmpPtr(lhs, ptr);
return jumpWithPatch(label, cond);
}
- void branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label) {
- testPtr(lhs, rhs);
- j(cond, label);
- }
- void branchTestPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
- testPtr(lhs, imm);
- j(cond, label);
- }
- void branchTestPtr(Condition cond, const Address& lhs, Imm32 imm, Label* label) {
- testPtr(Operand(lhs), imm);
- j(cond, label);
- }
void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
subq(imm, lhs);
j(cond, label);
}
void movePtr(Register src, Register dest) {
movq(src, dest);
}
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
@@ -289,15 +289,36 @@ MacroAssembler::branchPtr(Condition cond
}
void
MacroAssembler::branchPtr(Condition cond, const Address& lhs, ImmWord rhs, Label* label)
{
branchPtrImpl(cond, lhs, rhs, label);
}
+void
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label)
+{
+ testPtr(lhs, rhs);
+ j(cond, label);
+}
+
+void
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Imm32 rhs, Label* label)
+{
+ testPtr(lhs, rhs);
+ j(cond, label);
+}
+
+void
+MacroAssembler::branchTestPtr(Condition cond, const Address& lhs, Imm32 rhs, Label* label)
+{
+ testPtr(Operand(lhs), rhs);
+ j(cond, label);
+}
+
//}}} check_macroassembler_style
// ===============================================================
} // namespace jit
} // namespace js
#endif /* jit_x86_shared_MacroAssembler_x86_shared_inl_h */
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -585,28 +585,16 @@ class MacroAssemblerX86 : public MacroAs
CodeOffsetJump branchPtrWithPatch(Condition cond, S lhs, T ptr, RepatchLabel* label) {
branchPtr(cond, lhs, ptr, label);
return CodeOffsetJump(size());
}
void branchPtr(Condition cond, Register lhs, Register rhs, RepatchLabel* label) {
cmpPtr(lhs, rhs);
j(cond, label);
}
- void branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label) {
- testPtr(lhs, rhs);
- j(cond, label);
- }
- void branchTestPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
- testPtr(lhs, imm);
- j(cond, label);
- }
- void branchTestPtr(Condition cond, const Address& lhs, Imm32 imm, Label* label) {
- testPtr(Operand(lhs), imm);
- j(cond, label);
- }
void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
subl(imm, lhs);
j(cond, label);
}
void movePtr(ImmWord imm, Register dest) {
movl(Imm32(imm.value), dest);
}