Skip to main content

qcode/value/util/
body_mut.rs

1//! The exclusive mutation backing for a function pass ([`BodyMut`]).
2//!
3//! [`BodyView`] gives the read layer a `Copy` static provider that
4//! routes arena reads to the pass's own function. [`BodyMut`] is its mutable
5//! sibling: a single function's arenas borrowed `&mut` in place from
6//! `Context.bodies[id]` for exclusive mutation by one worker (the driver's
7//! `Context::split` hands out disjoint body borrows).
8//!
9//! All *shared* data (types, varnodes, spaces, registers, name map) stays behind
10//! the `&Shared` view, reachable read-only. The inherent verb + read methods below
11//! route each write to the borrowed function's arena; a function pass must not mutate another
12//! function (asserted). The module-scope twin of every verb is an inherent method
13//! on [`Context`]; the shorter-lived reborrow needed to
14//! hand the host to a value that owns it by value (a [`Builder`](crate::builder::Builder)
15//! or a mutation `BaseRef`) is [`BodyMut::reborrow`].
16
17use crate::{
18    context::Context,
19    error::{Error, ErrorTy, Result},
20    value::{
21        BlockParamRef, BlockRef, BodyView, FunctionBody, FunctionId, FunctionRef, InstructionRef,
22        QCodeView, ValueId,
23        block::{BasicBlock, BlockId, EdgeData, EdgeId},
24        block_param::{BlockParam, BlockParamId},
25        insn::{Instruction, InstructionId, Mnemonic},
26    },
27};
28
29/// A single function borrowed `&mut` in place from `Context.bodies[id]` for
30/// exclusive mutation (its interface stays in `Context.interfaces[id]`,
31/// reachable read-only through `interfaces`).
32///
33/// Out of scope (and asserted against on construction): a function with
34/// *reattributed* blocks — a roster block stored in, or parented to, a different
35/// function. Those functions go through the sequential (module) path.
36pub struct BodyMut<'a, 'str> {
37    pub fun: &'a mut FunctionBody<'str>,
38    /// The module's shared IR state, **read-only**. A checked-out function pass
39    /// reaches shared data (types, literals, spaces, registers) immutably; it
40    /// mints types/literals through the interners' `&self` paths, and mints no
41    /// varnodes/temp-spaces (only the V1 argpromote pass does, and it runs on
42    /// the module path). Holds **no** `&Context` — bodies are out of reach by
43    /// construction (context-split stage 5b-ii Pin B).
44    pub shared: &'a crate::context::Shared<'str>,
45    /// Every function's published interface (never checked out): the
46    /// caller-reasoning surface a pass may consult about its callees.
47    pub interfaces:
48        &'a jstd::registry::Registry<FunctionId, crate::value::function::FunctionInterface<'str>>,
49}
50
51impl<'a, 'str> BodyMut<'a, 'str> {
52    /// Wrap `fun` over the module's shared state and interface registry. Block
53    /// ownership is now derived from the storing arena (a rostered block lives in
54    /// `fun`'s own arena by construction), so there is no reattribution state left
55    /// to scan for here.
56    pub fn new(
57        fun: &'a mut FunctionBody<'str>,
58        shared: &'a crate::context::Shared<'str>,
59        interfaces: &'a jstd::registry::Registry<
60            FunctionId,
61            crate::value::function::FunctionInterface<'str>,
62        >,
63    ) -> Self {
64        Self {
65            fun,
66            shared,
67            interfaces,
68        }
69    }
70
71    /// Wrap `fun` (checked out under `id`) over a whole module `&Context` — the
72    /// module/test-scope convenience constructor (narrows to the shared state +
73    /// interface registry).
74    pub fn from_ctx(fun: &'a mut FunctionBody<'str>, ctx: &'a Context<'str>) -> Self {
75        Self::new(fun, &ctx.shared, &ctx.interfaces)
76    }
77
78    /// A shorter-lived `BodyMut` reborrowing this one's exclusive references, so
79    /// the host can be handed to a mutation ref (which owns its host by value)
80    /// without consuming the original.
81    pub fn reborrow(&mut self) -> BodyMut<'_, 'str> {
82        BodyMut {
83            fun: &mut *self.fun,
84            shared: self.shared,
85            interfaces: self.interfaces,
86        }
87    }
88
89    /// Narrows this pass backing to the concrete body-local builder.
90    pub fn builder(&mut self, block: BlockId) -> crate::builder::Builder<'str, '_> {
91        crate::builder::Builder::new(&mut *self.fun, self.shared, self.interfaces, block)
92    }
93}
94
95/// The verb + read surface of a checked-out function pass, delegating to the
96/// owned `FunctionBody`'s inherent verbs and `self.shared`. The module-scope twin of
97/// each verb is an inherent method on [`Context`]; the
98/// primitives below (`function{,_mut}`/`shared`/`view`, and the no-op
99/// call-site cache) are the checked-out specializations.
100impl<'a, 'str> BodyMut<'a, 'str> {
101    // ---- primitives ---------------------------------------------------------
102
103    /// The owned function's storage (write). Panics if `f` is not this function.
104    pub fn function_mut(&mut self, f: FunctionId) -> &mut FunctionBody<'str> {
105        assert_eq!(
106            f,
107            self.fun.id(),
108            "a checked-out function pass may not mutate another function"
109        );
110        self.fun
111    }
112    /// The owned function's storage (read).
113    pub fn function(&self, f: FunctionId) -> &FunctionBody<'str> {
114        assert_eq!(
115            f,
116            self.fun.id(),
117            "a checked-out function pass may not read another function's arenas mutably"
118        );
119        self.fun
120    }
121    /// The module's shared IR state ([`Shared`]) (read).
122    ///
123    /// [`Shared`]: crate::context::Shared
124    pub fn shr(&self) -> &crate::context::Shared<'str> {
125        self.shared
126    }
127    /// The static immutable provider for shared reads over this pass body.
128    pub fn view(&self) -> BodyView<'_, 'str> {
129        BodyView::new(&*self.fun, self.shared, self.interfaces)
130    }
131    // ---- function-scoped read wrappers --------------------------------------
132
133    /// A read [`BlockRef`] over `id`, body-routed.
134    pub fn block_ref(&self, id: BlockId) -> BlockRef<'str, '_, BodyView<'_, 'str>> {
135        self.view().block_ref(id)
136    }
137    /// A read [`InstructionRef`] over `id`.
138    pub fn insn_ref(&self, id: InstructionId) -> InstructionRef<'str, '_, BodyView<'_, 'str>> {
139        self.view().insn_ref(id)
140    }
141    /// A read [`BlockParamRef`] over `id`.
142    pub fn param_ref(&self, id: BlockParamId) -> BlockParamRef<'str, '_, BodyView<'_, 'str>> {
143        self.view().param_ref(id)
144    }
145    /// A read [`FunctionRef`] over `id`.
146    pub fn function_ref(&self, id: FunctionId) -> FunctionRef<'str, '_, BodyView<'_, 'str>> {
147        self.view().function_ref(id)
148    }
149
150    // ---- births -------------------------------------------------------------
151    //
152    // (The derived mut accessors — `instruction_mut`/`block_mut`/
153    // `block_param_mut` — are [`QCodeMut`](crate::value::QCodeMut) defaults.)
154
155    pub fn push_edge(&mut self, edge: EdgeData) -> EdgeId {
156        self.fun.edges.push(edge)
157    }
158
159    pub fn push_insn(&mut self, insn: Instruction<'str>) -> InstructionId {
160        self.fun.push_insn(insn)
161    }
162
163    pub fn push_block(&mut self, block: BasicBlock<'str>) -> BlockId {
164        self.fun.push_block(block)
165    }
166
167    pub fn make_block(&mut self) -> BlockId {
168        self.fun.make_block()
169    }
170
171    pub fn push_block_param(&mut self, param: BlockParam<'str>) -> BlockParamId {
172        self.fun.push_block_param(param)
173    }
174
175    pub fn push_mnemonic(&mut self, mnemonic: Mnemonic, size: usize) -> InstructionId {
176        let shared = self.shared;
177        self.fun.push_mnemonic(shared, mnemonic, size)
178    }
179
180    pub fn push_mnemonic_with_type(
181        &mut self,
182        mnemonic: Mnemonic,
183        type_id: crate::types::TypeId,
184    ) -> InstructionId {
185        self.fun.push_mnemonic_with_type(mnemonic, type_id)
186    }
187
188    // ---- CFG / use-map verbs ------------------------------------------------
189    //
190    // The body-local mutation verbs live on the [`QCodeMut`] trait
191    // (`value::view_mut`), shared with the module host. Only the verbs whose
192    // spelling diverges between hosts stay inherent here.
193
194    /// Remove CFG edge `edge_id` (unqualified; `EdgeId` is body-local). The
195    /// module-path twin is the function-qualified
196    /// [`Context::remove_cfg_edge`](crate::context::Context::remove_cfg_edge).
197    pub fn remove_cfg_edge(&mut self, edge_id: EdgeId) {
198        self.fun.remove_cfg_edge(edge_id)
199    }
200
201    // ---- names --------------------------------------------------------------
202
203    pub fn register_local_name(
204        &mut self,
205        id: ValueId,
206        name: std::borrow::Cow<'str, str>,
207        old_name: Option<&str>,
208    ) -> Result<()> {
209        let existing = match id.name_scope_function() {
210            Some(func) => self
211                .function(func)
212                .names
213                .get(&name)
214                .map(|id| id.qualify(func)),
215            None => self.shr().get_named(&name),
216        };
217        if let Some(existing) = existing {
218            return if existing == id {
219                Ok(())
220            } else {
221                Err(Error::spanless(ErrorTy::DuplicateName(name.to_string())))
222            };
223        }
224        match id.name_scope_function() {
225            Some(func) => self
226                .function_mut(func)
227                .names
228                .register(name, id.localize(func), old_name),
229            None => {
230                unimplemented!("a checked-out host has read-only shared access (mints via &self)")
231            }
232        }
233    }
234}