Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8b46ffe
Initial setup for pliron macros
rahulmutt Feb 11, 2026
55cee67
Fix proc_macro/proc_macro2 errors
rahulmutt Feb 12, 2026
67ded2e
Reverse order
rahulmutt Feb 12, 2026
9adcaa5
Support default format
rahulmutt Feb 12, 2026
16e29d0
Add fully qualified paths
rahulmutt Feb 12, 2026
ead8491
Fix optional format
rahulmutt Feb 12, 2026
ea90252
Tests passing
rahulmutt Feb 12, 2026
8696329
Formatting
rahulmutt Feb 12, 2026
d60e2b5
Update to use pliron_op
rahulmutt Feb 12, 2026
da3e9a9
Support generics
rahulmutt Feb 12, 2026
8364049
Update builtin types
rahulmutt Feb 12, 2026
ba32194
support attr_get_set
rahulmutt Feb 12, 2026
39ff073
Update with new attributes field
rahulmutt Feb 12, 2026
e5995a5
Add docs and validation for certain entity fields
rahulmutt Feb 12, 2026
a093ce1
Remove space from expect
rahulmutt Feb 12, 2026
b3eb85e
Use UFCS for derive impl
rahulmutt Feb 13, 2026
2f705e1
Update tests/rewriter.rs
rahulmutt Feb 13, 2026
3f4ac36
Update tests/common/mod.rs
rahulmutt Feb 13, 2026
6051831
Migrate tests/interfaces.rs
rahulmutt Feb 13, 2026
2a45798
Migrate src/type.rs
rahulmutt Feb 13, 2026
6749c6b
Migrate src/debug_info.rs
rahulmutt Feb 13, 2026
55f601f
Migrate ir_construct
rahulmutt Feb 13, 2026
54e3f8a
Support attributes w/o type signature
rahulmutt Feb 13, 2026
d92b052
Update test
rahulmutt Feb 13, 2026
b101bbc
Migrate llvm ops
rahulmutt Feb 13, 2026
3c76ae0
Migrate types
rahulmutt Feb 13, 2026
2f7485c
Update llvm attributes and fix bug in generating succ verifiers for e…
rahulmutt Feb 13, 2026
bee58ca
interfaces are not supported for type and attribute
rahulmutt Feb 13, 2026
e8d6a5b
Require comma separation with support for trailing commas
rahulmutt Feb 13, 2026
5b123d0
Update rest of files with comma mandate
rahulmutt Feb 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
796 changes: 796 additions & 0 deletions pliron-derive/src/derive_entity.rs

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions pliron-derive/src/interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub(crate) fn interface_impl(
interface_verifiers_slice: Path,
id: Path,
all_verifiers_fn_type: Path,
get_id_static: Ident,
get_id_static: (Path, Ident),
) -> Result<proc_macro2::TokenStream> {
let r#impl = syn::parse2::<ItemImpl>(input.into())?;

Expand All @@ -105,13 +105,14 @@ pub(crate) fn interface_impl(
let trait_cast = quote! {
::pliron::type_to_trait!(#rust_ty, #intr_name);
};
let (get_id_static_trait, get_id_static_method) = get_id_static;

let verifiers_entry = quote! {
const _: () = {
#[cfg_attr(not(target_family = "wasm"), ::pliron::linkme::distributed_slice(#interface_verifiers_slice), linkme(crate = ::pliron::linkme))]
static INTERFACE_VERIFIER: std::sync::LazyLock<(#id, (#all_verifiers_fn_type))> =
std::sync::LazyLock::new(||
(#rust_ty::#get_id_static(),
Copy link
Contributor Author

@rahulmutt rahulmutt Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Highlighting this as this also improves UX by not forcing users to import ::pliron::op::Op, or any of the other entity traits and keeps the macro generated code explicit.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. I did encounter this myself, but without a second though just added the import. This makes it much better for new users.

(<#rust_ty as #get_id_static_trait>::#get_id_static_method(),
<#rust_ty as #intr_name>::__all_verifiers)
);

Expand Down
172 changes: 166 additions & 6 deletions pliron-derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod derive_attr;
mod derive_entity;
mod derive_format;
mod derive_op;
mod derive_type;
Expand Down Expand Up @@ -492,17 +493,174 @@ pub fn op_interface(_attr: TokenStream, item: TokenStream) -> TokenStream {
pub fn op_interface_impl(_attr: TokenStream, item: TokenStream) -> TokenStream {
let interface_verifiers_slice = parse_quote! { ::pliron::op::OP_INTERFACE_VERIFIERS };
let id = parse_quote! { ::pliron::op::OpId };
let get_id_static = format_ident!("{}", "get_opid_static");
let get_id_static_method = format_ident!("{}", "get_opid_static");
let get_id_static_trait = parse_quote! { ::pliron::op::Op };
let all_verifiers_fn_type = parse_quote! { ::pliron::op::OpInterfaceAllVerifiers };
to_token_stream(interfaces::interface_impl(
item,
interface_verifiers_slice,
id,
all_verifiers_fn_type,
get_id_static,
(get_id_static_trait, get_id_static_method),
))
}

/// `#[pliron_type(...)]`: Unified macro for defining IR types.
///
/// This macro provides a simplified, unified syntax for defining IR types by expanding
/// into the existing type definition macros. It supports the following configuration options:
///
/// - `name = "dialect.type_name"`: The fully qualified name of the type (required)
/// - `format = "format_string"`: Custom format string for printing/parsing (optional)
/// - `interfaces = [Interface1, Interface2, ...]`: List of interfaces to implement (optional)
/// - `verifier = "succ"`: Verifier implementation, currently only "succ" is supported (optional)
/// - `generate_get = true/false`: Whether to generate a get method for the type (optional, default: false)
///
/// ## Examples
///
/// ### Basic type definition:
/// ```
/// use pliron::derive::pliron_type;
///
/// #[pliron_type(name = "test.unit_type", format, verifier = "succ")]
/// #[derive(Debug, Clone, PartialEq, Eq, Hash)]
/// pub struct UnitType;
/// ```
///
/// ### Type with custom format:
/// ```
/// use pliron::derive::pliron_type;
///
/// #[pliron_type(
/// name = "test.flags_type",
/// format = "`type` `{` $flags `}`",
/// verifier = "succ"
/// )]
/// #[derive(Debug, Clone, PartialEq, Eq, Hash)]
/// struct FlagsType {
/// flags: u32,
/// }
/// ```
///
/// ### Type with get method generation:
/// ```
/// use pliron::derive::pliron_type;
///
/// #[pliron_type(
/// name = "test.vector_type",
/// generate_get = true,
/// format,
/// verifier = "succ"
/// )]
/// #[derive(Debug, Clone, PartialEq, Eq, Hash)]
/// struct VectorType {
/// elem_ty: u32,
/// num_elems: u32,
/// }
/// ```
#[proc_macro_attribute]
pub fn pliron_type(args: TokenStream, input: TokenStream) -> TokenStream {
to_token_stream(derive_entity::pliron_type(args, input))
}

/// `#[pliron_attr(...)]`: Unified macro for defining IR attributes.
///
/// This macro provides a simplified, unified syntax for defining IR attributes by expanding
/// into the existing attribute definition macros. It supports the following configuration options:
///
/// - `name = "dialect.attribute_name"`: The fully qualified name of the attribute (required)
/// - `format = "format_string"`: Custom format string for printing/parsing (optional)
/// - `interfaces = [Interface1, Interface2, ...]`: List of interfaces to implement (optional)
/// - `verifier = "succ"`: Verifier implementation, currently only "succ" is supported (optional)
///
/// ## Examples
///
/// ### Basic attribute definition:
/// ```
/// use pliron::derive::pliron_attr;
///
/// #[pliron_attr(name = "test.string_attr", format, verifier = "succ")]
/// #[derive(Debug, Clone, PartialEq, Eq, Hash)]
/// struct StringAttr {
/// value: String,
/// }
/// ```
///
/// ### Attribute with custom format:
/// ```
/// use pliron::derive::pliron_attr;
///
/// #[pliron_attr(
/// name = "test.string_attr",
/// format = "`attr` `(` $value `)`",
/// verifier = "succ"
/// )]
/// #[derive(Debug, Clone, PartialEq, Eq, Hash)]
/// struct StringAttr {
/// value: String,
/// }
/// ```
#[proc_macro_attribute]
pub fn pliron_attr(args: TokenStream, input: TokenStream) -> TokenStream {
to_token_stream(derive_entity::pliron_attr(args, input))
}

/// `#[pliron_op(...)]`: Unified macro for defining IR operations.
///
/// This macro provides a simplified, unified syntax for defining IR operations by expanding
/// into the existing operation definition macros. It supports the following configuration options:
///
/// - `name = "dialect.op_name"`: The fully qualified name of the operation (required)
/// - `format = "format_string"`: Custom format string for printing/parsing (optional)
/// - `interfaces = [Interface1, Interface2, ...]`: List of interfaces to implement (optional)
/// - `attributes = (attr_name: AttrType, ...)`: List of attributes with their types (optional)
/// - `verifier = "succ"`: Verifier implementation, currently only "succ" is supported (optional)
///
/// ## Examples
///
/// ### Basic operation definition:
/// ```
/// use pliron::derive::pliron_op;
///
/// #[pliron_op(name = "test.my_op", format, verifier = "succ")]
/// struct MyOp;
/// ```
///
/// ### Operation with custom format and interfaces:
/// ```
/// use pliron::derive::pliron_op;
/// use pliron::builtin::op_interfaces::NRegionsInterface;
///
/// #[pliron_op(
/// name = "test.if_op",
/// format = "`(`$0`)` region($0)",
/// interfaces = [ NRegionsInterface<1> ],
/// verifier = "succ"
/// )]
/// struct IfOp;
/// ```
///
/// ### Operation with attributes:
/// ```
/// use pliron::derive::pliron_op;
/// use pliron::builtin::attributes::{UnitAttr, IntegerAttr};
///
/// #[pliron_op(
/// name = "dialect.test",
/// format,
/// attributes = (attr1: UnitAttr, attr2: IntegerAttr),
/// verifier = "succ"
/// )]
/// struct CallOp;
/// ```
///
/// The `attributes` parameter generates getter and setter methods for each attribute,
/// equivalent to using `#[derive_attr_get_set(...)]`.
#[proc_macro_attribute]
pub fn pliron_op(args: TokenStream, input: TokenStream) -> TokenStream {
to_token_stream(derive_entity::pliron_op(args, input))
}

/// Derive implementation of an [Op](../pliron/op/trait.Op.html) Interface for an Op.
/// Note that an impl can be derived only for those interfaces that do not require any
/// methods to be defined during the impl.
Expand Down Expand Up @@ -636,14 +794,15 @@ pub fn attr_interface(_attr: TokenStream, item: TokenStream) -> TokenStream {
pub fn attr_interface_impl(_attr: TokenStream, item: TokenStream) -> TokenStream {
let interface_verifiers_slice = parse_quote! { ::pliron::attribute::ATTR_INTERFACE_VERIFIERS };
let id = parse_quote! { ::pliron::attribute::AttrId };
let get_id_static = format_ident!("{}", "get_attr_id_static");
let get_id_static_method = format_ident!("{}", "get_attr_id_static");
let get_id_static_trait = parse_quote! { ::pliron::attribute::Attribute };
let all_verifiers_fn_type = parse_quote! { ::pliron::attribute::AttrInterfaceAllVerifiers };
to_token_stream(interfaces::interface_impl(
item,
interface_verifiers_slice,
id,
all_verifiers_fn_type,
get_id_static,
(get_id_static_trait, get_id_static_method),
))
}

Expand Down Expand Up @@ -745,13 +904,14 @@ pub fn type_interface(_attr: TokenStream, item: TokenStream) -> TokenStream {
pub fn type_interface_impl(_attr: TokenStream, item: TokenStream) -> TokenStream {
let interface_verifiers_slice = parse_quote! { ::pliron::r#type::TYPE_INTERFACE_VERIFIERS };
let id = parse_quote! { ::pliron::r#type::TypeId };
let get_id_static = format_ident!("{}", "get_type_id_static");
let get_id_static_method = format_ident!("{}", "get_type_id_static");
let get_id_static_trait = parse_quote! { ::pliron::r#type::Type };
let all_verifiers_fn_type = parse_quote! { ::pliron::r#type::TypeInterfaceAllVerifiers };
to_token_stream(interfaces::interface_impl(
item,
interface_verifiers_slice,
id,
all_verifiers_fn_type,
get_id_static,
(get_id_static_trait, get_id_static_method),
))
}
2 changes: 1 addition & 1 deletion pliron-derive/tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use pliron::{builtin::op_interfaces::IsTerminatorInterface, impl_verify_succ, op::Op};
use pliron::{builtin::op_interfaces::IsTerminatorInterface, impl_verify_succ};
use pliron_derive::{def_op, derive_op_interface_impl, format_op};

#[def_op("test.return")]
Expand Down
57 changes: 24 additions & 33 deletions pliron-llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ use thiserror::Error;
use pliron::builtin::attributes::IntegerAttr;
use pliron::common_traits::Verify;
use pliron::context::Context;
use pliron::derive::{def_attribute, format, format_attribute};
use pliron::derive::{format, pliron_attr};
use pliron::location::Located;
use pliron::parsable::{IntoParseResult, Parsable};
use pliron::printable::Printable;
use pliron::result::Result;
use pliron::{impl_printable_for_display, impl_verify_succ, input_error, verify_err_noloc};
use pliron::{impl_printable_for_display, input_error, verify_err_noloc};

use crate::llvm_sys::core::FastmathFlags;

Expand All @@ -24,17 +24,14 @@ use crate::llvm_sys::core::FastmathFlags;
/// "nsw" and "nuw" bits indicate that the operation is guaranteed to not overflow
/// (in the signed or unsigned case, respectively). This gives the optimizer more information
/// and can be used for things like C signed integer values, which are undefined on overflow.
#[def_attribute("llvm.integer_overlflow_flags")]
#[format_attribute]
#[pliron_attr(name = "llvm.integer_overlflow_flags", format, verifier = "succ")]
#[derive(PartialEq, Eq, Clone, Debug, Default, Hash)]
pub struct IntegerOverflowFlagsAttr {
pub nsw: bool,
pub nuw: bool,
}

impl_verify_succ!(IntegerOverflowFlagsAttr);

#[def_attribute("llvm.fast_math_flags")]
#[pliron_attr(name = "llvm.fast_math_flags", verifier = "succ")]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct FastmathFlagsAttr(pub FastmathFlags);

Expand All @@ -56,8 +53,6 @@ impl From<FastmathFlagsAttr> for FastmathFlags {
}
}

impl_verify_succ!(FastmathFlagsAttr);

impl Display for FastmathFlagsAttr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<")?;
Expand Down Expand Up @@ -105,8 +100,7 @@ impl Parsable for FastmathFlagsAttr {
}
}

#[def_attribute("llvm.icmp_predicate")]
#[format_attribute]
#[pliron_attr(name = "llvm.icmp_predicate", verifier = "succ", format)]
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub enum ICmpPredicateAttr {
EQ,
Expand All @@ -121,10 +115,7 @@ pub enum ICmpPredicateAttr {
UGE,
}

impl_verify_succ!(ICmpPredicateAttr);

#[def_attribute("llvm.fcmp_predicate")]
#[format_attribute]
#[pliron_attr(name = "llvm.fcmp_predicate", format, verifier = "succ")]
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub enum FCmpPredicateAttr {
False,
Expand All @@ -144,7 +135,6 @@ pub enum FCmpPredicateAttr {
UNO,
True,
}
impl_verify_succ!(FCmpPredicateAttr);

/// An index for a GEP can be either a constant or an SSA operand.
/// Contrary to its name, this isn't an [Attribute][pliron::attribute::Attribute].
Expand All @@ -158,16 +148,17 @@ pub enum GepIndexAttr {
OperandIdx(usize),
}

#[def_attribute("llvm.gep_indices")]
#[format_attribute("`[` vec($0, CharSpace(`,`)) `]`")]
#[pliron_attr(
name = "llvm.gep_indices",
format = "`[` vec($0, CharSpace(`,`)) `]`",
verifier = "succ"
)]
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub struct GepIndicesAttr(pub Vec<GepIndexAttr>);
impl_verify_succ!(GepIndicesAttr);

/// An attribute that contains a list of case values for a switch operation.
#[def_attribute("llvm.case_values")]
#[pliron_attr(name = "llvm.case_values", format = "`[` vec($0, CharSpace(`,`)) `]`")]
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
#[format_attribute("`[` vec($0, CharSpace(`,`)) `]`")]
pub struct CaseValuesAttr(pub Vec<IntegerAttr>);

#[derive(Debug, Error)]
Expand All @@ -190,8 +181,7 @@ impl Verify for CaseValuesAttr {
}
}

#[def_attribute("llvm.linkage")]
#[format_attribute]
#[pliron_attr(name = "llvm.linkage", format, verifier = "succ")]
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub enum LinkageAttr {
ExternalLinkage,
Expand All @@ -212,25 +202,26 @@ pub enum LinkageAttr {
LinkerPrivateLinkage,
LinkerPrivateWeakLinkage,
}
impl_verify_succ!(LinkageAttr);

#[def_attribute("llvm.insert_extract_value_indices")]
#[format_attribute("`[` vec($0, CharSpace(`,`)) `]`")]
#[pliron_attr(
name = "llvm.insert_extract_value_indices",
format = "`[` vec($0, CharSpace(`,`)) `]`",
verifier = "succ"
)]
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub struct InsertExtractValueIndicesAttr(pub Vec<u32>);
impl_verify_succ!(InsertExtractValueIndicesAttr);

#[def_attribute("llvm.align")]
#[format_attribute("$0")]
#[pliron_attr(name = "llvm.align", format = "$0", verifier = "succ")]
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub struct AlignmentAttr(pub u32);
impl_verify_succ!(AlignmentAttr);

#[def_attribute("llvm.shuffle_vector_mask")]
#[format_attribute("`[` vec($0, CharSpace(`,`)) `]`")]
#[pliron_attr(
name = "llvm.shuffle_vector_mask",
format = "`[` vec($0, CharSpace(`,`)) `]`",
verifier = "succ"
)]
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub struct ShuffleVectorMaskAttr(pub Vec<i32>);
impl_verify_succ!(ShuffleVectorMaskAttr);

#[cfg(test)]
mod tests {
Expand Down
Loading