Add miscellaneous operations to x64 assembler.
Review URL: http://codereview.chromium.org/113997 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2089 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
8c78e673ad
commit
ea0644506d
@ -36,6 +36,10 @@ namespace internal {
|
||||
|
||||
class Memory {
|
||||
public:
|
||||
static uint16_t& uint16_at(Address addr) {
|
||||
return *reinterpret_cast<uint16_t*>(addr);
|
||||
}
|
||||
|
||||
static uint32_t& uint32_at(Address addr) {
|
||||
return *reinterpret_cast<uint32_t*>(addr);
|
||||
}
|
||||
|
@ -55,6 +55,12 @@ void Assembler::emitq(uint64_t x, RelocInfo::Mode rmode) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::emitw(uint16_t x) {
|
||||
Memory::uint16_at(pc_) = x;
|
||||
pc_ += sizeof(uint16_t);
|
||||
}
|
||||
|
||||
|
||||
// High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B.
|
||||
// REX.W is set. REX.X is cleared.
|
||||
void Assembler::emit_rex_64(Register reg, Register rm_reg) {
|
||||
@ -118,14 +124,14 @@ void Assembler::emit_optional_rex_32(Register reg, const Operand& op) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::set_target_address_at(byte* location, byte* value) {
|
||||
UNIMPLEMENTED();
|
||||
Address Assembler::target_address_at(Address pc) {
|
||||
return Memory::Address_at(pc);
|
||||
}
|
||||
|
||||
|
||||
byte* Assembler::target_address_at(byte* location) {
|
||||
UNIMPLEMENTED();
|
||||
return NULL;
|
||||
void Assembler::set_target_address_at(Address pc, Address target) {
|
||||
Memory::Address_at(pc) = target;
|
||||
CPU::FlushICache(pc, sizeof(intptr_t));
|
||||
}
|
||||
|
||||
|
||||
@ -166,6 +172,8 @@ void RelocInfo::set_target_address(Address target) {
|
||||
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
|
||||
Assembler::set_target_address_at(pc_, target);
|
||||
}
|
||||
|
||||
|
||||
Object* RelocInfo::target_object() {
|
||||
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
|
||||
return *reinterpret_cast<Object**>(pc_);
|
||||
|
@ -77,7 +77,73 @@ uint64_t CpuFeatures::supported_ = 0;
|
||||
uint64_t CpuFeatures::enabled_ = 0;
|
||||
|
||||
void CpuFeatures::Probe() {
|
||||
// TODO(X64): UNIMPLEMENTED
|
||||
ASSERT(Heap::HasBeenSetup());
|
||||
ASSERT(supported_ == 0);
|
||||
if (Serializer::enabled()) return; // No features if we might serialize.
|
||||
|
||||
Assembler assm(NULL, 0);
|
||||
Label cpuid, done;
|
||||
#define __ assm.
|
||||
// Save old esp, since we are going to modify the stack.
|
||||
__ push(rbp);
|
||||
__ pushfq();
|
||||
__ push(rcx);
|
||||
__ push(rbx);
|
||||
__ movq(rbp, rsp);
|
||||
|
||||
// If we can modify bit 21 of the EFLAGS register, then CPUID is supported.
|
||||
__ pushfq();
|
||||
__ pop(rax);
|
||||
__ movq(rdx, rax);
|
||||
__ xor_(rax, Immediate(0x200000)); // Flip bit 21.
|
||||
__ push(rax);
|
||||
__ popfq();
|
||||
__ pushfq();
|
||||
__ pop(rax);
|
||||
__ xor_(rax, rdx); // Different if CPUID is supported.
|
||||
__ j(not_zero, &cpuid);
|
||||
|
||||
// CPUID not supported. Clear the supported features in edx:eax.
|
||||
__ xor_(rax, rax);
|
||||
__ jmp(&done);
|
||||
|
||||
// Invoke CPUID with 1 in eax to get feature information in
|
||||
// ecx:edx. Temporarily enable CPUID support because we know it's
|
||||
// safe here.
|
||||
__ bind(&cpuid);
|
||||
__ movq(rax, Immediate(1));
|
||||
supported_ = (1 << CPUID);
|
||||
{ Scope fscope(CPUID);
|
||||
__ cpuid();
|
||||
}
|
||||
supported_ = 0;
|
||||
|
||||
// Move the result from ecx:edx to rax and make sure to mark the
|
||||
// CPUID feature as supported.
|
||||
__ movl(rax, rdx); // Zero-extended to 64 bits.
|
||||
__ shl(rcx, Immediate(32));
|
||||
__ or_(rax, rcx);
|
||||
__ or_(rax, Immediate(1 << CPUID));
|
||||
|
||||
// Done.
|
||||
__ bind(&done);
|
||||
__ movq(rsp, rbp);
|
||||
__ pop(rbx);
|
||||
__ pop(rcx);
|
||||
__ popfq();
|
||||
__ pop(rbp);
|
||||
__ ret(0);
|
||||
#undef __
|
||||
|
||||
CodeDesc desc;
|
||||
assm.GetCode(&desc);
|
||||
Object* code =
|
||||
Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB), NULL);
|
||||
if (!code->IsCode()) return;
|
||||
LOG(CodeCreateEvent("Builtin", Code::cast(code), "CpuFeatures::Probe"));
|
||||
typedef uint64_t (*F0)();
|
||||
F0 probe = FUNCTION_CAST<F0>(Code::cast(code)->entry());
|
||||
supported_ = probe();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -368,6 +434,26 @@ void Assembler::shift(Register dst, int subcode) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::bt(const Operand& dst, Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(src, dst);
|
||||
emit(0x0F);
|
||||
emit(0xA3);
|
||||
emit_operand(src, dst);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::bts(const Operand& dst, Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(src, dst);
|
||||
emit(0x0F);
|
||||
emit(0xAB);
|
||||
emit_operand(src, dst);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::call(Label* L) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
@ -401,6 +487,23 @@ void Assembler::call(Register adr) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::cpuid() {
|
||||
ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CPUID));
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit(0x0F);
|
||||
emit(0xA2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::cqo() {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64();
|
||||
emit(0x99);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::dec(Register dst) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
@ -419,6 +522,15 @@ void Assembler::dec(const Operand& dst) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::enter(Immediate size) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit(0xC8);
|
||||
emitw(size.value_); // 16 bit operand, always.
|
||||
emit(0);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::hlt() {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
@ -530,6 +642,49 @@ void Assembler::jmp(Register target) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::lea(Register dst, const Operand& src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(dst, src);
|
||||
emit(0x8D);
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::leave() {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit(0xC9);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movl(Register dst, const Operand& src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_optional_rex_32(dst, src);
|
||||
emit(0x8B);
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movl(Register dst, Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_optional_rex_32(dst, src);
|
||||
emit(0x8B);
|
||||
emit(0xC0 | (dst.code() & 0x7) << 3 | (src.code() & 0x7));
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movl(const Operand& dst, Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_optional_rex_32(src, dst);
|
||||
emit(0x89);
|
||||
emit_operand(src, dst);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movq(Register dst, const Operand& src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
@ -548,6 +703,15 @@ void Assembler::movq(Register dst, Register src) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movq(const Operand& dst, Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit_rex_64(src, dst);
|
||||
emit(0x89);
|
||||
emit_operand(src, dst);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::movq(Register dst, Immediate value) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
@ -716,6 +880,13 @@ void Assembler::pop(const Operand& dst) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::popfq() {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit(0x9D);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::push(Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
@ -735,6 +906,43 @@ void Assembler::push(const Operand& src) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::push(Immediate value) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
if (is_int8(value.value_)) {
|
||||
emit(0x6A);
|
||||
emit(value.value_); // Emit low byte of value.
|
||||
} else {
|
||||
emit(0x68);
|
||||
emitl(value.value_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Assembler::pushfq() {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
emit(0x9C);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::rcl(Register dst, uint8_t imm8) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
ASSERT(is_uint6(imm8)); // illegal shift count
|
||||
if (imm8 == 1) {
|
||||
emit_rex_64(dst);
|
||||
emit(0xD1);
|
||||
emit(0xD0 | (dst.code() & 0x7));
|
||||
} else {
|
||||
emit_rex_64(dst);
|
||||
emit(0xC1);
|
||||
emit(0xD0 | (dst.code() & 0x7));
|
||||
emit(imm8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Assembler::ret(int imm16) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
@ -749,6 +957,21 @@ void Assembler::ret(int imm16) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::xchg(Register dst, Register src) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
if (src.is(rax) || dst.is(rax)) { // Single-byte encoding
|
||||
Register other = src.is(rax) ? dst : src;
|
||||
emit_rex_64(other);
|
||||
emit(0x90 | (other.code() & 0x7));
|
||||
} else {
|
||||
emit_rex_64(src, dst);
|
||||
emit(0x87);
|
||||
emit(0xC0 | (src.code() & 0x7) << 3 | (dst.code() & 0x7));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Assembler::testb(Register reg, Immediate mask) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
|
@ -294,11 +294,11 @@ class CpuFeatures : public AllStatic {
|
||||
static void Probe();
|
||||
// Check whether a feature is supported by the target CPU.
|
||||
static bool IsSupported(Feature f) {
|
||||
return (supported_ & (static_cast<uint64_t>(1) << f)) != 0;
|
||||
return (supported_ & (V8_UINT64_C(1) << f)) != 0;
|
||||
}
|
||||
// Check whether a feature is currently enabled.
|
||||
static bool IsEnabled(Feature f) {
|
||||
return (enabled_ & (static_cast<uint64_t>(1) << f)) != 0;
|
||||
return (enabled_ & (V8_UINT64_C(1) << f)) != 0;
|
||||
}
|
||||
// Enable a specified feature within a scope.
|
||||
class Scope BASE_EMBEDDED {
|
||||
@ -307,7 +307,7 @@ class CpuFeatures : public AllStatic {
|
||||
explicit Scope(Feature f) {
|
||||
ASSERT(CpuFeatures::IsSupported(f));
|
||||
old_enabled_ = CpuFeatures::enabled_;
|
||||
CpuFeatures::enabled_ |= (static_cast<uint64_t>(1) << f);
|
||||
CpuFeatures::enabled_ |= (V8_UINT64_C(1) << f);
|
||||
}
|
||||
~Scope() { CpuFeatures::enabled_ = old_enabled_; }
|
||||
private:
|
||||
@ -355,8 +355,9 @@ class Assembler : public Malloced {
|
||||
void GetCode(CodeDesc* desc);
|
||||
|
||||
// Read/Modify the code target in the branch/call instruction at pc.
|
||||
inline static Address target_address_at(Address pc);
|
||||
inline static void set_target_address_at(Address pc, Address target);
|
||||
// On the x64 architecture, the address is absolute, not relative.
|
||||
static inline Address target_address_at(Address pc);
|
||||
static inline void set_target_address_at(Address pc, Address target);
|
||||
|
||||
// Distance between the address of the code target in the call instruction
|
||||
// and the return address
|
||||
@ -387,13 +388,10 @@ class Assembler : public Malloced {
|
||||
void Align(int m);
|
||||
|
||||
// Stack
|
||||
void pushad();
|
||||
void popad();
|
||||
void pushfq();
|
||||
void popfq();
|
||||
|
||||
void pushfd();
|
||||
void popfd();
|
||||
|
||||
void push(const Immediate& x);
|
||||
void push(Immediate value);
|
||||
void push(Register src);
|
||||
void push(const Operand& src);
|
||||
void push(Label* label, RelocInfo::Mode relocation_mode);
|
||||
@ -401,7 +399,7 @@ class Assembler : public Malloced {
|
||||
void pop(Register dst);
|
||||
void pop(const Operand& dst);
|
||||
|
||||
void enter(const Immediate& size);
|
||||
void enter(Immediate size);
|
||||
void leave();
|
||||
|
||||
// Moves
|
||||
@ -409,6 +407,10 @@ class Assembler : public Malloced {
|
||||
void movb(const Operand& dst, int8_t imm8);
|
||||
void movb(const Operand& dst, Register src);
|
||||
|
||||
void movl(Register dst, Register src);
|
||||
void movl(Register dst, const Operand& src);
|
||||
void movl(const Operand& dst, Register src);
|
||||
|
||||
void movq(Register dst, int32_t imm32);
|
||||
void movq(Register dst, Immediate x);
|
||||
void movq(Register dst, const Operand& src);
|
||||
@ -515,7 +517,8 @@ class Assembler : public Malloced {
|
||||
void dec(Register dst);
|
||||
void dec(const Operand& dst);
|
||||
|
||||
void cdq();
|
||||
// Sign-extends rax into rdx:rax.
|
||||
void cqo();
|
||||
|
||||
void idiv(Register src);
|
||||
|
||||
@ -830,6 +833,7 @@ class Assembler : public Malloced {
|
||||
inline void emitl(uint32_t x);
|
||||
inline void emit(Handle<Object> handle);
|
||||
inline void emitq(uint64_t x, RelocInfo::Mode rmode);
|
||||
inline void emitw(uint16_t x);
|
||||
void emit(Immediate x) { emitl(x.value_); }
|
||||
|
||||
// Emits a REX prefix that encodes a 64-bit operand size and
|
||||
@ -858,6 +862,9 @@ class Assembler : public Malloced {
|
||||
// REX.W is set and REX.R clear.
|
||||
inline void emit_rex_64(const Operand& op);
|
||||
|
||||
// Emit a REX prefix that only sets REX.W to choose a 64-bit operand size.
|
||||
void emit_rex_64() { emit(0x48); }
|
||||
|
||||
// High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B.
|
||||
// REX.W is clear.
|
||||
inline void emit_rex_32(Register reg, Register rm_reg);
|
||||
|
Loading…
Reference in New Issue
Block a user