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:
whesse@chromium.org 2009-06-02 13:40:52 +00:00
parent 8c78e673ad
commit ea0644506d
4 changed files with 261 additions and 19 deletions

View File

@ -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);
}

View File

@ -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_);

View File

@ -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_;

View File

@ -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);