Allow binding immediates to instructions (#1012)

This change should make the code more clear (and less code) when adding encodings for instructions with specific immediates; e.g., a constant with a 0 immediate could be encoded as an XOR with something like `const.bind(...)` without explicitly creating the necessary predicates. It has several parts:
* Introduce Bindable trait to instructions
* Convert all instruction bindings to use Bindable::bind()
* Add ability to bind immediates to BoundInstruction
This is an attempt to reduce some of the issues in #955.
This commit is contained in:
Andrew Brown
2019-10-10 08:54:46 -07:00
committed by GitHub
parent f1c25c2c5a
commit 6d690e5275
6 changed files with 477 additions and 341 deletions

View File

@@ -1,5 +1,4 @@
use std::rc::Rc;
use crate::cdsl::formats::FormatRegistry;
use crate::cdsl::instructions::{
InstSpec, Instruction, InstructionPredicate, InstructionPredicateNode,
InstructionPredicateNumber, InstructionPredicateRegistry, ValueTypeOrAny,
@@ -7,6 +6,8 @@ use crate::cdsl::instructions::{
use crate::cdsl::recipes::{EncodingRecipeNumber, Recipes};
use crate::cdsl::settings::SettingPredicateNumber;
use crate::cdsl::types::ValueType;
use std::rc::Rc;
use std::string::ToString;
/// Encoding for a concrete instruction.
///
@@ -61,19 +62,25 @@ pub(crate) struct EncodingBuilder {
}
impl EncodingBuilder {
pub fn new(inst: InstSpec, recipe: EncodingRecipeNumber, encbits: u16) -> Self {
pub fn new(
inst: InstSpec,
recipe: EncodingRecipeNumber,
encbits: u16,
formats: &FormatRegistry,
) -> Self {
let (inst_predicate, bound_type) = match &inst {
InstSpec::Bound(inst) => {
let other_typevars = &inst.inst.polymorphic_info.as_ref().unwrap().other_typevars;
assert!(
inst.value_types.len() == other_typevars.len() + 1,
assert_eq!(
inst.value_types.len(),
other_typevars.len() + 1,
"partially bound polymorphic instruction"
);
// Add secondary type variables to the instruction predicate.
let value_types = &inst.value_types;
let mut inst_predicate = None;
let mut inst_predicate: Option<InstructionPredicate> = None;
for (typevar, value_type) in other_typevars.iter().zip(value_types.iter().skip(1)) {
let value_type = match value_type {
ValueTypeOrAny::Any => continue,
@@ -84,6 +91,24 @@ impl EncodingBuilder {
inst_predicate = Some(type_predicate.into());
}
// Add immediate value predicates
for (immediate_value, immediate_operand) in inst
.immediate_values
.iter()
.zip(inst.inst.operands_in.iter().filter(|o| o.is_immediate()))
{
let immediate_predicate = InstructionPredicate::new_is_field_equal(
formats.get(inst.inst.format),
immediate_operand.name,
immediate_value.to_string(),
);
inst_predicate = if let Some(type_predicate) = inst_predicate {
Some(type_predicate.and(immediate_predicate))
} else {
Some(immediate_predicate.into())
}
}
let ctrl_type = value_types[0]
.clone()
.expect("Controlling type shouldn't be Any");