Bug 915833 - SpiderMonkey: Add support for immediate addresses on x64. r=sstangl

This commit is contained in:
Dan Gohman 2013-09-12 15:31:44 -07:00
parent 2f0a25f9b6
commit f679cd4daa
5 changed files with 209 additions and 66 deletions

View File

@ -561,6 +561,13 @@ public:
m_formatter.oneByteOp64(OP_ADD_GvEv, dst, base, offset);
}
void addq_mr(const void* addr, RegisterID dst)
{
spew("addq %p, %s",
addr, nameIReg(8, dst));
m_formatter.oneByteOp64(OP_ADD_GvEv, dst, addr);
}
void addq_ir(int imm, RegisterID dst)
{
spew("addq $0x%x, %s", imm, nameIReg(8,dst));
@ -585,10 +592,22 @@ public:
m_formatter.immediate32(imm);
}
}
#else
void addq_im(int imm, const void* addr)
{
spew("addq %d, %p", imm, addr);
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_ADD, addr);
m_formatter.immediate8(imm);
} else {
m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_ADD, addr);
m_formatter.immediate32(imm);
}
}
#endif
void addl_im(int imm, const void* addr)
{
FIXME_INSN_PRINTING;
spew("addl %d, %p", imm, addr);
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, addr);
m_formatter.immediate8(imm);
@ -597,7 +616,6 @@ public:
m_formatter.immediate32(imm);
}
}
#endif
void andl_rr(RegisterID src, RegisterID dst)
{
@ -665,6 +683,13 @@ public:
m_formatter.oneByteOp64(OP_OR_GvEv, dst, base, offset);
}
void orq_mr(const void* addr, RegisterID dst)
{
spew("orq %p, %s",
addr, nameIReg(8, dst));
m_formatter.oneByteOp64(OP_OR_GvEv, dst, addr);
}
void andq_ir(int imm, RegisterID dst)
{
spew("andq $0x%x, %s", imm, nameIReg(8,dst));
@ -878,6 +903,13 @@ public:
m_formatter.oneByteOp64(OP_SUB_GvEv, dst, base, offset);
}
void subq_mr(const void* addr, RegisterID dst)
{
spew("subq %p, %s",
addr, nameIReg(8, dst));
m_formatter.oneByteOp64(OP_SUB_GvEv, dst, addr);
}
void subq_ir(int imm, RegisterID dst)
{
spew("subq $0x%x, %s", imm, nameIReg(8,dst));
@ -1254,7 +1286,23 @@ public:
m_formatter.immediate32(imm);
}
}
#else
void cmpq_im(int imm, const void* addr)
{
spew("cmpq $0x%x, %p", imm, addr);
if (CAN_SIGN_EXTEND_8_32(imm)) {
m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_CMP, addr);
m_formatter.immediate8(imm);
} else {
m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_CMP, addr);
m_formatter.immediate32(imm);
}
}
void cmpq_rm(RegisterID reg, const void* addr)
{
spew("cmpq %s, %p", nameIReg(8, reg), addr);
m_formatter.oneByteOp64(OP_CMP_EvGv, reg, addr);
}
#endif
void cmpl_rm(RegisterID reg, const void* addr)
{
spew("cmpl %s, %p",
@ -1273,7 +1321,6 @@ public:
m_formatter.immediate32(imm);
}
}
#endif
void cmpw_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale)
{
@ -1558,14 +1605,14 @@ public:
m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, base, offset);
}
#if WTF_CPU_X86
void movl_mr(const void* base, RegisterID index, int scale, RegisterID dst)
{
int32_t disp = addressImmediate(base);
spew("movl %d(,%s,%d), %s",
int(base), nameIReg(index), scale, nameIReg(dst));
m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, index, scale, int(base));
disp, nameIReg(index), scale, nameIReg(dst));
m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, index, scale, disp);
}
#endif
void movl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
{
@ -1574,7 +1621,6 @@ public:
m_formatter.oneByteOp(OP_MOV_GvEv, dst, base, index, scale, offset);
}
#if !WTF_CPU_X86_64
void movl_mr(const void* addr, RegisterID dst)
{
spew("movl %p, %s",
@ -1584,7 +1630,6 @@ public:
else
m_formatter.oneByteOp(OP_MOV_GvEv, dst, addr);
}
#endif
void movl_i32r(int imm, RegisterID dst)
{
@ -1683,6 +1728,16 @@ public:
m_formatter.oneByteOp64(OP_MOV_EvGv, src, base, index, scale, offset);
}
void movq_rm(RegisterID src, const void* addr)
{
spew("movq %s, %p",
nameIReg(8, src), addr);
if (src == X86Registers::eax)
movq_EAXm(addr);
else
m_formatter.oneByteOp64(OP_MOV_EvGv, src, addr);
}
void movq_mEAX(const void* addr)
{
FIXME_INSN_PRINTING;
@ -1717,6 +1772,16 @@ public:
m_formatter.oneByteOp64(OP_MOV_GvEv, dst, base, index, scale, offset);
}
void movq_mr(const void* addr, RegisterID dst)
{
spew("movq %p, %s",
addr, nameIReg(8, dst));
if (dst == X86Registers::eax)
movq_mEAX(addr);
else
m_formatter.oneByteOp64(OP_MOV_GvEv, dst, addr);
}
void leaq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
{
spew("leaq %d(%s,%s,%d), %s",
@ -1739,6 +1804,12 @@ public:
m_formatter.oneByteOp64(OP_GROUP11_EvIz, GROUP11_MOV, base, index, scale, offset);
m_formatter.immediate32(imm);
}
void movq_i32m(int imm, const void* addr)
{
spew("movq %d, %p", imm, addr);
m_formatter.oneByteOp64(OP_GROUP11_EvIz, GROUP11_MOV, addr);
m_formatter.immediate32(imm);
}
// Note that this instruction sign-extends its 32-bit immediate field to 64
// bits and loads the 64-bit value into a 64-bit register.
@ -1791,7 +1862,7 @@ public:
m_formatter.oneByteRipOp64(OP_MOV_GvEv, dst, 0);
return JmpSrc(m_formatter.size());
}
#else
#endif
void movl_rm(RegisterID src, const void* addr)
{
spew("movl %s, %p",
@ -1804,11 +1875,10 @@ public:
void movl_i32m(int imm, const void* addr)
{
FIXME_INSN_PRINTING;
spew("movl %d, %p", imm, addr);
m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, addr);
m_formatter.immediate32(imm);
}
#endif
void movb_rm(RegisterID src, int offset, RegisterID base)
{
@ -2205,7 +2275,6 @@ public:
m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)dst, base, offset);
}
#if !WTF_CPU_X86_64
void addsd_mr(const void* address, XMMRegisterID dst)
{
spew("addsd %p, %s",
@ -2220,7 +2289,6 @@ public:
m_formatter.prefix(PRE_SSE_F3);
m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)dst, address);
}
#endif
void cvtss2sd_rr(XMMRegisterID src, XMMRegisterID dst)
{
@ -3144,6 +3212,26 @@ public:
reinterpret_cast<const void**>(where)[-1] = value;
}
// Test whether the given address will fit in an address immediate field.
// This is always true on x86, but on x64 it's only true for addreses
// which fit in the 32-bit immediate field.
static bool isAddressImmediate(const void *address) {
intptr_t value = reinterpret_cast<intptr_t>(address);
int32_t immediate = static_cast<int32_t>(value);
return value == immediate;
}
// Convert the given address to a 32-bit immediate field value. This is
// a no-op on x86, but on x64 it asserts that the address is actually
// a valid address immediate.
static int32_t addressImmediate(const void *address) {
#if WTF_CPU_X86_64
// x64's 64-bit addresses don't all fit in the 32-bit immediate.
ASSERT(isAddressImmediate(address));
#endif
return static_cast<int32_t>(reinterpret_cast<intptr_t>(address));
}
private:
static int32_t getInt32(void* where)
@ -3237,14 +3325,13 @@ private:
memoryModRM_disp32(reg, index, scale, offset);
}
#if !WTF_CPU_X86_64
void oneByteOp(OneByteOpcodeID opcode, int reg, const void* address)
{
m_buffer.ensureSpace(maxInstructionSize);
m_buffer.putByteUnchecked(opcode);
memoryModRM(reg, address);
}
#else
#if WTF_CPU_X86_64
void oneByteRipOp(OneByteOpcodeID opcode, int reg, int ripOffset)
{
m_buffer.ensureSpace(maxInstructionSize);
@ -3317,7 +3404,6 @@ private:
memoryModRM(reg, base, index, scale, offset);
}
#if !WTF_CPU_X86_64
void twoByteOp(TwoByteOpcodeID opcode, int reg, const void* address)
{
m_buffer.ensureSpace(maxInstructionSize);
@ -3325,7 +3411,6 @@ private:
m_buffer.putByteUnchecked(opcode);
memoryModRM(reg, address);
}
#endif
void threeByteOp(ThreeByteOpcodeID opcode, ThreeByteEscape escape, int reg, RegisterID rm)
{
@ -3400,6 +3485,14 @@ private:
memoryModRM(reg, base, index, scale, offset);
}
void oneByteOp64(OneByteOpcodeID opcode, int reg, const void* address)
{
m_buffer.ensureSpace(maxInstructionSize);
emitRexW(reg, 0, 0);
m_buffer.putByteUnchecked(opcode);
memoryModRM(reg, address);
}
void twoByteOp64(TwoByteOpcodeID opcode, int reg, RegisterID rm)
{
m_buffer.ensureSpace(maxInstructionSize);
@ -3766,14 +3859,19 @@ private:
m_buffer.putIntUnchecked(offset);
}
#if !WTF_CPU_X86_64
void memoryModRM(int reg, const void* address)
{
int32_t disp = addressImmediate(address);
#if WTF_CPU_X86_64
// On x64-64, non-RIP-relative absolute mode requires a SIB.
putModRmSib(ModRmMemoryNoDisp, reg, noBase, noIndex, 0);
#else
// noBase + ModRmMemoryNoDisp means noBase + ModRmMemoryDisp32!
putModRm(ModRmMemoryNoDisp, reg, noBase);
m_buffer.putIntUnchecked(reinterpret_cast<int32_t>(address));
}
#endif
m_buffer.putIntUnchecked(disp);
}
AssemblerBuffer m_buffer;
} m_formatter;

