1use calyx_utils::{CalyxResult, Error, Id};
2use std::str::FromStr;
3use strum::EnumCount;
4use strum_macros::{AsRefStr, EnumCount, EnumString, FromRepr};
5
6pub const DEPRECATED_ATTRIBUTES: &[&str] = &["static"];
8
9#[derive(
10 EnumCount,
11 FromRepr,
12 AsRefStr,
13 EnumString,
14 Clone,
15 Copy,
16 Hash,
17 PartialEq,
18 Eq,
19 Debug,
20)]
21#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
22#[repr(u8)]
23pub enum BoolAttr {
25 #[strum(serialize = "toplevel")]
26 TopLevel,
28 #[strum(serialize = "external")]
29 External,
31 #[strum(serialize = "nointerface")]
32 NoInterface,
34 #[strum(serialize = "reset")]
35 Reset,
37 #[strum(serialize = "clk")]
38 Clk,
40 #[strum(serialize = "stable")]
41 Stable,
43 #[strum(serialize = "data")]
44 Data,
46 #[strum(serialize = "control")]
47 Control,
49 #[strum(serialize = "share")]
50 Share,
52 #[strum(serialize = "state_share")]
53 StateShare,
55 #[strum(serialize = "generated")]
56 Generated,
58 #[strum(serialize = "new_fsm")]
59 NewFSM,
61 #[strum(serialize = "one_hot")]
62 OneHot,
66 #[strum(serialize = "inline")]
67 Inline,
69 #[strum(serialize = "promoted")]
70 Promoted,
72 #[strum(serialize = "par")]
73 ParCtrl,
76 #[strum(serialize = "fast")]
77 Fast,
79 #[strum(serialize = "protected")]
80 Protected,
82 #[strum(serialize = "fsm_control")]
83 FSMControl,
85 #[strum(serialize = "one_state")]
86 OneState,
88}
89
90impl From<BoolAttr> for Attribute {
91 fn from(attr: BoolAttr) -> Self {
92 Attribute::Bool(attr)
93 }
94}
95impl std::fmt::Display for BoolAttr {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 write!(f, "{}", self.as_ref())
98 }
99}
100
101#[derive(AsRefStr, EnumString, Clone, Copy, Hash, PartialEq, Eq, Debug)]
102#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
103pub enum NumAttr {
105 #[strum(serialize = "go")]
108 Go,
109 #[strum(serialize = "done")]
110 Done,
111 #[strum(serialize = "read_together")]
113 ReadTogether,
114 #[strum(serialize = "write_together")]
115 WriteTogether,
116 #[strum(serialize = "sync")]
117 Sync,
119 #[strum(serialize = "bound")]
120 Bound,
122 #[strum(serialize = "promotable")]
123 Promotable,
126 #[strum(serialize = "compactable")]
127 Compactable,
129 #[strum(serialize = "interval")]
130 Interval,
136 #[strum(serialize = "state")]
137 State,
138}
139impl From<NumAttr> for Attribute {
140 fn from(attr: NumAttr) -> Self {
141 Attribute::Num(attr)
142 }
143}
144impl std::fmt::Display for NumAttr {
145 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146 write!(f, "{}", self.as_ref())
147 }
148}
149
150#[derive(AsRefStr, Clone, Copy, Hash, PartialEq, Eq, Debug)]
151#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
152#[allow(non_camel_case_types)]
153pub enum InternalAttr {
155 DEAD,
156 NODE_ID,
157 BEGIN_ID,
158 END_ID,
159 ST_ID,
160 LOOP,
161 START,
162 END,
163 SCHEDULE_ID,
164
165 UNROLL,
167 INLINE,
168 OFFLOAD,
169 ACYCLIC,
170 NUM_STATES,
171}
172impl From<InternalAttr> for Attribute {
173 fn from(attr: InternalAttr) -> Self {
174 Attribute::Internal(attr)
175 }
176}
177
178#[derive(
179 AsRefStr,
180 EnumString,
181 Clone,
182 Copy,
183 Hash,
184 PartialEq,
185 Eq,
186 Debug,
187 strum_macros::Display,
188 PartialOrd,
189 Ord,
190)]
191#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
192pub enum SetAttr {
193 #[strum(serialize = "pos")]
194 Pos,
196}
197#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
198#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
199pub enum SetAttribute {
200 Set(SetAttr),
201 Unknown(Id),
202}
203
204impl Ord for SetAttribute {
205 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
206 match (self, other) {
207 (SetAttribute::Set(s1), SetAttribute::Set(s2)) => s1.cmp(s2),
208 (SetAttribute::Set(_), SetAttribute::Unknown(_)) => {
209 std::cmp::Ordering::Less
210 }
211 (SetAttribute::Unknown(_), SetAttribute::Set(_)) => {
212 std::cmp::Ordering::Greater
213 }
214 (SetAttribute::Unknown(id1), SetAttribute::Unknown(id2)) => {
215 id1.as_ref().cmp(id2.as_ref())
216 }
217 }
218 }
219}
220
221impl PartialOrd for SetAttribute {
222 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
223 Some(self.cmp(other))
224 }
225}
226
227impl From<Id> for SetAttribute {
228 fn from(v: Id) -> Self {
229 Self::Unknown(v)
230 }
231}
232
233impl From<SetAttr> for SetAttribute {
234 fn from(v: SetAttr) -> Self {
235 Self::Set(v)
236 }
237}
238
239impl std::fmt::Display for SetAttribute {
240 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241 match self {
242 SetAttribute::Set(set_attr) => set_attr.fmt(f),
243 SetAttribute::Unknown(id) => id.fmt(f),
244 }
245 }
246}
247
248impl FromStr for SetAttribute {
249 type Err = Error;
250 fn from_str(s: &str) -> CalyxResult<Self> {
251 if let Ok(s) = SetAttr::from_str(s) {
252 Ok(SetAttribute::Set(s))
253 } else {
254 if s.to_uppercase() == s {
256 return Err(Error::misc(format!(
257 "Invalid attribute: {s}. All caps attributes are reserved for internal use."
258 )));
259 }
260 Ok(SetAttribute::Unknown(s.into()))
261 }
262 }
263}
264
265#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
266#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
267pub enum Attribute {
271 Bool(BoolAttr),
272 Num(NumAttr),
273 Internal(InternalAttr),
274 Unknown(Id),
277}
278impl std::fmt::Display for Attribute {
279 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
280 match self {
281 Attribute::Bool(b) => write!(f, "{}", b.as_ref()),
282 Attribute::Num(n) => write!(f, "{}", n.as_ref()),
283 Attribute::Internal(i) => write!(f, "{}", i.as_ref()),
284 Attribute::Unknown(s) => write!(f, "{s}"),
285 }
286 }
287}
288impl FromStr for Attribute {
289 type Err = Error;
290
291 fn from_str(s: &str) -> CalyxResult<Self> {
292 if let Ok(b) = BoolAttr::from_str(s) {
293 Ok(Attribute::Bool(b))
294 } else if let Ok(n) = NumAttr::from_str(s) {
295 Ok(Attribute::Num(n))
296 } else {
297 if DEPRECATED_ATTRIBUTES.contains(&s) {
298 log::warn!(
299 "The attribute @{s} is deprecated and will be ignored by the compiler."
300 );
301 }
302
303 if let Ok(SetAttribute::Set(_)) = SetAttribute::from_str(s) {
304 log::warn!(
305 "Set attribute {s} incorrectly written as a standard attribute, i.e. '@{s}(..)' or '\"{s}\" = ..'. This will be ignored by the compiler. Instead write '@{s}{{..}}' or '\"{s}\" = {{..}}'."
306 );
307 }
308
309 if s.to_uppercase() == s {
311 return Err(Error::misc(format!(
312 "Invalid attribute: {s}. All caps attributes are reserved for internal use."
313 )));
314 }
315 Ok(Attribute::Unknown(s.into()))
316 }
317 }
318}
319
320#[derive(Default, Debug, Clone, PartialEq, Eq)]
321pub(super) struct InlineAttributes {
323 attrs: u32,
325}
326
327impl InlineAttributes {
328 pub const fn is_empty(&self) -> bool {
330 self.attrs == 0
331 }
332
333 pub fn insert(&mut self, attr: BoolAttr) {
335 self.attrs |= 1 << attr as u8;
336 }
337
338 pub fn has(&self, attr: BoolAttr) -> bool {
340 self.attrs & (1 << (attr as u8)) != 0
341 }
342
343 pub fn remove(&mut self, attr: BoolAttr) {
345 self.attrs &= !(1 << attr as u8);
346 }
347
348 pub(super) fn iter(&self) -> impl Iterator<Item = BoolAttr> + '_ {
350 (0..(BoolAttr::COUNT as u8)).filter_map(|idx| {
351 if self.attrs & (1 << idx) != 0 {
352 Some(BoolAttr::from_repr(idx).unwrap())
353 } else {
354 None
355 }
356 })
357 }
358}
359
360#[cfg(feature = "serialize")]
361impl serde::Serialize for InlineAttributes {
362 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
363 where
364 S: serde::Serializer,
365 {
366 self.to_owned().attrs.serialize(ser)
367 }
368}