summaryrefslogtreecommitdiff
path: root/Libraries/LibX86
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-11-17 10:24:55 +0100
committerAndreas Kling <kling@serenityos.org>2020-11-17 17:09:49 +0100
commit0e132d345fbe0ce67e62c64340c0fd1086d5c028 (patch)
tree7073a4463b5da5db33d0fdd1bf041d62826ded1a /Libraries/LibX86
parent4c343c5f26a195ae1bb34646d403281472260c7f (diff)
downloadserenity-0e132d345fbe0ce67e62c64340c0fd1086d5c028.zip
LibX86: Pack the Instruction data structure
This patch shrinks X86::Instruction from 56 to 28 bytes by packing data members more tightly and removing some entirely. There is still some data duplication between Instruction and the corresponding InstructionDescriptor but it will be a bit tricky to get much more out of it. This looks like a 1-2% improvement on general emulation speed. :^)
Diffstat (limited to 'Libraries/LibX86')
-rw-r--r--Libraries/LibX86/Instruction.cpp4
-rw-r--r--Libraries/LibX86/Instruction.h159
2 files changed, 41 insertions, 122 deletions
diff --git a/Libraries/LibX86/Instruction.cpp b/Libraries/LibX86/Instruction.cpp
index aad2fd19bd..c8713e723a 100644
--- a/Libraries/LibX86/Instruction.cpp
+++ b/Libraries/LibX86/Instruction.cpp
@@ -1209,8 +1209,8 @@ static String relative_address(u32 origin, bool x32, i32 imm)
String Instruction::to_string(u32 origin, const SymbolProvider* symbol_provider, bool x32) const
{
StringBuilder builder;
- if (m_segment_prefix.has_value())
- builder.appendf("%s: ", register_name(m_segment_prefix.value()));
+ if (has_segment_prefix())
+ builder.appendf("%s: ", register_name(segment_prefix().value()));
if (has_address_size_override_prefix())
builder.append(m_a32 ? "a32 " : "a16 ");
if (has_operand_size_override_prefix())
diff --git a/Libraries/LibX86/Instruction.h b/Libraries/LibX86/Instruction.h
index d943bbfd51..98428b7334 100644
--- a/Libraries/LibX86/Instruction.h
+++ b/Libraries/LibX86/Instruction.h
@@ -378,7 +378,7 @@ public:
String to_string_fpu80(const Instruction&) const;
String to_string_mm(const Instruction&) const;
- bool is_register() const { return m_register_index != 0xffffffff; }
+ bool is_register() const { return m_register_index != 0x7f; }
unsigned register_index() const { return m_register_index; }
RegisterIndex32 reg32() const { return static_cast<RegisterIndex32>(register_index()); }
@@ -420,7 +420,6 @@ private:
void decode16(InstructionStreamType&);
template<typename InstructionStreamType>
void decode32(InstructionStreamType&);
-
template<typename CPU>
LogicalAddress resolve16(const CPU&, Optional<SegmentRegister>);
template<typename CPU>
@@ -429,22 +428,16 @@ private:
template<typename CPU>
u32 evaluate_sib(const CPU&, SegmentRegister& default_segment) const;
- unsigned m_register_index { 0xffffffff };
union {
- u32 m_offset32 { 0 };
- u16 m_offset16;
+ u32 m_displacement32 { 0 };
+ u16 m_displacement16;
};
u8 m_rm { 0 };
u8 m_sib { 0 };
u8 m_displacement_bytes { 0 };
-
- union {
- u32 m_displacement32 { 0 };
- u16 m_displacement16;
- };
-
- bool m_has_sib { false };
+ u8 m_register_index : 7 { 0x7f };
+ bool m_has_sib : 1 { false };
};
class Instruction {
@@ -453,16 +446,17 @@ public:
static Instruction from_stream(InstructionStreamType&, bool o32, bool a32);
~Instruction() { }
- ALWAYS_INLINE MemoryOrRegisterReference& modrm() const
- {
- ASSERT(has_rm());
- return m_modrm;
- }
+ ALWAYS_INLINE MemoryOrRegisterReference& modrm() const { return m_modrm; }
ALWAYS_INLINE InstructionHandler handler() const { return m_descriptor->handler; }
- bool has_segment_prefix() const { return m_segment_prefix.has_value(); }
- Optional<SegmentRegister> segment_prefix() const { return m_segment_prefix; }
+ bool has_segment_prefix() const { return m_segment_prefix != 0xff; }
+ ALWAYS_INLINE Optional<SegmentRegister> segment_prefix() const
+ {
+ if (has_segment_prefix())
+ return static_cast<SegmentRegister>(m_segment_prefix);
+ return {};
+ }
bool has_address_size_override_prefix() const { return m_has_address_size_override_prefix; }
bool has_operand_size_override_prefix() const { return m_has_operand_size_override_prefix; }
@@ -477,13 +471,8 @@ public:
String mnemonic() const;
u8 op() const { return m_op; }
- u8 sub_op() const { return m_sub_op; }
u8 rm() const { return m_modrm.m_rm; }
- u8 slash() const
- {
- ASSERT(has_rm());
- return (rm() >> 3) & 7;
- }
+ u8 slash() const { return (rm() >> 3) & 7; }
u8 imm8() const { return m_imm1; }
u16 imm16() const { return m_imm1; }
@@ -499,7 +488,6 @@ public:
LogicalAddress imm_address16_16() const { return LogicalAddress(imm16_1(), imm16_2()); }
LogicalAddress imm_address16_32() const { return LogicalAddress(imm16_1(), imm32_2()); }
- bool has_rm() const { return m_has_rm; }
bool has_sub_op() const
{
return m_op == 0x0f;
@@ -528,27 +516,21 @@ private:
const char* reg16_name() const;
const char* reg32_name() const;
- u8 m_op { 0 };
- u8 m_sub_op { 0 };
+ InstructionDescriptor* m_descriptor { nullptr };
+ mutable MemoryOrRegisterReference m_modrm;
u32 m_imm1 { 0 };
u32 m_imm2 { 0 };
- u8 m_register_index { 0 };
- bool m_a32 { false };
- bool m_o32 { false };
- bool m_has_lock_prefix { false };
-
- bool m_has_rm { false };
-
+ u8 m_segment_prefix { 0xff };
+ u8 m_register_index { 0xff };
+ u8 m_op { 0 };
+ u8 m_sub_op { 0 };
u8 m_extra_bytes { 0 };
-
- Optional<SegmentRegister> m_segment_prefix;
- bool m_has_operand_size_override_prefix { false };
- bool m_has_address_size_override_prefix { false };
u8 m_rep_prefix { 0 };
-
- mutable MemoryOrRegisterReference m_modrm;
-
- InstructionDescriptor* m_descriptor { nullptr };
+ bool m_a32 : 1 { false };
+ bool m_o32 : 1 { false };
+ bool m_has_lock_prefix : 1 { false };
+ bool m_has_operand_size_override_prefix : 1 { false };
+ bool m_has_address_size_override_prefix : 1 { false };
};
template<typename CPU>
@@ -602,27 +584,13 @@ ALWAYS_INLINE LogicalAddress MemoryOrRegisterReference::resolve32(const CPU& cpu
u32 offset = 0;
switch (m_rm & 0x07) {
- case 0:
- offset = cpu.eax().value() + m_displacement32;
- break;
- case 1:
- offset = cpu.ecx().value() + m_displacement32;
- break;
- case 2:
- offset = cpu.edx().value() + m_displacement32;
- break;
- case 3:
- offset = cpu.ebx().value() + m_displacement32;
+ case 0 ... 3:
+ case 6 ... 7:
+ offset = cpu.const_gpr32((RegisterIndex32)(m_rm & 0x07)).value() + m_displacement32;
break;
case 4:
offset = evaluate_sib(cpu, default_segment);
break;
- case 6:
- offset = cpu.esi().value() + m_displacement32;
- break;
- case 7:
- offset = cpu.edi().value() + m_displacement32;
- break;
default: // 5
if ((m_rm & 0xc0) == 0x00) {
offset = m_displacement32;
@@ -641,73 +609,28 @@ ALWAYS_INLINE LogicalAddress MemoryOrRegisterReference::resolve32(const CPU& cpu
template<typename CPU>
ALWAYS_INLINE u32 MemoryOrRegisterReference::evaluate_sib(const CPU& cpu, SegmentRegister& default_segment) const
{
- u32 scale = 0;
- switch (m_sib & 0xc0) {
- case 0x00:
- scale = 1;
- break;
- case 0x40:
- scale = 2;
- break;
- case 0x80:
- scale = 4;
- break;
- case 0xc0:
- scale = 8;
- break;
- }
+ u32 scale_shift = m_sib >> 6;
u32 index = 0;
switch ((m_sib >> 3) & 0x07) {
- case 0:
- index = cpu.eax().value();
- break;
- case 1:
- index = cpu.ecx().value();
- break;
- case 2:
- index = cpu.edx().value();
- break;
- case 3:
- index = cpu.ebx().value();
+ case 0 ... 3:
+ case 5 ... 7:
+ index = cpu.const_gpr32((RegisterIndex32)((m_sib >> 3) & 0x07)).value();
break;
case 4:
index = 0;
break;
- case 5:
- index = cpu.ebp().value();
- break;
- case 6:
- index = cpu.esi().value();
- break;
- case 7:
- index = cpu.edi().value();
- break;
}
u32 base = m_displacement32;
switch (m_sib & 0x07) {
- case 0:
- base += cpu.eax().value();
- break;
- case 1:
- base += cpu.ecx().value();
- break;
- case 2:
- base += cpu.edx().value();
- break;
- case 3:
- base += cpu.ebx().value();
+ case 0 ... 3:
+ case 6 ... 7:
+ base += cpu.const_gpr32((RegisterIndex32)(m_sib & 0x07)).value();
break;
case 4:
default_segment = SegmentRegister::SS;
base += cpu.esp().value();
break;
- case 6:
- base += cpu.esi().value();
- break;
- case 7:
- base += cpu.edi().value();
- break;
default: // 5
switch ((m_rm >> 6) & 3) {
case 0:
@@ -724,7 +647,7 @@ ALWAYS_INLINE u32 MemoryOrRegisterReference::evaluate_sib(const CPU& cpu, Segmen
break;
}
- return (scale * index) + base;
+ return (index << scale_shift) + base;
}
template<typename CPU, typename T>
@@ -820,7 +743,7 @@ ALWAYS_INLINE unsigned Instruction::length() const
unsigned len = 1;
if (has_sub_op())
++len;
- if (m_has_rm) {
+ if (m_descriptor->has_rm) {
++len;
if (m_modrm.m_has_sib)
++len;
@@ -878,7 +801,7 @@ ALWAYS_INLINE Instruction::Instruction(InstructionStreamType& stream, bool o32,
}
auto segment_prefix = to_segment_prefix(opbyte);
if (segment_prefix.has_value()) {
- m_segment_prefix = segment_prefix;
+ m_segment_prefix = (u8)segment_prefix.value();
continue;
}
m_op = opbyte;
@@ -892,8 +815,7 @@ ALWAYS_INLINE Instruction::Instruction(InstructionStreamType& stream, bool o32,
m_descriptor = m_o32 ? &s_table32[m_op] : &s_table16[m_op];
}
- m_has_rm = m_descriptor->has_rm;
- if (m_has_rm) {
+ if (m_descriptor->has_rm) {
// Consume ModR/M (may include SIB and displacement.)
m_modrm.decode(stream, m_a32);
m_register_index = (m_modrm.m_rm >> 3) & 7;
@@ -1050,15 +972,12 @@ ALWAYS_INLINE void MemoryOrRegisterReference::decode32(InstructionStreamType& st
if ((m_sib & 0x07) == 5) {
switch ((m_rm >> 6) & 0x03) {
case 0:
- ASSERT(!m_displacement_bytes || m_displacement_bytes == 4);
m_displacement_bytes = 4;
break;
case 1:
- ASSERT(!m_displacement_bytes || m_displacement_bytes == 1);
m_displacement_bytes = 1;
break;
case 2:
- ASSERT(!m_displacement_bytes || m_displacement_bytes == 4);
m_displacement_bytes = 4;
break;
default: