refactor(msl-out): create a type for bounds check iter items

Co-Authored-By: Erich Gubler <erichdongubler@gmail.com>
This commit is contained in:
Andy Leiserson 2025-04-08 16:08:57 -07:00 committed by Erich Gubler
parent a7afb56276
commit a0dbe5ebc6
2 changed files with 38 additions and 14 deletions

View File

@ -18,7 +18,11 @@ use crate::{
arena::{Handle, HandleSet},
back::{self, Baked},
common,
proc::{self, index, NameKey, TypeResolution},
proc::{
self,
index::{self, BoundsCheck},
NameKey, TypeResolution,
},
valid, FastHashMap, FastHashSet,
};
@ -723,13 +727,7 @@ impl<'a> ExpressionContext<'a> {
fn bounds_check_iter(
&self,
chain: Handle<crate::Expression>,
) -> impl Iterator<
Item = (
Handle<crate::Expression>,
index::GuardedIndex,
index::IndexableLength,
),
> + '_ {
) -> impl Iterator<Item = BoundsCheck> + '_ {
index::bounds_check_iter(chain, self.module, self.function, self.info)
}
@ -2778,7 +2776,13 @@ impl<W: Write> Writer<W> {
let mut check_written = false;
// Iterate over the access chain, handling each required bounds check.
for (base, index, length) in context.bounds_check_iter(chain) {
for item in context.bounds_check_iter(chain) {
let BoundsCheck {
base,
index,
length,
} = item;
if check_written {
write!(self.out, " && ")?;
} else {

View File

@ -342,12 +342,27 @@ pub fn access_needs_check(
Some(length)
}
/// Items returned by the [`bounds_check_iter`] iterator.
#[cfg_attr(not(feature = "msl-out"), allow(dead_code))]
pub(crate) struct BoundsCheck {
/// The base of the [`Access`] or [`AccessIndex`] expression.
///
/// [`Access`]: crate::Expression::Access
/// [`AccessIndex`]: crate::Expression::AccessIndex
pub base: Handle<crate::Expression>,
/// The index being accessed.
pub index: GuardedIndex,
/// The length of `base`.
pub length: IndexableLength,
}
/// Returns an iterator of accesses within the chain of `Access` and
/// `AccessIndex` expressions starting from `chain` that may need to be
/// bounds-checked at runtime.
///
/// They're yielded as `(base, index)` pairs, where `base` is the type that the
/// access expression will produce and `index` is the index being used.
/// Items are yielded as [`BoundsCheck`] instances.
///
/// Accesses through a struct are omitted, since you never need a bounds check
/// for accessing a struct field.
@ -359,7 +374,7 @@ pub(crate) fn bounds_check_iter<'a>(
module: &'a crate::Module,
function: &'a crate::Function,
info: &'a valid::FunctionInfo,
) -> impl Iterator<Item = (Handle<crate::Expression>, GuardedIndex, IndexableLength)> + 'a {
) -> impl Iterator<Item = BoundsCheck> + 'a {
iter::from_fn(move || {
let (next_expr, result) = match function.expressions[chain] {
crate::Expression::Access { base, index } => {
@ -384,8 +399,13 @@ pub(crate) fn bounds_check_iter<'a>(
})
.flatten()
.filter_map(|(base, index)| {
access_needs_check(base, index, module, &function.expressions, info)
.map(|length| (base, index, length))
access_needs_check(base, index, module, &function.expressions, info).map(|length| {
BoundsCheck {
base,
index,
length,
}
})
})
}