pulsar_ir/
lib.rs

1//! The IR can be structured or unstructured, dependending on the requirements
2//! of the backend.
3//!
4//! Copyright (C) 2024 Ethan Uppal. All rights reserved.
5
6use self::{label::LabelName, operand::Operand, variable::Variable};
7use std::fmt::Display;
8
9pub mod basic_block;
10pub mod branch_condition;
11pub mod control_flow_graph;
12pub mod generator;
13pub mod label;
14pub mod operand;
15pub mod variable;
16
17pub enum Ir {
18    Add(Variable, Operand, Operand),
19    Mul(Variable, Operand, Operand),
20    Assign(Variable, Operand),
21    GetParam(Variable),
22    Return(Option<Operand>),
23
24    /// `LocalAlloc(result, size, count)` allocates an array of `count`
25    /// elements, each of `size` bytes, and stores a pointer to the array in
26    /// `result`.
27    LocalAlloc(Variable, usize, usize),
28
29    /// `Store { result, value, index }` loads `value` into index `index` of
30    /// `result`.
31    Store {
32        result: Variable,
33        value: Operand,
34        index: Operand
35    },
36
37    /// `Load { result, value, index }` loads the value at index `index` of
38    /// `value` into `result`.
39    Load {
40        result: Variable,
41        value: Operand,
42        index: Operand
43    },
44
45    Map {
46        result: Variable,
47        parallel_factor: usize,
48        f: LabelName,
49        input: Operand,
50        length: usize
51    },
52    Call(Option<Variable>, LabelName, Vec<Operand>)
53}
54
55impl Display for Ir {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        match &self {
58            Self::Add(result, lhs, rhs) => {
59                write!(f, "{} = {} + {}", result, lhs, rhs)
60            }
61            Self::Mul(result, lhs, rhs) => {
62                write!(f, "{} = {} * {}", result, lhs, rhs)
63            }
64            Self::Assign(result, from) => write!(f, "{} = {}", result, from),
65            Self::GetParam(result) => write!(f, "{} = <next param>", result),
66            Self::Return(value_opt) => write!(
67                f,
68                "ret{}",
69                if let Some(value) = value_opt {
70                    format!(" {}", value)
71                } else {
72                    "".into()
73                }
74            ),
75            Self::LocalAlloc(result, size, count) => {
76                write!(f, "{} = <{} * ({} bytes)>", result, count, size)
77            }
78            Self::Store {
79                result,
80                value,
81                index
82            } => {
83                write!(f, "{}[{}] = {}", result, index, value)
84            }
85            Self::Load {
86                result,
87                value,
88                index
89            } => {
90                write!(f, "{} = {}[{}]", result, index, value)
91            }
92            Self::Map {
93                result,
94                parallel_factor,
95                f: func,
96                input,
97                length: _
98            } => {
99                write!(
100                    f,
101                    "{} = map<{}>({}, {})",
102                    result, parallel_factor, func, input
103                )
104            }
105            Self::Call(result_opt, name, args) => {
106                write!(
107                    f,
108                    "{}{}({})",
109                    if let Some(result) = result_opt {
110                        format!("{} = ", result)
111                    } else {
112                        "".into()
113                    },
114                    name,
115                    args.iter()
116                        .map(|arg| arg.to_string())
117                        .collect::<Vec<_>>()
118                        .join(", ")
119                )
120            }
121        }
122    }
123}