Skip to content

Instantly share code, notes, and snippets.

@agolajko
Last active August 8, 2022 22:26
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agolajko/77faf455f94fd674f1fb50c2b196b66d to your computer and use it in GitHub Desktop.
Save agolajko/77faf455f94fd674f1fb50c2b196b66d to your computer and use it in GitHub Desktop.
Quick trick for better looping in Cairo

Returning fp for calling functions in Cairo loops

Getting loops to work in Starknet's Cairo can be complicated. Currently you need to fiddle around a lot with ap, fp and pc even for mundane computations. Further, when calling a function within a loop tempvar will be dereferenced causing the loop to fail. For example the following code will not run:

tempvar iterator=10
tempvar sum=0

loop_start:
        let (local a, local b)=div (10, 5)

        tempvar sum=sum+iterator
        tempvar iterator=iterator-1
jmp loop_start if  iterator != 0

A solution that allows calling function within loops, we save the variables that we want to save before the function call, with the [ap]= sum; ap++ command. Then we call the modified function, which besides it's normal return values also returns my_fp using the commands in the code.

With this fp, we restore the saved variables, using tempvar sum=[my_fp-2-2-2]. The -2-2-2 in general depends on the number of variables being saved, and the number of inputs the functions has. Eg. if we save 5 variables with [ap], and the add_one function call had 12 inputs, then we would have to write [my_fp-12-2-5], ...,[my_fp-12-2-1] respectively for the 5 restoration calls.

The fixed -2 is constant (from here). In general the formula is -#inputs-#saved_variables-2.

This is ellucidated in the following snippet:

tempvar  sum=0
tempvar iterator=10

loop_start:

    [ap]=sum; ap++
    [ap]=iterator; ap++
    let (my_fp, a,  b)=add_one (100, 50)

    tempvar sum=[my_fp-4-2]
    tempvar iterator=[my_fp-4-1]
    tempvar sum=sum+a+b
    tempvar iterator=iterator-1
jmp loop_start if  iterator != 0

func add_one(x, y) -> (my_fp, q, r):
    let fp_and_pc = get_fp_and_pc()
    tempvar my_fp = fp_and_pc.fp_val

    return (my_fp=my_fp,q=x+1, r=y+1)

end 

With this trick (including fp in the function return) the code remains readable and performant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment