mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
[FunC] Auto-inline functions-wrappers T f(...args) { return anotherF(...args); }
This will allow to easily implement camelCase wrappers aside stdlib, even without changing hashes of existing contracts. Also, stdlib renamings could be easily performed in the same manner, even with arguments reordered.
This commit is contained in:
parent
bac4e3df97
commit
18050a7591
12 changed files with 929 additions and 60 deletions
|
@ -31,7 +31,8 @@
|
|||
["whales-nominators/nominators.fc", 8941364499854379927692172316865293429893094891593442801401542636695127885153]
|
||||
|
||||
|
||||
["tact-examples/treasure_Treasure.code.fc", 13962538639825790677138656603323869918938565499584297120566680287245364723897]
|
||||
["tact-examples/jetton_SampleJetton.code.fc", 94076762218493729104783735200107713211245710256802265203823917715299139499110]
|
||||
["tact-examples/jetton_JettonDefaultWallet.code.fc", 29421313492520031238091587108198906058157443241743283101866538036369069620563]
|
||||
// (April 2024) tact hashes changed, because '__tact_address_eq()' is now inlined as a wrapper
|
||||
["tact-examples/treasure_Treasure.code.fc", 74579212939836529446778705921340099196942507859825095056546203678047252921894]
|
||||
["tact-examples/jetton_SampleJetton.code.fc", 90109697379313597998231209537203822165325184678797680193687781490465875320451]
|
||||
["tact-examples/jetton_JettonDefaultWallet.code.fc", 40972091374757565863193840427121230466303309310521439431197914284004190565629]
|
||||
["tact-examples/maps_MapTestContract.code.fc", 22556550222249123835909180266811414538971143565993192846012583552876721649744]
|
||||
|
|
239
crypto/func/auto-tests/tests/camel1.fc
Normal file
239
crypto/func/auto-tests/tests/camel1.fc
Normal file
|
@ -0,0 +1,239 @@
|
|||
;; Here we test "functions that just wrap other functions" (camelCase in particular):
|
||||
;; > builder beginCell() { return begin_cell(); }
|
||||
;; Such functions, when called, are explicitly inlined during code generation (even without `inline` modifier).
|
||||
;; It means, that `beginCell()` is replaced to `begin_cell()` (and effectively to `NEWC`).
|
||||
;; Moreover, body of `beginCell` is NOT codegenerated at all.
|
||||
;; Hence, we can write camelCase wrappers (as well as more intelligible namings around stdlib functions)
|
||||
;; without affecting performance and even bytecode hashes.
|
||||
;; 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 beginCell() { return begin_cell(); }
|
||||
cell endCell(builder b) { return end_cell(b); }
|
||||
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); }
|
||||
|
||||
(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); }
|
||||
|
||||
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 dict::new() { return new_dict(); }
|
||||
cell dict::iset(cell dict, int keyLen, int index, slice value) { return idict_set(dict, keyLen, index, value); }
|
||||
(cell, ()) ~dict::iset(cell dict, int keyLen, int index, slice value) { return ~idict_set(dict, keyLen, index, value); }
|
||||
(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 emptyTuple() { return empty_tuple(); }
|
||||
tuple emptyTuple1() { return emptyTuple(); }
|
||||
tuple emptyTuple11() { return emptyTuple1(); }
|
||||
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";
|
||||
|
||||
() throwIf(int excNo, int condition) impure { 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";
|
||||
|
||||
() fake1Wrapper(int a, int b, int c) { return fake1(a, b, c); }
|
||||
() fake2Wrapper(int a, int b, int c) { return fake2(a, b, c); }
|
||||
() fake3Wrapper(int a, int b, int c) { return fake3(a, b, c); }
|
||||
() fake4Wrapper(int a, int b, int c) { return fake4(a, b, c); }
|
||||
|
||||
[int, int, int] test1() method_id(101) {
|
||||
int x = 1;
|
||||
int y = 1;
|
||||
cell to_be_ref = beginCell().endCell();
|
||||
builder in_c = beginCell().storeUint(123, 8);
|
||||
in_c = storeRef(in_c, to_be_ref);
|
||||
var (a, b, c) = computeDataSize(in_c.endCell(), 10);
|
||||
throwIf(101, b != 8);
|
||||
throwIf(101, c != 1);
|
||||
return [a, add(b, x), add(c, y)];
|
||||
}
|
||||
|
||||
[[int, int, int], int, int, int] test2() method_id(102) {
|
||||
cell dict = dict::new();
|
||||
dict = dict::iset(dict, 32, 456, beginCell().storeUint(4560, 32).endCell().beginParse());
|
||||
dict.dict::iset(32, 789, beginCell().storeUint(7890, 32).endCell().beginParse());
|
||||
dict~dict::iset(32, 123, beginCell().storeUint(0, 64).storeUint(1230, 32).storeUint(1231, 32).storeUint(1232, 32).endCell().beginParse());
|
||||
|
||||
var (mink, minv, _) = dict::tryIGetMin(dict, 32);
|
||||
;; skip 64 bits
|
||||
minv~skipBits(16);
|
||||
minv = minv.skipBits(16);
|
||||
minv.skipBits(16000); ;; does nothing
|
||||
(minv, _) = ~skipBits(minv, 16);
|
||||
skipBits(minv, 16000); ;; does nothing
|
||||
minv~skipBits(16);
|
||||
;; load 3*32
|
||||
var minv1 = minv~loadUint(32);
|
||||
var minv2 = minv~loadUint(32);
|
||||
var minv3 = minv~loadUint(32);
|
||||
|
||||
var (_, found123) = dict::tryIGet(dict, 32, 123);
|
||||
var (_, found456) = dict::tryIGet(dict, 32, 456);
|
||||
var (_, found789) = dict::tryIGet(dict, 32, 789);
|
||||
return [[minv1, minv2, minv3], found123, found456, found789];
|
||||
}
|
||||
|
||||
tuple test3() method_id(103) {
|
||||
tuple with34 = initial2(emptyTuple1());
|
||||
with34~tuplePush(34);
|
||||
|
||||
tuple t = emptyTuple11();
|
||||
t = tuplePush(t, 12);
|
||||
tuplePush(t, emptyTuple11()); ;; does nothing
|
||||
t~tuplePush(emptyTuple1());
|
||||
t~tuplePush(with34.tupleAt(0));
|
||||
t.tuplePush("123"s); ;; does nothing
|
||||
|
||||
[cell, int, cell] tri = [nullValue(), 90 + 1, null()];
|
||||
int f = tripleSecond(tri);
|
||||
(t, _) = ~tuplePush(t, f);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
(int) test4(int a, int b, int c) method_id(104) {
|
||||
fake1Wrapper(a, b, c);
|
||||
fake2Wrapper(a, b, c);
|
||||
fake3Wrapper(a, b, c);
|
||||
fake4Wrapper(a, b, c);
|
||||
return 10;
|
||||
}
|
||||
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
{-
|
||||
method_id | in | out
|
||||
TESTCASE | 101 | | [ 2 9 2 ]
|
||||
TESTCASE | 102 | | [ [ 1230 1231 1232 ] -1 -1 0 ]
|
||||
TESTCASE | 103 | | [ 12 [] 34 91 ]
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test1 PROC:<{
|
||||
//
|
||||
NEWC // _5
|
||||
ENDC // to_be_ref
|
||||
123 PUSHINT // to_be_ref _8=123
|
||||
NEWC // to_be_ref _8=123 _9
|
||||
8 STU // to_be_ref in_c
|
||||
STREF // in_c
|
||||
ENDC // _16
|
||||
10 PUSHINT // _16 _17=10
|
||||
CDATASIZE // a b c
|
||||
OVER // a b c b
|
||||
8 NEQINT // a b c _21
|
||||
101 THROWIF
|
||||
DUP // a b c c
|
||||
1 NEQINT // a b c _25
|
||||
101 THROWIF
|
||||
SWAP // a c b
|
||||
INC // a c _28
|
||||
SWAP // a _28 c
|
||||
INC // a _28 _29
|
||||
TRIPLE // _27
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test2 PROC:<{
|
||||
...
|
||||
16 PUSHINT // dict minv _45=16
|
||||
SDSKIPFIRST // dict minv
|
||||
16 PUSHINT // dict minv _47=16
|
||||
SDSKIPFIRST // dict minv
|
||||
16 PUSHINT // dict minv _52=16
|
||||
SDSKIPFIRST // dict minv
|
||||
16 PUSHINT // dict minv _57=16
|
||||
SDSKIPFIRST // dict minv
|
||||
...
|
||||
32 PUSHINT // dict minv1 minv2 minv3 found123 _78=456 dict _79=32
|
||||
DICTIGET
|
||||
NULLSWAPIFNOT // dict minv1 minv2 minv3 found123 _99 _100
|
||||
789 PUSHINT
|
||||
s2 POP
|
||||
s0 s6 XCHG
|
||||
32 PUSHINT // found456 minv1 minv2 minv3 found123 _83=789 dict _84=32
|
||||
...
|
||||
4 TUPLE // _86
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test3 PROC:<{
|
||||
//
|
||||
NIL // _1
|
||||
initial1 CALLDICT // with34
|
||||
...
|
||||
TRIPLE // t tri
|
||||
SECOND // t f
|
||||
TPUSH // t
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test4 PROC:<{
|
||||
// a b c
|
||||
s2 s1 s0 PUSH3 // a b c a b c
|
||||
DROP DROP DROP
|
||||
s1 s0 s2 PUSH3 // a b c b c a
|
||||
DROP DROP DROP
|
||||
s0 s2 s1 PUSH3 // a b c c a b
|
||||
DROP DROP DROP
|
||||
s0 s2 XCHG // c b a
|
||||
DROP DROP DROP
|
||||
10 PUSHINT // _7=10
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen_avoid DECLPROC beginCell
|
||||
@fif_codegen_avoid DECLPROC storeUint
|
||||
@fif_codegen_avoid DECLPROC storeRef
|
||||
@fif_codegen_avoid DECLPROC computeDataSize
|
||||
@fif_codegen_avoid DECLPROC tryIdictGet
|
||||
@fif_codegen_avoid DECLPROC emptyTuple
|
||||
@fif_codegen_avoid DECLPROC storeUint1
|
||||
@fif_codegen_avoid DECLPROC initial2
|
||||
@fif_codegen_avoid DECLPROC add
|
||||
-}
|
208
crypto/func/auto-tests/tests/camel2.fc
Normal file
208
crypto/func/auto-tests/tests/camel2.fc
Normal file
|
@ -0,0 +1,208 @@
|
|||
;; Here we also test "functions that just wrap other functions" like in camel1.fc,
|
||||
;; but when they reorder arguments, e.g.
|
||||
;; > T f(x,y) { return anotherF(y,x); }
|
||||
;; This also works, even for wrappers of wrappers, even if anotherF is asm(with reorder).
|
||||
;; But swapping arguments may sometimes lead to bytecode changes (see test2),
|
||||
;; both with compute-asm-ltr and without it.
|
||||
|
||||
#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 beginCell() { return begin_cell(); }
|
||||
cell endCell(builder b) { return end_cell(b); }
|
||||
builder storeRef1(builder b, cell c) { return store_ref(b, c); }
|
||||
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); }
|
||||
|
||||
() throwIf(int condition, int excNo) impure { return throw_if(excNo, condition); }
|
||||
|
||||
() fake(int a, int b, int c) impure 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); }
|
||||
|
||||
(int, int, int) test1() method_id(101) {
|
||||
int x = 1;
|
||||
int y = 1;
|
||||
cell to_be_ref = beginCell().endCell();
|
||||
builder in_c = beginCell().storeUint1(123, 8);
|
||||
in_c = storeRef1(in_c, to_be_ref);
|
||||
var (a, b, c) = computeDataSize1(in_c.endCell(), 10);
|
||||
throwIf(0, 101);
|
||||
return (a, b + x, c + y);
|
||||
}
|
||||
|
||||
(int, int, int) test2() method_id(102) {
|
||||
int x = 1;
|
||||
int y = 1;
|
||||
cell to_be_ref = beginCell().endCell();
|
||||
builder in_c = beginCell().storeUint2(8, 123);
|
||||
in_c = storeRef2(to_be_ref, in_c);
|
||||
var (a, b, c) = computeDataSize2(10, in_c.endCell());
|
||||
return (a, b + x, c + y);
|
||||
}
|
||||
|
||||
(int, int, int) test3() method_id(103) {
|
||||
int x = 1;
|
||||
int y = 1;
|
||||
cell to_be_ref = begin_cell().end_cell();
|
||||
builder in_c = begin_cell().store_uint(123, 8);
|
||||
in_c = store_ref(in_c, to_be_ref);
|
||||
var (a, b, c) = compute_data_size(in_c.end_cell(), 10);
|
||||
return (a, b + x, c + y);
|
||||
}
|
||||
|
||||
builder beginCell1() { return begin_cell(); }
|
||||
builder beginCell11() { return beginCell1(); }
|
||||
builder beginCell111() { return beginCell11(); }
|
||||
|
||||
cell endCell1(builder b) { return end_cell(b); }
|
||||
cell endCell11(builder b) { return endCell1(b); }
|
||||
|
||||
slice beginParse1(cell c) { return begin_parse(c); }
|
||||
slice beginParse11(cell c) { return beginParse1(c); }
|
||||
|
||||
builder storeInt1(builder b, int bw, int x) { return store_int(b, x, bw); }
|
||||
builder storeInt11(int bw, int x, builder b) { return storeInt1(b, bw, x); }
|
||||
builder storeInt111(builder b, int x, int bw) { return storeInt11(bw, x, b); }
|
||||
|
||||
slice test4() method_id(104) {
|
||||
builder b = beginCell111();
|
||||
b = storeInt11(32, 1, b);
|
||||
b = storeInt111(b, 2, 32).storeInt111(3, 32);
|
||||
return b.endCell11().beginParse11();
|
||||
}
|
||||
|
||||
(int) test5(int a, int b, int c) method_id(105) {
|
||||
fake(a, b, c);
|
||||
fake2(b, c, a);
|
||||
fake3(c, a, b);
|
||||
fake4(c, b, a);
|
||||
return a;
|
||||
}
|
||||
|
||||
() main() {
|
||||
throw(0);
|
||||
}
|
||||
|
||||
{-
|
||||
method_id | in | out
|
||||
TESTCASE | 101 | | 2 9 2
|
||||
TESTCASE | 102 | | 2 9 2
|
||||
TESTCASE | 103 | | 2 9 2
|
||||
TESTCASE | 104 | | CS{Cell{0018000000010000000200000003} bits: 0..96; refs: 0..0}
|
||||
|
||||
test1 and test3 fif code is absolutely identical, test2 (due to reorder) is a bit different:
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test1 PROC:<{
|
||||
//
|
||||
NEWC // _5
|
||||
ENDC // to_be_ref
|
||||
NEWC // to_be_ref _8
|
||||
123 PUSHINT // to_be_ref _8 _9=123
|
||||
SWAP // to_be_ref _9=123 _8
|
||||
8 STU // to_be_ref in_c
|
||||
STREF // in_c
|
||||
ENDC // _16
|
||||
10 PUSHINT // _16 _17=10
|
||||
CDATASIZE // a b c
|
||||
SWAP // a c b
|
||||
INC // a c _22
|
||||
SWAP // a _22 c
|
||||
INC // a _22 _23
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test2 PROC:<{
|
||||
//
|
||||
NEWC // _5
|
||||
ENDC // to_be_ref
|
||||
NEWC // to_be_ref _8
|
||||
123 PUSHINT // to_be_ref _8 _10=123
|
||||
SWAP // to_be_ref _10=123 _8
|
||||
8 STU // to_be_ref in_c
|
||||
STREF // in_c
|
||||
10 PUSHINT
|
||||
SWAP
|
||||
ENDC
|
||||
SWAP
|
||||
CDATASIZE // a b c
|
||||
SWAP // a c b
|
||||
INC // a c _19
|
||||
SWAP // a _19 c
|
||||
INC // a _19 _20
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test3 PROC:<{
|
||||
//
|
||||
NEWC // _5
|
||||
ENDC // to_be_ref
|
||||
NEWC // to_be_ref _8
|
||||
123 PUSHINT // to_be_ref _8 _9=123
|
||||
SWAP // to_be_ref _9=123 _8
|
||||
8 STU // to_be_ref in_c
|
||||
STREF // in_c
|
||||
ENDC // _16
|
||||
10 PUSHINT // _16 _17=10
|
||||
CDATASIZE // a b c
|
||||
SWAP // a c b
|
||||
INC // a c _19
|
||||
SWAP // a _19 c
|
||||
INC // a _19 _20
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test4 PROC:<{
|
||||
//
|
||||
NEWC // b
|
||||
1 PUSHINT // b _3=1
|
||||
SWAP // _3=1 b
|
||||
32 STI // b
|
||||
2 PUSHINT
|
||||
SWAP // _5=2 b
|
||||
32 STI
|
||||
3 PUSHINT
|
||||
SWAP
|
||||
32 STI // b
|
||||
ENDC // _11
|
||||
CTOS // _12
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test5 PROC:<{
|
||||
// a b c
|
||||
s2 s1 s0 PUSH3 // a b c a b c
|
||||
DROP DROP DROP
|
||||
s2 s1 s0 PUSH3 // a b c a b c
|
||||
DROP DROP DROP
|
||||
s2 s1 s0 PUSH3 // a b c a b c
|
||||
DROP DROP DROP
|
||||
s2 PUSH
|
||||
-ROT // a a b c
|
||||
DROP DROP DROP
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen_avoid storeUint1
|
||||
@fif_codegen_avoid storeUint2
|
||||
-}
|
104
crypto/func/auto-tests/tests/camel3.fc
Normal file
104
crypto/func/auto-tests/tests/camel3.fc
Normal file
|
@ -0,0 +1,104 @@
|
|||
;; Here we test that if you declare a wrapper like
|
||||
;; > builder beginCell() { return begin_cell(); }
|
||||
;; but use it NOT only as a direct call, BUT as a 1-st class function
|
||||
;; (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 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); }
|
||||
|
||||
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 emptyTuple() { return empty_tuple(); }
|
||||
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 tupleGetFirst(tuple t) { return first(t); }
|
||||
|
||||
|
||||
(var, var) getBeginEnd() inline {
|
||||
return (beginCell, endCell);
|
||||
}
|
||||
|
||||
(builder) begAndStore(beg, store, int x) {
|
||||
return store(x, 8, beg());
|
||||
}
|
||||
|
||||
(int, int, int) test1() {
|
||||
var (_, computer) = (0, computeDataSize2);
|
||||
var (beg, end) = getBeginEnd();
|
||||
|
||||
tuple t = emptyTuple();
|
||||
t~tuplePush(storeRef);
|
||||
var refStorer = tupleGetFirst(t);
|
||||
|
||||
int x = 1;
|
||||
int y = 1;
|
||||
cell to_be_ref = beginCell().endCell();
|
||||
builder in_c = begAndStore(beg, storeUint3, 123);
|
||||
in_c = refStorer(in_c, to_be_ref);
|
||||
var (a, b, c) = computer(10, end(in_c));
|
||||
return (a, b + x, c + y);
|
||||
}
|
||||
|
||||
(int, int, int) main() {
|
||||
return test1();
|
||||
}
|
||||
|
||||
{-
|
||||
method_id | in | out
|
||||
TESTCASE | 0 | | 2 9 2
|
||||
|
||||
@fif_codegen DECLPROC beginCell
|
||||
@fif_codegen DECLPROC computeDataSize2
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
storeUint3 PROC:<{
|
||||
// i bw b
|
||||
SWAP // i b bw
|
||||
STUX // _3
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
storeRef PROC:<{
|
||||
// b c
|
||||
SWAP // c b
|
||||
STREF // _2
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
CONT:<{
|
||||
computeDataSize2 CALLDICT
|
||||
}> // computer
|
||||
getBeginEnd INLINECALLDICT // computer beg end
|
||||
NIL // computer beg end t
|
||||
...
|
||||
NEWC // computer beg end refStorer _19
|
||||
ENDC // computer beg end refStorer to_be_ref
|
||||
...
|
||||
CONT:<{
|
||||
storeUint3 CALLDICT
|
||||
}>
|
||||
...
|
||||
begAndStore CALLDICT // computer to_be_ref end refStorer in_c
|
||||
"""
|
||||
|
||||
@fif_codegen_avoid emptyTuple
|
||||
@fif_codegen_avoid tuplePush
|
||||
-}
|
130
crypto/func/auto-tests/tests/camel4.fc
Normal file
130
crypto/func/auto-tests/tests/camel4.fc
Normal file
|
@ -0,0 +1,130 @@
|
|||
;; 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 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); }
|
||||
|
||||
_ 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";
|
||||
_ asmFunc4(int a, (int, (int, int)) b, int c) { return asm_func_4(a, b, c); }
|
||||
|
||||
int postpone_elections() {
|
||||
return false;
|
||||
}
|
||||
|
||||
(int) setAndGetData(int ret) {
|
||||
cell c = begin_cell().store_uint(ret, 8).end_cell();
|
||||
set_data(c);
|
||||
slice s = get_data().begin_parse();
|
||||
throwIf(101, 0);
|
||||
var unused = throwIf2(101, 0);
|
||||
return s~load_uint(8);
|
||||
}
|
||||
|
||||
int setAndGetDataWrapper(int ret) {
|
||||
return setAndGetData(ret);
|
||||
}
|
||||
|
||||
int test1() method_id(101) {
|
||||
cell c = begin_cell().storeUint(32, 10000000).end_cell();
|
||||
slice s = c.begin_parse();
|
||||
return s~load_uint(32);
|
||||
}
|
||||
|
||||
int test2(int ret) method_id {
|
||||
return setAndGetDataWrapper(ret);
|
||||
}
|
||||
|
||||
int test3() method_id(103) {
|
||||
return initial2(10);
|
||||
}
|
||||
|
||||
global tuple t;
|
||||
|
||||
int foo(int x) {
|
||||
t~tpush(x);
|
||||
return x * 10;
|
||||
}
|
||||
|
||||
(tuple, tuple) test4() method_id(104) {
|
||||
t = empty_tuple();
|
||||
tuple t2 = asmFunc4(foo(11), (foo(22), (foo(33), foo(44))), foo(55));
|
||||
return (t, t2);
|
||||
}
|
||||
|
||||
int test5() method_id(105) {
|
||||
if (1) {
|
||||
return postpone_elections();
|
||||
}
|
||||
return 123;
|
||||
}
|
||||
|
||||
int main(int ret) {
|
||||
return setAndGetDataWrapper(ret);
|
||||
}
|
||||
|
||||
int recv_external(int ret) {
|
||||
return setAndGetData(ret);
|
||||
}
|
||||
|
||||
{-
|
||||
method_id | in | out
|
||||
TESTCASE | 101 | | 32
|
||||
TESTCASE | 103 | | 10
|
||||
TESTCASE | 104 | | [ 11 22 33 44 55 ] [ 220 330 440 110 550 ]
|
||||
TESTCASE | 105 | | 0
|
||||
TESTCASE | 74435 | 99 | 99
|
||||
TESTCASE | 0 | 98 | 98
|
||||
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
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test3 PROC:<{
|
||||
//
|
||||
10 PUSHINT // _0=10
|
||||
initial2 CALLDICT // _1
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
test2 PROC:<{
|
||||
// ret
|
||||
setAndGetData CALLDICT // _1
|
||||
}>
|
||||
"""
|
||||
|
||||
@fif_codegen
|
||||
"""
|
||||
11 PUSHINT
|
||||
foo CALLDICT
|
||||
22 PUSHINT
|
||||
foo CALLDICT
|
||||
33 PUSHINT
|
||||
foo CALLDICT
|
||||
44 PUSHINT
|
||||
foo CALLDICT
|
||||
55 PUSHINT
|
||||
foo CALLDICT
|
||||
asmFunc4 CALLDICT // t2
|
||||
"""
|
||||
|
||||
@fif_codegen_avoid setAndGetDataWrapper
|
||||
-}
|
Loading…
Add table
Add a link
Reference in a new issue