Open mskvortsov opened 4 years ago
Manually written code utilizing WHILE primitive:
gcd: ; (a b -- gcd)
PUSHCONT {
DUP ; ( -- a b b)
ISPOS ; ( -- a b s)
}
PUSHCONT {
SWAP ; ( -- b a)
OVER ; ( -- b a b)
MOD ; ( -- b r)
}
WHILE
DROP
An experimental version with cfg as state machine
gcd:
;; static cfg description
NIL ; placeholder, zero bb
PUSHCONT { ; bb 1, entry
DUP ISPOS ; branch condition
PUSHINT 2 PUSHINT 3 CONDSEL ; branch
}
PUSHCONT { ; bb 2, loop
SWAP OVER MOD ; computation
DUP ISPOS ; branch condition
PUSHINT 2 PUSHINT 3 CONDSEL ; branch
}
PUSHCONT { ; bb 3, exit
DROP ; computation
PUSHINT 0 ; branch, zero means exit
}
;; pack basic blocks into tuple at c13
TUPLE 4
POPCTR c13
;; execute cfg
PUSHINT 1 ; label of entry block
PUSHCONT { DUP }
PUSHCONT { PUSHCTR c13 SWAP INDEXVAR EXECUTE }
WHILE
;; drop zero bb label
DROP
The c13 global register used in the code above must be saved and restored around a call to any functions generated in such a manner. So here is a version without using c13:
gcd:
PUSHINT 1 ; entry block label
PUSHCONT { DUP } ; while condition
PUSHCONT { ; while body
PUSHCONT { ; bb 1, entry
DUP ISPOS ; branch condition
PUSHINT 2 PUSHINT 3 CONDSEL ; branch
}
PUSHCONT { ; bb 2, loop
SWAP OVER MOD ; computation
DUP ISPOS ; branch condition
PUSHINT 2 PUSHINT 3 CONDSEL ; branch
}
PUSHCONT { ; bb 3, exit
DROP ; computation
PUSHINT 0 ; branch, zero implies exit
}
TUPLE 3 SWAP DEC INDEXVAR ; select next bb
EXECUTE
}
WHILE
DROP ; drop zero bb label
Results of measuring gas consumption for all gcd variants.
#include "ton-sdk/tvm.h"
extern int gcd(int, int);
TVM_CUSTOM_EXCEPTION(FAILED, 101);
void bench_Impl() {
ACCEPT();
tvm_assert(gcd(20988936657440586486151264256610222593863921,
67280421310721) == 1, FAILED);
}
Variant | Gas |
---|---|
baseline | 6780 |
clang | 12468 |
structured cf | 8238 |
state machine w/ c13 | 10904 |
state machine w/o c13 | 11901 |
Baseline gcd:
gcd:
DROP2
ONE
Update: | Variant | Gas |
---|---|---|
baseline | 4547 | |
clang | 10235 | |
structured cf | 6005 | |
state machine w/ c13 | 8671 | |
state machine w/o c13 | 9668 |
Note: for the input given, gcd makes 15 iterations.
Keeping basic blocks on the stack right before arguments, 6875 units of gas:
gcd:
PUSHCONT { ; entry
DUP ISPOS
PUSH s4 ; {loop}
PUSH s4 ; {exit}
IFELSE
}
PUSHCONT { ; loop
SWAP OVER MOD
DUP ISPOS
PUSH s4 ; {loop}
PUSH s4 ; {exit}
IFELSE
}
PUSHCONT { ; exit
DROP
}
BLKSWAP 2, 3 ; 2 arguments, 3 BBs
PUSH s4 ; {entry}
EXECUTE
BLKSWAP 3, 1 ; 3 BBs, 1 return value
BLKDROP 3
→
→