Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion crates/cairo-lang-lowering/src/cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use crate::objects::{
use crate::{
Block, BlockEnd, Location, Lowered, MatchArm, MatchEnumInfo, MatchEnumValue, MatchInfo,
StatementDesnap, StatementEnumConstruct, StatementIntoBox, StatementSnapshot,
StatementStructConstruct, VarRemapping, VarUsage, Variable,
StatementStructConstruct, StatementUnbox, VarRemapping, VarUsage, Variable,
};

type LookupCache = (CacheLookups, Vec<(DefsFunctionWithBodyIdCached, MultiLoweringCached)>);
Expand Down Expand Up @@ -911,6 +911,7 @@ enum StatementCached {

// Boxing.
IntoBox(StatementIntoBoxCached),
Unbox(StatementUnboxCached),

Snapshot(StatementSnapshotCached),
Desnap(StatementDesnapCached),
Expand Down Expand Up @@ -939,6 +940,7 @@ impl StatementCached {
Statement::IntoBox(stmt) => {
StatementCached::IntoBox(StatementIntoBoxCached::new(stmt, ctx))
}
Statement::Unbox(stmt) => StatementCached::Unbox(StatementUnboxCached::new(stmt, ctx)),
}
}
fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> Statement<'db> {
Expand All @@ -953,6 +955,7 @@ impl StatementCached {
StatementCached::Snapshot(stmt) => Statement::Snapshot(stmt.embed(ctx)),
StatementCached::Desnap(stmt) => Statement::Desnap(stmt.embed(ctx)),
StatementCached::IntoBox(stmt) => Statement::IntoBox(stmt.embed(ctx)),
StatementCached::Unbox(stmt) => Statement::Unbox(stmt.embed(ctx)),
}
}
}
Expand Down Expand Up @@ -1270,6 +1273,23 @@ impl StatementIntoBoxCached {
}
}

#[derive(Serialize, Deserialize)]
struct StatementUnboxCached {
input: VarUsageCached,
output: usize,
}
impl StatementUnboxCached {
fn new<'db>(stmt: StatementUnbox<'db>, ctx: &mut CacheSavingContext<'db>) -> Self {
Self { input: VarUsageCached::new(stmt.input, ctx), output: stmt.output.index() }
}
fn embed<'db>(self, ctx: &mut CacheLoadingContext<'db>) -> StatementUnbox<'db> {
StatementUnbox {
input: self.input.embed(ctx),
output: ctx.lowered_variables_id[self.output],
}
}
}

#[derive(Serialize, Deserialize, Clone)]
struct LocationCached {
/// The stable location of the object.
Expand Down
3 changes: 2 additions & 1 deletion crates/cairo-lang-lowering/src/concretize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ pub fn concretize_lowered<'db>(
| Statement::Desnap(_)
| Statement::StructConstruct(_)
| Statement::StructDestructure(_)
| Statement::IntoBox(_) => {}
| Statement::IntoBox(_)
| Statement::Unbox(_) => {}
}
}
if let BlockEnd::Match { info } = &mut block.end {
Expand Down
13 changes: 12 additions & 1 deletion crates/cairo-lang-lowering/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use salsa::Database;

use crate::objects::{
MatchExternInfo, Statement, StatementCall, StatementConst, StatementIntoBox,
StatementStructDestructure, VariableId,
StatementStructDestructure, StatementUnbox, VariableId,
};
use crate::{
Block, BlockEnd, Lowered, MatchArm, MatchEnumInfo, MatchEnumValue, MatchInfo, StatementDesnap,
Expand Down Expand Up @@ -189,6 +189,7 @@ impl<'db> DebugWithDb<'db> for Statement<'db> {
Statement::Snapshot(stmt) => stmt.fmt(f, ctx),
Statement::Desnap(stmt) => stmt.fmt(f, ctx),
Statement::IntoBox(stmt) => stmt.fmt(f, ctx),
Statement::Unbox(stmt) => stmt.fmt(f, ctx),
}
}
}
Expand Down Expand Up @@ -376,3 +377,13 @@ impl<'db> DebugWithDb<'db> for StatementIntoBox<'db> {
write!(f, ")")
}
}

impl<'db> DebugWithDb<'db> for StatementUnbox<'db> {
type Db = LoweredFormatter<'db>;

