sway_ir/
variable.rs

1//! A value representing a function-local variable.
2
3use crate::{
4    context::Context,
5    irtype::{Type, TypeContent},
6    pretty::DebugWithContext,
7    Constant,
8};
9
10/// A wrapper around an [ECS](https://github.com/orlp/slotmap) handle into the
11/// [`Context`].
12#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, DebugWithContext)]
13pub struct LocalVar(#[in_context(local_vars)] pub slotmap::DefaultKey);
14
15#[doc(hidden)]
16#[derive(Clone, DebugWithContext)]
17pub struct LocalVarContent {
18    pub ptr_ty: Type,
19    pub initializer: Option<Constant>,
20    pub mutable: bool,
21}
22
23impl LocalVar {
24    /// Return a new local of a specific type with an optional [`Constant`] initializer.  If a
25    /// local is marked as mutable then it is guaranteed to be on the stack rather than in
26    /// read-only memory.
27    pub fn new(
28        context: &mut Context,
29        ty: Type,
30        initializer: Option<Constant>,
31        mutable: bool,
32    ) -> Self {
33        let ptr_ty = Type::new_typed_pointer(context, ty);
34        let content = LocalVarContent {
35            ptr_ty,
36            initializer,
37            mutable,
38        };
39        LocalVar(context.local_vars.insert(content))
40    }
41
42    /// Return the type of this local variable, which is always a pointer.
43    pub fn get_type(&self, context: &Context) -> Type {
44        context.local_vars[self.0].ptr_ty
45    }
46
47    /// Return the inner (pointed to) type.
48    pub fn get_inner_type(&self, context: &Context) -> Type {
49        let TypeContent::TypedPointer(inner_ty) = self.get_type(context).get_content(context)
50        else {
51            unreachable!("Local var type is always a pointer.")
52        };
53        *inner_ty
54    }
55
56    /// Return the initializer for this local variable.
57    pub fn get_initializer<'a>(&self, context: &'a Context) -> Option<&'a Constant> {
58        context.local_vars[self.0].initializer.as_ref()
59    }
60
61    /// Return whether this local variable is mutable.
62    pub fn is_mutable(&self, context: &Context) -> bool {
63        context.local_vars[self.0].mutable
64    }
65
66    /// Change this local variable's mutability.
67    pub fn set_mutable(&self, context: &mut Context, mutable: bool) {
68        context.local_vars[self.0].mutable = mutable;
69    }
70}
71
72/// A wrapper around an [ECS](https://github.com/orlp/slotmap) handle into the
73/// [`Context`].
74#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, DebugWithContext)]
75pub struct GlobalVar(#[in_context(global_vars)] pub slotmap::DefaultKey);
76
77#[doc(hidden)]
78#[derive(Clone, DebugWithContext)]
79pub struct GlobalVarContent {
80    pub ptr_ty: Type,
81    pub initializer: Option<Constant>,
82    pub mutable: bool,
83}
84
85impl GlobalVar {
86    /// Return a new Global of a specific type with an optional [`Constant`] initializer.  If a
87    /// Global is marked as mutable then it is guaranteed to be on the stack rather than in
88    /// read-only memory.
89    pub fn new(
90        context: &mut Context,
91        ty: Type,
92        initializer: Option<Constant>,
93        mutable: bool,
94    ) -> Self {
95        let ptr_ty = Type::new_typed_pointer(context, ty);
96        let content = GlobalVarContent {
97            ptr_ty,
98            initializer,
99            mutable,
100        };
101        GlobalVar(context.global_vars.insert(content))
102    }
103
104    /// Return the type of this Global variable, which is always a pointer.
105    pub fn get_type(&self, context: &Context) -> Type {
106        context.global_vars[self.0].ptr_ty
107    }
108
109    /// Return the inner (pointed to) type.
110    pub fn get_inner_type(&self, context: &Context) -> Type {
111        let TypeContent::TypedPointer(inner_ty) = self.get_type(context).get_content(context)
112        else {
113            unreachable!("Global var type is always a pointer.")
114        };
115        *inner_ty
116    }
117
118    /// Return the initializer for this Global variable.
119    pub fn get_initializer<'a>(&self, context: &'a Context) -> Option<&'a Constant> {
120        context.global_vars[self.0].initializer.as_ref()
121    }
122
123    /// Return whether this Global variable is mutable.
124    pub fn is_mutable(&self, context: &Context) -> bool {
125        context.global_vars[self.0].mutable
126    }
127
128    /// Change this Global variable's mutability.
129    pub fn set_mutable(&self, context: &mut Context, mutable: bool) {
130        context.global_vars[self.0].mutable = mutable;
131    }
132}