aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2023-01-28 21:00:08 -0800
committeriximeow <me@iximeow.net>2023-07-04 19:01:38 -0700
commitf9d3ce1f2f447b55a003ec273642de63d7aa988f (patch)
tree089af66cf37975f23cef28caeb35344aede9efb3
parentb577312dd61edaac2551794578ace22287031bdb (diff)
store non-rex expected bank when first witnessing operand size prefix
the expectation here is that we can set a default `vqp_size` pretty cheaply (Prefixes::new is one store, on x86_64 anyway...). then, when we see an `operand_size` prefix, it's rare enough we can pay a little extra to speculate on *likely* implication, and update some state (`vqp_size` is *probably* going to be 2 because of it) accordingly. the cases where `vqp_size` would go unused and this was wasted effort are relativlely rare. on the other hand, we can't profitably give `rex` this treatment: `rex.w` would set `vqp_size` to `qword`, but rex-prefixed instructions are so often byte-size registers that updating `vqp_size` (conditionally, no less), is only break-even. so, keep a check for `rex.w` at use site, where it's only a choice between `qword` or `whatver-size-a-non-rex.w-prefixed-instruction-would-be-sized`, which has been kept up to date by speculation when detecting `operand_size`.
-rw-r--r--src/long_mode/mod.rs37
1 files changed, 29 insertions, 8 deletions
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index 3b2b68d..1d7148c 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -4534,6 +4534,7 @@ pub struct Prefixes {
rex: PrefixRex,
segment: Segment,
evex_data: EvexData,
+ vqp_size: RegisterBank,
}
/// the `avx512`-related data from an [`evex`](https://en.wikipedia.org/wiki/EVEX_prefix) prefix.
@@ -4610,6 +4611,7 @@ impl Prefixes {
rex: PrefixRex { bits: 0 },
segment: Segment::DS,
evex_data: EvexData { bits: 0 },
+ vqp_size: RegisterBank::D,
}
}
#[inline]
@@ -4625,9 +4627,19 @@ impl Prefixes {
#[inline]
fn operand_size(&self) -> bool { self.bits & 0x1 == 1 }
#[inline]
- fn set_operand_size(&mut self) { self.bits = self.bits | 0x1 }
+ fn set_operand_size(&mut self) {
+ self.bits = self.bits | 0x1;
+ self.vqp_size = RegisterBank::W;
+ }
#[inline]
- fn unset_operand_size(&mut self) { self.bits = self.bits & !0x1 }
+ fn unset_operand_size(&mut self) {
+ self.bits = self.bits & !0x1;
+ if self.rex.w() {
+ self.vqp_size = RegisterBank::Q;
+ } else {
+ self.vqp_size = RegisterBank::D;
+ }
+ }
#[inline]
fn address_size(&self) -> bool { self.bits & 0x2 == 2 }
#[inline]
@@ -4703,6 +4715,15 @@ impl Prefixes {
self.rex.bits = bits;
}
+ #[inline(always)]
+ fn vqp_size(&self) -> RegisterBank {
+ if self.rex.w() {
+ RegisterBank::Q
+ } else {
+ self.vqp_size
+ }
+ }
+
#[inline]
fn vex_from_c5(&mut self, bits: u8) {
// collect rex bits
@@ -6844,7 +6865,7 @@ fn read_operands<
// cool! we can precompute width and know we need to read_E.
if !operand_code.has_byte_operands() {
// further, this is an vdq E
- bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
+ bank = instruction.prefixes.vqp_size();
instruction.regs[0].bank = bank;
instruction.mem_size = bank as u8;
r = if instruction.prefixes.rex_unchecked().r() { 0b1000 } else { 0 };
@@ -6909,7 +6930,7 @@ fn read_operands<
// cool! we can precompute width and know we need to read_E.
if !operand_code.has_byte_operands() {
// further, this is an vdq E
- bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
+ bank = instruction.prefixes.vqp_size();
instruction.mem_size = bank as u8;
opwidth = bank as u8;
} else {
@@ -7023,7 +7044,7 @@ fn read_operands<
instruction.operand_count = 0;
return Ok(());
}
- let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
+ let bank = instruction.prefixes.vqp_size();
// always *ax, but size is determined by prefixes (or lack thereof)
instruction.regs[0] =
RegSpec::from_parts(0, false, bank);
@@ -7095,7 +7116,7 @@ fn read_operands<
}
3 => {
// category == 3, Zv_Ivq_R
- let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
+ let bank = instruction.prefixes.vqp_size();
instruction.regs[0] =
RegSpec::from_parts(reg, instruction.prefixes.rex_unchecked().b(), bank);
sink.record(
@@ -7436,7 +7457,7 @@ fn read_operands<
instruction.mem_size = 2;
RegisterBank::W
};
- let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
+ let bank = instruction.prefixes.vqp_size();
let modrm = read_modrm(words)?;
instruction.operands[1] = read_E(words, instruction, modrm, w, sink)?;
@@ -7558,7 +7579,7 @@ fn read_operands<
instruction.operands[1] = OperandSpec::ImmI8;
}
24 => {
- let bank = bank_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
+ let bank = instruction.prefixes.vqp_size();
let numwidth = if bank as u8 == 8 { 4 } else { bank as u8 };
instruction.regs[0] =
RegSpec::gp_from_parts_non_byte(0, false, bank);