Add encoding size information to EncInfo.

Two new pieces of information are available for all encoding recipes:

- The size in bytes of an encoded instruction, and
- The range of a branch encoded with the recipe, if any.

In the meta language, EncRecipe takes two new constructor arguments. The
size is required for all encodings and branch_range is required for all
recipes used to encode branches.
This commit is contained in:
Jakob Stoklund Olesen
2017-04-05 11:04:17 -07:00
parent 6ab35e54b8
commit eb1052718b
10 changed files with 169 additions and 14 deletions

View File

@@ -5,5 +5,6 @@ use ir::types;
use isa::EncInfo;
use isa::constraints::*;
use isa::enc_tables::{Level1Entry, Level2Entry};
use isa::encoding::RecipeSizing;
include!(concat!(env!("OUT_DIR"), "/encoding-arm32.rs"));

View File

@@ -5,5 +5,6 @@ use ir::types;
use isa::EncInfo;
use isa::constraints::*;
use isa::enc_tables::{Level1Entry, Level2Entry};
use isa::encoding::RecipeSizing;
include!(concat!(env!("OUT_DIR"), "/encoding-arm64.rs"));

View File

@@ -7,6 +7,7 @@
//! It is the register allocator's job to make sure that the register constraints on value operands
//! are satisfied.
use binemit::CodeOffset;
use isa::{RegClass, RegUnit};
/// Register constraint for a single value operand or instruction result.
@@ -48,7 +49,7 @@ pub enum ConstraintKind {
Stack,
}
/// Constraints for an encoding recipe.
/// Value operand constraints for an encoding recipe.
#[derive(Clone)]
pub struct RecipeConstraints {
/// Constraints for the instruction's fixed value operands.
@@ -66,3 +67,60 @@ pub struct RecipeConstraints {
/// constraints must be derived from the calling convention ABI.
pub outs: &'static [OperandConstraint],
}
/// Constraints on the range of a branch instruction.
///
/// A branch instruction usually encodes its destination as a signed n-bit offset from an origin.
/// The origin depends on the ISA and the specific instruction:
///
/// - RISC-V and ARM Aarch64 use the address of the branch instruction, `origin = 0`.
/// - Intel uses the address of the instruction following the branch, `origin = 2` for a 2-byte
/// branch instruction.
/// - ARM's A32 encoding uses the address of the branch instruction + 8 bytes, `origin = 8`.
#[derive(Clone, Copy)]
pub struct BranchRange {
/// Offset in bytes from the address of the branch instruction to the origin used for computing
/// the branch displacement. This is the destination of a branch that encodes a 0 displacement.
pub origin: u8,
/// Number of bits in the signed byte displacement encoded in the instruction. This does not
/// account for branches that can only target aligned addresses.
pub bits: u8,
}
impl BranchRange {
/// Determine if this branch range can represent the range from `branch` to `dest`, where
/// `branch` is the code offset of the branch instruction itself and `dest` is the code offset
/// of the destination EBB header.
///
/// This method does not detect if the range is larger than 2 GB.
pub fn contains(self, branch: CodeOffset, dest: CodeOffset) -> bool {
let d = dest.wrapping_sub(branch + self.origin as CodeOffset) as i32;
let s = 32 - self.bits;
d == d << s >> s
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn branch_range() {
// ARM T1 branch.
let t1 = BranchRange { origin: 4, bits: 9 };
assert!(t1.contains(0, 0));
assert!(t1.contains(0, 2));
assert!(t1.contains(2, 0));
assert!(t1.contains(1000, 1000));
// Forward limit.
assert!(t1.contains(1000, 1258));
assert!(!t1.contains(1000, 1260));
// Backward limit
assert!(t1.contains(1000, 748));
assert!(!t1.contains(1000, 746));
}
}

View File

@@ -1,7 +1,8 @@
//! The `Encoding` struct.
use binemit::CodeOffset;
use isa::constraints::{RecipeConstraints, BranchRange};
use std::fmt;
use isa::constraints::RecipeConstraints;
/// Bits needed to encode an instruction as binary machine code.
///
@@ -78,12 +79,28 @@ impl fmt::Display for DisplayEncoding {
}
}
/// Code size information for an encoding recipe.
///
/// All encoding recipes correspond to an exact instruction size.
pub struct RecipeSizing {
/// Size in bytes of instructions encoded with this recipe.
pub bytes: u8,
/// Allowed branch range in this recipe, if any.
///
/// All encoding recipes for branches have exact branch range information.
pub branch_range: Option<BranchRange>,
}
/// Information about all the encodings in this ISA.
#[derive(Clone)]
pub struct EncInfo {
/// Constraints on value operands per recipe.
pub constraints: &'static [RecipeConstraints],
/// Code size information per recipe.
pub sizing: &'static [RecipeSizing],
/// Names of encoding recipes.
pub names: &'static [&'static str],
}
@@ -101,4 +118,23 @@ impl EncInfo {
recipe_names: self.names,
}
}
/// Get the exact size in bytes of instructions encoded with `enc`.
///
/// Returns 0 for illegal encodings.
pub fn bytes(&self, enc: Encoding) -> CodeOffset {
self.sizing
.get(enc.recipe())
.map(|s| s.bytes as CodeOffset)
.unwrap_or(0)
}
/// Get the branch range that is supported by `enc`, if any.
///
/// This will never return `None` for a legal branch encoding.
pub fn branch_range(&self, enc: Encoding) -> Option<BranchRange> {
self.sizing
.get(enc.recipe())
.and_then(|s| s.branch_range)
}
}

View File

@@ -5,5 +5,6 @@ use ir::types;
use isa::EncInfo;
use isa::constraints::*;
use isa::enc_tables::{Level1Entry, Level2Entry};
use isa::encoding::RecipeSizing;
include!(concat!(env!("OUT_DIR"), "/encoding-intel.rs"));

View File

@@ -40,7 +40,7 @@
//! The configured target ISA trait object is a `Box<TargetIsa>` which can be used for multiple
//! concurrent function compilations.
pub use isa::constraints::{RecipeConstraints, OperandConstraint, ConstraintKind};
pub use isa::constraints::{RecipeConstraints, OperandConstraint, ConstraintKind, BranchRange};
pub use isa::encoding::{Encoding, EncInfo};
pub use isa::registers::{RegInfo, RegUnit, RegClass, RegClassIndex};

View File

@@ -6,6 +6,7 @@ use ir::{Opcode, InstructionData};
use isa::EncInfo;
use isa::constraints::*;
use isa::enc_tables::{Level1Entry, Level2Entry};
use isa::encoding::RecipeSizing;
use predicates;
use super::registers::*;