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:
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user