Commit 88635e40 authored by whesse@chromium.org's avatar whesse@chromium.org

Implement memory operands for instructions in the x64 assembler.

Review URL: http://codereview.chromium.org/113841

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2062 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9c829faf
......@@ -173,13 +173,32 @@ Object** RelocInfo::call_object_address() {
return reinterpret_cast<Object**>(pc_ + 1);
}
// -----------------------------------------------------------------------------
// Implementation of Operand
Operand::Operand(Register base, int32_t disp) {
len_ = 1;
if (base.is(rsp) || base.is(r12)) {
// SIB byte is needed to encode (rsp + offset) or (r12 + offset).
set_sib(times_1, rsp, base);
}
if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
set_modrm(0, rsp);
} else if (is_int8(disp)) {
set_modrm(1, base);
set_disp8(disp);
} else {
set_modrm(2, base);
set_disp32(disp);
}
}
void Operand::set_modrm(int mod, Register rm) {
ASSERT((mod & -4) == 0);
buf_[0] = mod << 6 | (rm.code() & 0x7);
// Set REX.B to the high bit of rm.code().
rex_ |= (rm.code() >> 3);
len_ = 1;
}
......@@ -193,8 +212,15 @@ void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
len_ = 2;
}
void Operand::set_disp8(int disp) {
ASSERT(is_int8(disp));
ASSERT(len_ == 1 || len_ == 2);
int8_t* p = reinterpret_cast<int8_t*>(&buf_[len_]);
*p = disp;
len_ += sizeof(int8_t);
}
void Operand::set_disp32(int32_t disp) {
void Operand::set_disp32(int disp) {
ASSERT(len_ == 1 || len_ == 2);
int32_t* p = reinterpret_cast<int32_t*>(&buf_[len_]);
*p = disp;
......@@ -202,11 +228,6 @@ void Operand::set_disp32(int32_t disp) {
}
Operand::Operand(Register reg) {
// reg
set_modrm(3, reg);
}
} } // namespace v8::internal
#endif // V8_X64_ASSEMBLER_X64_INL_H_
......@@ -253,143 +253,44 @@ enum ScaleFactor {
class Operand BASE_EMBEDDED {
public:
// reg
INLINE(explicit Operand(Register reg));
// MemoryOperand
INLINE(explicit Operand()) { UNIMPLEMENTED(); }
// Returns true if this Operand is a wrapper for the specified register.
bool is_reg(Register reg) const;
// These constructors have been moved to MemOperand, and should
// be removed from Operand as soon as all their uses use MemOperands instead.
// [disp/r]
INLINE(explicit Operand(intptr_t disp, RelocInfo::Mode rmode)) {
UNIMPLEMENTED();
}
// disp only must always be relocated
// [base + disp/r]
explicit Operand(Register base, int32_t disp,
RelocInfo::Mode rmode = RelocInfo::NONE);
INLINE(Operand(Register base, int32_t disp));
// [base + index*scale + disp/r]
explicit Operand(Register base,
Register index,
ScaleFactor scale,
int32_t disp,
RelocInfo::Mode rmode = RelocInfo::NONE);
Operand(Register base,
Register index,
ScaleFactor scale,
int32_t disp);
// [index*scale + disp/r]
explicit Operand(Register index,
ScaleFactor scale,
int32_t disp,
RelocInfo::Mode rmode = RelocInfo::NONE);
// End of constructors and methods that have been moved to MemOperand.
Operand(Register index,
ScaleFactor scale,
int32_t disp);
private:
byte rex_;
byte buf_[10];
// The number of bytes in buf_.
unsigned int len_;
// Only valid if len_ > 4.
RelocInfo::Mode rmode_;
// Set the ModRM byte without an encoded 'reg' register. The
// register is encoded later as part of the emit_operand operation.
// set_modrm can be called before or after set_sib and set_disp*.
inline void set_modrm(int mod, Register rm);
// Set the SIB byte if one is needed. Sets the length to 2 rather than 1.
inline void set_sib(ScaleFactor scale, Register index, Register base);
inline void set_disp8(int8_t disp);
inline void set_disp32(int32_t disp);
friend class Assembler;
};
// Adds operand displacement fields (offsets added to the memory address).
// Needs to be called after set_sib, not before it.
inline void set_disp8(int disp);
inline void set_disp32(int disp);
class MemOperand : public Operand {
public:
// [disp/r]
INLINE(explicit MemOperand(int32_t disp, RelocInfo::Mode rmode)) :
Operand() {
UNIMPLEMENTED();
}
// disp only must always be relocated
// [base + disp/r]
explicit MemOperand(Register base, int32_t disp,
RelocInfo::Mode rmode = RelocInfo::NONE);
// [base + index*scale + disp/r]
explicit MemOperand(Register base,
Register index,
ScaleFactor scale,
int32_t disp,
RelocInfo::Mode rmode = RelocInfo::NONE);
// [index*scale + disp/r]
explicit MemOperand(Register index,
ScaleFactor scale,
int32_t disp,
RelocInfo::Mode rmode = RelocInfo::NONE);
};
// -----------------------------------------------------------------------------
// A Displacement describes the 32bit immediate field of an instruction which
// may be used together with a Label in order to refer to a yet unknown code
// position. Displacements stored in the instruction stream are used to describe
// the instruction and to chain a list of instructions using the same Label.
// A Displacement contains 2 different fields:
//
// next field: position of next displacement in the chain (0 = end of list)
// type field: instruction type
//
// A next value of null (0) indicates the end of a chain (note that there can
// be no displacement at position zero, because there is always at least one
// instruction byte before the displacement).
//
// Displacement _data field layout
//
// |31.....2|1......0|
// [ next | type |
class Displacement BASE_EMBEDDED {
public:
enum Type {
UNCONDITIONAL_JUMP,
CODE_RELATIVE,
OTHER
};
int data() const { return data_; }
Type type() const { return TypeField::decode(data_); }
void next(Label* L) const {
int n = NextField::decode(data_);
n > 0 ? L->link_to(n) : L->Unuse();
}
void link_to(Label* L) { init(L, type()); }
explicit Displacement(int data) { data_ = data; }
Displacement(Label* L, Type type) { init(L, type); }
void print() {
PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"),
NextField::decode(data_));
}
private:
int data_;
class TypeField: public BitField<Type, 0, 2> {};
class NextField: public BitField<int, 2, 32-2> {};
void init(Label* L, Type type);
friend class Assembler;
};
// CpuFeatures keeps track of which features are supported by the target CPU.
// Supported features must be enabled by a Scope before use.
// Example:
......@@ -850,11 +751,6 @@ class Assembler : public Malloced {
void bind_to(Label* L, int pos);
void link_to(Label* L, Label* appendix);
// displacements
inline Displacement disp_at(Label* L);
inline void disp_at_put(Label* L, Displacement disp);
inline void emit_disp(Label* L, Displacement::Type type);
// record reloc info for current pc_
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
......
......@@ -153,11 +153,11 @@ TEST(AssemblerX64MemoryOperands) {
__ push(rsi); // Value at (rbp - 8)
__ push(rsi); // Value at (rbp - 16)
__ push(rdi); // Value at (rbp - 24)
// const int kStackElementSize = 8;
// __ mov(rax, Operand(rbp,-3 * kStackElementSize));
__ pop(rax);
__ pop(rax);
__ pop(rax);
const int kStackElementSize = 8;
__ mov(rax, Operand(rbp, -3 * kStackElementSize));
__ pop(rsi);
__ pop(rsi);
__ pop(rsi);
__ pop(rbp);
__ nop();
__ ret(0);
......@@ -166,7 +166,7 @@ TEST(AssemblerX64MemoryOperands) {
assm.GetCode(&desc);
// Call the function from C++.
int result = FUNCTION_CAST<F2>(buffer)(3, 2);
CHECK_EQ(2, result);
CHECK_EQ(3, result);
}
TEST(AssemblerX64ControlFlow) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment