1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

[FunC] Make all functions impure by default, add "pure" specifier

This commit is contained in:
Aleksandr Kirsanov 2024-05-03 13:26:57 +03:00
parent a3e9e03019
commit 85c60d1263
No known key found for this signature in database
GPG key ID: B758BBAA01FFB3D3
61 changed files with 3511 additions and 3500 deletions

View file

@ -1,17 +1,17 @@
tuple empty_tuple() asm "NIL";
forall X -> (tuple, ()) tpush(tuple t, X x) asm "TPUSH";
tuple empty_tuple() pure asm "NIL";
forall X -> (tuple, ()) tpush(tuple t, X x) pure asm "TPUSH";
tuple emptyTuple() { return empty_tuple(); }
forall X -> (tuple, ()) tuplePush(tuple t, X value) { return tpush(t, value); }
tuple asm_func_1(int x, int y, int z) asm "3 TUPLE";
tuple asm_func_2(int x, int y, int z) asm (z y x -> 0) "3 TUPLE";
tuple asm_func_3(int x, int y, int z) asm (y z x -> 0) "3 TUPLE";
tuple asm_func_4(int a, (int, (int, int)) b, int c) asm (b a c -> 0) "5 TUPLE";
tuple asm_func_1(int x, int y, int z) pure asm "3 TUPLE";
tuple asm_func_2(int x, int y, int z) pure asm (z y x -> 0) "3 TUPLE";
tuple asm_func_3(int x, int y, int z) pure asm (y z x -> 0) "3 TUPLE";
tuple asm_func_4(int a, (int, (int, int)) b, int c) pure asm (b a c -> 0) "5 TUPLE";
_ asmFunc1(int x, int y, int z) { return asm_func_1(x, y, z); }
_ asmFunc3(int x, int y, int z) { return asm_func_3(x, y, z); }
(tuple, ()) asm_func_modify(tuple a, int b, int c) asm (c b a -> 0) "SWAP TPUSH SWAP TPUSH";
(tuple, ()) asm_func_modify(tuple a, int b, int c) pure asm (c b a -> 0) "SWAP TPUSH SWAP TPUSH";
(tuple, ()) asmFuncModify(tuple a, int b, int c) { return asm_func_modify(a, b, c); }
global tuple t;

View file

@ -8,12 +8,12 @@
;; This works with ~functions also. And even works with wrappers of wrappers.
;; Moreover, such wrappers can reorder input parameters, see a separate test camel2.fc.
builder begin_cell() asm "NEWC";
cell end_cell(builder b) asm "ENDC";
builder store_ref(builder b, cell c) asm(c b) "STREF";
slice begin_parse(cell c) asm "CTOS";
slice skip_bits(slice s, int len) asm "SDSKIPFIRST";
(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST";
builder begin_cell() pure asm "NEWC";
cell end_cell(builder b) pure asm "ENDC";
builder store_ref(builder b, cell c) pure asm(c b) "STREF";
slice begin_parse(cell c) pure asm "CTOS";
slice skip_bits(slice s, int len) pure asm "SDSKIPFIRST";
(slice, ()) ~skip_bits(slice s, int len) pure asm "SDSKIPFIRST";
builder beginCell() { return begin_cell(); }
cell endCell(builder b) { return end_cell(b); }
@ -21,19 +21,19 @@ builder storeRef(builder b, cell c) { return store_ref(b, c); }
builder storeUint(builder b, int i, int bw) { return store_uint(b, i, bw); }
;; 'inline' is not needed actually, but if it exists, it's just ignored
slice beginParse(cell c) inline { return begin_parse(c); }
slice skipBits(slice s, int len) inline { return skip_bits(s, len); }
(slice, ()) ~skipBits(slice s, int len) inline { return ~skip_bits(s, len); }
(slice, int) ~loadUint(slice s, int len) inline { return load_uint(s, len); }
slice beginParse(cell c) pure inline { return begin_parse(c); }
slice skipBits(slice s, int len) pure inline { return skip_bits(s, len); }
(slice, ()) ~skipBits(slice s, int len) pure inline { return ~skip_bits(s, len); }
(slice, int) ~loadUint(slice s, int len) pure inline { return load_uint(s, len); }
(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE";
(int, int, int) computeDataSize(cell c, int maxCells) impure { return compute_data_size(c, maxCells); }
(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE";
(int, int, int) computeDataSize(cell c, int maxCells) { return compute_data_size(c, maxCells); }
cell new_dict() asm "NEWDICT";
cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET";
(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET";
(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT";
(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2";
cell new_dict() pure asm "NEWDICT";
cell idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET";
(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) pure asm(value index dict key_len) "DICTISET";
(slice, int) idict_get?(cell dict, int key_len, int index) pure asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT";
(int, slice, int) idict_get_min?(cell dict, int key_len) pure asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2";
cell dict::new() { return new_dict(); }
cell dict::iset(cell dict, int keyLen, int index, slice value) { return idict_set(dict, keyLen, index, value); }
@ -41,11 +41,11 @@ cell dict::iset(cell dict, int keyLen, int index, slice value) { return idict_se
(slice, int) dict::tryIGet(cell dict, int keyLen, int index) { return idict_get?(dict, keyLen, index); }
(int, slice, int) dict::tryIGetMin(cell dict, int keyLen) { return idict_get_min?(dict, keyLen); }
tuple empty_tuple() asm "NIL";
forall X -> tuple tpush(tuple t, X value) asm "TPUSH";
forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH";
forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND";
forall X -> X null() asm "PUSHNULL";
tuple empty_tuple() pure asm "NIL";
forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH";
forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH";
forall X, Y, Z -> Y triple_second([X, Y, Z] p) pure asm "SECOND";
forall X -> X null() pure asm "PUSHNULL";
tuple emptyTuple() { return empty_tuple(); }
tuple emptyTuple1() { return emptyTuple(); }
@ -54,19 +54,19 @@ forall X -> tuple tuplePush(tuple t, X value) { return tpush(t, value); }
forall X -> (tuple, ()) ~tuplePush(tuple t, X value) { return ~tpush(t, value); }
forall X -> X tupleAt(tuple t, int index) { return at(t, index); }
forall X1, Y2, Z3 -> Y2 tripleSecond([X1, Y2, Z3] p) { return triple_second(p); }
forall X -> X nullValue() asm "PUSHNULL";
forall X -> X nullValue() pure asm "PUSHNULL";
() throwIf(int excNo, int condition) impure { return throw_if(excNo, condition); }
() throwIf(int excNo, int condition) { return throw_if(excNo, condition); }
tuple initial1(tuple x) { return x; }
_ initial2(x) { return initial1(x); }
int add(int x, int y) { return x + y; } ;; this is also a wrapper, as its body is _+_(x,y)
() fake1(int a, int b, int c) impure asm(a b c) "DROP DROP DROP";
() fake2(int a, int b, int c) impure asm(b c a) "DROP DROP DROP";
() fake3(int a, int b, int c) impure asm(c a b) "DROP DROP DROP";
() fake4(int a, int b, int c) impure asm(c b a) "DROP DROP DROP";
() fake1(int a, int b, int c) asm(a b c) "DROP DROP DROP";
() fake2(int a, int b, int c) asm(b c a) "DROP DROP DROP";
() fake3(int a, int b, int c) asm(c a b) "DROP DROP DROP";
() fake4(int a, int b, int c) asm(c b a) "DROP DROP DROP";
() fake1Wrapper(int a, int b, int c) { return fake1(a, b, c); }
() fake2Wrapper(int a, int b, int c) { return fake2(a, b, c); }
@ -95,9 +95,9 @@ int add(int x, int y) { return x + y; } ;; this is also a wrapper, as its body i
;; skip 64 bits
minv~skipBits(16);
minv = minv.skipBits(16);
minv.skipBits(16000); ;; does nothing
minv.skipBits(11); ;; does nothing
(minv, _) = ~skipBits(minv, 16);
skipBits(minv, 16000); ;; does nothing
skipBits(minv, 11); ;; does nothing
minv~skipBits(16);
;; load 3*32
var minv1 = minv~loadUint(32);

View file

@ -7,10 +7,10 @@
#pragma compute-asm-ltr;
builder begin_cell() asm "NEWC";
cell end_cell(builder b) asm "ENDC";
slice begin_parse(cell c) asm "CTOS";
builder store_ref(builder b, cell c) asm(c b) "STREF";
builder begin_cell() pure asm "NEWC";
cell end_cell(builder b) pure asm "ENDC";
slice begin_parse(cell c) pure asm "CTOS";
builder store_ref(builder b, cell c) pure asm(c b) "STREF";
builder beginCell() { return begin_cell(); }
cell endCell(builder b) { return end_cell(b); }
@ -19,13 +19,13 @@ builder storeRef2(cell c, builder b) { return store_ref(b, c); }
builder storeUint1(builder b, int x, int bw) { return store_uint(b, x, bw); }
builder storeUint2(builder b, int bw, int x) { return store_uint(b, x, bw); }
(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE";
(int, int, int) computeDataSize1(cell c, int maxCells) impure { return compute_data_size(c, maxCells); }
(int, int, int) computeDataSize2(int maxCells, cell c) impure { return compute_data_size(c, maxCells); }
(int, int, int) compute_data_size(cell c, int max_cells) pure asm "CDATASIZE";
(int, int, int) computeDataSize1(cell c, int maxCells) { return compute_data_size(c, maxCells); }
(int, int, int) computeDataSize2(int maxCells, cell c) { return compute_data_size(c, maxCells); }
() throwIf(int condition, int excNo) impure { return throw_if(excNo, condition); }
() throwIf(int condition, int excNo) { return throw_if(excNo, condition); }
() fake(int a, int b, int c) impure asm "DROP DROP DROP";
() fake(int a, int b, int c) asm "DROP DROP DROP";
() fake2(int b, int c, int a) { return fake(a,b,c); }
() fake3(int c, int a, int b) { return fake(a,b,c); }
() fake4(int c, int b, int a) { return fake(a,b,c); }

View file

@ -4,22 +4,22 @@
;; (save to a variable, return from a function, etc.)
;; it also works, since a function becomes codegenerated (though direct calls are expectedly inlined).
builder begin_cell() asm "NEWC";
cell end_cell(builder b) asm "ENDC";
builder store_ref(builder b, cell c) asm(c b) "STREF";
builder begin_cell() pure asm "NEWC";
cell end_cell(builder b) pure asm "ENDC";
builder store_ref(builder b, cell c) pure asm(c b) "STREF";
builder beginCell() { return begin_cell(); }
cell endCell(builder b) { return end_cell(b); }
builder storeRef(builder b, cell c) { return store_ref(b, c); }
builder storeUint3(int i, int bw, builder b) { return store_uint(b, i, bw); }
(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE";
(int, int, int) computeDataSize2(int maxCells, cell c) impure { return compute_data_size(c, maxCells); }
(int, int, int) compute_data_size(cell c, int max_cells) asm "CDATASIZE";
(int, int, int) computeDataSize2(int maxCells, cell c) { return compute_data_size(c, maxCells); }
tuple empty_tuple() asm "NIL";
forall X -> tuple tpush(tuple t, X value) asm "TPUSH";
forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH";
forall X -> X first(tuple t) asm "FIRST";
tuple empty_tuple() pure asm "NIL";
forall X -> tuple tpush(tuple t, X value) pure asm "TPUSH";
forall X -> (tuple, ()) ~tpush(tuple t, X value) pure asm "TPUSH";
forall X -> X first(tuple t) pure asm "FIRST";
tuple emptyTuple() { return empty_tuple(); }
forall X -> tuple tuplePush(tuple t, X value) { return tpush(t, value); }

View file

@ -1,22 +1,21 @@
;; Here we test that a just-return function is not a valid wrapper, it will not be inlined.
;; (doesn't use all arguments, has different pureness, has method_id, etc.)
builder begin_cell() asm "NEWC";
cell end_cell(builder b) asm "ENDC";
slice begin_parse(cell c) asm "CTOS";
() set_data(cell c) impure asm "c4 POP";
cell get_data() asm "c4 PUSH";
tuple empty_tuple() asm "NIL";
forall X -> (tuple, ()) tpush(tuple t, X x) asm "TPUSH";
builder begin_cell() pure asm "NEWC";
cell end_cell(builder b) pure asm "ENDC";
slice begin_parse(cell c) pure asm "CTOS";
() set_data(cell c) asm "c4 POP";
cell get_data() pure asm "c4 PUSH";
tuple empty_tuple() pure asm "NIL";
forall X -> (tuple, ()) tpush(tuple t, X x) pure asm "TPUSH";
builder storeUint(builder b, int x, int unused) { return store_uint(b, x, x); }
() throwIf(int excNo, int cond) impure { throw_if(excNo, cond); }
() throwIf2(int excNo, int cond) { return throw_if(excNo, cond); }
() throwIf(int excNo, int cond) { throw_if(excNo, cond); }
_ initial1(x) { return x; }
_ initial2(x) { return initial1(x); }
tuple asm_func_4(int a, (int, (int, int)) b, int c) asm (b a c -> 0) "5 TUPLE";
tuple asm_func_4(int a, (int, (int, int)) b, int c) pure asm (b a c -> 0) "5 TUPLE";
_ asmFunc4(int a, (int, (int, int)) b, int c) { return asm_func_4(a, b, c); }
int postpone_elections() {
@ -28,7 +27,6 @@ int postpone_elections() {
set_data(c);
slice s = get_data().begin_parse();
throwIf(101, 0);
var unused = throwIf2(101, 0);
return s~load_uint(8);
}
@ -90,7 +88,6 @@ TESTCASE | -1 | 97 | 97
@fif_codegen DECLPROC storeUint
@fif_codegen DECLPROC throwIf
@fif_codegen DECLPROC throwIf2
@fif_codegen DECLPROC postpone_elections
@fif_codegen 74435 DECLMETHOD test2

View file

@ -28,14 +28,14 @@ const int int240 = ((int1 + int2) * 10) << 3;
int iget240() { return int240; }
builder newc() asm "NEWC";
slice endcs(builder b) asm "ENDC" "CTOS";
int sdeq (slice s1, slice s2) asm "SDEQ";
builder stslicer(builder b, slice s) asm "STSLICER";
builder newc() pure asm "NEWC";
slice endcs(builder b) pure asm "ENDC" "CTOS";
int sdeq (slice s1, slice s2) pure asm "SDEQ";
builder stslicer(builder b, slice s) pure asm "STSLICER";
builder storeUint(builder b, int x, int len) { return store_uint(b, x, len); }
_ endSlice(builder b) { return endcs(b); }
() throwUnless(int excno, int cond) impure { return throw_unless(excno, cond); }
() throwUnless(int excno, int cond) { return throw_unless(excno, cond); }
_ main() {
int i1 = iget1();

View file

@ -1,13 +1,13 @@
global int g;
_ foo_repeat() impure inline {
_ foo_repeat() inline {
g = 1;
repeat(5) {
g *= 2;
}
}
int foo_until() impure inline {
int foo_until() inline {
g = 1;
int i = 0;
do {
@ -17,7 +17,7 @@ int foo_until() impure inline {
return i;
}
int foo_while() impure inline {
int foo_while() inline {
g = 1;
int i = 0;
while (i < 10) {

View file

@ -26,9 +26,9 @@ int string_crc32() method_id {
return "transfer(slice, int)"c;
}
builder newc() asm "NEWC";
builder newc() pure asm "NEWC";
slice endcs(builder b) asm "ENDC" "CTOS";
int sdeq (slice s1, slice s2) asm "SDEQ";
int sdeq (slice s1, slice s2) pure asm "SDEQ";
_ main() {
slice s_ascii = ascii_slice();

View file

@ -1,6 +1,6 @@
#include "../../../smartcont/mathlib.fc";
forall X -> (tuple, ()) ~tset(tuple t, int idx, X val) asm(t val idx) "SETINDEXVAR";
forall X -> (tuple, ()) ~tset(tuple t, int idx, X val) pure asm(t val idx) "SETINDEXVAR";
;; computes 1-acos(x)/Pi by a very simple, extremely slow (~70k gas) and imprecise method
;; fixed256 acos_prepare_slow(fixed255 x);