fn fmt(&self, f: &mut std::fmt::Formatter<'_>, ctx: &Self::Db) -> std::fmt::Result {
write!(f, "unbox(")?;
self.input.fmt(f, ctx)?;
write!(f, ")")
}
}
27 changes: 26 additions & 1 deletion crates/cairo-lang-lowering/src/lower/generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ use crate::objects::{
Statement, StatementCall, StatementConst, StatementStructConstruct, StatementStructDestructure,
VarUsage,
};
use crate::{StatementDesnap, StatementEnumConstruct, StatementIntoBox, StatementSnapshot};
use crate::{
StatementDesnap, StatementEnumConstruct, StatementIntoBox, StatementSnapshot, StatementUnbox,
};

#[derive(Clone, Default)]
pub struct StatementsBuilder<'db> {
Expand Down Expand Up @@ -276,3 +278,26 @@ impl<'db> IntoBox<'db> {
VarUsage { var_id: output, location: self.location }
}
}

/// Generator for [StatementUnbox].
pub struct Unbox<'db> {
pub input: VarUsage<'db>,
pub location: LocationId<'db>,
}
impl<'db> Unbox<'db> {
pub fn add(
self,
ctx: &mut LoweringContext<'db, '_>,
builder: &mut StatementsBuilder<'db>,
) -> VarUsage<'db> {
let box_ty = extract_matches!(
ctx.variables[self.input.var_id].ty.long(ctx.db),
semantic::TypeLongId::Concrete
);
let output_ty =
extract_matches!(box_ty.generic_args(ctx.db)[0], semantic::GenericArgumentId::Type);
let output = ctx.new_var(VarRequest { ty: output_ty, location: self.location });
builder.push_statement(Statement::Unbox(StatementUnbox { input: self.input, output }));
VarUsage { var_id: output, location: self.location }
}
}
9 changes: 8 additions & 1 deletion crates/cairo-lang-lowering/src/lower/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1391,14 +1391,21 @@ fn perform_function_call<'db>(
// Extern function.
assert!(coupon_input.is_none(), "Extern functions cannot have a __coupon__ argument.");

// Handle into_box specially - emit IntoBox instead of a call.
// Handle boxing - place a placeholder instead of calling the libfunc just yet, for
// later optimization purposes.
let info = ctx.db.core_info();
if extern_function_id == info.into_box {
assert!(extra_ret_tys.is_empty(), "into_box should not have extra return types");
let input = inputs.into_iter().exactly_one().expect("into_box expects exactly one input");
let res = generators::IntoBox { input, location }.add(ctx, &mut builder.statements);
return Ok((vec![], LoweredExpr::AtVariable(res)));
}
if extern_function_id == info.unbox {
assert!(extra_ret_tys.is_empty(), "unbox should not have extra return types");
let input = inputs.into_iter().exactly_one().expect("unbox expects exactly one input");
let res = generators::Unbox { input, location }.add(ctx, &mut builder.statements);
return Ok((vec![], LoweredExpr::AtVariable(res)));
}

