[x64] Refactor representation of {Operand}
Make the separation between Operands pointing to Label locations and standard memory operands more clear. Also provide a separate method for emitting "label operands", so this does not get inlined everywhere (label operands are used much less often than memory operands). R=jkummerow@chromium.org Bug: v8:13570 Change-Id: I3482598cbf47eea878e06acc1ce2465325a597e0 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4088644 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/main@{#84763}
This commit is contained in:
parent
2635ba5a7f
commit
748e6d7c45
@ -584,6 +584,12 @@ void Assembler::GrowBuffer() {
|
||||
}
|
||||
|
||||
void Assembler::emit_operand(int code, Operand adr) {
|
||||
// Redirect to {emit_label_operand} if {adr} contains a label.
|
||||
if (adr.data().is_label_operand) {
|
||||
emit_label_operand(code, adr.data().label, adr.data().addend);
|
||||
return;
|
||||
}
|
||||
|
||||
DCHECK(is_uint3(code));
|
||||
const unsigned length = adr.data().len;
|
||||
DCHECK_GT(length, 0);
|
||||
@ -591,29 +597,27 @@ void Assembler::emit_operand(int code, Operand adr) {
|
||||
// Emit updated ModR/M byte containing the given register.
|
||||
DCHECK_EQ(adr.data().buf[0] & 0x38, 0);
|
||||
*pc_++ = adr.data().buf[0] | code << 3;
|
||||
// Emit the rest of the encoded operand.
|
||||
for (unsigned i = 1; i < length; i++) *pc_++ = adr.data().buf[i];
|
||||
}
|
||||
|
||||
// Recognize RIP relative addressing.
|
||||
if (adr.data().buf[0] == 5) {
|
||||
DCHECK_EQ(9u, length);
|
||||
Label* label = ReadUnalignedValue<Label*>(
|
||||
reinterpret_cast<Address>(&adr.data().buf[1]));
|
||||
if (label->is_bound()) {
|
||||
int offset =
|
||||
label->pos() - pc_offset() - sizeof(int32_t) + adr.data().addend;
|
||||
DCHECK_GE(0, offset);
|
||||
emitl(offset);
|
||||
} else if (label->is_linked()) {
|
||||
emitl(label->pos());
|
||||
label->link_to(pc_offset() - sizeof(int32_t));
|
||||
} else {
|
||||
DCHECK(label->is_unused());
|
||||
int32_t current = pc_offset();
|
||||
emitl(current);
|
||||
label->link_to(current);
|
||||
}
|
||||
void Assembler::emit_label_operand(int code, Label* label, int addend) {
|
||||
DCHECK(addend == 0 || (is_int8(addend) && label->is_bound()));
|
||||
V8_ASSUME(0 <= code && code <= 7);
|
||||
|
||||
*pc_++ = 5 | (code << 3);
|
||||
if (label->is_bound()) {
|
||||
int offset = label->pos() - pc_offset() - sizeof(int32_t) + addend;
|
||||
DCHECK_GE(0, offset);
|
||||
emitl(offset);
|
||||
} else if (label->is_linked()) {
|
||||
emitl(label->pos());
|
||||
label->link_to(pc_offset() - sizeof(int32_t));
|
||||
} else {
|
||||
// Emit the rest of the encoded operand.
|
||||
for (unsigned i = 1; i < length; i++) *pc_++ = adr.data().buf[i];
|
||||
DCHECK(label->is_unused());
|
||||
int32_t current = pc_offset();
|
||||
emitl(current);
|
||||
label->link_to(current);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,11 +161,22 @@ enum ScaleFactor : int8_t {
|
||||
class V8_EXPORT_PRIVATE Operand {
|
||||
public:
|
||||
struct Data {
|
||||
byte rex = 0;
|
||||
byte buf[9] = {0};
|
||||
byte len = 1; // number of bytes of buf_ in use.
|
||||
int8_t addend = 0; // for rip + offset + addend.
|
||||
union {
|
||||
// {label} is set if {is_label_operand} is true.
|
||||
Label* label;
|
||||
|
||||
// Buffer for encoded memory operand:
|
||||
// Register (1 byte) + SIB (0 or 1 byte) + displacement (0, 1, or 4 byte).
|
||||
byte buf[6] = {0};
|
||||
};
|
||||
|
||||
byte len = 1; // Number of bytes of buf in use.
|
||||
bool is_label_operand = false;
|
||||
byte rex = 0; // Rex prefix, only for memory operands.
|
||||
int8_t addend = 0; // For label-relative operand: rip + offset + addend.
|
||||
};
|
||||
// {Data::len} is 8-byte aligned, which makes it fast to access.
|
||||
static_assert(offsetof(Data, len) % kSystemPointerSize == 0);
|
||||
|
||||
// [base + disp/r]
|
||||
V8_INLINE constexpr Operand(Register base, int32_t disp) {
|
||||
@ -221,8 +232,8 @@ class V8_EXPORT_PRIVATE Operand {
|
||||
data_.addend = addend;
|
||||
DCHECK_NOT_NULL(label);
|
||||
DCHECK(addend == 0 || (is_int8(addend) && label->is_bound()));
|
||||
set_modrm(0, rbp);
|
||||
set_disp64(reinterpret_cast<intptr_t>(label));
|
||||
data_.is_label_operand = true;
|
||||
data_.label = label;
|
||||
}
|
||||
|
||||
Operand(const Operand&) V8_NOEXCEPT = default;
|
||||
@ -268,13 +279,6 @@ class V8_EXPORT_PRIVATE Operand {
|
||||
data_.len += sizeof(int32_t);
|
||||
}
|
||||
|
||||
V8_INLINE void set_disp64(int64_t disp) {
|
||||
DCHECK_EQ(1, data_.len);
|
||||
Address p = reinterpret_cast<Address>(&data_.buf[data_.len]);
|
||||
WriteUnalignedValue(p, disp);
|
||||
data_.len += sizeof(disp);
|
||||
}
|
||||
|
||||
Data data_;
|
||||
};
|
||||
|
||||
@ -2287,10 +2291,14 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
|
||||
}
|
||||
|
||||
// Emit the ModR/M byte, and optionally the SIB byte and
|
||||
// 1- or 4-byte offset for a memory operand. Also used to encode
|
||||
// a three-bit opcode extension into the ModR/M byte.
|
||||
// 1- or 4-byte offset for a memory operand.
|
||||
// Also used to encode a three-bit opcode extension into the ModR/M byte.
|
||||
void emit_operand(int rm, Operand adr);
|
||||
|
||||
// Emit a RIP-relative operand.
|
||||
// Also used to encode a three-bit opcode extension into the ModR/M byte.
|
||||
V8_NOINLINE void emit_label_operand(int rm, Label* label, int addend = 0);
|
||||
|
||||
// Emit a ModR/M byte with registers coded in the reg and rm_reg fields.
|
||||
void emit_modrm(Register reg, Register rm_reg) {
|
||||
emit(0xC0 | reg.low_bits() << 3 | rm_reg.low_bits());
|
||||
|
Loading…
Reference in New Issue
Block a user