x64: move encodings to a separate module

In order to benchmark the encoding code with criterion, the functions
and structures must be public. Moving this code to its own module
(instead of keeping as a submodule to `inst`), allows `inst` to remain
private. This avoids having to expose and document (or ignore
documenting) the numerous instruction variants in `inst` while allowing
access to the encoding code. This commit changes no functionality.
This commit is contained in:
Andrew Brown
2021-05-10 10:50:56 -07:00
parent 05d57d8ded
commit 02796fc670
7 changed files with 28 additions and 16 deletions

View File

@@ -208,6 +208,8 @@ impl EvexInstruction {
}
}
/// Describe the register index to use. This wrapper is a type-safe way to pass
/// around the registers defined in `inst/regs.rs`.
#[derive(Copy, Clone, Default)]
pub struct Register(u8);
impl From<u8> for Register {
@@ -216,13 +218,18 @@ impl From<u8> for Register {
Self(reg)
}
}
impl Into<u8> for Register {
fn into(self) -> u8 {
self.0
}
}
/// Defines the EVEX context for the `L'`, `L`, and `b` bits (bits 6:4 of EVEX P2 byte). Table 2-36 in
/// section 2.6.10 (Intel Software Development Manual, volume 2A) describes how these bits can be
/// used together for certain classes of instructions; i.e., special care should be taken to ensure
/// that instructions use an applicable correct `EvexContext`. Table 2-39 contains cases where
/// opcodes can result in an #UD.
#[allow(dead_code)] // Rounding and broadcast modes are not yet used.
#[allow(dead_code, missing_docs)] // Rounding and broadcast modes are not yet used.
pub enum EvexContext {
RoundingRegToRegFP {
rc: EvexRoundingControl,
@@ -250,7 +257,7 @@ impl Default for EvexContext {
impl EvexContext {
/// Encode the `L'`, `L`, and `b` bits (bits 6:4 of EVEX P2 byte) for merging with the P2 byte.
fn bits(&self) -> u8 {
pub fn bits(&self) -> u8 {
match self {
Self::RoundingRegToRegFP { rc } => 0b001 | rc.bits() << 1,
Self::NoRoundingFP { sae, length } => (*sae as u8) | length.bits() << 1,
@@ -261,7 +268,7 @@ impl EvexContext {
}
/// The EVEX format allows choosing a vector length in the `L'` and `L` bits; see `EvexContext`.
#[allow(dead_code)] // Wider-length vectors are not yet used.
#[allow(dead_code, missing_docs)] // Wider-length vectors are not yet used.
pub enum EvexVectorLength {
V128,
V256,
@@ -287,7 +294,7 @@ impl Default for EvexVectorLength {
}
/// The EVEX format allows defining rounding control in the `L'` and `L` bits; see `EvexContext`.
#[allow(dead_code)] // Rounding controls are not yet used.
#[allow(dead_code, missing_docs)] // Rounding controls are not yet used.
pub enum EvexRoundingControl {
RNE,
RD,
@@ -309,7 +316,7 @@ impl EvexRoundingControl {
/// Defines the EVEX masking behavior; masking support is described in section 2.6.4 of the Intel
/// Software Development Manual, volume 2A.
#[allow(dead_code)] // Masking is not yet used.
#[allow(dead_code, missing_docs)] // Masking is not yet used.
pub enum EvexMasking {
None,
Merging { k: u8 },
@@ -324,7 +331,7 @@ impl Default for EvexMasking {
impl EvexMasking {
/// Encode the `z` bit for merging with the P2 byte.
fn z_bit(&self) -> u8 {
pub fn z_bit(&self) -> u8 {
match self {
Self::None | Self::Merging { .. } => 0,
Self::Zeroing { .. } => 1,
@@ -332,7 +339,7 @@ impl EvexMasking {
}
/// Encode the `aaa` bits for merging with the P2 byte.
fn aaa_bits(&self) -> u8 {
pub fn aaa_bits(&self) -> u8 {
match self {
Self::None => 0b000,
Self::Merging { k } | Self::Zeroing { k } => {

View File

@@ -1,3 +1,4 @@
//! Contains the encoding machinery for the various x64 instruction formats.
use crate::{isa::x64, machinst::MachBuffer};
use std::vec::Vec;
@@ -5,6 +6,8 @@ pub mod evex;
pub mod rex;
pub mod vex;
/// The encoding formats in this module all require a way of placing bytes into
/// a buffer.
pub trait ByteSink {
/// Add 1 byte to the code section.
fn put1(&mut self, _: u8);

View File

@@ -28,8 +28,9 @@ pub(crate) fn low8_will_sign_extend_to_32(x: u32) -> bool {
xs == ((xs << 24) >> 24)
}
/// Encode the ModR/M byte.
#[inline(always)]
pub(crate) fn encode_modrm(m0d: u8, enc_reg_g: u8, rm_e: u8) -> u8 {
pub fn encode_modrm(m0d: u8, enc_reg_g: u8, rm_e: u8) -> u8 {
debug_assert!(m0d < 4);
debug_assert!(enc_reg_g < 8);
debug_assert!(rm_e < 8);
@@ -155,6 +156,7 @@ impl From<(OperandSize, Reg)> for RexFlags {
/// Allows using the same opcode byte in different "opcode maps" to allow for more instruction
/// encodings. See appendix A in the Intel Software Developer's Manual, volume 2A, for more details.
#[allow(missing_docs)]
pub enum OpcodeMap {
None,
_0F,

View File

@@ -2,16 +2,16 @@ use crate::binemit::{Addend, Reloc};
use crate::ir::immediates::{Ieee32, Ieee64};
use crate::ir::LibCall;
use crate::ir::TrapCode;
use crate::isa::x64::inst::args::*;
use crate::isa::x64::inst::*;
use crate::machinst::{inst_common, MachBuffer, MachInstEmit, MachLabel};
use core::convert::TryInto;
use encoding::evex::{EvexInstruction, EvexVectorLength};
use encoding::rex::{
use crate::isa::x64::encoding::evex::{EvexInstruction, EvexVectorLength};
use crate::isa::x64::encoding::rex::{
emit_simm, emit_std_enc_enc, emit_std_enc_mem, emit_std_reg_mem, emit_std_reg_reg, int_reg_enc,
low8_will_sign_extend_to_32, low8_will_sign_extend_to_64, reg_enc, LegacyPrefixes, OpcodeMap,
RexFlags,
};
use crate::isa::x64::inst::args::*;
use crate::isa::x64::inst::*;
use crate::machinst::{inst_common, MachBuffer, MachInstEmit, MachLabel};
use core::convert::TryInto;
use log::debug;
use regalloc::{Reg, Writable};

View File

@@ -22,7 +22,6 @@ pub mod args;
mod emit;
#[cfg(test)]
mod emit_tests;
pub(crate) mod encoding;
pub mod regs;
pub mod unwind;
@@ -2856,7 +2855,7 @@ impl EmitState {
self.stack_map = None;
}
fn cur_srcloc(&self) -> SourceLoc {
pub(crate) fn cur_srcloc(&self) -> SourceLoc {
self.cur_srcloc
}
}

View File

@@ -18,6 +18,7 @@ use target_lexicon::Triple;
use crate::isa::unwind::systemv;
mod abi;
pub mod encoding;
mod inst;
mod lower;
mod settings;