1use core::fmt::Display;
2
3use super::{Branch, CoopMma, NonSemantic, Plane, Synchronization, Type, Value};
4use crate::{
5 AddressSpace, Arithmetic, AtomicOp, Bitwise, Id, InstructionModes, Memory, Metadata,
6 OperationArgs, OperationReflect, Operator, Scope, TensorIndexingOps, TmaOps,
7 comparison::Comparison, marker::Marker,
8};
9use crate::{BarrierOps, SourceLoc, TypeHash};
10use alloc::{
11 format,
12 string::{String, ToString},
13 vec::Vec,
14};
15use derive_more::derive::From;
16use itertools::Itertools;
17
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26#[derive(Debug, Clone, TypeHash, PartialEq, Eq, Hash, From, OperationReflect)]
27#[operation(opcode_name = OpCode)]
28#[allow(dead_code, missing_docs, clippy::large_enum_variant)] pub enum Operation {
30 #[operation(pure)]
31 #[from(ignore)]
32 Copy(#[args(allow_ptr)] Value),
33 ConstructAggregate(#[args(allow_ptr)] Vec<Value>),
36 ExtractAggregateField(AggregateExtractOperands),
39 DeclareVariable {
40 #[args(skip)]
41 value_ty: Type,
42 #[args(skip)]
43 addr_space: AddressSpace,
44 #[args(skip)]
45 alignment: usize,
46 },
47 #[operation(nested)]
48 Memory(Memory),
49 #[operation(nested)]
50 Arithmetic(Arithmetic),
51 #[operation(nested)]
52 Comparison(Comparison),
53 #[operation(nested)]
54 Bitwise(Bitwise),
55 #[operation(nested)]
56 Operator(Operator),
57 #[operation(nested)]
58 Atomic(AtomicOp),
59 #[operation(nested)]
60 Metadata(Metadata),
61 #[operation(nested)]
62 Branch(Branch),
63 #[operation(nested)]
64 Synchronization(Synchronization),
65 #[from(ignore)]
73 WorkgroupUniformLoad(#[args(allow_ptr, ptr_read)] Value),
74 #[operation(nested)]
75 Plane(Plane),
76 #[operation(nested)]
77 CoopMma(CoopMma),
78 #[operation(nested)]
79 Barrier(BarrierOps),
80 #[operation(nested)]
81 Tma(TmaOps),
82 #[operation(nested)]
83 TensorIndexing(TensorIndexingOps),
84 #[operation(nested)]
86 NonSemantic(NonSemantic),
87 #[operation(nested)]
89 Marker(Marker),
90}
91
92#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
94#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeHash)]
95pub struct Instruction {
96 pub out: Option<Value>,
97 pub source_loc: Option<SourceLoc>,
98 pub modes: InstructionModes,
99 pub operation: Operation,
100}
101
102impl Instruction {
103 pub fn new(operation: impl Into<Operation>, out: Value) -> Self {
104 Instruction {
105 out: Some(out),
106 operation: operation.into(),
107 source_loc: None,
108 modes: Default::default(),
109 }
110 }
111
112 pub fn no_out(operation: impl Into<Operation>) -> Self {
113 Instruction {
114 out: None,
115 operation: operation.into(),
116 source_loc: None,
117 modes: Default::default(),
118 }
119 }
120
121 #[track_caller]
122 pub fn out(&self) -> Value {
123 self.out.unwrap()
124 }
125
126 #[track_caller]
127 pub fn ty(&self) -> Type {
128 self.out().ty
129 }
130}
131
132impl Display for Instruction {
133 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
134 match &self.operation {
135 Operation::Operator(Operator::Cast(op)) => {
136 write!(
137 f,
138 "{} = cast<{}>({}) : ({}) -> ({})",
139 self.out(),
140 self.ty(),
141 op.input,
142 op.input.ty,
143 self.out().ty,
144 )
145 }
146 Operation::Operator(Operator::Reinterpret(op)) => {
147 write!(f, "{} = bitcast<{}>({})", self.out(), self.ty(), op.input)
148 }
149 _ => {
150 if let Some(out) = self.out {
151 let mut vars_str = String::new();
152 for (i, val) in self.operation.args().unwrap_or_default().iter().enumerate() {
153 if i != 0 {
154 vars_str.push_str(", ");
155 }
156 vars_str.push_str(&val.ty.to_string());
157 }
158 write!(
159 f,
160 "{out} = {} : ({}) -> ({})",
161 self.operation, vars_str, out.ty
162 )
163 } else {
164 write!(f, "{}", self.operation)
165 }
166 }
167 }
168 }
169}
170
171impl Display for Operation {
172 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
173 match self {
174 Operation::Copy(variable) => write!(f, "{variable}"),
175 Operation::ConstructAggregate(variables) => {
176 write!(f, "aggregate({})", variables.iter().join(", "))
177 }
178 Operation::ExtractAggregateField(AggregateExtractOperands { aggregate, field }) => {
179 write!(f, "extract({aggregate}, {field})")
180 }
181 Operation::DeclareVariable {
182 value_ty,
183 addr_space,
184 alignment,
185 } => {
186 write!(
187 f,
188 "declare_var<{value_ty}>({addr_space}, align: {alignment})"
189 )
190 }
191 Operation::Memory(memory) => write!(f, "{memory}"),
192 Operation::Arithmetic(arithmetic) => write!(f, "{arithmetic}"),
193 Operation::Comparison(comparison) => write!(f, "{comparison}"),
194 Operation::Bitwise(bitwise) => write!(f, "{bitwise}"),
195 Operation::Operator(operator) => write!(f, "{operator}"),
196 Operation::Atomic(atomic) => write!(f, "{atomic}"),
197 Operation::Metadata(metadata) => write!(f, "{metadata}"),
198 Operation::Branch(branch) => write!(f, "{branch}"),
199 Operation::Synchronization(synchronization) => write!(f, "{synchronization}"),
200 Operation::WorkgroupUniformLoad(val) => {
201 write!(f, "workgroup_uniform_load({val})")
202 }
203 Operation::Plane(plane) => write!(f, "{plane}"),
204 Operation::CoopMma(coop_mma) => write!(f, "{coop_mma}"),
205 Operation::NonSemantic(non_semantic) => write!(f, "{non_semantic}"),
206 Operation::Barrier(barrier_ops) => write!(f, "{barrier_ops}"),
207 Operation::Tma(tma_ops) => write!(f, "{tma_ops}"),
208 Operation::TensorIndexing(ops) => write!(f, "{ops}"),
209 Operation::Marker(marker) => write!(f, "{marker}"),
210 }
211 }
212}
213
214pub fn fmt_vararg(args: &[impl Display]) -> String {
215 if args.is_empty() {
216 "".to_string()
217 } else {
218 let str = args
219 .iter()
220 .map(|it| it.to_string())
221 .collect::<Vec<_>>()
222 .join(", ");
223 format!(", {str}")
224 }
225}
226
227#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
228#[derive(Debug, Clone, TypeHash, PartialEq, Eq, Hash, OperationArgs)]
229#[allow(missing_docs)]
230pub struct IndexOperands {
231 #[args(allow_ptr)]
232 pub list: Value,
233 pub index: Value,
234 pub unroll_factor: usize, pub checked: bool,
236}
237
238#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
239#[derive(Debug, Clone, TypeHash, PartialEq, Eq, Hash, OperationArgs)]
240#[allow(missing_docs)]
241pub struct StoreOperands {
242 #[args(allow_ptr, ptr_write)]
243 pub ptr: Value,
244 pub value: Value,
245}
246
247#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
248#[derive(Debug, Clone, TypeHash, PartialEq, Eq, Hash, OperationArgs)]
249#[allow(missing_docs)]
250pub struct BinaryOperands {
251 pub lhs: Value,
252 pub rhs: Value,
253}
254
255#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
256#[derive(Debug, Clone, TypeHash, PartialEq, Eq, Hash, OperationArgs)]
257#[allow(missing_docs)]
258pub struct AtomicBinaryOperands {
259 #[args(allow_ptr, ptr_read, ptr_write)]
260 pub ptr: Value,
261 pub value: Value,
262}
263
264#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
265#[derive(Debug, Clone, TypeHash, PartialEq, Eq, Hash, OperationArgs)]
266#[allow(missing_docs)]
267pub struct AggregateExtractOperands {
268 #[args(allow_ptr)]
269 pub aggregate: Value,
270 pub field: usize,
271}
272
273#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
275#[derive(Debug, Clone, TypeHash, PartialEq, Eq, Hash)]
276pub struct Function {
277 pub explicit_params: Vec<Value>,
279 pub scope: Scope,
282}
283
284pub type Closure = Id;
286
287impl Display for Function {
288 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
289 let params = self.explicit_params.iter().join(", ");
290 let instructions = self.scope.instructions.borrow().iter().join("\n");
291 write!(f, "|{params}| {{\n{instructions}\n}}")
292 }
293}
294
295#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
296#[derive(Debug, Clone, TypeHash, PartialEq, Eq, Hash, OperationArgs)]
297#[allow(missing_docs)]
298pub struct UnaryOperands {
299 pub input: Value,
300}
301
302impl From<Branch> for Instruction {
303 fn from(value: Branch) -> Self {
304 Instruction::no_out(value)
305 }
306}
307
308impl From<Synchronization> for Instruction {
309 fn from(value: Synchronization) -> Self {
310 Instruction::no_out(value)
311 }
312}
313
314impl From<NonSemantic> for Instruction {
315 fn from(value: NonSemantic) -> Self {
316 Instruction::no_out(value)
317 }
318}