Skip extra work when inferring REX prefixes

As explained in the added documentation and #1342, if we prevent `infer_rex()` and `w()` from being used together then we don't need to check whether the W bit is set when figuring out if a REX prefix is needed in `needs_rex()`. This should improve compile time for x86 very slightly since all `infer_rex()` instructions will no longer need this check.
This commit is contained in:
Andrew Brown
2020-03-31 09:03:03 -07:00
parent d0daef6f60
commit a4c1147045

View File

@@ -74,10 +74,15 @@ fn evex2(rm: RegUnit, reg: RegUnit) -> u8 {
0x00 | r_ | (b << 1) | (x << 2) | (r << 3) 0x00 | r_ | (b << 1) | (x << 2) | (r << 3)
} }
/// Determines whether a REX prefix should be emitted. /// Determines whether a REX prefix should be emitted. A REX byte always has 0100 in bits 7:4; bits
/// 3:0 correspond to WRXB. W allows certain instructions to declare a 64-bit operand size; because
/// [needs_rex] is only used by [infer_rex] and we prevent [infer_rex] from using [w] in
/// [Template::build], we do not need to check again whether [w] forces an inferred REX prefix--it
/// always does and should be encoded like `.rex().w()`. The RXB are extension of ModR/M or SIB
/// fields; see section 2.2.1.2 in the Intel Software Development Manual.
#[inline] #[inline]
fn needs_rex(bits: u16, rex: u8) -> bool { fn needs_rex(rex: u8) -> bool {
rex != BASE_REX || EncodingBits::from(bits).rex_w() == 1 rex != BASE_REX
} }
// Emit a REX prefix. // Emit a REX prefix.
@@ -107,7 +112,7 @@ fn put_rexop1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
/// Emit a single-byte opcode with inferred REX prefix. /// Emit a single-byte opcode with inferred REX prefix.
fn put_dynrexop1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) { fn put_dynrexop1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
debug_assert_eq!(bits & 0x0f00, 0, "Invalid encoding bits for DynRexOp1*"); debug_assert_eq!(bits & 0x0f00, 0, "Invalid encoding bits for DynRexOp1*");
if needs_rex(bits, rex) { if needs_rex(rex) {
rex_prefix(bits, rex, sink); rex_prefix(bits, rex, sink);
} }
sink.put1(bits as u8); sink.put1(bits as u8);
@@ -136,7 +141,7 @@ fn put_dynrexop2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
0x0400, 0x0400,
"Invalid encoding bits for DynRexOp2*" "Invalid encoding bits for DynRexOp2*"
); );
if needs_rex(bits, rex) { if needs_rex(rex) {
rex_prefix(bits, rex, sink); rex_prefix(bits, rex, sink);
} }
sink.put1(0x0f); sink.put1(0x0f);
@@ -190,7 +195,7 @@ fn put_dynrexmp2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
); );
let enc = EncodingBits::from(bits); let enc = EncodingBits::from(bits);
sink.put1(PREFIX[(enc.pp() - 1) as usize]); sink.put1(PREFIX[(enc.pp() - 1) as usize]);
if needs_rex(bits, rex) { if needs_rex(rex) {
rex_prefix(bits, rex, sink); rex_prefix(bits, rex, sink);
} }
sink.put1(0x0f); sink.put1(0x0f);
@@ -228,7 +233,7 @@ fn put_dynrexmp3<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
); );
let enc = EncodingBits::from(bits); let enc = EncodingBits::from(bits);
sink.put1(PREFIX[(enc.pp() - 1) as usize]); sink.put1(PREFIX[(enc.pp() - 1) as usize]);
if needs_rex(bits, rex) { if needs_rex(rex) {
rex_prefix(bits, rex, sink); rex_prefix(bits, rex, sink);
} }
sink.put1(0x0f); sink.put1(0x0f);