View File

@ -248,11 +248,9 @@ class AssemblerX86Shared
case Operand::MEM_SCALE:
masm.movl_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
break;
#ifdef JS_CPU_X86
case Operand::MEM_ADDRESS:
case Operand::MEM_ADDRESS32:
masm.movl_mr(src.address(), dest.code());
break;
#endif
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -268,11 +266,9 @@ class AssemblerX86Shared
case Operand::MEM_SCALE:
masm.movl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
break;
#ifdef JS_CPU_X86
case Operand::MEM_ADDRESS:
case Operand::MEM_ADDRESS32:
masm.movl_rm(src.code(), dest.address());
break;
#endif
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -737,11 +733,9 @@ class AssemblerX86Shared
case Operand::MEM_SCALE:
masm.cmpl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
break;
#ifdef JS_CPU_X86
case Operand::MEM_ADDRESS:
case Operand::MEM_ADDRESS32:
masm.cmpl_im(imm.value, op.address());
break;
#endif
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -754,11 +748,9 @@ class AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.cmpl_rm(rhs.code(), lhs.disp(), lhs.base());
break;
#ifdef JS_CPU_X86
case Operand::MEM_ADDRESS:
case Operand::MEM_ADDRESS32:
masm.cmpl_rm(rhs.code(), lhs.address());
break;
#endif
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -771,11 +763,9 @@ class AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.cmpl_im(imm.value, op.disp(), op.base());
break;
#ifdef JS_CPU_X86
case Operand::MEM_ADDRESS:
case Operand::MEM_ADDRESS32:
masm.cmpl_im(imm.value, op.address());
break;
#endif
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -822,11 +812,9 @@ class AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.addl_im(imm.value, op.disp(), op.base());
break;
#ifdef JS_CPU_X86
case Operand::MEM_ADDRESS:
case Operand::MEM_ADDRESS32:
masm.addl_im(imm.value, op.address());
break;
#endif
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -1227,11 +1215,9 @@ class AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.addsd_mr(src.disp(), src.base(), dest.code());
break;
#ifdef JS_CPU_X86
case Operand::MEM_ADDRESS:
case Operand::MEM_ADDRESS32:
masm.addsd_mr(src.address(), dest.code());
break;
#endif
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -1245,11 +1231,9 @@ class AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.addss_mr(src.disp(), src.base(), dest.code());
break;
#ifdef JS_CPU_X86
case Operand::MEM_ADDRESS:
case Operand::MEM_ADDRESS32:
masm.addss_mr(src.address(), dest.code());
break;
#endif
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}