let ret_tys = extern_facade_return_tys(ctx, ret_ty);
let call_result = generators::Call {
Expand Down
4 changes: 2 additions & 2 deletions crates/cairo-lang-lowering/src/lower/test_data/for
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ Parameters: v0: core::RangeCheck, v1: core::gas::GasBuiltin, v2: core::box::Box:
blk0 (root):
Statements:
(v3: core::array::Array::<core::felt252>) <- core::array::array_new::<core::felt252>()
(v4: core::array::Span::<core::felt252>) <- core::box::unbox::<core::array::Span::<core::felt252>>(v2)
(v4: core::array::Span::<core::felt252>) <- unbox(v2)
(v5: core::array::SpanIter::<core::felt252>) <- struct_construct(v4)
(v6: core::RangeCheck, v7: core::gas::GasBuiltin, v8: core::panics::PanicResult::<(core::array::SpanIter::<core::felt252>, core::array::Array::<core::felt252>, ())>) <- test::foo[78-125](v0, v1, v5, v3)
End:
Expand Down Expand Up @@ -394,7 +394,7 @@ End:
blk2:
Statements:
(v13: core::gas::GasBuiltin) <- core::gas::redeposit_gas(v5)
(v14: @core::felt252) <- core::box::unbox::<@core::felt252>(v11)
(v14: @core::felt252) <- unbox(v11)
(v15: core::felt252) <- desnap(v14)
(v16: core::array::Array::<core::felt252>) <- core::array::array_append::<core::felt252>(v3, v15)
(v17: core::array::Span::<core::felt252>) <- struct_construct(v10)
Expand Down
4 changes: 2 additions & 2 deletions crates/cairo-lang-lowering/src/lower/test_data/loop
Original file line number Diff line number Diff line change
Expand Up @@ -2277,7 +2277,7 @@ End:

blk2:
Statements:
(v10: core::integer::u32) <- core::box::unbox::<core::integer::u32>(v8)
(v10: core::integer::u32) <- unbox(v8)
(v11: core::integer::u32) <- 1
End:
Match(match core::integer::u32_eq(v10, v11) {
Expand Down Expand Up @@ -2612,7 +2612,7 @@ End:

blk2:
Statements:
(v10: core::integer::u32) <- core::box::unbox::<core::integer::u32>(v8)
(v10: core::integer::u32) <- unbox(v8)
(v11: core::integer::u32) <- 1
End:
Match(match core::integer::u32_eq(v10, v11) {
Expand Down
16 changes: 16 additions & 0 deletions crates/cairo-lang-lowering/src/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ pub enum Statement<'db> {

// Boxing.
IntoBox(StatementIntoBox<'db>),
Unbox(StatementUnbox<'db>),
}
impl<'db> Statement<'db> {
pub fn inputs(&self) -> &[VarUsage<'db>] {
Expand All @@ -309,6 +310,7 @@ impl<'db> Statement<'db> {
Statement::Snapshot(stmt) => std::slice::from_ref(&stmt.input),
Statement::Desnap(stmt) => std::slice::from_ref(&stmt.input),
Statement::IntoBox(stmt) => std::slice::from_ref(&stmt.input),
Statement::Unbox(stmt) => std::slice::from_ref(&stmt.input),
}
}

Expand All @@ -322,6 +324,7 @@ impl<'db> Statement<'db> {
Statement::Snapshot(stmt) => std::slice::from_mut(&mut stmt.input),
Statement::Desnap(stmt) => std::slice::from_mut(&mut stmt.input),
Statement::IntoBox(stmt) => std::slice::from_mut(&mut stmt.input),
Statement::Unbox(stmt) => std::slice::from_mut(&mut stmt.input),
}
}

Expand All @@ -335,6 +338,7 @@ impl<'db> Statement<'db> {
Statement::Snapshot(stmt) => stmt.outputs.as_slice(),
Statement::Desnap(stmt) => std::slice::from_ref(&stmt.output),
Statement::IntoBox(stmt) => std::slice::from_ref(&stmt.output),
Statement::Unbox(stmt) => std::slice::from_ref(&stmt.output),
}
}

Expand All @@ -348,6 +352,7 @@ impl<'db> Statement<'db> {
Statement::Snapshot(stmt) => stmt.outputs.as_mut_slice(),
Statement::Desnap(stmt) => std::slice::from_mut(&mut stmt.output),
Statement::IntoBox(stmt) => std::slice::from_mut(&mut stmt.output),
Statement::Unbox(stmt) => std::slice::from_mut(&mut stmt.output),
}
}
pub fn location(&self) -> Option<LocationId<'db>> {
Expand All @@ -361,6 +366,7 @@ impl<'db> Statement<'db> {
Statement::Snapshot(stmt) => Some(stmt.input.location),
Statement::Desnap(stmt) => Some(stmt.input.location),
Statement::IntoBox(stmt) => Some(stmt.input.location),
Statement::Unbox(stmt) => Some(stmt.input.location),
}
}
pub fn location_mut(&mut self) -> Option<&mut LocationId<'db>> {
Expand All @@ -373,6 +379,7 @@ impl<'db> Statement<'db> {
Statement::Snapshot(stmt) => Some(&mut stmt.input.location),
Statement::Desnap(stmt) => Some(&mut stmt.input.location),
Statement::IntoBox(stmt) => Some(&mut stmt.input.location),
Statement::Unbox(stmt) => Some(&mut stmt.input.location),
}
}
}
Expand Down Expand Up @@ -488,6 +495,15 @@ pub struct StatementIntoBox<'db> {
pub output: VariableId,
}

/// A statement that unboxes a value.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StatementUnbox<'db> {
/// The boxed value to unbox.
pub input: VarUsage<'db>,
/// The variable to bind the unboxed value to.
pub output: VariableId,
}

