#![cfg(feature = "with-cheatcode")]
use crate::{
error::{panic::ToNativeAssertError, Result},
libfuncs::LibfuncHelper,
metadata::{runtime_bindings::RuntimeBindingsMeta, MetadataStorage},
utils::{get_integer_layout, ProgramRegistryExt},
};
use cairo_lang_sierra::{
extensions::{
core::{CoreLibfunc, CoreType},
starknet::testing::CheatcodeConcreteLibfunc,
ConcreteLibfunc,
},
program_registry::ProgramRegistry,
};
use melior::{
dialect::llvm::{self, alloca, AllocaOptions, LoadStoreOptions},
helpers::{ArithBlockExt, BuiltinBlockExt, LlvmBlockExt},
ir::{
attribute::{IntegerAttribute, TypeAttribute},
r#type::IntegerType,
Block, BlockLike, Location,
},
Context,
};
pub fn build<'ctx, 'this>(
context: &'ctx Context,
registry: &ProgramRegistry<CoreType, CoreLibfunc>,
entry: &'this Block<'ctx>,
location: Location<'ctx>,
helper: &LibfuncHelper<'ctx, 'this>,
metadata: &mut MetadataStorage,
info: &CheatcodeConcreteLibfunc,
) -> Result<()> {
let (result_type, result_layout) = registry.build_type_with_layout(
context,
helper,
metadata,
&info.branch_signatures()[0].vars[0].ty,
)?;
let result_ptr = helper
.init_block()
.append_operation(alloca(
context,
helper.init_block().const_int(context, location, 1, 64)?,
llvm::r#type::pointer(context, 0),
location,
AllocaOptions::new()
.align(Some(IntegerAttribute::new(
IntegerType::new(context, 64).into(),
result_layout.align().try_into()?,
)))
.elem_type(Some(TypeAttribute::new(result_type))),
))
.result(0)?
.into();
let selector = helper
.init_block()
.const_int(context, location, info.selector.clone(), 256)?;
let selector_ptr =
helper
.init_block()
.alloca_int(context, location, 256, get_integer_layout(256).align())?;
helper
.init_block()
.store(context, location, selector_ptr, selector)?;
let span_felt252_type = llvm::r#type::r#struct(
context,
&[llvm::r#type::r#struct(
context,
&[
llvm::r#type::pointer(context, 0),
IntegerType::new(context, 32).into(),
IntegerType::new(context, 32).into(),
IntegerType::new(context, 32).into(),
],
false,
)],
false,
);
let args_ptr = helper.init_block().alloca1(
context,
location,
span_felt252_type,
get_integer_layout(64).align(),
)?;
entry.store(context, location, args_ptr, entry.argument(0)?.into())?;
metadata
.get_mut::<RuntimeBindingsMeta>()
.to_native_assert_error("runtime bindings should be available")?
.vtable_cheatcode(
context,
helper,
entry,
location,
result_ptr,
selector_ptr,
args_ptr,
)?;
let result = entry.append_op_result(llvm::load(
context,
result_ptr,
result_type,
location,
LoadStoreOptions::new(),
))?;
helper.br(entry, 0, &[result], location)
}