midenc_codegen_masm/masm/
mod.rs

1mod function;
2pub mod intrinsics;
3mod module;
4mod program;
5mod region;
6
7pub use midenc_hir::{
8    Local, LocalId, MasmBlock as Block, MasmBlockId as BlockId, MasmImport as Import, MasmOp as Op,
9    ModuleImportInfo,
10};
11use serde::{Deserialize, Serialize};
12
13pub use self::{
14    function::{FrozenFunctionList, Function, FunctionList},
15    module::{FrozenModuleTree, Module, ModuleTree},
16    program::{Library, Program},
17    region::Region,
18};
19
20/// This represents a descriptor for a pointer translated from the IR into a form suitable for
21/// referencing data in Miden's linear memory.
22#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
23pub struct NativePtr {
24    /// This is the address of the word containing the first byte of data
25    pub waddr: u32,
26    /// This is the element index of the word referenced by `waddr` containing the first byte of
27    /// data
28    ///
29    /// Each element is assumed to be a 32-bit value/chunk
30    pub index: u8,
31    /// This is the byte offset into the 32-bit chunk referenced by `index`
32    ///
33    /// This offset is where the data referenced by the pointer actually starts.
34    pub offset: u8,
35    /// This is the assumed address space of the pointer value.
36    ///
37    /// This address space is unknown by default, but can be specified if known statically.
38    /// The address space determines whether the pointer is valid in certain contexts. For
39    /// example, attempting to load a pointer with address space 0 is invalid if not operating
40    /// in the root context.
41    ///
42    /// Currently this has no effect, but is here as we expand support for multiple memories.
43    pub addrspace: midenc_hir::AddressSpace,
44}
45impl NativePtr {
46    pub fn new(waddr: u32, index: u8, offset: u8) -> Self {
47        Self {
48            waddr,
49            index,
50            offset,
51            addrspace: Default::default(),
52        }
53    }
54
55    /// Translates a raw pointer (assumed to be in a byte-addressable address space) to
56    /// a native pointer value, in the default [hir::AddressSpace].
57    pub fn from_ptr(addr: u32) -> Self {
58        // The native word address for `addr` is derived by splitting
59        // the byte-addressable space into 32-bit chunks, each chunk
60        // belonging to a single field element. Thus, each word of the
61        // native address space represents 128 bits of byte-addressable
62        // memory.
63        //
64        // By dividing `addr` by 16, we get the word index (i.e. address)
65        // where the data starts.
66        let waddr = addr / 16;
67        // If our address is not word-aligned, we need to determine what
68        // element index contains the 32-bit chunk where the data begins
69        let woffset = addr % 16;
70        let index = (woffset / 4) as u8;
71        // If our address is not element-aligned, we need to determine
72        // what byte offset contains the first byte of the data
73        let offset = (woffset % 4) as u8;
74        Self {
75            waddr,
76            index,
77            offset,
78            addrspace: Default::default(),
79        }
80    }
81
82    /// Returns true if this pointer is aligned to a word boundary
83    pub const fn is_word_aligned(&self) -> bool {
84        self.index == 0 && self.offset == 0
85    }
86
87    /// Returns true if this pointer is aligned to a field element boundary
88    pub const fn is_element_aligned(&self) -> bool {
89        self.offset == 0
90    }
91
92    /// Returns true if this pointer is not word or element aligned
93    pub const fn is_unaligned(&self) -> bool {
94        self.offset > 0
95    }
96
97    /// Returns the byte alignment implied by this pointer value.
98    ///
99    /// For example, a pointer to the first word in linear memory, i.e. address 0,
100    /// with an element index of 1, and offset of 16, is equivalent to an address
101    /// in byte-addressable memory of 48, which has an implied alignment of 16 bytes.
102    pub const fn alignment(&self) -> u32 {
103        2u32.pow(self.as_ptr().trailing_zeros())
104    }
105
106    /// Converts this native pointer back to a byte-addressable pointer value
107    pub const fn as_ptr(&self) -> u32 {
108        (self.waddr * 16) + (self.index as u32 * 4) + self.offset as u32
109    }
110}