1use crate::{
2 ConstantValue, ElemType,
3 dialect::synchronization::SyncScope,
4 prelude::*,
5 types::{AtomicType, PointerType, VectorType, scalar::*},
6};
7use pliron::{
8 alloc::vec::Vec,
9 attribute::{AttrObj, AttributeDict},
10 builtin::{attr_interfaces::TypedAttrInterface, ops::ConstantOp, types::IntegerType},
11 context::Context,
12 derive::{op_interface, type_interface},
13 opts::dce::SideEffects,
14 r#type::{TypeHandle, type_cast},
15 value::Use,
16};
17
18pub mod aliasing;
19pub mod memory_slot;
20
21#[macro_export]
22macro_rules! verify_op_succ {
23 () => {
24 fn verify(
25 _op: &dyn pliron::op::Op,
26 _ctx: &pliron::context::Context,
27 ) -> pliron::result::Result<()>
28 where
29 Self: Sized,
30 {
31 Ok(())
32 }
33 };
34}
35
36#[macro_export]
37macro_rules! verify_ty_succ {
38 () => {
39 fn verify(
40 _op: &dyn pliron::r#type::Type,
41 _ctx: &pliron::context::Context,
42 ) -> pliron::result::Result<()>
43 where
44 Self: Sized,
45 {
46 Ok(())
47 }
48 };
49}
50
51#[macro_export]
52macro_rules! verify_attr_succ {
53 () => {
54 fn verify(
55 _op: &dyn pliron::attribute::Attribute,
56 _ctx: &pliron::context::Context,
57 ) -> pliron::result::Result<()>
58 where
59 Self: Sized,
60 {
61 Ok(())
62 }
63 };
64}
65
66#[macro_export]
67macro_rules! Pure {
68 ($ty: ty) => {
69 $crate::NoSideEffects!($ty);
70 $crate::NoMemoryEffect!($ty);
71 };
72}
73
74#[op_interface]
75pub trait TriviallyUnrollable: MaterializableOp {
76 verify_op_succ!();
77}
78
79#[op_interface]
82pub trait MaterializableOp {
83 verify_op_succ!();
84 fn materialize(
85 &self,
86 ctx: &mut Context,
87 result_ty: Vec<TypeHandle>,
88 operands: Vec<Value>,
89 attributes: AttributeDict,
90 ) -> Ptr<Operation>;
91}
92
93#[macro_export]
94macro_rules! CanMaterialize {
95 ($ty: ty) => {
96 #[::pliron::derive::op_interface_impl]
97 impl $crate::interfaces::MaterializableOp for $ty {
98 fn materialize(
99 &self,
100 ctx: &mut pliron::context::Context,
101 result_ty: Vec<pliron::r#type::TypeHandle>,
102 operands: Vec<Value>,
103 attributes: pliron::attribute::AttributeDict,
104 ) -> pliron::context::Ptr<pliron::operation::Operation> {
105 use pliron::op::Op;
106 let op = pliron::operation::Operation::new(
107 ctx,
108 Self::get_concrete_op_info(),
109 result_ty,
110 operands,
111 vec![],
112 0,
113 );
114 op.deref_mut(ctx).attributes = attributes;
115 op
116 }
117 }
118 };
119}
120
121CanMaterialize!(ConstantOp);
122
123#[op_interface]
124pub trait Synchronizes: SideEffects {
125 verify_op_succ!();
126
127 fn minimum_scope(&self, ctx: &Context) -> SyncScope;
130 fn maximum_scope(&self, ctx: &Context) -> SyncScope;
133}
134
135macro_rules! synchronizes {
136 ($ty: ty, $scope: expr) => {
137 #[::pliron::derive::op_interface_impl]
138 impl crate::interfaces::Synchronizes for $ty {
139 #[allow(unused_variables)]
140 fn minimum_scope(&self, ctx: &::pliron::context::Context) -> SyncScope {
141 $scope
142 }
143 #[allow(unused_variables)]
144 fn maximum_scope(&self, ctx: &::pliron::context::Context) -> SyncScope {
145 $scope
146 }
147 }
148 #[pliron::derive::op_interface_impl]
149 impl pliron::opts::dce::SideEffects for $ty {
150 fn has_side_effects(&self, _ctx: &Context) -> bool {
151 true
152 }
153 }
154 };
155}
156pub(crate) use synchronizes;
157
158#[derive(Clone, Copy, Debug, PartialEq, Eq)]
159pub enum MemoryEffect {
160 Read(Value),
161 Write(Value),
162 ReadAll,
163 WriteAll,
164}
165
166#[op_interface]
167pub trait MemoryEffects {
168 verify_op_succ!();
169 fn memory_effects(&self, ctx: &Context) -> Vec<MemoryEffect>;
170}
171
172#[macro_export]
173macro_rules! NoMemoryEffect {
174 ($ty: ty) => {
175 #[::pliron::derive::op_interface_impl]
176 impl $crate::interfaces::MemoryEffects for $ty {
177 fn memory_effects(
178 &self,
179 _ctx: &pliron::context::Context,
180 ) -> $crate::alloc::vec::Vec<$crate::interfaces::MemoryEffect> {
181 $crate::alloc::vec![]
182 }
183 }
184 };
185}
186
187NoMemoryEffect!(ConstantOp);
188
189#[type_interface]
190pub trait AlignedType {
191 verify_ty_succ!();
192
193 fn align(&self, ctx: &Context) -> usize;
194}
195
196#[macro_export]
197macro_rules! aligned {
198 ($ty: ty, $align: expr) => {
199 #[::pliron::derive::type_interface_impl]
200 impl $crate::interfaces::AlignedType for $ty {
201 #[allow(unused_variables)]
202 fn align(&self, ctx: &::pliron::context::Context) -> usize {
203 $align
204 }
205 }
206 };
207}
208
209#[type_interface]
210pub trait SizedType: AlignedType {
211 verify_ty_succ!();
212 fn size(&self, ctx: &Context) -> usize;
213 fn size_bits(&self, ctx: &Context) -> usize {
214 self.size(ctx) * 8
215 }
216}
217
218#[macro_export]
219macro_rules! sized {
220 ($ty: ty, $size: expr) => {
221 #[::pliron::derive::type_interface_impl]
222 impl $crate::interfaces::SizedType for $ty {
223 #[allow(unused_variables)]
224 fn size(&self, ctx: &::pliron::context::Context) -> usize {
225 $size
226 }
227 }
228 };
229}
230
231#[macro_export]
232macro_rules! HasSideEffects {
233 ($ty: ty) => {
234 #[::pliron::derive::op_interface_impl]
235 impl pliron::opts::dce::SideEffects for $ty {
236 fn has_side_effects(&self, _ctx: &pliron::context::Context) -> bool {
237 true
238 }
239 }
240 };
241}
242
243#[macro_export]
244macro_rules! NoSideEffects {
245 ($ty: ty) => {
246 #[::pliron::derive::op_interface_impl]
247 impl pliron::opts::dce::SideEffects for $ty {
248 fn has_side_effects(&self, _ctx: &pliron::context::Context) -> bool {
249 false
250 }
251 }
252 };
253}
254
255#[type_interface]
256pub trait MaybeVectorizedType {
257 verify_ty_succ!();
258
259 fn vector_size(&self, ctx: &Context) -> usize;
260 fn try_vector_size(&self, ctx: &Context) -> Option<usize> {
261 Some(self.vector_size(ctx))
262 }
263}
264
265#[macro_export]
266macro_rules! scalar {
267 ($ty: ty) => {
268 #[::pliron::derive::type_interface_impl]
269 impl $crate::interfaces::MaybeVectorizedType for $ty {
270 fn vector_size(&self, _ctx: &::pliron::context::Context) -> usize {
271 1
272 }
273 }
274
275 #[::pliron::derive::type_interface_impl]
276 impl $crate::interfaces::ScalarizableType for $ty {
277 fn scalar_type(&self, ctx: &Context) -> ::pliron::r#type::TypeHandle {
278 use ::pliron::r#type::Type;
279 self.get_self_handle(ctx)
280 }
281 }
282
283 #[::pliron::derive::type_interface_impl]
284 impl $crate::interfaces::HasElementType for $ty {
285 fn element_type(&self, ctx: &Context) -> Option<::pliron::r#type::TypeHandle> {
286 use ::pliron::r#type::Type;
287 Some(self.get_self_handle(ctx))
288 }
289 }
290 };
291}
292
293#[type_interface]
294pub trait MaybePackedType {
295 verify_ty_succ!();
296
297 fn packing_factor(&self, ctx: &Context) -> usize;
298}
299
300macro_rules! not_packed {
301 ($ty: ty) => {
302 #[::pliron::derive::type_interface_impl]
303 impl crate::interfaces::MaybePackedType for $ty {
304 fn packing_factor(&self, _ctx: &::pliron::context::Context) -> usize {
305 1
306 }
307 }
308 };
309}
310pub(crate) use not_packed;
311
312#[type_interface]
313pub trait ScalarizableType {
314 verify_ty_succ!();
315 fn scalar_type(&self, ctx: &Context) -> TypeHandle;
316}
317
318#[type_interface]
319pub trait ScalarType {
320 verify_ty_succ!();
321 fn elem_type(&self, ctx: &Context) -> ElemType;
322}
323
324#[type_interface]
325pub trait IndexableType {
326 verify_ty_succ!();
327
328 fn indexed_type(&self, ctx: &Context) -> TypeHandle;
329}
330
331#[type_interface]
332pub trait HasElementType {
333 verify_ty_succ!();
334 fn element_type(&self, ctx: &Context) -> Option<TypeHandle>;
335}
336
337#[op_interface]
338pub trait SimplifyInterface {
339 verify_op_succ!();
340 fn check_fold(&self, ctx: &Context, operand_attrs: &[Option<AttrObj>]) -> Option<Value>;
341}
342
343#[op_interface]
344pub trait CanonicalizeInterface {
345 verify_op_succ!();
346 fn canonicalize(&self, ctx: &mut Context, rewriter: &mut MatchRewriter) -> Result<()>;
347}
348
349#[attr_interface]
350pub trait ConstantAttr: TypedAttrInterface {
351 verify_attr_succ!();
352 fn as_const_val(&self, ctx: &Context) -> ConstantValue;
353 fn float_as_f64(&self, _ctx: &Context) -> Option<f64> {
354 None
355 }
356}
357
358#[macro_export]
359macro_rules! try_cast_ty {
360 ($ty: expr, $ctx: expr, $interface: ty) => {
361 $crate::prelude::type_cast::<$interface>(&*$ty)
362 .ok_or_else(|| {
363 $crate::alloc::format!(
364 "Expected type {} {} to implement {}",
365 $ty.get_type_id(),
366 $ty.disp($ctx),
367 stringify!($interface)
368 )
369 })
370 .unwrap()
371 };
372}
373
374#[macro_export]
375macro_rules! try_cast_op {
376 ($op: expr, $ctx: expr, $interface: ty) => {
377 $crate::prelude::op_cast::<$interface>(&*$op)
378 .ok_or_else(|| {
379 $crate::alloc::format!(
380 "Expected op {} {} to implement {}",
381 $op.get_opid(),
382 $op.disp($ctx),
383 stringify!($interface)
384 )
385 })
386 .unwrap()
387 };
388}
389
390#[macro_export]
391macro_rules! match_ty {
392 (($handle: expr) { $($ty: ty => $body: expr,)*; _ => $default: expr }) => {
393 (|| {
394 $(if $handle.is::<$ty>() {
395 return $body;
396 })*
397 $default
398 })()
399 };
400 (($handle: expr) { $($ty: ty => $body: expr,)* }) => {
401 (|| {
402 $(if $handle.is::<$ty>() {
403 return $body;
404 })*
405 unreachable!()
406 })()
407 };
408}
409
410pub trait TypedExt: Typed {
411 fn size(&self, ctx: &Context) -> usize {
412 let ty = self.get_type(ctx).deref(ctx);
413 let sized = try_cast_ty!(ty, ctx, dyn SizedType);
414 sized.size(ctx)
415 }
416
417 fn size_bits(&self, ctx: &Context) -> usize {
418 let ty = self.get_type(ctx).deref(ctx);
419 let sized = try_cast_ty!(ty, ctx, dyn SizedType);
420 sized.size_bits(ctx)
421 }
422
423 fn unpacked_size_bits(&self, ctx: &Context) -> usize {
424 self.element_ty(ctx).scalar_ty(ctx).size_bits(ctx) / self.packing_factor(ctx)
425 }
426
427 fn align(&self, ctx: &Context) -> usize {
428 let ty = self.get_type(ctx).deref(ctx);
429 let aligned = try_cast_ty!(ty, ctx, dyn AlignedType);
430 aligned.align(ctx)
431 }
432
433 fn is_ptr(&self, ctx: &Context) -> bool {
434 let ty = self.get_type(ctx).deref(ctx);
435 ty.is::<PointerType>()
436 }
437
438 fn is_atomic(&self, ctx: &Context) -> bool {
439 let ty = self.get_type(ctx).deref(ctx);
440 ty.is::<AtomicType>()
441 }
442
443 fn is_vector(&self, ctx: &Context) -> bool {
444 let ty = self.get_type(ctx).deref(ctx);
445 ty.is::<VectorType>()
446 }
447
448 fn is_vector_of_size(&self, ctx: &Context, size: usize) -> bool {
449 let ty = self.get_type(ctx).deref(ctx);
450 ty.downcast_ref::<VectorType>()
451 .is_some_and(|it| it.vectorization == size)
452 }
453
454 fn is_immutable(&self, ctx: &Context) -> bool {
455 !self.is_ptr(ctx)
456 }
457
458 fn vector_size(&self, ctx: &Context) -> usize {
459 let ty = self.get_type(ctx).deref(ctx);
460 let maybe_vec = try_cast_ty!(ty, ctx, dyn MaybeVectorizedType);
461 maybe_vec.vector_size(ctx)
462 }
463
464 fn try_get_vector_size(&self, ctx: &Context) -> Option<usize> {
465 let ty = self.get_type(ctx).deref(ctx);
466 let maybe_vec = type_cast::<dyn MaybeVectorizedType>(&*ty)?;
467 maybe_vec.try_vector_size(ctx)
468 }
469
470 fn packing_factor(&self, ctx: &Context) -> usize {
471 let ty = self.get_type(ctx).deref(ctx);
472 let maybe_packed = try_cast_ty!(ty, ctx, dyn MaybePackedType);
473 maybe_packed.packing_factor(ctx)
474 }
475
476 fn scalar_ty(&self, ctx: &Context) -> TypeHandle {
477 let ty = self.element_ty(ctx).deref(ctx);
478 let scalarizable = try_cast_ty!(ty, ctx, dyn ScalarizableType);
479 scalarizable.scalar_type(ctx)
480 }
481
482 fn element_ty(&self, ctx: &Context) -> TypeHandle {
483 let ty = self.get_type(ctx).deref(ctx);
484 let has_element_type = try_cast_ty!(ty, ctx, dyn HasElementType);
485 has_element_type
486 .element_type(ctx)
487 .expect("Expected element type to be some")
488 }
489
490 fn unwrap_ptr(&self, ctx: &Context) -> TypeHandle {
491 if let Some(ptr) = self.get_type(ctx).deref(ctx).downcast_ref::<PointerType>() {
492 ptr.inner
493 } else {
494 self.get_type(ctx)
495 }
496 }
497
498 fn try_get_scalar_ty(&self, ctx: &Context) -> Option<TypeHandle> {
499 let ty = self.get_type(ctx).deref(ctx);
500 let scalarizable = type_cast::<dyn ScalarizableType>(&*ty)?;
501 Some(scalarizable.scalar_type(ctx))
502 }
503
504 fn try_get_scalar_elem_ty(&self, ctx: &Context) -> Option<TypeHandle> {
505 let ty = self.get_type(ctx).deref(ctx);
506 let has_elem = type_cast::<dyn HasElementType>(&*ty)?;
507 let ty = has_elem.element_type(ctx)?.deref(ctx);
508 let scalarizable = type_cast::<dyn ScalarizableType>(&*ty)?;
509 Some(scalarizable.scalar_type(ctx))
510 }
511
512 fn is_index(&self, ctx: &Context) -> bool {
513 let ty = self.get_type(ctx).deref(ctx);
514 ty.is::<IndexType>()
515 }
516
517 fn is_int(&self, ctx: &Context) -> bool {
518 let ty = self.get_type(ctx).deref(ctx);
519 ty.is::<IntegerType>()
520 }
521
522 fn is_signed_int(&self, ctx: &Context) -> bool {
523 let ty = self.get_type(ctx).deref(ctx);
524 ty.downcast_ref::<IntegerType>()
525 .is_some_and(|it| it.is_signed())
526 }
527
528 fn is_unsigned_int(&self, ctx: &Context) -> bool {
529 let ty = self.get_type(ctx).deref(ctx);
530 ty.downcast_ref::<IntegerType>()
531 .is_some_and(|it| !it.is_signed())
532 }
533
534 fn is_int_of_width(&self, ctx: &Context, width: usize) -> bool {
535 let ty = self.get_type(ctx).deref(ctx);
536 ty.downcast_ref::<IntegerType>()
537 .is_some_and(|it| it.width() as usize == width)
538 }
539
540 fn is_float64(&self, ctx: &Context) -> bool {
541 self.get_type(ctx).deref(ctx).is::<Float64Type>()
542 }
543
544 fn is_float32(&self, ctx: &Context) -> bool {
545 self.get_type(ctx).deref(ctx).is::<Float32Type>()
546 }
547
548 fn is_tfloat32(&self, ctx: &Context) -> bool {
549 self.get_type(ctx).deref(ctx).is::<TFloat32Type>()
550 }
551
552 fn is_float16(&self, ctx: &Context) -> bool {
553 self.get_type(ctx).deref(ctx).is::<Float16Type>()
554 }
555
556 fn is_bfloat16(&self, ctx: &Context) -> bool {
557 self.get_type(ctx).deref(ctx).is::<BFloat16Type>()
558 }
559
560 fn is_float(&self, ctx: &Context) -> bool {
561 self.is_float16(ctx)
562 | self.is_float32(ctx)
563 | self.is_float64(ctx)
564 | self.is_tfloat32(ctx)
565 | self.is_bfloat16(ctx)
566 }
567
568 fn is_bool(&self, ctx: &Context) -> bool {
569 self.get_type(ctx).deref(ctx).is::<BoolType>()
570 }
571}
572
573impl<T: Typed> TypedExt for T {}
574
575pub trait TypeExt {
576 fn as_ptr(&self, ctx: &Context) -> PointerType;
577}
578
579impl TypeExt for TypeHandle {
580 fn as_ptr(&self, ctx: &Context) -> PointerType {
581 *TypedHandle::from_handle(*self, ctx)
582 .expect("Should be pointer")
583 .deref(ctx)
584 }
585}
586
587pub trait ValueExt {
588 fn replace_all_uses_except_with(&self, ctx: &Context, except: Use<Value>, other: &Value);
589}
590
591impl ValueExt for Value {
592 fn replace_all_uses_except_with(&self, ctx: &Context, except: Use<Value>, other: &Value) {
593 self.replace_some_uses_with(ctx, |_, r#use| r#use != &except, other);
594 }
595}