diff options
author | iximeow <me@iximeow.net> | 2023-01-28 21:00:08 -0800 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2023-07-04 19:01:38 -0700 |
commit | f9d3ce1f2f447b55a003ec273642de63d7aa988f (patch) | |
tree | 089af66cf37975f23cef28caeb35344aede9efb3 | |
parent | b577312dd61edaac2551794578ace22287031bdb (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.rs | 37 |
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); |