View File

@ -175,11 +175,12 @@ class Operand
REG,
MEM_REG_DISP,
FPREG,
MEM_SCALE
MEM_SCALE,
MEM_ADDRESS32
};
private:
Kind kind_ : 3;
Kind kind_ : 4;
int32_t base_ : 5;
Scale scale_ : 3;
int32_t index_ : 5;
@ -218,6 +219,11 @@ class Operand
base_(reg.code()),
disp_(disp)
{ }
explicit Operand(const AbsoluteAddress &address)
: kind_(MEM_ADDRESS32)
{
disp_ = JSC::X86Assembler::addressImmediate(address.addr);
}
Address toAddress() const {
JS_ASSERT(kind() == MEM_REG_DISP);
@ -256,6 +262,10 @@ class Operand
JS_ASSERT(kind() == MEM_REG_DISP || kind() == MEM_SCALE);
return disp_;
}
void *address() const {
JS_ASSERT(kind() == MEM_ADDRESS32);
return reinterpret_cast<void *>(intptr_t(disp_));
}
};
} // namespace jit
@ -410,6 +420,9 @@ class Assembler : public AssemblerX86Shared
case Operand::MEM_SCALE:
masm.movq_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
break;
case Operand::MEM_ADDRESS32:
masm.movq_mr(src.address(), dest.code());
break;
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -425,6 +438,9 @@ class Assembler : public AssemblerX86Shared
case Operand::MEM_SCALE:
masm.movq_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
break;
case Operand::MEM_ADDRESS32:
masm.movq_rm(src.code(), dest.address());
break;
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -440,6 +456,9 @@ class Assembler : public AssemblerX86Shared
case Operand::MEM_SCALE:
masm.movq_i32m(imm32.value, dest.disp(), dest.base(), dest.index(), dest.scale());
break;
case Operand::MEM_ADDRESS32:
masm.movq_i32m(imm32.value, dest.address());
break;
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -476,6 +495,9 @@ class Assembler : public AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.addq_im(imm.value, dest.disp(), dest.base());
break;
case Operand::MEM_ADDRESS32:
masm.addq_im(imm.value, dest.address());
break;
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -491,6 +513,9 @@ class Assembler : public AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.addq_mr(src.disp(), src.base(), dest.code());
break;
case Operand::MEM_ADDRESS32:
masm.addq_mr(src.address(), dest.code());
break;
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -510,6 +535,9 @@ class Assembler : public AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.subq_mr(src.disp(), src.base(), dest.code());
break;
case Operand::MEM_ADDRESS32:
masm.subq_mr(src.address(), dest.code());
break;
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -537,6 +565,9 @@ class Assembler : public AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.orq_mr(src.disp(), src.base(), dest.code());
break;
case Operand::MEM_ADDRESS32:
masm.orq_mr(src.address(), dest.code());
break;
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -622,6 +653,9 @@ class Assembler : public AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.cmpq_rm(rhs.code(), lhs.disp(), lhs.base());
break;
case Operand::MEM_ADDRESS32:
masm.cmpq_rm(rhs.code(), lhs.address());
break;
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}
@ -634,6 +668,9 @@ class Assembler : public AssemblerX86Shared
case Operand::MEM_REG_DISP:
masm.cmpq_im(rhs.value, lhs.disp(), lhs.base());
break;
case Operand::MEM_ADDRESS32:
masm.cmpq_im(rhs.value, lhs.address());
break;
default:
MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
}

