Merge pull request #3497 from bjorn3/misc_meta_simplifications

Misc meta crate cleanups
This commit is contained in:
Chris Fallin
2021-11-01 11:24:44 -07:00
committed by GitHub
13 changed files with 148 additions and 132 deletions

View File

@@ -84,32 +84,26 @@ impl InstructionFormat {
} }
} }
pub(crate) struct InstructionFormatBuilder { pub(crate) struct InstructionFormatBuilder(InstructionFormat);
name: &'static str,
num_value_operands: usize,
has_value_list: bool,
imm_fields: Vec<FormatField>,
typevar_operand: Option<usize>,
}
impl InstructionFormatBuilder { impl InstructionFormatBuilder {
pub fn new(name: &'static str) -> Self { pub fn new(name: &'static str) -> Self {
Self { Self(InstructionFormat {
name, name,
num_value_operands: 0, num_value_operands: 0,
has_value_list: false, has_value_list: false,
imm_fields: Vec::new(), imm_fields: Vec::new(),
typevar_operand: None, typevar_operand: None,
} })
} }
pub fn value(mut self) -> Self { pub fn value(mut self) -> Self {
self.num_value_operands += 1; self.0.num_value_operands += 1;
self self
} }
pub fn varargs(mut self) -> Self { pub fn varargs(mut self) -> Self {
self.has_value_list = true; self.0.has_value_list = true;
self self
} }
@@ -118,42 +112,23 @@ impl InstructionFormatBuilder {
kind: operand_kind.clone(), kind: operand_kind.clone(),
member: operand_kind.rust_field_name, member: operand_kind.rust_field_name,
}; };
self.imm_fields.push(field); self.0.imm_fields.push(field);
self
}
pub fn imm_with_name(mut self, member: &'static str, operand_kind: &OperandKind) -> Self {
let field = FormatField {
kind: operand_kind.clone(),
member,
};
self.imm_fields.push(field);
self self
} }
pub fn typevar_operand(mut self, operand_index: usize) -> Self { pub fn typevar_operand(mut self, operand_index: usize) -> Self {
assert!(self.typevar_operand.is_none()); assert!(self.0.typevar_operand.is_none());
assert!(self.has_value_list || operand_index < self.num_value_operands); assert!(operand_index < self.0.num_value_operands);
self.typevar_operand = Some(operand_index); self.0.typevar_operand = Some(operand_index);
self self
} }
pub fn build(self) -> Rc<InstructionFormat> { pub fn build(mut self) -> Rc<InstructionFormat> {
let typevar_operand = if self.typevar_operand.is_some() { if self.0.typevar_operand.is_none() && self.0.num_value_operands > 0 {
self.typevar_operand
} else if self.has_value_list || self.num_value_operands > 0 {
// Default to the first value operand, if there's one. // Default to the first value operand, if there's one.
Some(0) self.0.typevar_operand = Some(0);
} else {
None
}; };
Rc::new(InstructionFormat { Rc::new(self.0)
name: self.name,
num_value_operands: self.num_value_operands,
has_value_list: self.has_value_list,
imm_fields: self.imm_fields,
typevar_operand,
})
} }
} }

View File

