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);  | 
