Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/meta/src/cdsl/formats.rs
1693 views
1
use crate::cdsl::operands::OperandKind;
2
use std::fmt;
3
use std::rc::Rc;
4
5
/// An immediate field in an instruction format.
6
///
7
/// This corresponds to a single member of a variant of the `InstructionData`
8
/// data type.
9
#[derive(Debug)]
10
pub(crate) struct FormatField {
11
/// Immediate operand kind.
12
pub kind: OperandKind,
13
14
/// Member name in InstructionData variant.
15
pub member: &'static str,
16
}
17
18
/// Every instruction opcode has a corresponding instruction format which determines the number of
19
/// operands and their kinds. Instruction formats are identified structurally, i.e., the format of
20
/// an instruction is derived from the kinds of operands used in its declaration.
21
///
22
/// The instruction format stores two separate lists of operands: Immediates and values. Immediate
23
/// operands (including entity references) are represented as explicit members in the
24
/// `InstructionData` variants. The value operands are stored differently, depending on how many
25
/// there are. Beyond a certain point, instruction formats switch to an external value list for
26
/// storing value arguments. Value lists can hold an arbitrary number of values.
27
///
28
/// All instruction formats must be predefined in the meta shared/formats.rs module.
29
#[derive(Debug)]
30
pub(crate) struct InstructionFormat {
31
/// Instruction format name in CamelCase. This is used as a Rust variant name in both the
32
/// `InstructionData` and `InstructionFormat` enums.
33
pub name: &'static str,
34
35
pub num_value_operands: usize,
36
37
pub has_value_list: bool,
38
39
pub imm_fields: Vec<FormatField>,
40
41
pub num_block_operands: usize,
42
43
pub num_raw_block_operands: usize,
44
45
/// Index of the value input operand that is used to infer the controlling type variable. By
46
/// default, this is `0`, the first `value` operand. The index is relative to the values only,
47
/// ignoring immediate operands.
48
pub typevar_operand: Option<usize>,
49
}
50
51
/// A tuple serving as a key to deduplicate InstructionFormat.
52
#[derive(Hash, PartialEq, Eq)]
53
pub(crate) struct FormatStructure {
54
pub num_value_operands: usize,
55
pub has_value_list: bool,
56
pub num_block_operands: usize,
57
pub num_raw_block_operands: usize,
58
/// Tuples of (Rust field name / Rust type) for each immediate field.
59
pub imm_field_names: Vec<(&'static str, &'static str)>,
60
}
61
62
impl fmt::Display for InstructionFormat {
63
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
64
let imm_args = self
65
.imm_fields
66
.iter()
67
.map(|field| format!("{}: {}", field.member, field.kind.rust_type))
68
.collect::<Vec<_>>()
69
.join(", ");
70
fmt.write_fmt(format_args!(
71
"{}(imms=({}), vals={}, blocks={}, raw_blocks={})",
72
self.name,
73
imm_args,
74
self.num_value_operands,
75
self.num_block_operands,
76
self.num_raw_block_operands,
77
))?;
78
Ok(())
79
}
80
}
81
82
impl InstructionFormat {
83
/// Returns a tuple that uniquely identifies the structure.
84
pub fn structure(&self) -> FormatStructure {
85
FormatStructure {
86
num_value_operands: self.num_value_operands,
87
has_value_list: self.has_value_list,
88
num_block_operands: self.num_block_operands,
89
num_raw_block_operands: self.num_raw_block_operands,
90
imm_field_names: self
91
.imm_fields
92
.iter()
93
.map(|field| (field.kind.rust_field_name, field.kind.rust_type))
94
.collect::<Vec<_>>(),
95
}
96
}
97
}
98
99
pub(crate) struct InstructionFormatBuilder(InstructionFormat);
100
101
impl InstructionFormatBuilder {
102
pub fn new(name: &'static str) -> Self {
103
Self(InstructionFormat {
104
name,
105
num_value_operands: 0,
106
has_value_list: false,
107
num_block_operands: 0,
108
num_raw_block_operands: 0,
109
imm_fields: Vec::new(),
110
typevar_operand: None,
111
})
112
}
113
114
pub fn value(mut self) -> Self {
115
self.0.num_value_operands += 1;
116
self
117
}
118
119
pub fn varargs(mut self) -> Self {
120
self.0.has_value_list = true;
121
self
122
}
123
124
pub fn block(mut self) -> Self {
125
self.0.num_block_operands += 1;
126
self
127
}
128
129
pub fn raw_block(mut self) -> Self {
130
self.0.num_raw_block_operands += 1;
131
self
132
}
133
134
pub fn imm(mut self, operand_kind: &OperandKind) -> Self {
135
let field = FormatField {
136
kind: operand_kind.clone(),
137
member: operand_kind.rust_field_name,
138
};
139
self.0.imm_fields.push(field);
140
self
141
}
142
143
pub fn typevar_operand(mut self, operand_index: usize) -> Self {
144
assert!(self.0.typevar_operand.is_none());
145
assert!(operand_index < self.0.num_value_operands);
146
self.0.typevar_operand = Some(operand_index);
147
self
148
}
149
150
pub fn build(mut self) -> Rc<InstructionFormat> {
151
if self.0.typevar_operand.is_none() && self.0.num_value_operands > 0 {
152
// Default to the first value operand, if there's one.
153
self.0.typevar_operand = Some(0);
154
};
155
156
Rc::new(self.0)
157
}
158
}
159
160