Standard functions
Standard functions areasm wrappers. Many functions from the standard library are translated to the Fift assembler directly. For example, TVM has a HASHCU instruction, which is “calculate hash of a cell”. It pops a cell from the stack and pushes an integer in the range 0 to 2256-1. Therefore, the method cell.hash is defined:
CELL will be the topmost element (self).
Custom functions
incThenNegate(10) is translated into those commands.
Specify @pure if the body does not modify TVM state or throw exceptions.
The return type for asm functions is mandatory. For regular functions, it’s inferred from return statements.
Multi-line asm
To embed a multi-line command, use triple quotes:
// comments valid for Fift.
Stack order for multiple slots
When calling a function, arguments are pushed in the declared order. The last parameter becomes the topmost stack element. If an instruction produces several slots, the resulting type should be a tensor or a struct. For example, write a functionabs2 that calculates abs() for two values at once: abs2(-5, -10) = (5, 10). The comments show the stack layout for each step. The rightmost value represents the top of the stack.
Stack-based argument reordering
Sometimes a function accepts parameters in an order different from what a TVM instruction expects. For example,GETSTORAGEFEE expects the parameters in the order cells, bits, seconds, and workchain. For a clearer API, the function should take the workchain as its first argument. To reorder stack positions, use the asm(<INPUT_ORDER>) syntax:
asm(-> <RETURN_ORDER>) syntax:
asm(<INPUT_ORDER> -> <RETURN_ORDER>). Reordering is mostly used with mutate variables.
mutate and self in assembler functions
The mutate keyword, which makes a parameter mutable, implicitly returns updated values through the stack in both regular and asm functions.
Consider regular functions first. The compiler applies all transformations automatically.
increment() using asm:
void. The type system treats it as returning no value. However, INC leaves a number on the stack — that’s a hidden “return x” from a manual implementation.
Similarly, it works for mutate self. An asm function should place newSelf on the stack before the actual result:
self for chaining, specify a return type:
asm is compatible with structures
Methods on structures can be declared in asm when their field layout is known. Fields are placed sequentially. For example, a structure with a single field is equivalent to that field.
map<K, V> methods on TVM dictionaries:
Generics in asm should be single-slot
Consider tuple.push. The TPUSH instruction pops (tuple, someVal) and pushes (newTuple). It works with any T that occupies a single stack slot, such as int, int8, or slice.
t.push(somePoint) work? It does not compile, because Point { x, y } occupies two stack slots rather than one, which breaks the expected the stack.
asm do not.
Do not use asm for micro-optimizations
Use asm only for rarely used TVM instructions that are not covered by the standard library, such as manual merkle-proof parsing or extended hash calculations.
Using asm for micro-optimizations is discouraged. The compiler already produces bitcode from clear, structured logic. For example, it automatically inlines simple functions, so one-line helper methods do not add gas overhead.
32 STU sequence provides no advantage in this case. The compiler:
- inlines the function
- merges constant
flagswith subsequent stores intoSTSLICECONST