View File

@ -509,19 +509,31 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
}
void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) {
mov(ImmPtr(lhs.addr), ScratchReg);
branch32(cond, Address(ScratchReg, 0), rhs, label);
if (JSC::X86Assembler::isAddressImmediate(lhs.addr)) {
branch32(cond, Operand(lhs), rhs, label);
} else {
mov(ImmPtr(lhs.addr), ScratchReg);
branch32(cond, Address(ScratchReg, 0), rhs, label);
}
}
void branch32(Condition cond, const AbsoluteAddress &lhs, Register rhs, Label *label) {
mov(ImmPtr(lhs.addr), ScratchReg);
branch32(cond, Address(ScratchReg, 0), rhs, label);
if (JSC::X86Assembler::isAddressImmediate(lhs.addr)) {
branch32(cond, Operand(lhs), rhs, label);
} else {
mov(ImmPtr(lhs.addr), ScratchReg);
branch32(cond, Address(ScratchReg, 0), rhs, label);
}
}
// Specialization for AbsoluteAddress.
void branchPtr(Condition cond, const AbsoluteAddress &addr, const Register &ptr, Label *label) {
JS_ASSERT(ptr != ScratchReg);
mov(ImmPtr(addr.addr), ScratchReg);
branchPtr(cond, Operand(ScratchReg, 0x0), ptr, label);
if (JSC::X86Assembler::isAddressImmediate(addr.addr)) {
branchPtr(cond, Operand(addr), ptr, label);
} else {
mov(ImmPtr(addr.addr), ScratchReg);
branchPtr(cond, Operand(ScratchReg, 0x0), ptr, label);
}
}
void branchPrivatePtr(Condition cond, Address lhs, ImmPtr ptr, Label *label) {
@ -593,8 +605,12 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
movq(imm, dest);
}
void loadPtr(const AbsoluteAddress &address, Register dest) {
mov(ImmPtr(address.addr), ScratchReg);
movq(Operand(ScratchReg, 0x0), dest);
if (JSC::X86Assembler::isAddressImmediate(address.addr)) {
movq(Operand(address), dest);
} else {
mov(ImmPtr(address.addr), ScratchReg);
movq(Operand(ScratchReg, 0x0), dest);
}
}
void loadPtr(const Address &address, Register dest) {
movq(Operand(address), dest);
@ -631,8 +647,12 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
movq(src, dest);
}
void storePtr(const Register &src, const AbsoluteAddress &address) {
mov(ImmPtr(address.addr), ScratchReg);
movq(src, Operand(ScratchReg, 0x0));
if (JSC::X86Assembler::isAddressImmediate(address.addr)) {
movq(src, Operand(address));
} else {
mov(ImmPtr(address.addr), ScratchReg);
movq(src, Operand(ScratchReg, 0x0));
}
}
void rshiftPtr(Imm32 imm, Register dest) {
shrq(imm, dest);
@ -1065,8 +1085,12 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
}
void inc64(AbsoluteAddress dest) {
mov(ImmPtr(dest.addr), ScratchReg);
addPtr(Imm32(1), Address(ScratchReg, 0));
if (JSC::X86Assembler::isAddressImmediate(dest.addr)) {
addPtr(Imm32(1), Operand(dest));
} else {
mov(ImmPtr(dest.addr), ScratchReg);
addPtr(Imm32(1), Address(ScratchReg, 0));
}
}
// If source is a double, load it into dest. If source is int32,

