11#![ cfg( feature = "with-libfunc-counter" ) ]
2-
2+ //! The libfunc counter feature is used to generate information counting how many time a libfunc has been called.
3+ //!
4+ //! When this feature is used, the compiler will call the important methods:
5+ //!
6+ //! 1. `count_libfunc`: called before every libfunc execution.
7+ //!
8+ //! 2. `build_array_counter`: called only once to build the array of counters (one for each libfuncs). The order of
9+ //! is based on the libfuncs' declaration order.
10+ //!
11+ //! 3. `store_array_counter`: called before finishing each entrypoint execution. It transforms the MLIR array into a
12+ //! Rust vector which is then stored in `LIBFUNC_COUNTER`, a static variable that registers the array of counters by
13+ //! execution, along with its `counter_id` (which is relative to the execution).
14+ //!
15+ //! In the context of Starknet contracts, we need to add support for building
16+ //! the arrays of counters for multiple executions. To do so, we need one important element, which must be set before every contract
17+ //! execution:
18+ //!
19+ //! A counter to track the ID of the current array of counter, which gets updated every time we switch to another
20+ //! contract. Since a contract can call other contracts, we need a way of restoring the counter after every execution.
21+ //!
22+ //! See `cairo-native-run` for an example on how to do it.
323use std:: { collections:: HashSet , os:: raw:: c_void, ptr} ;
424
525use melior:: {
@@ -104,7 +124,7 @@ impl LibfuncCounterMeta {
104124 )
105125 }
106126
107- pub fn build_counter_id < ' c , ' a > (
127+ fn build_counter_id < ' c , ' a > (
108128 & mut self ,
109129 context : & ' c Context ,
110130 module : & Module ,
@@ -136,6 +156,8 @@ impl LibfuncCounterMeta {
136156 block. append_op_result ( memref:: load ( libfunc_counter_id_ptr, & [ ] , location) )
137157 }
138158
159+ /// Indexes the array of counters and increments
160+ /// the one relative to the given libfunc index
139161 pub fn store_array_counter < ' c , ' a > (
140162 & mut self ,
141163 context : & Context ,
@@ -144,13 +166,11 @@ impl LibfuncCounterMeta {
144166 location : Location ,
145167 libfunc_amount : u32 ,
146168 ) -> Result < ( ) > {
147- let array_ty = llvm:: r#type:: array ( IntegerType :: new ( context, 32 ) . into ( ) , libfunc_amount) ;
148-
149- let counter_id = self . build_counter_id ( context, module, & block, location) ?;
169+ let counter_id = self . build_counter_id ( context, module, block, location) ?;
150170 let function_ptr = self . build_function (
151171 context,
152172 module,
153- & block,
173+ block,
154174 location,
155175 LibfuncCounterBinding :: StoreArrayCounter ,
156176 ) ?;
@@ -176,16 +196,15 @@ impl LibfuncCounterMeta {
176196 Ok ( ( ) )
177197 }
178198
179- fn build_array_counter < ' c , ' a > (
199+ /// Build the array of counters
200+ fn build_array_counter < ' c > (
180201 & mut self ,
181202 context : & ' c Context ,
182203 module : & Module ,
183- block : & ' a Block < ' c > ,
184204 location : Location < ' c > ,
185205 libfunc_amount : u32 ,
186206 ) -> Result < ( ) > {
187207 let array_ty = llvm:: r#type:: array ( IntegerType :: new ( context, 32 ) . into ( ) , libfunc_amount) ;
188- let k0 = block. const_int ( context, location, 0 , 32 ) ?;
189208
190209 module. body ( ) . append_operation (
191210 ods:: llvm:: mlir_global (
@@ -200,16 +219,6 @@ impl LibfuncCounterMeta {
200219 . into ( ) ,
201220 ) ;
202221
203- let global_address = block. append_op_result (
204- ods:: llvm:: mlir_addressof (
205- context,
206- llvm:: r#type:: pointer ( context, 0 ) ,
207- FlatSymbolRefAttribute :: new ( context, LibfuncCounterBinding :: ArrayCounter . symbol ( ) ) ,
208- location,
209- )
210- . into ( ) ,
211- ) ?;
212-
213222 Ok ( ( ) )
214223 }
215224
@@ -223,7 +232,7 @@ impl LibfuncCounterMeta {
223232 libfuncs_amount : u32 ,
224233 ) -> Result < ( ) > {
225234 if self . active_map . insert ( LibfuncCounterBinding :: ArrayCounter ) {
226- self . build_array_counter ( context, module, block , location, libfuncs_amount) ?;
235+ self . build_array_counter ( context, module, location, libfuncs_amount) ?;
227236 }
228237
229238 let u32_ty = IntegerType :: new ( context, 32 ) . into ( ) ;
@@ -242,9 +251,10 @@ impl LibfuncCounterMeta {
242251
243252 let array_counter = block. load ( context, location, array_counter_ptr, array_ty) ?;
244253
245- let value_counter = block. extract_value ( context, location, array_counter, u32_ty, libfunc_idx) ?;
254+ let value_counter =
255+ block. extract_value ( context, location, array_counter, u32_ty, libfunc_idx) ?;
246256 let value_incremented = block. addi ( value_counter, k1, location) ?;
247-
257+
248258 let array_counter = block. insert_value (
249259 context,
250260 location,
@@ -287,9 +297,11 @@ pub mod libfunc_counter_runtime {
287297 metadata:: { libfunc_counter:: LibfuncCounterMeta , MetadataStorage } ,
288298 } ;
289299
300+ /// Contains an array of vector for each execution completed
290301 pub static LIBFUNC_COUNTER : LazyLock < Mutex < HashMap < u64 , Vec < u32 > > > > =
291302 LazyLock :: new ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
292303
304+ /// Increase the libfunc's counter given its index
293305 pub fn count_libfunc (
294306 context : & Context ,
295307 module : & Module ,
@@ -317,8 +329,10 @@ pub mod libfunc_counter_runtime {
317329 libfuncs_amount : u32 ,
318330 ) {
319331 let mut libfunc_counter = LIBFUNC_COUNTER . lock ( ) . unwrap ( ) ;
320- let vec = ( 0 ..libfuncs_amount) . map ( |i| dbg ! ( * array_counter. add( i as usize ) ) ) . collect_vec ( ) ;
321-
332+ let vec = ( 0 ..libfuncs_amount)
333+ . map ( |i| * array_counter. add ( i as usize ) )
334+ . collect_vec ( ) ;
335+
322336 libfunc_counter. insert ( counter_id, vec) ;
323337 }
324338}
0 commit comments