diff --git a/src/aeso_builtins.erl b/src/aeso_builtins.erl index 4d328fc..1eea814 100644 --- a/src/aeso_builtins.erl +++ b/src/aeso_builtins.erl @@ -39,10 +39,11 @@ builtin_deps1({map_upd_default, Type}) -> [{map_lookup_default, Type}, map_pu builtin_deps1(map_from_list) -> [map_put]; builtin_deps1(str_equal) -> [str_equal_p]; builtin_deps1(string_concat) -> [string_concat_inner1, string_concat_inner2]; -builtin_deps1(int_to_str) -> [int_to_str_, int_digits]; -builtin_deps1(addr_to_str) -> [base58_int, string_concat]; -builtin_deps1(base58_int) -> [base58_int_encode, base58_int_pad, string_reverse, string_concat]; -builtin_deps1(base58_int_encode) -> [base58_int_encode_, base58_tab]; +builtin_deps1(int_to_str) -> [{baseX_int, 10}]; +builtin_deps1(addr_to_str) -> [{baseX_int, 58}]; +builtin_deps1({baseX_int, X}) -> [{baseX_int_pad, X}]; +builtin_deps1({baseX_int_pad, X}) -> [{baseX_int_encode, X}]; +builtin_deps1({baseX_int_encode, X}) -> [{baseX_int_encode_, X}, {baseX_tab, X}, {baseX_digits, X}]; builtin_deps1(string_reverse) -> [string_reverse_]; builtin_deps1(_) -> []. @@ -108,8 +109,6 @@ check_event_type(Evts, Icode) -> || {constr_t, _, {con, _, Name}, Types} <- Evts, T <- Types ]. check_event_type(EvtName, Type, Icode) -> - io:format("~p: ~p??\n", [EvtName, Type]), - io:format("=> ~p\n", [aeso_ast_to_icode:ast_typerep(Type, Icode)]), VMType = try aeso_ast_to_icode:ast_typerep(Type, Icode) @@ -123,11 +122,47 @@ check_event_type(EvtName, Type, Icode) -> false -> error({EvtName, payload_should_be_string, is, VMType}) end. +bfun(B, {IArgs, IExpr, IRet}) -> + {{builtin, B}, [private], IArgs, IExpr, IRet}. + +builtin_function(BF) -> + case BF of + {event, EventT} -> bfun(BF, builtin_event(EventT)); + abort -> bfun(BF, builtin_abort()); + {map_lookup, Type} -> bfun(BF, builtin_map_lookup(Type)); + map_put -> bfun(BF, builtin_map_put()); + map_delete -> bfun(BF, builtin_map_delete()); + map_size -> bfun(BF, builtin_map_size()); + {map_get, Type} -> bfun(BF, builtin_map_get(Type)); + {map_lookup_default, Type} -> bfun(BF, builtin_map_lookup_default(Type)); + map_member -> bfun(BF, builtin_map_member()); + {map_upd, Type} -> bfun(BF, builtin_map_upd(Type)); + {map_upd_default, Type} -> bfun(BF, builtin_map_upd_default(Type)); + map_from_list -> bfun(BF, builtin_map_from_list()); + list_concat -> bfun(BF, builtin_list_concat()); + string_length -> bfun(BF, builtin_string_length()); + string_concat -> bfun(BF, builtin_string_concat()); + string_concat_inner1 -> bfun(BF, builtin_string_concat_inner1()); + string_concat_inner2 -> bfun(BF, builtin_string_concat_inner2()); + str_equal_p -> bfun(BF, builtin_str_equal_p()); + str_equal -> bfun(BF, builtin_str_equal()); + int_to_str -> bfun(BF, builtin_int_to_str()); + addr_to_str -> bfun(BF, builtin_addr_to_str()); + {baseX_int, X} -> bfun(BF, builtin_baseX_int(X)); + {baseX_digits, X} -> bfun(BF, builtin_baseX_digits(X)); + {baseX_tab, X} -> bfun(BF, builtin_baseX_tab(X)); + {baseX_int_pad, X} -> bfun(BF, builtin_baseX_int_pad(X)); + {baseX_int_encode, X} -> bfun(BF, builtin_baseX_int_encode(X)); + {baseX_int_encode_, X} -> bfun(BF, builtin_baseX_int_encode_(X)); + string_reverse -> bfun(BF, builtin_string_reverse()); + string_reverse_ -> bfun(BF, builtin_string_reverse_()) + end. + %% Event primitive (dependent on Event type) %% %% We need to switch on the event and prepare the correct #event for icode_to_asm %% NOTE: we assume all errors are already checked! -builtin_function(Builtin = {event, EventT}) -> +builtin_event(EventT) -> A = fun(X) -> aeb_opcodes:mnemonic(X) end, VIx = fun(Ix) -> v(lists:concat(["v", Ix])) end, ArgPats = fun(Ts) -> [ VIx(Ix) || Ix <- lists:seq(0, length(Ts) - 1) ] end, @@ -149,149 +184,132 @@ builtin_function(Builtin = {event, EventT}) -> {variant_t, Cons} = EventT, Tags = lists:seq(0, length(Cons) - 1), - {{builtin, Builtin}, [private], - [{"e", event}], - {switch, v(e), - [{Pat(Tag, Types), Clause(Tag, Con, Types)} - || {Tag, {constr_t, _, Con, Types}} <- lists:zip(Tags, Cons) ]}, - {tuple, []}}; + {[{"e", event}], + {switch, v(e), + [{Pat(Tag, Types), Clause(Tag, Con, Types)} + || {Tag, {constr_t, _, Con, Types}} <- lists:zip(Tags, Cons) ]}, + {tuple, []}}. %% Abort primitive. -builtin_function(abort) -> +builtin_abort() -> A = fun(X) -> aeb_opcodes:mnemonic(X) end, - {{builtin, abort}, [private], - [{"s", string}], + {[{"s", string}], {inline_asm, [A(?PUSH1),0, %% Push a dummy 0 for the first arg A(?REVERT)]}, %% Stack: 0,Ptr - {tuple,[]}}; + {tuple,[]}}. %% Map primitives -builtin_function(Builtin = {map_lookup, Type}) -> +builtin_map_lookup(Type) -> Ret = aeso_icode:option_typerep(Type), - {{builtin, Builtin}, [private], - [{"m", word}, {"k", word}], - prim_call(?PRIM_CALL_MAP_GET, #integer{value = 0}, - [#var_ref{name = "m"}, #var_ref{name = "k"}], - [word, word], Ret), - Ret}; + {[{"m", word}, {"k", word}], + prim_call(?PRIM_CALL_MAP_GET, #integer{value = 0}, + [#var_ref{name = "m"}, #var_ref{name = "k"}], + [word, word], Ret), + Ret}. -builtin_function(Builtin = map_put) -> +builtin_map_put() -> %% We don't need the types for put. - {{builtin, Builtin}, [private], - [{"m", word}, {"k", word}, {"v", word}], - prim_call(?PRIM_CALL_MAP_PUT, #integer{value = 0}, - [v(m), v(k), v(v)], - [word, word, word], word), - word}; + {[{"m", word}, {"k", word}, {"v", word}], + prim_call(?PRIM_CALL_MAP_PUT, #integer{value = 0}, + [v(m), v(k), v(v)], [word, word, word], word), + word}. -builtin_function(Builtin = map_delete) -> - {{builtin, Builtin}, [private], - [{"m", word}, {"k", word}], - prim_call(?PRIM_CALL_MAP_DELETE, #integer{value = 0}, - [v(m), v(k)], - [word, word], word), - word}; +builtin_map_delete() -> + {[{"m", word}, {"k", word}], + prim_call(?PRIM_CALL_MAP_DELETE, #integer{value = 0}, + [v(m), v(k)], [word, word], word), + word}. -builtin_function(Builtin = map_size) -> - Name = {builtin, Builtin}, - {Name, [private], [{"m", word}], - prim_call(?PRIM_CALL_MAP_SIZE, #integer{value = 0}, - [v(m)], [word], word), - word}; +builtin_map_size() -> + {[{"m", word}], + prim_call(?PRIM_CALL_MAP_SIZE, #integer{value = 0}, + [v(m)], [word], word), + word}. %% Map builtins -builtin_function(Builtin = {map_get, Type}) -> +builtin_map_get(Type) -> %% function map_get(m, k) = %% switch(map_lookup(m, k)) %% Some(v) => v - {{builtin, Builtin}, [private], - [{"m", word}, {"k", word}], - {switch, ?call({map_lookup, Type}, [v(m), v(k)]), - [{option_some(v(v)), v(v)}]}, - Type}; + {[{"m", word}, {"k", word}], + {switch, ?call({map_lookup, Type}, [v(m), v(k)]), [{option_some(v(v)), v(v)}]}, + Type}. -builtin_function(Builtin = {map_lookup_default, Type}) -> +builtin_map_lookup_default(Type) -> %% function map_lookup_default(m, k, default) = %% switch(map_lookup(m, k)) %% None => default %% Some(v) => v - {{builtin, Builtin}, [private], - [{"m", word}, {"k", word}, {"default", Type}], - {switch, ?call({map_lookup, Type}, [v(m), v(k)]), - [{option_none(), v(default)}, - {option_some(v(v)), v(v)}]}, - Type}; + {[{"m", word}, {"k", word}, {"default", Type}], + {switch, ?call({map_lookup, Type}, [v(m), v(k)]), + [{option_none(), v(default)}, + {option_some(v(v)), v(v)}]}, + Type}. -builtin_function(Builtin = map_member) -> +builtin_map_member() -> %% function map_member(m, k) : bool = %% switch(Map.lookup(m, k)) %% None => false %% _ => true - {{builtin, Builtin}, [private], - [{"m", word}, {"k", word}], - {switch, ?call({map_lookup, word}, [v(m), v(k)]), - [{option_none(), {integer, 0}}, - {{var_ref, "_"}, {integer, 1}}]}, - word}; + {[{"m", word}, {"k", word}], + {switch, ?call({map_lookup, word}, [v(m), v(k)]), + [{option_none(), {integer, 0}}, + {{var_ref, "_"}, {integer, 1}}]}, + word}. -builtin_function(Builtin = {map_upd, Type}) -> +builtin_map_upd(Type) -> %% function map_upd(map, key, fun) = %% map_put(map, key, fun(map_get(map, key))) - {{builtin, Builtin}, [private], - [{"map", word}, {"key", word}, {"valfun", word}], + {[{"map", word}, {"key", word}, {"valfun", word}], ?call(map_put, [v(map), v(key), #funcall{ function = v(valfun), args = [?call({map_get, Type}, [v(map), v(key)])] }]), - word}; + word}. -builtin_function(Builtin = {map_upd_default, Type}) -> +builtin_map_upd_default(Type) -> %% function map_upd(map, key, val, fun) = %% map_put(map, key, fun(map_lookup_default(map, key, val))) - {{builtin, Builtin}, [private], - [{"map", word}, {"key", word}, {"val", word}, {"valfun", word}], + {[{"map", word}, {"key", word}, {"val", word}, {"valfun", word}], ?call(map_put, [v(map), v(key), #funcall{ function = v(valfun), args = [?call({map_lookup_default, Type}, [v(map), v(key), v(val)])] }]), - word}; + word}. -builtin_function(Builtin = map_from_list) -> +builtin_map_from_list() -> %% function map_from_list(xs, acc) = %% switch(xs) %% [] => acc %% (k, v) :: xs => map_from_list(xs, acc { [k] = v }) - {{builtin, Builtin}, [private], - [{"xs", {list, {tuple, [word, word]}}}, {"acc", word}], + {[{"xs", {list, {tuple, [word, word]}}}, {"acc", word}], {switch, v(xs), [{{list, []}, v(acc)}, {{binop, '::', {tuple, [v(k), v(v)]}, v(ys)}, ?call(map_from_list, [v(ys), ?call(map_put, [v(acc), v(k), v(v)])])}]}, - word}; + word}. %% list_concat %% %% Concatenates two lists. -builtin_function(list_concat) -> - {{builtin, list_concat}, [private], - [{"l1", {list, word}}, {"l2", {list, word}}], +builtin_list_concat() -> + {[{"l1", {list, word}}, {"l2", {list, word}}], {switch, v(l1), [{{list, []}, v(l2)}, {{binop, '::', v(hd), v(tl)}, {binop, '::', v(hd), ?call(list_concat, [v(tl), v(l2)])}} ] }, - word}; + word}. -builtin_function(string_length) -> +builtin_string_length() -> %% function length(str) = %% switch(str) %% {n} -> n // (ab)use the representation - {{builtin, string_length}, [private], - [{"s", string}], - ?DEREF(n, s, ?V(n)), - word}; + {[{"s", string}], + ?DEREF(n, s, ?V(n)), + word}. %% str_concat - concatenate two strings %% @@ -299,9 +317,8 @@ builtin_function(string_length) -> %% top of the Heap and the address to it is returned. The tricky bit is when %% the words from the second string has to be shifted to fit next to the first %% string. -builtin_function(string_concat) -> - {{builtin, string_concat}, [private], - [{"s1", string}, {"s2", string}], +builtin_string_concat() -> + {[{"s1", string}, {"s2", string}], ?DEREF(n1, s1, ?DEREF(n2, s2, {ifte, ?EQ(n2, 0), @@ -313,13 +330,12 @@ builtin_function(string_concat) -> ?V(ret) %% Put the actual return value ]})} )), - word}; + word}. -builtin_function(string_concat_inner1) -> +builtin_string_concat_inner1() -> %% Copy all whole words from the first string, and set up for word fusion %% Special case when the length of the first string is divisible by 32. - {{builtin, string_concat_inner1}, [private], - [{"n1", word}, {"p1", pointer}, {"n2", word}, {"p2", pointer}], + {[{"n1", word}, {"p1", pointer}, {"n2", word}, {"p2", pointer}], ?DEREF(w1, p1, {ifte, ?GT(n1, 32), {seq, [?V(w1), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, @@ -328,13 +344,12 @@ builtin_function(string_concat_inner1) -> ?call(string_concat_inner2, [?I(32), ?I(0), ?V(n2), ?V(p2)]), ?call(string_concat_inner2, [?SUB(32, n1), ?V(w1), ?V(n2), ?V(p2)])} }), - word}; + word}. -builtin_function(string_concat_inner2) -> +builtin_string_concat_inner2() -> %% Current "work in progess" word 'x', has 'o' bytes that are "free" - fill them from %% words of the second string. - {{builtin, string_concat_inner2}, [private], - [{"o", word}, {"x", word}, {"n2", word}, {"p2", pointer}], + {[{"o", word}, {"x", word}, {"n2", word}, {"p2", pointer}], {ifte, ?LT(n2, 1), {seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]}, %% Use MSIZE as dummy return value ?DEREF(w2, p2, @@ -348,163 +363,121 @@ builtin_function(string_concat_inner2) -> {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]} %% Use MSIZE as dummy return value }) }, - word}; + word}. -builtin_function(str_equal_p) -> +builtin_str_equal_p() -> %% function str_equal_p(n, p1, p2) = %% if(n =< 0) true %% else %% let w1 = *p1 %% let w2 = *p2 %% w1 == w2 && str_equal_p(n - 32, p1 + 32, p2 + 32) - {{builtin, str_equal_p}, [private], - [{"n", word}, {"p1", pointer}, {"p2", pointer}], - {ifte, ?LT(n, 1), - ?I(1), - ?DEREF(w1, p1, - ?DEREF(w2, p2, - ?AND(?EQ(w1, w2), - ?call(str_equal_p, [?SUB(n, 32), ?NXT(p1), ?NXT(p2)]))))}, - word}; + {[{"n", word}, {"p1", pointer}, {"p2", pointer}], + {ifte, ?LT(n, 1), + ?I(1), + ?DEREF(w1, p1, + ?DEREF(w2, p2, + ?AND(?EQ(w1, w2), + ?call(str_equal_p, [?SUB(n, 32), ?NXT(p1), ?NXT(p2)]))))}, + word}. -builtin_function(str_equal) -> +builtin_str_equal() -> %% function str_equal(s1, s2) = %% let n1 = length(s1) %% let n2 = length(s2) %% n1 == n2 && str_equal_p(n1, s1 + 32, s2 + 32) - {{builtin, str_equal}, [private], - [{"s1", string}, {"s2", string}], - ?DEREF(n1, s1, - ?DEREF(n2, s2, - ?AND(?EQ(n1, n2), ?call(str_equal_p, [?V(n1), ?NXT(s1), ?NXT(s2)])) - )), - word}; + {[{"s1", string}, {"s2", string}], + ?DEREF(n1, s1, + ?DEREF(n2, s2, + ?AND(?EQ(n1, n2), ?call(str_equal_p, [?V(n1), ?NXT(s1), ?NXT(s2)])) + )), + word}. -builtin_function(int_to_str) -> - {{builtin, int_to_str}, [private], - [{"i0", word}], - {switch, {ifte, ?LT(i0, 0), - {tuple, [?I(2), ?NEG(i0), ?BSL(45, 31)]}, - {tuple, [?I(1), ?V(i0), ?I(0)]}}, - [{{tuple, [v(off), v(i), v(x)]}, - ?LET(ret, {inline_asm, [?A(?MSIZE)]}, - ?LET(n, ?call(int_digits, [?DIV(i, 10), ?I(0)]), - ?LET(fac, ?EXP(10, n), - {seq, [?ADD(n, off), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, %% Store str len - ?call(int_to_str_, - [?MOD(i, fac), ?ADD(x, ?BSL(?ADD(48, ?DIV(i, fac)), ?SUB(32, off))), ?DIV(fac, 10), ?V(off)]), - {inline_asm, [?A(?POP)]}, ?V(ret)]} - )))}]}, - word}; +builtin_int_to_str() -> + {[{"i", word}], ?call({baseX_int, 10}, [?V(i)]), word}. -builtin_function(int_to_str_) -> - {{builtin, int_to_str_}, [private], - [{"x", word}, {"y", word}, {"fac", word}, {"n", word}], - {ifte, ?EQ(fac, 0), - {seq, [?V(y), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, ?V(n)]}, - {ifte, ?EQ(?MOD(n, 32), 0), - %% We've filled a word, write it and start on new word - {seq, [?V(y), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, - ?call(int_to_str_, - [?MOD(x, fac), ?BSL(?ADD(48, ?DIV(x, fac)), 31), - ?DIV(fac, 10), ?I(1)])]}, - ?call(int_to_str_, - [?MOD(x, fac), ?ADD(y, ?BSL(?ADD(48, ?DIV(x, fac)), ?SUB(31, n))), - ?DIV(fac, 10), ?ADD(n, 1)])} - }, - word}; +builtin_baseX_tab(_X = 10) -> + {[{"ix", word}], ?ADD($0, ix), word}; +builtin_baseX_tab(_X = 58) -> + <> = <<"123456789ABCDEFGHJKLMNPQRSTUVWXY">>, + <> = <<"Zabcdefghijkmnopqrstuvwxyz", 0:48>>, + {[{"ix", word}], + {ifte, ?LT(ix, 32), + ?BYTE(ix, Fst32), + ?BYTE(?SUB(ix, 32), Lst26) + }, + word}. -builtin_function(int_digits) -> - {{builtin, int_digits}, [private], - [{"x", word}, {"n", word}], - {ifte, ?EQ(x, 0), ?V(n), ?call(int_digits, [?DIV(x, 10), ?ADD(n, 1)])}, - word}; +builtin_baseX_int(X) -> + {[{"w", word}], + ?LET(ret, {inline_asm, [?A(?MSIZE)]}, + {seq, [?call({baseX_int_pad, X}, [?V(w), ?I(0), ?I(0)]), {inline_asm, [?A(?POP)]}, ?V(ret)]}), + word}. -builtin_function(base58_tab) -> - Fst32 = 22252025330403739761829862310514590177935513752035045390683118730099851483225, - Lst26 = 40880219588527126470443504235291962205031881694701834176631306799289575931904, - {{builtin, base58_tab}, [private], - [{"ix", word}], - {ifte, ?LT(ix, 32), - ?BYTE(ix, Fst32), - ?BYTE(?SUB(ix, 32), Lst26) - }, word}; +builtin_baseX_int_pad(X = 10) -> + {[{"src", word}, {"ix", word}, {"dst", word}], + {ifte, ?LT(src, 0), + ?call({baseX_int_encode, X}, [?NEG(src), ?I(1), ?BSL($-, 31)]), + ?call({baseX_int_encode, X}, [?V(src), ?V(ix), ?V(dst)])}, + word}; +builtin_baseX_int_pad(X = 58) -> + {[{"src", word}, {"ix", word}, {"dst", word}], + {ifte, ?GT(?ADD(?DIV(ix, 31), ?BYTE(ix, src)), 0), + ?call({baseX_int_encode, X}, [?V(src), ?V(ix), ?V(dst)]), + ?call({baseX_int_pad, X}, [?V(src), ?ADD(ix, 1), ?ADD(dst, ?BSL($1, ?SUB(31, ix)))])}, + word}. -builtin_function(base58_int) -> - {{builtin, base58_int}, [private], - [{"w", word}], - ?LET(str0, ?call(base58_int_encode, [?V(w)]), - ?LET(str1, ?call(base58_int_pad, [?V(w), ?I(0), ?I(0)]), - ?LET(str2, ?call(string_concat, [?V(str0), ?V(str1)]), - ?call(string_reverse, [?V(str2)]) - ))), - word}; +builtin_baseX_int_encode(X) -> + {[{"src", word}, {"ix", word}, {"dst", word}], + ?LET(n, ?call({baseX_digits, X}, [?V(src), ?I(0)]), + {seq, [?ADD(n, ?ADD(ix, 1)), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, + ?call({baseX_int_encode_, X}, [?V(src), ?V(dst), ?EXP(X, n), ?V(ix)])]}), + word}. -builtin_function(string_reverse) -> - {{builtin, string_reverse}, [private], - [{"s", string}], - ?DEREF(n, s, - ?LET(ret, {inline_asm, [?A(?MSIZE)]}, - {seq, [?V(n), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, - ?call(string_reverse_, [?NXT(s), ?I(0), ?I(31), ?SUB(?V(n), 1)]), - {inline_asm, [?A(?POP)]}, ?V(ret)]})), - word}; +builtin_baseX_int_encode_(X) -> + {[{"src", word}, {"dst", word}, {"fac", word}, {"ix", word}], + {ifte, ?EQ(fac, 0), + {seq, [?V(dst), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]}, + {ifte, ?EQ(ix, 32), + %% We've filled a word, write it and start on new word + {seq, [?V(dst), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, + ?call({baseX_int_encode_, X}, [?V(src), ?I(0), ?V(fac), ?I(0)])]}, + ?call({baseX_int_encode_, X}, + [?MOD(src, fac), ?ADD(dst, ?BSL(?call({baseX_tab, X}, [?DIV(src, fac)]), ?SUB(31, ix))), + ?DIV(fac, X), ?ADD(ix, 1)])} + }, + word}. -builtin_function(string_reverse_) -> - {{builtin, string_reverse_}, [private], - [{"p", pointer}, {"x", word}, {"i1", word}, {"i2", word}], - {ifte, ?LT(i2, 0), - {seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]}, - ?LET(p1, ?ADD(p, ?MUL(?DIV(i2, 32), 32)), - ?DEREF(w, p1, - ?LET(b, ?BYTE(?MOD(i2, 32), w), - {ifte, ?LT(i1, 0), - {seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, - ?call(string_reverse_, - [?V(p), ?BSL(b, 31), ?I(30), ?SUB(i2, 1)])]}, - ?call(string_reverse_, - [?V(p), ?ADD(x, ?BSL(b, i1)), ?SUB(i1, 1), ?SUB(i2, 1)])})))}, - word}; +builtin_baseX_digits(X) -> + {[{"x0", word}, {"dgts", word}], + ?LET(x1, ?DIV(x0, X), + {ifte, ?EQ(x1, 0), ?V(dgts), ?call({baseX_digits, X}, [?V(x1), ?ADD(dgts, 1)])}), + word}. -builtin_function(base58_int_pad) -> - {{builtin, base58_int_pad}, [private], - [{"w", word}, {"i", word}, {"x", word}], - {ifte, ?GT(?BYTE(i, w), 0), - {seq, [?V(i), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, - ?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, - {inline_asm, [?A(?PUSH1), 64, ?A(?MSIZE), ?A(?SUB)]}]}, - ?call(base58_int_pad, [?V(w), ?ADD(i, 1), - ?ADD(x, ?BSL(49, ?SUB(31, i)))])}, - word}; +builtin_string_reverse() -> + {[{"s", string}], + ?DEREF(n, s, + ?LET(ret, {inline_asm, [?A(?MSIZE)]}, + {seq, [?V(n), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, + ?call(string_reverse_, [?NXT(s), ?I(0), ?I(31), ?SUB(?V(n), 1)]), + {inline_asm, [?A(?POP)]}, ?V(ret)]})), + word}. -builtin_function(base58_int_encode) -> - {{builtin, base58_int_encode}, [private], - [{"w", word}], - ?LET(ret, {inline_asm, [?A(?MSIZE), ?A(?PUSH1), 0, ?A(?MSIZE), ?A(?MSTORE)]}, %% write placeholder - ?LET(n, ?call(base58_int_encode_, [?V(w), ?I(0), ?I(0), ?I(31)]), - {seq, [?V(ret), {inline_asm, [?A(?DUP2), ?A(?SWAP1), ?A(?MSTORE)]}, - ?V(ret)]})), - word}; +builtin_string_reverse_() -> + {[{"p", pointer}, {"x", word}, {"i1", word}, {"i2", word}], + {ifte, ?LT(i2, 0), + {seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]}, + ?LET(p1, ?ADD(p, ?MUL(?DIV(i2, 32), 32)), + ?DEREF(w, p1, + ?LET(b, ?BYTE(?MOD(i2, 32), w), + {ifte, ?LT(i1, 0), + {seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, + ?call(string_reverse_, + [?V(p), ?BSL(b, 31), ?I(30), ?SUB(i2, 1)])]}, + ?call(string_reverse_, + [?V(p), ?ADD(x, ?BSL(b, i1)), ?SUB(i1, 1), ?SUB(i2, 1)])})))}, + word}. -builtin_function(base58_int_encode_) -> - {{builtin, base58_int_encode_}, [private], - [{"w", word}, {"x", word}, {"n", word}, {"i", word}], - {ifte, ?EQ(w, 0), - {seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, ?V(n)]}, - {ifte, ?LT(i, 0), - {seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, - ?call(base58_int_encode_, - [?DIV(w, 58), ?BSL(?call(base58_tab, [?MOD(w, 58)]), 31), - ?ADD(n, 1), ?I(30)])]}, - ?call(base58_int_encode_, - [?DIV(w, 58), ?ADD(x, ?BSL(?call(base58_tab, [?MOD(w, 58)]), i)), - ?ADD(n, 1), ?SUB(i, 1)])}}, - word}; - - -builtin_function(addr_to_str) -> - {{builtin, addr_to_str}, [private], - [{"a", word}], - ?call(base58_int, [?V(a)]), - word}. +builtin_addr_to_str() -> + {[{"a", word}], ?call({baseX_int, 58}, [?V(a)]), word}.