View File

@ -116,7 +116,7 @@ class Operand
MEM_REG_DISP,
FPREG,
MEM_SCALE,
MEM_ADDRESS
MEM_ADDRESS32
};
private:
@ -160,11 +160,11 @@ class Operand
disp_(disp)
{ }
explicit Operand(const AbsoluteAddress &address)
: kind_(MEM_ADDRESS),
: kind_(MEM_ADDRESS32),
disp_(reinterpret_cast<int32_t>(address.addr))
{ }
explicit Operand(const void *address)
: kind_(MEM_ADDRESS),
: kind_(MEM_ADDRESS32),
disp_(reinterpret_cast<int32_t>(address))
{ }
@ -206,7 +206,7 @@ class Operand
return disp_;
}
void *address() const {
JS_ASSERT(kind() == MEM_ADDRESS);
JS_ASSERT(kind() == MEM_ADDRESS32);
return reinterpret_cast<void *>(disp_);
}
};
@ -386,7 +386,7 @@ class Assembler : public AssemblerX86Shared
masm.cmpl_im_force32(imm.value, op.disp(), op.base());
writeDataRelocation(imm);
break;
case Operand::MEM_ADDRESS:
case Operand::MEM_ADDRESS32:
masm.cmpl_im(imm.value, op.address());
writeDataRelocation(imm);
break;