-
Notifications
You must be signed in to change notification settings - Fork 559
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added gas redeposit optimization stage. (#6280)
- Loading branch information
Showing
11 changed files
with
397 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 94 additions & 0 deletions
94
crates/cairo-lang-lowering/src/optimizations/gas_redeposit.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#[cfg(test)] | ||
#[path = "gas_redeposit_test.rs"] | ||
mod test; | ||
|
||
use cairo_lang_filesystem::flag::Flag; | ||
use cairo_lang_filesystem::ids::FlagId; | ||
use cairo_lang_semantic::corelib; | ||
use itertools::Itertools; | ||
|
||
use crate::db::LoweringGroup; | ||
use crate::ids::{ConcreteFunctionWithBodyId, SemanticFunctionIdEx}; | ||
use crate::implicits::FunctionImplicitsTrait; | ||
use crate::{BlockId, FlatBlockEnd, FlatLowered, Statement, StatementCall}; | ||
|
||
/// Adds redeposit gas actions. | ||
/// | ||
/// The algorithm is as follows: | ||
/// Check if the function will have the `GasBuiltin` implicit after the lower_implicits stage. | ||
/// If so, add a `redeposit_gas` call at the beginning of every branch in the code. | ||
/// Otherwise, do nothing. | ||
/// | ||
/// Note that for implementation simplicity this stage must be applied before `LowerImplicits` | ||
/// stage. | ||
pub fn gas_redeposit( | ||
db: &dyn LoweringGroup, | ||
function_id: ConcreteFunctionWithBodyId, | ||
lowered: &mut FlatLowered, | ||
) { | ||
if lowered.blocks.is_empty() { | ||
return; | ||
} | ||
if !matches!( | ||
db.get_flag(FlagId::new(db.upcast(), "add_redeposit_gas")), | ||
Some(flag) if matches!(*flag, Flag::AddRedepositGas(true)) | ||
) { | ||
return; | ||
} | ||
let gb_ty = corelib::get_core_ty_by_name(db.upcast(), "GasBuiltin".into(), vec![]); | ||
// Checking if the implicits of this function past lowering includes `GasBuiltin`. | ||
if let Ok(implicits) = db.function_with_body_implicits(function_id) { | ||
if !implicits.into_iter().contains(&gb_ty) { | ||
return; | ||
} | ||
} | ||
assert!( | ||
lowered.parameters.iter().all(|p| lowered.variables[*p].ty != gb_ty), | ||
"`GasRedeposit` stage must be called before `LowerImplicits` stage" | ||
); | ||
|
||
let redeposit_gas = corelib::get_function_id( | ||
db.upcast(), | ||
corelib::core_submodule(db.upcast(), "gas"), | ||
"redeposit_gas".into(), | ||
vec![], | ||
) | ||
.lowered(db); | ||
let mut stack = vec![BlockId::root()]; | ||
let mut visited = vec![false; lowered.blocks.len()]; | ||
let mut redeposit_commands = vec![]; | ||
while let Some(block_id) = stack.pop() { | ||
if visited[block_id.0] { | ||
continue; | ||
} | ||
visited[block_id.0] = true; | ||
let block = &lowered.blocks[block_id]; | ||
match &block.end { | ||
FlatBlockEnd::Goto(block_id, _) => { | ||
stack.push(*block_id); | ||
} | ||
FlatBlockEnd::Match { info } => { | ||
let location = info.location().with_auto_generation_note(db, "withdraw_gas"); | ||
for arm in info.arms() { | ||
stack.push(arm.block_id); | ||
redeposit_commands.push((arm.block_id, location)); | ||
} | ||
} | ||
&FlatBlockEnd::Return(..) | FlatBlockEnd::Panic(_) => {} | ||
FlatBlockEnd::NotSet => unreachable!("Block end not set"), | ||
} | ||
} | ||
for (block_id, location) in redeposit_commands { | ||
let block = &mut lowered.blocks[block_id]; | ||
block.statements.insert( | ||
0, | ||
Statement::Call(StatementCall { | ||
function: redeposit_gas, | ||
inputs: vec![], | ||
with_coupon: false, | ||
outputs: vec![], | ||
location, | ||
}), | ||
); | ||
} | ||
} |
77 changes: 77 additions & 0 deletions
77
crates/cairo-lang-lowering/src/optimizations/gas_redeposit_test.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
use std::ops::Deref; | ||
use std::sync::Arc; | ||
|
||
use cairo_lang_debug::DebugWithDb; | ||
use cairo_lang_filesystem::db::FilesGroupEx; | ||
use cairo_lang_filesystem::flag::Flag; | ||
use cairo_lang_filesystem::ids::FlagId; | ||
use cairo_lang_semantic::test_utils::setup_test_function; | ||
use cairo_lang_test_utils::parse_test_file::{TestFileRunner, TestRunnerResult}; | ||
use cairo_lang_utils::ordered_hash_map::OrderedHashMap; | ||
|
||
use super::gas_redeposit; | ||
use crate::db::LoweringGroup; | ||
use crate::fmt::LoweredFormatter; | ||
use crate::ids::ConcreteFunctionWithBodyId; | ||
use crate::test_utils::LoweringDatabaseForTesting; | ||
|
||
cairo_lang_test_utils::test_file_test_with_runner!( | ||
gas_redeposit, | ||
"src/optimizations/test_data", | ||
{ | ||
gas_redeposit: "gas_redeposit", | ||
}, | ||
GetRedepositTestRunner | ||
); | ||
|
||
struct GetRedepositTestRunner { | ||
db: LoweringDatabaseForTesting, | ||
} | ||
impl Default for GetRedepositTestRunner { | ||
fn default() -> Self { | ||
let mut db = LoweringDatabaseForTesting::new(); | ||
let flag = FlagId::new(&db, "add_redeposit_gas"); | ||
db.set_flag(flag, Some(Arc::new(Flag::AddRedepositGas(true)))); | ||
Self { db } | ||
} | ||
} | ||
|
||
impl TestFileRunner for GetRedepositTestRunner { | ||
fn run( | ||
&mut self, | ||
inputs: &OrderedHashMap<String, String>, | ||
_args: &OrderedHashMap<String, String>, | ||
) -> TestRunnerResult { | ||
let db = &self.db; | ||
let (test_function, semantic_diagnostics) = setup_test_function( | ||
db, | ||
inputs["function"].as_str(), | ||
inputs["function_name"].as_str(), | ||
inputs["module_code"].as_str(), | ||
) | ||
.split(); | ||
let function_id = | ||
ConcreteFunctionWithBodyId::from_semantic(db, test_function.concrete_function_id); | ||
|
||
let before = | ||
db.concrete_function_with_body_postpanic_lowered(function_id).unwrap().deref().clone(); | ||
|
||
let lowering_diagnostics = db.module_lowering_diagnostics(test_function.module_id).unwrap(); | ||
|
||
let mut after = before.clone(); | ||
gas_redeposit(db, function_id, &mut after); | ||
|
||
TestRunnerResult::success(OrderedHashMap::from([ | ||
("semantic_diagnostics".into(), semantic_diagnostics), | ||
( | ||
"before".into(), | ||
format!("{:?}", before.debug(&LoweredFormatter::new(db, &before.variables))), | ||
), | ||
( | ||
"after".into(), | ||
format!("{:?}", after.debug(&LoweredFormatter::new(db, &after.variables))), | ||
), | ||
("lowering_diagnostics".into(), lowering_diagnostics.format(db)), | ||
])) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.