1use alloc::{
7 boxed::Box,
8 string::{String, ToString},
9 vec::Vec,
10};
11use core::{
12 fmt::Display,
13 hash::{Hash, Hasher},
14};
15use thiserror::Error;
16
17use pliron::{
18 attribute::verify_attr,
19 builtin::{
20 attr_interfaces::TypedAttrInterface,
21 attributes::{IntegerAttr, StringAttr},
22 ops::ModuleOp,
23 types::{IntegerType, Signedness},
24 },
25 combine::{self, Parser, choice, parser::char::spaces},
26 common_traits::Verify,
27 context::Context,
28 derive::{attr_interface_impl, format, pliron_attr},
29 dict_key,
30 identifier::Identifier,
31 impl_printable_for_display, input_error,
32 location::Located,
33 op::Op,
34 parsable::{IntoParseResult, Parsable},
35 printable::Printable,
36 result::Result,
37 r#type::{TypeHandle, TypedHandle},
38 verify_err_noloc,
39};
40
41use crate::types::{ArrayType, PointerType, StructType, VectorType};
42
43use bitflags::bitflags;
44
45#[pliron_attr(name = "llvm.integer_overlflow_flags", format, verifier = "succ")]
53#[derive(PartialEq, Eq, Clone, Debug, Default, Hash)]
54pub struct IntegerOverflowFlagsAttr {
55 pub nsw: bool,
56 pub nuw: bool,
57}
58
59bitflags! {
60 #[derive(PartialEq, Eq, Clone, Debug, Hash, Copy)]
62 pub struct FastmathFlags: u8 {
63 const NNAN = 1;
64 const NINF = 2;
65 const NSZ = 4;
66 const ARCP = 8;
67 const CONTRACT = 16;
68 const AFN = 32;
69 const REASSOC = 64;
70 const FAST = 127;
71 }
72}
73
74#[pliron_attr(name = "llvm.fast_math_flags", verifier = "succ")]
75#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
76pub struct FastmathFlagsAttr(pub FastmathFlags);
77
78impl Default for FastmathFlagsAttr {
79 fn default() -> Self {
80 FastmathFlagsAttr(FastmathFlags::empty())
81 }
82}
83
84impl From<FastmathFlags> for FastmathFlagsAttr {
85 fn from(value: FastmathFlags) -> Self {
86 FastmathFlagsAttr(value)
87 }
88}
89
90impl From<FastmathFlagsAttr> for FastmathFlags {
91 fn from(attr: FastmathFlagsAttr) -> Self {
92 attr.0
93 }
94}
95
96impl Display for FastmathFlagsAttr {
97 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
98 write!(f, "<")?;
99 bitflags::parser::to_writer(&self.0, &mut *f)?;
100 write!(f, ">")
101 }
102}
103
104impl_printable_for_display!(FastmathFlagsAttr);
105
106#[derive(Debug, Error)]
107#[error("Error parsing fastmath flags: {0}")]
108pub struct FastmathFlagParseErr(pub bitflags::parser::ParseError);
109
110impl Parsable for FastmathFlagsAttr {
111 type Arg = ();
112
113 type Parsed = Self;
114
115 fn parse<'a>(
116 state_stream: &mut pliron::parsable::StateStream<'a>,
117 _arg: Self::Arg,
118 ) -> pliron::parsable::ParseResult<'a, Self::Parsed> {
119 let pos = state_stream.loc();
120 let allowed_chars = combine::choice!(
121 combine::parser::char::space().map(|c| c.to_string()),
122 combine::parser::char::alpha_num().map(|c| c.to_string()),
123 combine::parser::char::char('|').map(|c: char| c.to_string())
124 );
125
126 let (parsed, _): (Vec<String>, _) = combine::between(
127 combine::parser::char::char('<').with(spaces()),
128 spaces().with(combine::parser::char::char('>')),
129 combine::many(allowed_chars),
130 )
131 .parse_stream(state_stream)
132 .into_result()?;
133 let parsed_string = parsed.concat();
134
135 let (fast_math_flags, _) = bitflags::parser::from_str::<FastmathFlags>(&parsed_string)
136 .map_err(|e| input_error!(pos.clone(), FastmathFlagParseErr(e)))
137 .into_parse_result()?;
138
139 Ok(FastmathFlagsAttr(fast_math_flags)).into_parse_result()
140 }
141}
142
143bitflags! {
144 #[derive(PartialEq, Eq, Clone, Debug, Hash, Copy)]
146 pub struct GepNoWrapFlags: u8 {
147 const INBOUNDS = 1;
148 const NUSW = 2;
149 const NUW = 4;
150 }
151}
152
153impl GepNoWrapFlags {
154 pub fn normalized(self) -> Self {
156 if self.contains(Self::INBOUNDS) {
157 self | Self::NUSW
158 } else {
159 self
160 }
161 }
162}
163
164#[pliron_attr(name = "llvm.gep_no_wrap_flags", verifier = "succ")]
165#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
166pub struct GepNoWrapFlagsAttr(pub GepNoWrapFlags);
167
168impl Default for GepNoWrapFlagsAttr {
169 fn default() -> Self {
170 Self(GepNoWrapFlags::empty())
171 }
172}
173
174impl From<GepNoWrapFlags> for GepNoWrapFlagsAttr {
175 fn from(value: GepNoWrapFlags) -> Self {
176 Self(value.normalized())
177 }
178}
179
180impl From<GepNoWrapFlagsAttr> for GepNoWrapFlags {
181 fn from(attr: GepNoWrapFlagsAttr) -> Self {
182 attr.0
183 }
184}
185
186impl Display for GepNoWrapFlagsAttr {
187 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
188 let mut flags = self.0.normalized();
189
190 if flags.contains(GepNoWrapFlags::INBOUNDS) {
192 flags.remove(GepNoWrapFlags::NUSW);
193 }
194
195 write!(f, "<")?;
196 bitflags::parser::to_writer(&flags, &mut *f)?;
197 write!(f, ">")
198 }
199}
200
201impl_printable_for_display!(GepNoWrapFlagsAttr);
202
203#[derive(Debug, Error)]
204#[error("Error parsing GEP no-wrap flags: {0}")]
205pub struct GepNoWrapFlagParseErr(pub bitflags::parser::ParseError);
206
207impl Parsable for GepNoWrapFlagsAttr {
208 type Arg = ();
209 type Parsed = Self;
210
211 fn parse<'a>(
212 state_stream: &mut pliron::parsable::StateStream<'a>,
213 _arg: Self::Arg,
214 ) -> pliron::parsable::ParseResult<'a, Self::Parsed> {
215 let pos = state_stream.loc();
216 let allowed_chars = combine::choice!(
217 combine::parser::char::space().map(|c| c.to_string()),
218 combine::parser::char::alpha_num().map(|c| c.to_string()),
219 combine::parser::char::char('|').map(|c: char| c.to_string())
220 );
221
222 let (parsed, _): (Vec<String>, _) = combine::between(
223 combine::parser::char::char('<').with(spaces()),
224 spaces().with(combine::parser::char::char('>')),
225 combine::many(allowed_chars),
226 )
227 .parse_stream(state_stream)
228 .into_result()?;
229 let parsed_string = parsed.concat();
230
231 let (flags, _) = bitflags::parser::from_str::<GepNoWrapFlags>(&parsed_string)
232 .map_err(|e| input_error!(pos.clone(), GepNoWrapFlagParseErr(e)))
233 .into_parse_result()?;
234
235 Ok(GepNoWrapFlagsAttr(flags.normalized())).into_parse_result()
236 }
237}
238
239#[pliron_attr(name = "llvm.icmp_predicate", verifier = "succ", format)]
240#[derive(PartialEq, Eq, Clone, Debug, Hash)]
241pub enum ICmpPredicateAttr {
242 EQ,
243 NE,
244 SLT,
245 SLE,
246 SGT,
247 SGE,
248 ULT,
249 ULE,
250 UGT,
251 UGE,
252}
253
254#[pliron_attr(name = "llvm.fcmp_predicate", format, verifier = "succ")]
255#[derive(PartialEq, Eq, Clone, Debug, Hash)]
256pub enum FCmpPredicateAttr {
257 False,
258 OEQ,
259 OGT,
260 OGE,
261 OLT,
262 OLE,
263 ONE,
264 ORD,
265 UEQ,
266 UGT,
267 UGE,
268 ULT,
269 ULE,
270 UNE,
271 UNO,
272 True,
273}
274
275#[derive(PartialEq, Eq, Clone, Debug, Hash)]
278#[format]
279pub enum GepIndexAttr {
280 Constant(u32),
282 OperandIdx(usize),
285}
286
287#[pliron_attr(
288 name = "llvm.gep_indices",
289 format = "`[` vec($0, CharSpace(`,`)) `]`",
290 verifier = "succ"
291)]
292#[derive(PartialEq, Eq, Clone, Debug, Hash)]
293pub struct GepIndicesAttr(pub Vec<GepIndexAttr>);
294
295#[pliron_attr(name = "llvm.case_values", format = "`[` vec($0, CharSpace(`,`)) `]`")]
297#[derive(PartialEq, Eq, Clone, Debug, Hash)]
298pub struct CaseValuesAttr(pub Vec<IntegerAttr>);
299
300#[derive(Debug, Error)]
301#[error("Case values must be of the same type, but found different types: {0} and {1}")]
302pub struct CaseValuesAttrVerifyErr(pub String, pub String);
303
304impl Verify for CaseValuesAttr {
305 fn verify(&self, ctx: &Context) -> Result<()> {
306 self.0.windows(2).try_for_each(|pair| {
307 pair[0].verify(ctx)?;
308 if pair[0].get_type() != pair[1].get_type() {
309 verify_err_noloc!(CaseValuesAttrVerifyErr(
310 pair[0].get_type().disp(ctx).to_string(),
311 pair[1].get_type().disp(ctx).to_string()
312 ))
313 } else {
314 Ok(())
315 }
316 })
317 }
318}
319
320#[pliron_attr(name = "llvm.linkage", format, verifier = "succ")]
321#[derive(PartialEq, Eq, Clone, Debug, Hash)]
322pub enum LinkageAttr {
323 ExternalLinkage,
324 AvailableExternallyLinkage,
325 LinkOnceAnyLinkage,
326 LinkOnceODRLinkage,
327 LinkOnceODRAutoHideLinkage,
328 WeakAnyLinkage,
329 WeakODRLinkage,
330 AppendingLinkage,
331 InternalLinkage,
332 PrivateLinkage,
333 DLLImportLinkage,
334 DLLExportLinkage,
335 ExternalWeakLinkage,
336 GhostLinkage,
337 CommonLinkage,
338 LinkerPrivateLinkage,
339 LinkerPrivateWeakLinkage,
340}
341
342#[pliron_attr(
343 name = "llvm.insert_extract_value_indices",
344 format = "`[` vec($0, CharSpace(`,`)) `]`",
345 verifier = "succ"
346)]
347#[derive(PartialEq, Eq, Clone, Debug, Hash)]
348pub struct InsertExtractValueIndicesAttr(pub Vec<u32>);
349
350#[pliron_attr(name = "llvm.align", format = "$0", verifier = "succ")]
351#[derive(PartialEq, Eq, Clone, Debug, Hash)]
352pub struct AlignmentAttr(pub u32);
353
354#[pliron_attr(name = "llvm.addrspace", format = "$0", verifier = "succ")]
356#[derive(PartialEq, Eq, Clone, Debug, Hash)]
357pub struct AddressSpaceAttr(pub u32);
358
359#[pliron_attr(name = "llvm.zero", format = "$0", verifier = "succ")]
361#[derive(PartialEq, Eq, Clone, Debug, Hash)]
362pub struct ZeroAttr(pub TypeHandle);
363
364#[attr_interface_impl]
365impl TypedAttrInterface for ZeroAttr {
366 fn get_type(&self, _ctx: &Context) -> TypeHandle {
367 self.0
368 }
369}
370
371#[pliron_attr(name = "llvm.undef", format = "$0", verifier = "succ")]
373#[derive(PartialEq, Eq, Clone, Debug, Hash)]
374pub struct UndefAttr(pub TypeHandle);
375
376#[attr_interface_impl]
377impl TypedAttrInterface for UndefAttr {
378 fn get_type(&self, _ctx: &Context) -> TypeHandle {
379 self.0
380 }
381}
382
383#[pliron_attr(name = "llvm.poison", format = "$0", verifier = "succ")]
385#[derive(PartialEq, Eq, Clone, Debug, Hash)]
386pub struct PoisonAttr(pub TypeHandle);
387
388#[attr_interface_impl]
389impl TypedAttrInterface for PoisonAttr {
390 fn get_type(&self, _ctx: &Context) -> TypeHandle {
391 self.0
392 }
393}
394
395#[pliron_attr(
397 name = "llvm.bytes",
398 format = "`[` vec($0, CharSpace(`,`)) `]`",
399 verifier = "succ"
400)]
401#[derive(PartialEq, Eq, Clone, Debug, Hash)]
402pub struct BytesAttr(Vec<u8>);
403
404impl BytesAttr {
405 pub fn new(bytes: Vec<u8>) -> Self {
407 BytesAttr(bytes)
408 }
409}
410
411impl From<BytesAttr> for Vec<u8> {
412 fn from(value: BytesAttr) -> Self {
413 value.0
414 }
415}
416
417impl From<Vec<u8>> for BytesAttr {
418 fn from(value: Vec<u8>) -> Self {
419 BytesAttr::new(value)
420 }
421}
422
423impl AsRef<Vec<u8>> for BytesAttr {
424 fn as_ref(&self) -> &Vec<u8> {
425 &self.0
426 }
427}
428
429#[attr_interface_impl]
431impl TypedAttrInterface for BytesAttr {
432 fn get_type(&self, ctx: &Context) -> TypeHandle {
433 let i8_ty = IntegerType::get(ctx, 8, Signedness::Signless);
434 ArrayType::get(ctx, i8_ty.into(), self.0.len() as u64).into()
435 }
436}
437
438#[pliron_attr(name = "llvm.splat", format = "`<` $element ` : ` $ty `>`")]
440#[derive(Clone, Debug)]
441pub struct SplatAttr {
442 element: Box<dyn TypedAttrInterface>,
443 ty: TypedHandle<VectorType>,
444}
445
446impl PartialEq for SplatAttr {
447 fn eq(&self, other: &Self) -> bool {
448 self.ty == other.ty && PartialEq::eq(&self.element, &other.element)
449 }
450}
451
452impl Eq for SplatAttr {}
453
454impl Hash for SplatAttr {
455 fn hash<H: Hasher>(&self, state: &mut H) {
456 self.element.hash(state);
457 self.ty.hash(state);
458 }
459}
460
461impl SplatAttr {
462 pub fn new(element: Box<dyn TypedAttrInterface>, ty: TypedHandle<VectorType>) -> Self {
464 SplatAttr { element, ty }
465 }
466
467 pub fn element(&self) -> &dyn TypedAttrInterface {
469 &*self.element
470 }
471
472 pub fn ty(&self) -> TypedHandle<VectorType> {
474 self.ty
475 }
476}
477
478#[attr_interface_impl]
479impl TypedAttrInterface for SplatAttr {
480 fn get_type(&self, _ctx: &Context) -> TypeHandle {
481 self.ty.into()
482 }
483}
484
485fn verify_element(
487 ctx: &Context,
488 idx: usize,
489 element: &dyn TypedAttrInterface,
490 expected: TypeHandle,
491) -> Result<()> {
492 verify_attr(element, ctx)?;
493 let ty = element.get_type(ctx);
494 if ty != expected {
495 verify_err_noloc!(ConstAggregateVerifyErr::ElementType(
496 idx,
497 ty.disp(ctx).to_string(),
498 expected.disp(ctx).to_string()
499 ))?
500 }
501 Ok(())
502}
503
504impl Verify for SplatAttr {
505 fn verify(&self, ctx: &Context) -> Result<()> {
506 let elem_ty = self.ty.deref(ctx).elem_type();
508 verify_element(ctx, 0, self.element(), elem_ty)
509 }
510}
511
512#[pliron_attr(
514 name = "llvm.symbol_addr",
515 format = "`<@` $symbol ` : ` $ty `>`",
516 verifier = "succ"
517)]
518#[derive(PartialEq, Eq, Clone, Debug, Hash)]
519pub struct SymbolAddrAttr {
520 symbol: Identifier,
521 ty: TypedHandle<PointerType>,
522}
523
524impl SymbolAddrAttr {
525 pub fn new(symbol: Identifier, ty: TypedHandle<PointerType>) -> Self {
528 SymbolAddrAttr { symbol, ty }
529 }
530
531 pub fn symbol(&self) -> &Identifier {
533 &self.symbol
534 }
535
536 pub fn ty(&self) -> TypedHandle<PointerType> {
538 self.ty
539 }
540}
541
542#[attr_interface_impl]
543impl TypedAttrInterface for SymbolAddrAttr {
544 fn get_type(&self, _ctx: &Context) -> TypeHandle {
545 self.ty.into()
546 }
547}
548
549#[pliron_attr(
553 name = "llvm.aggregate",
554 format = "`<[` vec($elements, CharSpace(`,`)) `] : ` $ty `>`"
555)]
556#[derive(PartialEq, Eq, Clone, Debug, Hash)]
557pub struct AggregateAttr {
558 elements: Vec<Box<dyn TypedAttrInterface>>,
559 ty: TypeHandle,
560}
561
562impl AggregateAttr {
563 pub fn new(elements: Vec<Box<dyn TypedAttrInterface>>, ty: TypeHandle) -> Self {
565 AggregateAttr { elements, ty }
566 }
567
568 pub fn elements(&self) -> &[Box<dyn TypedAttrInterface>] {
570 &self.elements
571 }
572
573 pub fn ty(&self) -> TypeHandle {
575 self.ty
576 }
577}
578
579#[attr_interface_impl]
580impl TypedAttrInterface for AggregateAttr {
581 fn get_type(&self, _ctx: &Context) -> TypeHandle {
582 self.ty
583 }
584}
585
586#[derive(Debug, Error)]
587pub enum ConstAggregateVerifyErr {
588 #[error("{0} is not an array, struct or vector type")]
589 NotAnAggregate(String),
590 #[error("A constant of the scalable vector type {0} must use llvm.splat")]
591 ScalableAggregate(String),
592 #[error("Type {0} has {1} element(s), but {2} were provided")]
593 NumElements(String, u64, usize),
594 #[error("Element {0} is of type {1}, but {2} was expected")]
595 ElementType(usize, String, String),
596}
597
598impl Verify for AggregateAttr {
599 fn verify(&self, ctx: &Context) -> Result<()> {
600 let ty = self.ty.deref(ctx);
601 if let Some(array_ty) = ty.downcast_ref::<ArrayType>() {
602 if array_ty.size() != self.elements.len() as u64 {
603 verify_err_noloc!(ConstAggregateVerifyErr::NumElements(
604 self.ty.disp(ctx).to_string(),
605 array_ty.size(),
606 self.elements.len()
607 ))?
608 }
609 let elem_ty = array_ty.elem_type();
610 for (idx, element) in self.elements.iter().enumerate() {
611 verify_element(ctx, idx, &**element, elem_ty)?;
612 }
613 } else if let Some(struct_ty) = ty.downcast_ref::<StructType>() {
614 if struct_ty.is_opaque() || struct_ty.num_fields() != self.elements.len() {
615 verify_err_noloc!(ConstAggregateVerifyErr::NumElements(
616 self.ty.disp(ctx).to_string(),
617 if struct_ty.is_opaque() {
618 0
619 } else {
620 struct_ty.num_fields() as u64
621 },
622 self.elements.len()
623 ))?
624 }
625 for (idx, element) in self.elements.iter().enumerate() {
626 verify_element(ctx, idx, &**element, struct_ty.field_type(idx))?;
627 }
628 } else if let Some(vector_ty) = ty.downcast_ref::<VectorType>() {
629 if vector_ty.is_scalable() {
630 verify_err_noloc!(ConstAggregateVerifyErr::ScalableAggregate(
631 self.ty.disp(ctx).to_string()
632 ))?
633 }
634 if vector_ty.num_elements() as usize != self.elements.len() {
635 verify_err_noloc!(ConstAggregateVerifyErr::NumElements(
636 self.ty.disp(ctx).to_string(),
637 vector_ty.num_elements() as u64,
638 self.elements.len()
639 ))?
640 }
641 let elem_ty = vector_ty.elem_type();
642 for (idx, element) in self.elements.iter().enumerate() {
643 verify_element(ctx, idx, &**element, elem_ty)?;
644 }
645 } else {
646 verify_err_noloc!(ConstAggregateVerifyErr::NotAnAggregate(
647 self.ty.disp(ctx).to_string()
648 ))?
649 }
650 Ok(())
651 }
652}
653
654#[pliron_attr(name = "llvm.atomic_ordering", verifier = "succ", format)]
656#[derive(PartialEq, Eq, Clone, Debug, Hash)]
657pub enum AtomicOrderingAttr {
658 Monotonic,
659 Acquire,
660 Release,
661 AcqRel,
662 SeqCst,
663}
664
665#[pliron_attr(name = "llvm.atomic_rmw_kind", verifier = "succ", format)]
667#[derive(PartialEq, Eq, Clone, Debug, Hash)]
668pub enum AtomicRmwKindAttr {
669 Xchg,
670 Add,
671 Sub,
672 And,
673 Nand,
674 Or,
675 Xor,
676 Max,
677 Min,
678 UMax,
679 UMin,
680 FAdd,
681 FSub,
682 FMax,
683 FMin,
684}
685
686#[pliron_attr(name = "llvm.sync_scope", verifier = "succ", format)]
688#[derive(PartialEq, Eq, Clone, Debug, Default, Hash)]
689pub enum SyncScopeAttr {
690 #[default]
692 System,
693 SingleThread,
695 NamedScope(StringAttr),
697}
698
699impl SyncScopeAttr {
700 pub fn to_name(&self) -> String {
703 match self {
704 SyncScopeAttr::SingleThread => "singlethread".to_string(),
705 SyncScopeAttr::System => String::new(),
706 SyncScopeAttr::NamedScope(name) => name.as_str().to_string(),
707 }
708 }
709}
710
711#[pliron_attr(
712 name = "llvm.shuffle_vector_mask",
713 format = "`[` vec($0, CharSpace(`,`)) `]`",
714 verifier = "succ"
715)]
716#[derive(PartialEq, Eq, Clone, Debug, Hash)]
717pub struct ShuffleVectorMaskAttr(pub Vec<i32>);
718
719#[cfg(test)]
720mod tests {
721 use expect_test::expect;
722 use pliron::{parsable::parse_from_str, result::ExpectOk};
723
724 use super::*;
725
726 #[test]
727 fn test_fastmath_flags_attr_empty() {
728 let flags = FastmathFlags::empty();
729 assert_eq!(flags.bits(), 0);
730
731 let ctx = &mut Context::default();
732 let flags_attr: FastmathFlagsAttr = flags.into();
733 expect!["<>"].assert_eq(&flags_attr.disp(ctx).to_string());
734
735 let parsed = parse_from_str(FastmathFlagsAttr::parser(()), ctx, "<>").expect_ok(ctx);
736 assert_eq!(parsed, flags_attr);
737 }
738
739 #[test]
740 fn test_fastmath_flags_attr_set_flags() {
741 let mut flags = FastmathFlags::empty();
742 flags |= FastmathFlags::NNAN | FastmathFlags::NINF;
743 assert!(flags.contains(FastmathFlags::NNAN));
744 assert!(flags.contains(FastmathFlags::NINF));
745 assert!(!flags.contains(FastmathFlags::NSZ));
746 }
747
748 #[test]
749 fn test_fastmath_flags_attr_fmt() {
750 let ctx = &Context::default();
751 let flags: FastmathFlagsAttr = (FastmathFlags::NNAN | FastmathFlags::ARCP).into();
752 expect!["<NNAN | ARCP>"].assert_eq(&flags.disp(ctx).to_string());
753 }
754
755 #[test]
756 fn test_fastmath_flags_attr_fmt_fast() {
757 let ctx = &Context::default();
758 let flags: FastmathFlagsAttr = FastmathFlags::FAST.into();
759 expect!["<NNAN | NINF | NSZ | ARCP | CONTRACT | AFN | REASSOC>"]
760 .assert_eq(&flags.disp(ctx).to_string());
761 }
762
763 #[test]
764 fn test_fastmath_flags_attr_parse_valid() {
765 let ctx = &mut Context::default();
766
767 let parsed =
768 parse_from_str(FastmathFlagsAttr::parser(()), ctx, "<NNAN | ARCP>").expect_ok(ctx);
769 assert!(parsed.0.contains(FastmathFlags::NNAN));
770 assert!(parsed.0.contains(FastmathFlags::ARCP));
771 }
772
773 #[test]
775 fn test_fastmath_flags_attr_parse_fast() {
776 let ctx = &mut Context::default();
777
778 let parsed = parse_from_str(FastmathFlagsAttr::parser(()), ctx, "<FAST>").expect_ok(ctx);
779 assert!(parsed.0.contains(FastmathFlags::FAST));
780
781 assert!(parsed.0.contains(FastmathFlags::NNAN));
783 assert!(parsed.0.contains(FastmathFlags::NINF));
784 assert!(parsed.0.contains(FastmathFlags::NSZ));
785 assert!(parsed.0.contains(FastmathFlags::ARCP));
786 assert!(parsed.0.contains(FastmathFlags::CONTRACT));
787 assert!(parsed.0.contains(FastmathFlags::REASSOC));
788 }
789
790 #[test]
791 fn test_fastmath_flags_attr_parse_invalid() {
792 let ctx = &mut Context::default();
793 let input = "<INVALIDFLAG>";
794 match parse_from_str(FastmathFlagsAttr::parser(()), ctx, input) {
795 Ok(parsed) => {
796 panic!("Expected error, but got: {}", parsed);
797 }
798 Err(e) => {
799 expect![[r#"
800 Compilation error: invalid input program.
801 Parse error at line: 1, column: 1
802 Error parsing fastmath flags: unrecognized named flag `INVALIDFLAG`
803 "#]]
804 .assert_eq(&e.to_string());
805 }
806 }
807 }
808
809 #[test]
810 fn test_gep_no_wrap_flags_attr_fmt() {
811 let ctx = &Context::default();
812
813 let flags: GepNoWrapFlagsAttr = (GepNoWrapFlags::NUSW | GepNoWrapFlags::NUW).into();
814 expect!["<NUSW | NUW>"].assert_eq(&flags.disp(ctx).to_string());
815
816 let flags: GepNoWrapFlagsAttr = (GepNoWrapFlags::INBOUNDS | GepNoWrapFlags::NUW).into();
817 expect!["<INBOUNDS | NUW>"].assert_eq(&flags.disp(ctx).to_string());
818 }
819
820 #[test]
821 fn test_gep_no_wrap_flags_inbounds_implies_nusw() {
822 let flags: GepNoWrapFlagsAttr = GepNoWrapFlags::INBOUNDS.into();
823
824 assert!(flags.0.contains(GepNoWrapFlags::INBOUNDS));
825 assert!(flags.0.contains(GepNoWrapFlags::NUSW));
826 }
827
828 #[test]
829 fn test_gep_no_wrap_flags_attr_parse_valid() {
830 let ctx = &mut Context::default();
831
832 let parsed =
833 parse_from_str(GepNoWrapFlagsAttr::parser(()), ctx, "<INBOUNDS | NUW>").expect_ok(ctx);
834 assert!(parsed.0.contains(GepNoWrapFlags::INBOUNDS));
835 assert!(parsed.0.contains(GepNoWrapFlags::NUSW));
836 assert!(parsed.0.contains(GepNoWrapFlags::NUW));
837 }
838
839 #[test]
840 fn test_gep_no_wrap_flags_attr_parse_invalid() {
841 let ctx = &mut Context::default();
842 let input = "<INVALIDFLAG>";
843
844 let err = parse_from_str(GepNoWrapFlagsAttr::parser(()), ctx, input)
845 .expect_err("invalid GEP no-wrap flag must fail to parse");
846 expect![[r#"
847 Compilation error: invalid input program.
848 Parse error at line: 1, column: 1
849 Error parsing GEP no-wrap flags: unrecognized named flag `INVALIDFLAG`
850 "#]]
851 .assert_eq(&err.to_string());
852 }
853
854 fn assert_attr_roundtrips<A>(ctx: &mut Context, attr: A)
855 where
856 A: Parsable<Arg = (), Parsed = A> + Printable + PartialEq + core::fmt::Debug,
857 {
858 let printed = attr.disp(ctx).to_string();
859 let parsed = parse_from_str(A::parser(()), ctx, &printed).expect_ok(ctx);
860 assert_eq!(parsed, attr, "round-trip mismatch for `{printed}`");
861 }
862
863 #[test]
864 fn test_atomic_ordering_attr_roundtrip() {
865 let ctx = &mut Context::default();
866 for ordering in [
867 AtomicOrderingAttr::Monotonic,
868 AtomicOrderingAttr::Acquire,
869 AtomicOrderingAttr::Release,
870 AtomicOrderingAttr::AcqRel,
871 AtomicOrderingAttr::SeqCst,
872 ] {
873 assert_attr_roundtrips(ctx, ordering);
874 }
875 }
876
877 #[test]
878 fn test_atomic_rmw_kind_attr_roundtrip() {
879 let ctx = &mut Context::default();
880 for kind in [
881 AtomicRmwKindAttr::Xchg,
882 AtomicRmwKindAttr::Add,
883 AtomicRmwKindAttr::Sub,
884 AtomicRmwKindAttr::And,
885 AtomicRmwKindAttr::Nand,
886 AtomicRmwKindAttr::Or,
887 AtomicRmwKindAttr::Xor,
888 AtomicRmwKindAttr::Max,
889 AtomicRmwKindAttr::Min,
890 AtomicRmwKindAttr::UMax,
891 AtomicRmwKindAttr::UMin,
892 AtomicRmwKindAttr::FAdd,
893 AtomicRmwKindAttr::FSub,
894 AtomicRmwKindAttr::FMax,
895 AtomicRmwKindAttr::FMin,
896 ] {
897 assert_attr_roundtrips(ctx, kind);
898 }
899 }
900
901 #[test]
902 fn test_sync_scope_attr_roundtrip() {
903 let ctx = &mut Context::default();
904 for scope in [
905 SyncScopeAttr::SingleThread,
906 SyncScopeAttr::System,
907 SyncScopeAttr::NamedScope(StringAttr::new("device".to_string())),
908 ] {
909 assert_attr_roundtrips(ctx, scope);
910 }
911 }
912
913 #[test]
914 fn test_address_space_attr_roundtrip() {
915 let ctx = &mut Context::default();
916 for n in [0u32, 1, 3, 5, 7] {
917 assert_attr_roundtrips(ctx, AddressSpaceAttr(n));
918 }
919 }
920
921 #[test]
922 fn test_fp_half_attr_roundtrip() {
923 use pliron::{builtin::attributes::FPHalfAttr, utils::apfloat::Half};
924 let ctx = &mut Context::default();
925 for s in ["0.0", "1.5", "-2.25"] {
926 let value: Half = s.parse().expect("valid half literal");
927 assert_attr_roundtrips(ctx, FPHalfAttr(value));
928 }
929 }
930}
931
932dict_key!(
933 ATTR_KEY_LLVM_DATA_LAYOUT,
935 "llvm_data_layout"
936);
937
938dict_key!(
939 ATTR_KEY_LLVM_TARGET_TRIPLE,
941 "llvm_target_triple"
942);
943
944pub fn get_data_layout(ctx: &Context, module: ModuleOp) -> Option<String> {
946 module
947 .get_operation()
948 .deref(ctx)
949 .attributes
950 .get::<StringAttr>(&ATTR_KEY_LLVM_DATA_LAYOUT)
951 .map(|attr| attr.clone().into())
952}
953
954pub fn set_data_layout(ctx: &Context, module: ModuleOp, data_layout: String) {
956 module.get_operation().deref_mut(ctx).attributes.set(
957 ATTR_KEY_LLVM_DATA_LAYOUT.clone(),
958 StringAttr::new(data_layout),
959 );
960}
961
962pub fn get_target_triple(ctx: &Context, module: ModuleOp) -> Option<String> {
964 module
965 .get_operation()
966 .deref(ctx)
967 .attributes
968 .get::<StringAttr>(&ATTR_KEY_LLVM_TARGET_TRIPLE)
969 .map(|attr| attr.clone().into())
970}
971
972pub fn set_target_triple(ctx: &Context, module: ModuleOp, target_triple: String) {
974 module.get_operation().deref_mut(ctx).attributes.set(
975 ATTR_KEY_LLVM_TARGET_TRIPLE.clone(),
976 StringAttr::new(target_triple),
977 );
978}