Simplify binding of IntCC::Equals to SIMD icmp; fixes #1150

This commit is contained in:
Andrew Brown
2019-10-23 14:52:44 -07:00
parent e045a6df27
commit f37d1c7ecc
3 changed files with 21 additions and 48 deletions

View File

@@ -93,7 +93,10 @@ impl EncodingBuilder {
{ {
let immediate_predicate = InstructionPredicate::new_is_field_equal( let immediate_predicate = InstructionPredicate::new_is_field_equal(
&inst.inst.format, &inst.inst.format,
immediate_operand.name, immediate_operand
.kind
.default_member
.expect("Immediates must always have a default member name set."),
immediate_value.to_string(), immediate_value.to_string(),
); );
inst_predicate = if let Some(type_predicate) = inst_predicate { inst_predicate = if let Some(type_predicate) = inst_predicate {

View File

@@ -443,17 +443,15 @@ impl From<Immediate> for BindParameter {
} }
#[derive(Clone)] #[derive(Clone)]
#[allow(dead_code)] // TODO(#1150): remove this once we use it in legalization patterns.
pub enum Immediate { pub enum Immediate {
UInt8(u8), // When needed, this enum should be expanded to include other immediate types (e.g. u8, u128).
UInt128(u128), IntCC(IntCC),
} }
impl Display for Immediate { impl Display for Immediate {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
match self { match self {
Immediate::UInt8(x) => write!(f, "{}", x), Immediate::IntCC(x) => write!(f, "IntCC::{:?}", x),
Immediate::UInt128(x) => write!(f, "{}", x),
} }
} }
} }
@@ -790,9 +788,6 @@ pub enum FormatPredicateKind {
/// Is the referenced data object colocated? /// Is the referenced data object colocated?
IsColocatedData, IsColocatedData,
/// Does the operation have a specific condition code?
HasConditionCode(IntCC),
} }
#[derive(Clone, Hash, PartialEq, Eq)] #[derive(Clone, Hash, PartialEq, Eq)]
@@ -879,10 +874,6 @@ impl FormatPredicateNode {
FormatPredicateKind::IsColocatedData => { FormatPredicateKind::IsColocatedData => {
format!("predicates::is_colocated_data({}, func)", self.member_name) format!("predicates::is_colocated_data({}, func)", self.member_name)
} }
FormatPredicateKind::HasConditionCode(code) => format!(
"predicates::is_equal({}, IntCC::{:?})",
self.member_name, code
),
} }
} }
} }
@@ -1165,18 +1156,6 @@ impl InstructionPredicate {
)) ))
} }
pub fn new_has_condition_code(
format: &InstructionFormat,
condition_code: IntCC,
field_name: &'static str,
) -> InstructionPredicateNode {
InstructionPredicateNode::FormatPredicate(FormatPredicateNode::new(
format,
field_name,
FormatPredicateKind::HasConditionCode(condition_code),
))
}
pub fn and(mut self, new_node: InstructionPredicateNode) -> Self { pub fn and(mut self, new_node: InstructionPredicateNode) -> Self {
let node = self.node; let node = self.node;
let mut and_nodes = match node { let mut and_nodes = match node {
@@ -1318,7 +1297,7 @@ mod test {
use crate::shared::types::Int::{I32, I64}; use crate::shared::types::Int::{I32, I64};
fn field_to_operand(index: usize, field: OperandKindFields) -> Operand { fn field_to_operand(index: usize, field: OperandKindFields) -> Operand {
// pretend the index string is &'static // Pretend the index string is &'static.
let name = Box::leak(index.to_string().into_boxed_str()); let name = Box::leak(index.to_string().into_boxed_str());
let kind = OperandKindBuilder::new(name, field).build(); let kind = OperandKindBuilder::new(name, field).build();
let operand = OperandBuilder::new(name, kind).build(); let operand = OperandBuilder::new(name, kind).build();
@@ -1337,7 +1316,7 @@ mod test {
inputs: Vec<OperandKindFields>, inputs: Vec<OperandKindFields>,
outputs: Vec<OperandKindFields>, outputs: Vec<OperandKindFields>,
) -> Instruction { ) -> Instruction {
// setup a format from the input operands // Setup a format from the input operands.
let mut format = InstructionFormatBuilder::new("fake"); let mut format = InstructionFormatBuilder::new("fake");
for (i, f) in inputs.iter().enumerate() { for (i, f) in inputs.iter().enumerate() {
match f { match f {
@@ -1350,7 +1329,7 @@ mod test {
} }
let format = format.build(); let format = format.build();
// create the fake instruction // Create the fake instruction.
InstructionBuilder::new("fake", "A fake instruction for testing.", &format) InstructionBuilder::new("fake", "A fake instruction for testing.", &format)
.operands_in(field_to_operands(inputs).iter().collect()) .operands_in(field_to_operands(inputs).iter().collect())
.operands_out(field_to_operands(outputs).iter().collect()) .operands_out(field_to_operands(outputs).iter().collect())
@@ -1368,7 +1347,7 @@ mod test {
#[test] #[test]
fn ensure_bound_instructions_can_bind_immediates() { fn ensure_bound_instructions_can_bind_immediates() {
let inst = build_fake_instruction(vec![OperandKindFields::ImmValue], vec![]); let inst = build_fake_instruction(vec![OperandKindFields::ImmValue], vec![]);
let bound_inst = inst.bind(Immediate::UInt8(42)); let bound_inst = inst.bind(Immediate::IntCC(IntCC::Equal));
assert!(bound_inst.verify_bindings().is_ok()); assert!(bound_inst.verify_bindings().is_ok());
} }
@@ -1377,7 +1356,7 @@ mod test {
fn ensure_instructions_fail_to_bind() { fn ensure_instructions_fail_to_bind() {
let inst = build_fake_instruction(vec![], vec![]); let inst = build_fake_instruction(vec![], vec![]);
inst.bind(BindParameter::Lane(LaneType::IntType(I32))); inst.bind(BindParameter::Lane(LaneType::IntType(I32)));
// trying to bind to an instruction with no inputs should fail // Trying to bind to an instruction with no inputs should fail.
} }
#[test] #[test]
@@ -1394,8 +1373,9 @@ mod test {
#[should_panic] #[should_panic]
fn ensure_instructions_fail_to_bind_too_many_immediates() { fn ensure_instructions_fail_to_bind_too_many_immediates() {
let inst = build_fake_instruction(vec![OperandKindFields::ImmValue], vec![]); let inst = build_fake_instruction(vec![OperandKindFields::ImmValue], vec![]);
inst.bind(BindParameter::Immediate(Immediate::UInt8(0))) inst.bind(BindParameter::Immediate(Immediate::IntCC(IntCC::Equal)))
.bind(BindParameter::Immediate(Immediate::UInt8(1))); .bind(BindParameter::Immediate(Immediate::IntCC(IntCC::Equal)));
// trying to bind too many immediates to an instruction should fail // Trying to bind too many immediates to an instruction should fail; note that the immediate
// values are nonsensical but irrelevant to the purpose of this test.
} }
} }

View File

@@ -5,7 +5,7 @@ use std::collections::HashMap;
use crate::cdsl::encodings::{Encoding, EncodingBuilder}; use crate::cdsl::encodings::{Encoding, EncodingBuilder};
use crate::cdsl::instructions::{ use crate::cdsl::instructions::{
vector, Bindable, InstSpec, Instruction, InstructionGroup, InstructionPredicate, vector, Bindable, Immediate, InstSpec, Instruction, InstructionGroup, InstructionPredicate,
InstructionPredicateNode, InstructionPredicateRegistry, InstructionPredicateNode, InstructionPredicateRegistry,
}; };
use crate::cdsl::recipes::{EncodingRecipe, EncodingRecipeNumber, Recipes}; use crate::cdsl::recipes::{EncodingRecipe, EncodingRecipeNumber, Recipes};
@@ -2038,21 +2038,11 @@ pub(crate) fn define(
_ => panic!("invalid size for SIMD icmp"), _ => panic!("invalid size for SIMD icmp"),
}; };
let instruction = icmp.bind(vector(ty, sse_vector_size)); let instruction = icmp
let has_eq_condition_code = InstructionPredicate::new_has_condition_code( .bind(Immediate::IntCC(IntCC::Equal))
&*formats.int_compare, .bind(vector(ty, sse_vector_size));
IntCC::Equal,
"cond",
);
let template = rec_icscc_fpr.nonrex().opcodes(opcodes); let template = rec_icscc_fpr.nonrex().opcodes(opcodes);
e.enc_32_64_func(instruction, template, |builder| { e.enc_32_64_maybe_isap(instruction, template, isa_predicate);
let builder = builder.inst_predicate(has_eq_condition_code);
if let Some(p) = isa_predicate {
builder.isa_predicate(p)
} else {
builder
}
});
} }
// Reference type instructions // Reference type instructions