/// An arm of a match statement.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MatchArm<'db> {
Expand Down
2 changes: 1 addition & 1 deletion crates/cairo-lang-lowering/src/optimizations/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ fn default_moveable_functions() -> Vec<String> {
["bool_not_impl"],
["felt252_add", "felt252_sub", "felt252_mul", "felt252_div"],
["array::array_new", "array::array_append"],
["box::unbox", "box::box_forward_snapshot"],
["box::box_forward_snapshot"],
)
.map(|s| s.to_string())
.collect();
Expand Down
29 changes: 12 additions & 17 deletions crates/cairo-lang-lowering/src/optimizations/const_folding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ use crate::{
Block, BlockEnd, BlockId, DependencyType, Lowered, LoweringStage, MatchArm, MatchEnumInfo,
MatchExternInfo, MatchInfo, Statement, StatementCall, StatementConst, StatementDesnap,
StatementEnumConstruct, StatementIntoBox, StatementSnapshot, StatementStructConstruct,
StatementStructDestructure, VarRemapping, VarUsage, Variable, VariableArena, VariableId,
StatementStructDestructure, StatementUnbox, VarRemapping, VarUsage, Variable, VariableArena,
VariableId,
};

/// Converts a const value to a specialization arg.
Expand Down Expand Up @@ -356,6 +357,16 @@ impl<'db, 'mt> ConstFoldingContext<'db, 'mt> {
*stmt = Statement::Const(StatementConst::new_boxed(const_value, *output));
}
}
Statement::Unbox(StatementUnbox { input, output }) => {
if let Some(VarInfo::Box(inner)) = self.var_info.get(&input.var_id) {
let inner = inner.as_ref().clone();
if let VarInfo::Const(inner) =
self.var_info.entry(*output).insert_entry(inner).get()
{
*stmt = Statement::Const(StatementConst::new_flat(*inner, *output));
}
}
}
}
}

Expand Down Expand Up @@ -649,19 +660,6 @@ impl<'db, 'mt> ConstFoldingContext<'db, 'mt> {
self.storage_base_address_const.concretize(db, vec![arg]).lowered(db);
}
None
} else if id == self.unbox {
if let VarInfo::Box(inner) = self.var_info.get(&stmt.inputs[0].var_id)? {
let inner = inner.as_ref().clone();
if let VarInfo::Const(inner) =
self.var_info.entry(stmt.outputs[0]).insert_entry(inner).get()
{
return Some(Statement::Const(StatementConst::new_flat(
*inner,
stmt.outputs[0],
)));
}
}
None
} else if self.upcast_fns.contains(&id) {
let int_value = self.as_int(stmt.inputs[0].var_id)?;
let output = stmt.outputs[0];
Expand Down Expand Up @@ -1473,8 +1471,6 @@ pub struct ConstFoldingLibfuncInfo<'db> {
felt_mul: ExternFunctionId<'db>,
/// The `felt252_div` libfunc.
felt_div: ExternFunctionId<'db>,
/// The `unbox` libfunc.
unbox: ExternFunctionId<'db>,
/// The `box_forward_snapshot` libfunc.
box_forward_snapshot: GenericFunctionId<'db>,
/// The set of functions that check if numbers are equal.
Expand Down Expand Up @@ -1631,7 +1627,6 @@ impl<'db> ConstFoldingLibfuncInfo<'db> {
felt_add: core.extern_function_id("felt252_add"),
felt_mul: core.extern_function_id("felt252_mul"),
felt_div: core.extern_function_id("felt252_div"),
unbox: box_module.extern_function_id("unbox"),
box_forward_snapshot: box_module.generic_function_id("box_forward_snapshot"),
eq_fns,
uadd_fns,
Expand Down
10 changes: 9 additions & 1 deletion crates/cairo-lang-lowering/src/optimizations/dedup_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::utils::{Rebuilder, RebuilderEx};
use crate::{
Block, BlockEnd, BlockId, Lowered, Statement, StatementCall, StatementConst, StatementDesnap,
StatementEnumConstruct, StatementIntoBox, StatementSnapshot, StatementStructConstruct,
StatementStructDestructure, VarRemapping, VarUsage, VariableArena, VariableId,
StatementStructDestructure, StatementUnbox, VarRemapping, VarUsage, VariableArena, VariableId,
};

/// A canonic representation of a block (used to find duplicated blocks).
Expand Down Expand Up @@ -63,6 +63,10 @@ enum CanonicStatement<'db> {
input: CanonicVar,
output: CanonicVar,
},
Unbox {
input: CanonicVar,
output: CanonicVar,
},
Snapshot {
input: CanonicVar,
outputs: [CanonicVar; 2],
Expand Down Expand Up @@ -170,6 +174,10 @@ impl<'db, 'a> CanonicBlockBuilder<'db, 'a> {
input: self.handle_input(input),
output: self.handle_output(output),
},
Statement::Unbox(StatementUnbox { input, output }) => CanonicStatement::Unbox {
input: self.handle_input(input),
output: self.handle_output(output),
},
}
}
}
Expand Down
Loading