@@ -43,7 +43,7 @@ pub(crate) struct InstructionContent {
/// Output operands. The output operands must be SSA values or `variable_args`. /// Output operands. The output operands must be SSA values or `variable_args`.
pub operands_out: Vec<Operand>, pub operands_out: Vec<Operand>,
/// Instruction format, automatically derived from the input operands. /// Instruction format.
pub format: Rc<InstructionFormat>, pub format: Rc<InstructionFormat>,
/// One of the input or output operands is a free type variable. None if the instruction is not /// One of the input or output operands is a free type variable. None if the instruction is not

View File

@@ -39,12 +39,12 @@ impl Operand {
self self
} }
pub fn doc(&self) -> Option<&str> { pub fn doc(&self) -> &str {
if let Some(doc) = &self.doc { if let Some(doc) = &self.doc {
return Some(doc); return doc;
} }
match &self.kind.fields { match &self.kind.fields {
OperandKindFields::TypeVar(tvar) => Some(&tvar.doc), OperandKindFields::TypeVar(tvar) => &tvar.doc,
_ => self.kind.doc(), _ => self.kind.doc(),
} }
} }
@@ -130,40 +130,39 @@ impl OperandKind {
rust_field_name: &'static str, rust_field_name: &'static str,
rust_type: &'static str, rust_type: &'static str,
fields: OperandKindFields, fields: OperandKindFields,
doc: &'static str,
) -> Self { ) -> Self {
Self { Self {
rust_field_name, rust_field_name,
rust_type, rust_type,
fields, fields,
doc: None, doc: Some(doc),
} }
} }
pub fn with_doc(mut self, doc: &'static str) -> Self { fn doc(&self) -> &str {
assert!(self.doc.is_none());
self.doc = Some(doc);
self
}
fn doc(&self) -> Option<&str> {
if let Some(doc) = &self.doc { if let Some(doc) = &self.doc {
return Some(doc); return doc;
} }
match &self.fields { match &self.fields {
OperandKindFields::TypeVar(type_var) => Some(&type_var.doc), OperandKindFields::TypeVar(type_var) => &type_var.doc,
// The only method to create an OperandKind with `doc` set to None is using a TypeVar,
// so all other options are unreachable here.
OperandKindFields::ImmEnum(_) OperandKindFields::ImmEnum(_)
| OperandKindFields::ImmValue | OperandKindFields::ImmValue
| OperandKindFields::EntityRef | OperandKindFields::EntityRef
| OperandKindFields::VariableArgs => None, | OperandKindFields::VariableArgs => unreachable!(),
} }
} }
} }
impl Into<OperandKind> for &TypeVar { impl Into<OperandKind> for &TypeVar {
fn into(self) -> OperandKind { fn into(self) -> OperandKind {
OperandKind::new( OperandKind {
"value", rust_field_name: "value",
"ir::Value", rust_type: "ir::Value",
OperandKindFields::TypeVar(self.into()), fields: OperandKindFields::TypeVar(self.into()),
) doc: None,
}
} }
} }
impl Into<OperandKind> for &OperandKind { impl Into<OperandKind> for &OperandKind {

View File

@@ -6,7 +6,7 @@ use crate::shared::types as shared_types;
use cranelift_codegen_shared::constants; use cranelift_codegen_shared::constants;
// Rust name prefix used for the `rust_name` method. // Rust name prefix used for the `rust_name` method.
static _RUST_NAME_PREFIX: &str = "ir::types::"; static RUST_NAME_PREFIX: &str = "ir::types::";
// ValueType variants (i8, i32, ...) are provided in `shared::types.rs`. // ValueType variants (i8, i32, ...) are provided in `shared::types.rs`.
@@ -82,14 +82,7 @@ impl ValueType {
/// Return the name of this type for generated Rust source files. /// Return the name of this type for generated Rust source files.
pub fn rust_name(&self) -> String { pub fn rust_name(&self) -> String {
format!("{}{}", _RUST_NAME_PREFIX, self.to_string().to_uppercase()) format!("{}{}", RUST_NAME_PREFIX, self.to_string().to_uppercase())
}
/// Return true iff:
/// 1. self and other have equal number of lanes
/// 2. each lane in self has at least as many bits as a lane in other
pub fn _wider_or_equal(&self, rhs: &ValueType) -> bool {
(self.lane_count() == rhs.lane_count()) && (self.lane_bits() >= rhs.lane_bits())
} }
/// Return the total number of bits of an instance of this type. /// Return the total number of bits of an instance of this type.

View File

@@ -75,14 +75,12 @@ fn gen_instruction_data(formats: &[&InstructionFormat], fmt: &mut Formatter) {
fmtln!(fmt, "{} {{", format.name); fmtln!(fmt, "{} {{", format.name);
fmt.indent(|fmt| { fmt.indent(|fmt| {
fmt.line("opcode: Opcode,"); fmt.line("opcode: Opcode,");
if format.typevar_operand.is_some() { if format.has_value_list {
if format.has_value_list { fmt.line("args: ValueList,");
fmt.line("args: ValueList,"); } else if format.num_value_operands == 1 {
} else if format.num_value_operands == 1 { fmt.line("arg: Value,");
fmt.line("arg: Value,"); } else if format.num_value_operands > 0 {
} else { fmtln!(fmt, "args: [Value; {}],", format.num_value_operands);
fmtln!(fmt, "args: [Value; {}],", format.num_value_operands);
}
} }
for field in &format.imm_fields { for field in &format.imm_fields {
fmtln!(fmt, "{}: {},", field.member, field.kind.rust_type); fmtln!(fmt, "{}: {},", field.member, field.kind.rust_type);
@@ -287,17 +285,17 @@ fn gen_instruction_data_impl(formats: &[&InstructionFormat], fmt: &mut Formatter
let name = format!("&Self::{}", format.name); let name = format!("&Self::{}", format.name);
let mut members = vec!["opcode"]; let mut members = vec!["opcode"];
let args_eq = if format.typevar_operand.is_none() { let args_eq = if format.has_value_list {
None
} else if format.has_value_list {
members.push("args"); members.push("args");
Some("args1.as_slice(pool) == args2.as_slice(pool)") Some("args1.as_slice(pool) == args2.as_slice(pool)")
} else if format.num_value_operands == 1 { } else if format.num_value_operands == 1 {
members.push("arg"); members.push("arg");
Some("arg1 == arg2") Some("arg1 == arg2")
} else { } else if format.num_value_operands > 0 {
members.push("args"); members.push("args");
Some("args1 == args2") Some("args1 == args2")
} else {
None
}; };
for field in &format.imm_fields { for field in &format.imm_fields {
@@ -339,17 +337,17 @@ fn gen_instruction_data_impl(formats: &[&InstructionFormat], fmt: &mut Formatter
let name = format!("Self::{}", format.name); let name = format!("Self::{}", format.name);
let mut members = vec!["opcode"]; let mut members = vec!["opcode"];
let args = if format.typevar_operand.is_none() { let args = if format.has_value_list {
"&()"
} else if format.has_value_list {
members.push("ref args"); members.push("ref args");
"args.as_slice(pool)" "args.as_slice(pool)"
} else if format.num_value_operands == 1 { } else if format.num_value_operands == 1 {
members.push("ref arg"); members.push("ref arg");
"arg" "arg"
} else { } else if format.num_value_operands > 0{
members.push("ref args"); members.push("ref args");
"args" "args"
} else {
"&()"
}; };
for field in &format.imm_fields { for field in &format.imm_fields {
@@ -948,21 +946,11 @@ fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Fo
op.kind.rust_type.to_string() op.kind.rust_type.to_string()
}; };
args.push(format!("{}: {}", op.name, t)); args.push(format!("{}: {}", op.name, t));
args_doc.push(format!( args_doc.push(format!("- {}: {}", op.name, op.doc()));
"- {}: {}",
op.name,
op.doc()
.expect("every instruction's input operand must be documented")
));
} }
for op in &inst.operands_out { for op in &inst.operands_out {
rets_doc.push(format!( rets_doc.push(format!("- {}: {}", op.name, op.doc()));
"- {}: {}",
op.name,
op.doc()
.expect("every instruction's output operand must be documented")
));
} }
let rtype = match inst.value_results.len() { let rtype = match inst.value_results.len() {

View File

@@ -2,7 +2,12 @@ use crate::cdsl::operands::{OperandKind, OperandKindFields};
/// Small helper to initialize an OperandBuilder with the right kind, for a given name and doc. /// Small helper to initialize an OperandBuilder with the right kind, for a given name and doc.
fn new(format_field_name: &'static str, rust_type: &'static str, doc: &'static str) -> OperandKind { fn new(format_field_name: &'static str, rust_type: &'static str, doc: &'static str) -> OperandKind {
OperandKind::new(format_field_name, rust_type, OperandKindFields::EntityRef).with_doc(doc) OperandKind::new(
format_field_name,
rust_type,
OperandKindFields::EntityRef,
doc,
)
} }
pub(crate) struct EntityRefs { pub(crate) struct EntityRefs {
@@ -59,7 +64,10 @@ impl EntityRefs {
table: new("table", "ir::Table", "A table."), table: new("table", "ir::Table", "A table."),
varargs: OperandKind::new("", "&[Value]", OperandKindFields::VariableArgs).with_doc( varargs: OperandKind::new(
"",
"&[Value]",
OperandKindFields::VariableArgs,
r#" r#"
A variable size list of `value` operands. A variable size list of `value` operands.

View File

@@ -101,7 +101,7 @@ impl Formats {
shuffle: Builder::new("Shuffle") shuffle: Builder::new("Shuffle")
.value() .value()
.value() .value()
.imm_with_name("mask", &imm.uimm128) .imm(&imm.uimm128)
.build(), .build(),
int_compare: Builder::new("IntCompare") int_compare: Builder::new("IntCompare")

View File

@@ -73,40 +73,76 @@ pub(crate) struct Immediates {
pub atomic_rmw_op: OperandKind, pub atomic_rmw_op: OperandKind,
} }
fn new_imm(format_field_name: &'static str, rust_type: &'static str) -> OperandKind { fn new_imm(
OperandKind::new(format_field_name, rust_type, OperandKindFields::ImmValue) format_field_name: &'static str,
rust_type: &'static str,
doc: &'static str,
) -> OperandKind {
OperandKind::new(
format_field_name,
rust_type,
OperandKindFields::ImmValue,
doc,
)
} }
fn new_enum( fn new_enum(
format_field_name: &'static str, format_field_name: &'static str,
rust_type: &'static str, rust_type: &'static str,
values: EnumValues, values: EnumValues,
doc: &'static str,
) -> OperandKind { ) -> OperandKind {
OperandKind::new( OperandKind::new(
format_field_name, format_field_name,
rust_type, rust_type,
OperandKindFields::ImmEnum(values), OperandKindFields::ImmEnum(values),
doc,
) )
} }
impl Immediates { impl Immediates {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
imm64: new_imm("imm", "ir::immediates::Imm64").with_doc("A 64-bit immediate integer."), imm64: new_imm(
uimm8: new_imm("imm", "ir::immediates::Uimm8") "imm",
.with_doc("An 8-bit immediate unsigned integer."), "ir::immediates::Imm64",
uimm32: new_imm("imm", "ir::immediates::Uimm32") "A 64-bit immediate integer.",
.with_doc("A 32-bit immediate unsigned integer."), ),
uimm128: new_imm("imm", "ir::Immediate") uimm8: new_imm(
.with_doc("A 128-bit immediate unsigned integer."), "imm",
pool_constant: new_imm("constant_handle", "ir::Constant") "ir::immediates::Uimm8",
.with_doc("A constant stored in the constant pool."), "An 8-bit immediate unsigned integer.",
offset32: new_imm("offset", "ir::immediates::Offset32") ),
.with_doc("A 32-bit immediate signed offset."), uimm32: new_imm(
ieee32: new_imm("imm", "ir::immediates::Ieee32") "imm",
.with_doc("A 32-bit immediate floating point number."), "ir::immediates::Uimm32",
ieee64: new_imm("imm", "ir::immediates::Ieee64") "A 32-bit immediate unsigned integer.",
.with_doc("A 64-bit immediate floating point number."), ),
boolean: new_imm("imm", "bool").with_doc("An immediate boolean."), uimm128: new_imm(
"imm",
"ir::Immediate",
"A 128-bit immediate unsigned integer.",
),
pool_constant: new_imm(
"constant_handle",
"ir::Constant",
"A constant stored in the constant pool.",
),
offset32: new_imm(
"offset",
"ir::immediates::Offset32",
"A 32-bit immediate signed offset.",
),
ieee32: new_imm(
"imm",
"ir::immediates::Ieee32",
"A 32-bit immediate floating point number.",
),
ieee64: new_imm(
"imm",
"ir::immediates::Ieee64",
"A 64-bit immediate floating point number.",
),
boolean: new_imm("imm", "bool", "An immediate boolean."),
intcc: { intcc: {
let mut intcc_values = HashMap::new(); let mut intcc_values = HashMap::new();
intcc_values.insert("eq", "Equal"); intcc_values.insert("eq", "Equal");
@@ -121,8 +157,12 @@ impl Immediates {
intcc_values.insert("ult", "UnsignedLessThan"); intcc_values.insert("ult", "UnsignedLessThan");
intcc_values.insert("of", "Overflow"); intcc_values.insert("of", "Overflow");
intcc_values.insert("nof", "NotOverflow"); intcc_values.insert("nof", "NotOverflow");
new_enum("cond", "ir::condcodes::IntCC", intcc_values) new_enum(
.with_doc("An integer comparison condition code.") "cond",
"ir::condcodes::IntCC",
intcc_values,
"An integer comparison condition code.",
)
}, },
floatcc: { floatcc: {
@@ -141,18 +181,27 @@ impl Immediates {
floatcc_values.insert("ule", "UnorderedOrLessThanOrEqual"); floatcc_values.insert("ule", "UnorderedOrLessThanOrEqual");
floatcc_values.insert("ugt", "UnorderedOrGreaterThan"); floatcc_values.insert("ugt", "UnorderedOrGreaterThan");
floatcc_values.insert("uge", "UnorderedOrGreaterThanOrEqual"); floatcc_values.insert("uge", "UnorderedOrGreaterThanOrEqual");
new_enum("cond", "ir::condcodes::FloatCC", floatcc_values) new_enum(
.with_doc("A floating point comparison condition code") "cond",
"ir::condcodes::FloatCC",
floatcc_values,
"A floating point comparison condition code",
)
}, },
memflags: new_imm("flags", "ir::MemFlags").with_doc("Memory operation flags"), memflags: new_imm("flags", "ir::MemFlags", "Memory operation flags"),
trapcode: { trapcode: {
let mut trapcode_values = HashMap::new(); let mut trapcode_values = HashMap::new();
trapcode_values.insert("stk_ovf", "StackOverflow"); trapcode_values.insert("stk_ovf", "StackOverflow");
trapcode_values.insert("heap_oob", "HeapOutOfBounds"); trapcode_values.insert("heap_oob", "HeapOutOfBounds");
trapcode_values.insert("int_ovf", "IntegerOverflow"); trapcode_values.insert("int_ovf", "IntegerOverflow");
trapcode_values.insert("int_divz", "IntegerDivisionByZero"); trapcode_values.insert("int_divz", "IntegerDivisionByZero");
new_enum("code", "ir::TrapCode", trapcode_values).with_doc("A trap reason code.") new_enum(
"code",
"ir::TrapCode",
trapcode_values,
"A trap reason code.",
)
}, },
atomic_rmw_op: { atomic_rmw_op: {
let mut atomic_rmw_op_values = HashMap::new(); let mut atomic_rmw_op_values = HashMap::new();
@@ -167,8 +216,12 @@ impl Immediates {
atomic_rmw_op_values.insert("umax", "Umax"); atomic_rmw_op_values.insert("umax", "Umax");
atomic_rmw_op_values.insert("smin", "Smin"); atomic_rmw_op_values.insert("smin", "Smin");
atomic_rmw_op_values.insert("smax", "Smax"); atomic_rmw_op_values.insert("smax", "Smax");
new_enum("op", "ir::AtomicRmwOp", atomic_rmw_op_values) new_enum(
.with_doc("Atomic Read-Modify-Write Ops") "op",
"ir::AtomicRmwOp",
atomic_rmw_op_values,
"Atomic Read-Modify-Write Ops",
)
}, },
} }
} }

View File

@@ -319,7 +319,7 @@ impl InstructionData {
// included in the `InstructionData` for memory-size reasons. This case, returning // included in the `InstructionData` for memory-size reasons. This case, returning
// `None`, is left here to alert users of this method that they should retrieve the // `None`, is left here to alert users of this method that they should retrieve the
// value using the `DataFlowGraph`. // value using the `DataFlowGraph`.
&InstructionData::Shuffle { mask: _, .. } => None, &InstructionData::Shuffle { imm: _, .. } => None,
_ => None, _ => None,
} }
} }

View File

@@ -1264,8 +1264,8 @@ impl<'func, I: VCodeInst> LowerCtx for Lower<'func, I> {
fn get_immediate(&self, ir_inst: Inst) -> Option<DataValue> { fn get_immediate(&self, ir_inst: Inst) -> Option<DataValue> {
let inst_data = self.data(ir_inst); let inst_data = self.data(ir_inst);
match inst_data { match inst_data {
InstructionData::Shuffle { mask, .. } => { InstructionData::Shuffle { imm, .. } => {
let buffer = self.f.dfg.immediates.get(mask.clone()).unwrap().as_slice(); let buffer = self.f.dfg.immediates.get(imm.clone()).unwrap().as_slice();
let value = DataValue::V128(buffer.try_into().expect("a 16-byte data buffer")); let value = DataValue::V128(buffer.try_into().expect("a 16-byte data buffer"));
Some(value) Some(value)
} }

View File

@@ -395,8 +395,8 @@ pub fn write_operands(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt
} }
NullAry { .. } => write!(w, " "), NullAry { .. } => write!(w, " "),
TernaryImm8 { imm, args, .. } => write!(w, " {}, {}, {}", args[0], args[1], imm), TernaryImm8 { imm, args, .. } => write!(w, " {}, {}, {}", args[0], args[1], imm),
Shuffle { mask, args, .. } => { Shuffle { imm, args, .. } => {
let data = dfg.immediates.get(mask).expect( let data = dfg.immediates.get(imm).expect(
"Expected the shuffle mask to already be inserted into the immediates table", "Expected the shuffle mask to already be inserted into the immediates table",
); );
write!(w, " {}, {}, {}", args[0], args[1], data) write!(w, " {}, {}, {}", args[0], args[1], data)

View File

@@ -76,12 +76,12 @@ where
.as_slice(); .as_slice();
DataValue::V128(buffer.try_into().expect("a 16-byte data buffer")) DataValue::V128(buffer.try_into().expect("a 16-byte data buffer"))
} }
InstructionData::Shuffle { mask, .. } => { InstructionData::Shuffle { imm, .. } => {
let mask = state let mask = state
.get_current_function() .get_current_function()
.dfg .dfg
.immediates .immediates
.get(mask) .get(imm)
.unwrap() .unwrap()
.as_slice(); .as_slice();
DataValue::V128(mask.try_into().expect("a 16-byte vector mask")) DataValue::V128(mask.try_into().expect("a 16-byte vector mask"))

View File

@@ -2694,10 +2694,10 @@ impl<'a> Parser<'a> {
let b = self.match_value("expected SSA value second operand")?; let b = self.match_value("expected SSA value second operand")?;
self.match_token(Token::Comma, "expected ',' between operands")?; self.match_token(Token::Comma, "expected ',' between operands")?;
let uimm128 = self.match_uimm128(I8X16)?; let uimm128 = self.match_uimm128(I8X16)?;
let mask = ctx.function.dfg.immediates.push(uimm128); let imm = ctx.function.dfg.immediates.push(uimm128);
InstructionData::Shuffle { InstructionData::Shuffle {
opcode, opcode,
mask, imm,
args: [a, b], args: [a, b],
} }
} }