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

updated func and tonlib

This commit is contained in:
ton 2020-02-15 20:03:17 +04:00
parent 493ae2410c
commit a73d202ba2
50 changed files with 1340 additions and 271 deletions

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "func.h"
@ -323,6 +323,20 @@ void Op::show(std::ostream& os, const std::vector<TmpVar>& vars, std::string pfx
show_var_list(os, right, vars);
os << std::endl;
break;
case _Tuple:
os << pfx << dis << "MKTUPLE ";
show_var_list(os, left, vars);
os << " := ";
show_var_list(os, right, vars);
os << std::endl;
break;
case _UnTuple:
os << pfx << dis << "UNTUPLE ";
show_var_list(os, left, vars);
os << " := ";
show_var_list(os, right, vars);
os << std::endl;
break;
case _IntConst:
os << pfx << dis << "CONST ";
show_var_list(os, left, vars);

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "func.h"
@ -29,6 +29,7 @@ namespace funC {
void CodeBlob::simplify_var_types() {
for (TmpVar& var : vars) {
TypeExpr::remove_indirect(var.v_type);
var.v_type->recompute_width();
}
}
@ -354,7 +355,9 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
case _IntConst:
case _GlobVar:
case _Call:
case _CallInd: {
case _CallInd:
case _Tuple:
case _UnTuple: {
// left = EXEC right;
if (!next_var_info.count_used(left) && is_pure()) {
// all variables in `left` are not needed
@ -541,6 +544,8 @@ bool prune_unreachable(std::unique_ptr<Op>& ops) {
case Op::_SetGlob:
case Op::_Call:
case Op::_CallInd:
case Op::_Tuple:
case Op::_UnTuple:
case Op::_Import:
reach = true;
break;
@ -724,6 +729,8 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
}
break;
}
case _Tuple:
case _UnTuple:
case _GlobVar:
case _CallInd: {
for (var_idx_t i : left) {
@ -842,6 +849,8 @@ bool Op::mark_noreturn() {
case _Import:
case _IntConst:
case _Let:
case _Tuple:
case _UnTuple:
case _SetGlob:
case _GlobVar:
case _CallInd:

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "parser/srcread.h"
#include "func.h"
@ -121,12 +121,49 @@ AsmOp AsmOp::BlkDrop(int a) {
return AsmOp::Custom(os.str(), a, 0);
}
AsmOp AsmOp::BlkDrop2(int a, int b) {
if (!b) {
return BlkDrop(a);
}
std::ostringstream os;
os << a << " " << b << " BLKDROP2";
return AsmOp::Custom(os.str(), a + b, b);
}
AsmOp AsmOp::BlkReverse(int a, int b) {
std::ostringstream os;
os << a << " " << b << " REVERSE";
return AsmOp::Custom(os.str(), a + b, a + b);
}
AsmOp AsmOp::Tuple(int a) {
switch (a) {
case 1:
return AsmOp::Custom("SINGLE", 1, 1);
case 2:
return AsmOp::Custom("PAIR", 2, 1);
case 3:
return AsmOp::Custom("TRIPLE", 3, 1);
}
std::ostringstream os;
os << a << " TUPLE";
return AsmOp::Custom(os.str(), a, 1);
}
AsmOp AsmOp::UnTuple(int a) {
switch (a) {
case 1:
return AsmOp::Custom("UNSINGLE", 1, 1);
case 2:
return AsmOp::Custom("UNPAIR", 1, 2);
case 3:
return AsmOp::Custom("UNTRIPLE", 1, 3);
}
std::ostringstream os;
os << a << " UNTUPLE";
return AsmOp::Custom(os.str(), 1, a);
}
AsmOp AsmOp::IntConst(td::RefInt256 x) {
if (x->signed_fits_bits(8)) {
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT");

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "func.h"
@ -318,7 +318,7 @@ bool Op::generate_code_step(Stack& stack) {
stack.o << AsmOp::Custom(name + " GETGLOB", 0, 1);
if (left.size() != 1) {
assert(left.size() <= 15);
stack.o << exec_arg_op("UNTUPLE", (int)left.size(), 1, (int)left.size());
stack.o << AsmOp::UnTuple((int)left.size());
}
for (auto i : left) {
stack.push_new_var(i);
@ -396,6 +396,32 @@ bool Op::generate_code_step(Stack& stack) {
}
return true;
}
case _Tuple:
case _UnTuple: {
if (disabled()) {
return true;
}
std::vector<bool> last;
for (var_idx_t x : right) {
last.push_back(var_info[x] && var_info[x]->is_last());
}
stack.rearrange_top(right, std::move(last));
stack.opt_show();
int k = (int)stack.depth() - (int)right.size();
assert(k >= 0);
if (cl == _Tuple) {
stack.o << AsmOp::Tuple((int)right.size());
assert(left.size() == 1);
} else {
stack.o << AsmOp::UnTuple((int)left.size());
assert(right.size() == 1);
}
stack.s.resize(k);
for (int i = 0; i < (int)left.size(); i++) {
stack.push_new_var(left.at(i));
}
return true;
}
case _Call:
case _CallInd: {
if (disabled()) {
@ -483,7 +509,7 @@ bool Op::generate_code_step(Stack& stack) {
assert(stack.s[k + i].first == right[i]);
}
if (right.size() > 1) {
stack.o << exec_arg_op("TUPLE", (int)right.size(), (int)right.size(), 1);
stack.o << AsmOp::Tuple((int)right.size());
}
if (!right.empty()) {
std::string name = sym::symbols.get_name(fun_ref->sym_idx);

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include <vector>
@ -36,7 +36,7 @@ namespace funC {
extern int verbosity;
extern bool op_rewrite_comments;
constexpr int optimize_depth = 12;
constexpr int optimize_depth = 20;
enum Keyword {
_Eof = -1,
@ -101,6 +101,7 @@ enum Keyword {
_Extern,
_Inline,
_InlineRef,
_AutoApply,
_MethodId,
_Operator,
_Infix,
@ -134,7 +135,7 @@ class IdSc {
*/
struct TypeExpr {
enum te_type { te_Unknown, te_Var, te_Indirect, te_Atomic, te_Tensor, te_Map, te_Type, te_ForAll } constr;
enum te_type { te_Unknown, te_Var, te_Indirect, te_Atomic, te_Tensor, te_Tuple, te_Map, te_Type, te_ForAll } constr;
enum {
_Int = Keyword::_Int,
_Cell = Keyword::_Cell,
@ -160,6 +161,9 @@ struct TypeExpr {
: constr(_constr), value((int)list.size()), args(std::move(list)) {
compute_width();
}
TypeExpr(te_type _constr, TypeExpr* elem0) : constr(_constr), value(1), args{elem0} {
compute_width();
}
TypeExpr(te_type _constr, TypeExpr* elem0, std::vector<TypeExpr*> list)
: constr(_constr), value((int)list.size() + 1), args{elem0} {
args.insert(args.end(), list.begin(), list.end());
@ -185,6 +189,9 @@ struct TypeExpr {
bool is_map() const {
return constr == te_Map;
}
bool is_tuple() const {
return constr == te_Tuple;
}
bool has_fixed_width() const {
return minw == maxw;
}
@ -226,6 +233,15 @@ struct TypeExpr {
static TypeExpr* new_tensor(TypeExpr* te1, TypeExpr* te2, TypeExpr* te3) {
return new_tensor({te1, te2, te3});
}
static TypeExpr* new_tuple(TypeExpr* arg0) {
return new TypeExpr{te_Tuple, arg0};
}
static TypeExpr* new_tuple(std::vector<TypeExpr*> list, bool red = false) {
return new_tuple(new_tensor(std::move(list), red));
}
static TypeExpr* new_tuple(std::initializer_list<TypeExpr*> list) {
return new_tuple(new_tensor(std::move(list)));
}
static TypeExpr* new_var() {
return new TypeExpr{te_Var, --type_vars, 1};
}
@ -505,6 +521,8 @@ struct Op {
_SetGlob,
_Import,
_Return,
_Tuple,
_UnTuple,
_If,
_While,
_Until,
@ -789,7 +807,8 @@ struct Expr {
_Apply,
_VarApply,
_TypeApply,
_Tuple,
_MkTuple,
_Tensor,
_Const,
_Var,
_Glob,
@ -843,6 +862,12 @@ struct Expr {
bool is_type() const {
return flags & _IsType;
}
bool is_type_apply() const {
return cls == _TypeApply;
}
bool is_mktuple() const {
return cls == _MkTuple;
}
void chk_rvalue(const Lexem& lem) const;
void chk_lvalue(const Lexem& lem) const;
void chk_type(const Lexem& lem) const;
@ -855,7 +880,8 @@ struct Expr {
}
int define_new_vars(CodeBlob& code);
int predefine_vars();
std::vector<var_idx_t> pre_compile(CodeBlob& code) const;
std::vector<var_idx_t> pre_compile(CodeBlob& code, bool lval = false) const;
static std::vector<var_idx_t> pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here);
var_idx_t new_tmp(CodeBlob& code) const;
std::vector<var_idx_t> new_tmp_vect(CodeBlob& code) const {
return {new_tmp(code)};
@ -1004,6 +1030,7 @@ struct AsmOp {
static AsmOp BlkSwap(int a, int b);
static AsmOp BlkPush(int a, int b);
static AsmOp BlkDrop(int a);
static AsmOp BlkDrop2(int a, int b);
static AsmOp BlkReverse(int a, int b);
static AsmOp make_stk2(int a, int b, const char* str, int delta);
static AsmOp make_stk3(int a, int b, int c, const char* str, int delta);
@ -1024,6 +1051,8 @@ struct AsmOp {
return AsmOp(a_custom, args, retv, custom_op);
}
static AsmOp Parse(std::string custom_op, int args, int retv = 1);
static AsmOp Tuple(int a);
static AsmOp UnTuple(int a);
};
inline std::ostream& operator<<(std::ostream& os, const AsmOp& op) {
@ -1261,6 +1290,8 @@ struct StackTransform {
bool is_blkpush(int i, int j) const;
bool is_blkpush(int* i, int* j) const;
bool is_blkdrop(int* i) const;
bool is_blkdrop2(int i, int j) const;
bool is_blkdrop2(int* i, int* j) const;
bool is_reverse(int i, int j) const;
bool is_reverse(int* i, int* j) const;
bool is_nip_seq(int i, int j = 0) const;
@ -1270,7 +1301,10 @@ struct StackTransform {
bool is_pop_blkdrop(int* i, int* k) const;
bool is_2pop_blkdrop(int i, int j, int k) const;
bool is_2pop_blkdrop(int* i, int* j, int* k) const;
bool is_const_rot() const;
bool is_const_rot(int c) const;
bool is_const_rot(int* c) const;
bool is_const_pop(int c, int i) const;
bool is_const_pop(int* c, int* i) const;
void show(std::ostream& os, int mode = 0) const;
@ -1307,11 +1341,12 @@ struct Optimizer {
AsmOpCons* op_cons_[n];
int offs_[n];
StackTransform tr_[n];
int mode_{0};
Optimizer() {
}
Optimizer(bool debug) : debug_(debug) {
Optimizer(bool debug, int mode = 0) : debug_(debug), mode_(mode) {
}
Optimizer(AsmOpConsList code, bool debug = false) : Optimizer(debug) {
Optimizer(AsmOpConsList code, bool debug = false, int mode = 0) : Optimizer(debug, mode) {
set_code(std::move(code));
}
void set_code(AsmOpConsList code_);
@ -1327,12 +1362,15 @@ struct Optimizer {
void show_head() const;
void show_left() const;
void show_right() const;
bool find_const_op(int* op_idx, int cst);
bool is_const_push_swap() const;
bool rewrite_const_push_swap();
bool is_const_push_xchgs();
bool rewrite_const_push_xchgs();
bool is_const_rot() const;
bool rewrite_const_rot();
bool is_const_rot(int* c) const;
bool rewrite_const_rot(int c);
bool is_const_pop(int* c, int* i) const;
bool rewrite_const_pop(int c, int i);
bool simple_rewrite(int p, AsmOp&& new_op);
bool simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2);
bool simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3);
@ -1374,6 +1412,7 @@ struct Optimizer {
bool is_blkswap(int* i, int* j);
bool is_blkpush(int* i, int* j);
bool is_blkdrop(int* i);
bool is_blkdrop2(int* i, int* j);
bool is_reverse(int* i, int* j);
bool is_nip_seq(int* i, int* j);
bool is_pop_blkdrop(int* i, int* k);
@ -1381,8 +1420,8 @@ struct Optimizer {
AsmOpConsList extract_code();
};
AsmOpConsList optimize_code_head(AsmOpConsList op_list);
AsmOpConsList optimize_code(AsmOpConsList op_list);
AsmOpConsList optimize_code_head(AsmOpConsList op_list, int mode = 0);
AsmOpConsList optimize_code(AsmOpConsList op_list, int mode);
void optimize_code(AsmOpList& ops);
struct Stack {

View file

@ -14,10 +14,12 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "func.h"
using namespace std::literals::string_literals;
namespace funC {
/*
@ -164,7 +166,8 @@ bool Expr::deduce_type(const Lexem& lem) {
int Expr::define_new_vars(CodeBlob& code) {
switch (cls) {
case _Tuple:
case _Tensor:
case _MkTuple:
case _TypeApply: {
int res = 0;
for (const auto& x : args) {
@ -189,7 +192,8 @@ int Expr::define_new_vars(CodeBlob& code) {
int Expr::predefine_vars() {
switch (cls) {
case _Tuple:
case _Tensor:
case _MkTuple:
case _TypeApply: {
int res = 0;
for (const auto& x : args) {
@ -201,6 +205,7 @@ int Expr::predefine_vars() {
if (!sym) {
assert(val < 0 && here.defined());
sym = sym::define_symbol(~val, false, here);
// std::cerr << "predefining variable " << sym::symbols.get_name(~val) << std::endl;
if (!sym) {
throw src::ParseError{here, std::string{"redefined variable `"} + sym::symbols.get_name(~val) + "`"};
}
@ -216,12 +221,51 @@ var_idx_t Expr::new_tmp(CodeBlob& code) const {
return code.create_tmp_var(e_type, &here);
}
std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code) const {
std::vector<var_idx_t> Expr::pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here) {
while (lhs->is_type_apply()) {
lhs = lhs->args.at(0);
}
while (rhs->is_type_apply()) {
rhs = rhs->args.at(0);
}
if (lhs->is_mktuple()) {
if (rhs->is_mktuple()) {
return pre_compile_let(code, lhs->args.at(0), rhs->args.at(0), here);
}
auto right = rhs->pre_compile(code);
TypeExpr::remove_indirect(rhs->e_type);
auto unpacked_type = rhs->e_type->args.at(0);
std::vector<var_idx_t> tmp{code.create_tmp_var(unpacked_type, &rhs->here)};
code.emplace_back(lhs->here, Op::_UnTuple, tmp, std::move(right));
auto tvar = new Expr{_Var};
tvar->set_val(tmp[0]);
tvar->set_location(rhs->here);
tvar->e_type = unpacked_type;
pre_compile_let(code, lhs->args.at(0), tvar, here);
return tmp;
}
auto right = rhs->pre_compile(code);
if (lhs->cls == Expr::_GlobVar) {
assert(lhs->sym);
auto& op = code.emplace_back(here, Op::_SetGlob, std::vector<var_idx_t>{}, right, lhs->sym);
op.flags |= Op::_Impure;
} else {
auto left = lhs->pre_compile(code, true);
code.emplace_back(here, Op::_Let, std::move(left), right);
}
return right;
}
std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
if (lval && !(cls == _Tensor || cls == _Var || cls == _Hole || cls == _TypeApply)) {
std::cerr << "lvalue expression constructor is " << cls << std::endl;
throw src::Fatal{"cannot compile lvalue expression with unknown constructor"};
}
switch (cls) {
case _Tuple: {
case _Tensor: {
std::vector<var_idx_t> res;
for (const auto& x : args) {
auto add = x->pre_compile(code);
auto add = x->pre_compile(code, lval);
res.insert(res.end(), add.cbegin(), add.cend());
}
return res;
@ -253,7 +297,7 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code) const {
return rvect;
}
case _TypeApply:
return args[0]->pre_compile(code);
return args[0]->pre_compile(code, lval);
case _Var:
case _Hole:
return {val};
@ -289,25 +333,22 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code) const {
return rvect;
}
case _Letop: {
auto right = args[1]->pre_compile(code);
if (args[0]->cls == Expr::_GlobVar) {
assert(args[0]->sym);
auto& op = code.emplace_back(here, Op::_SetGlob, std::vector<var_idx_t>{}, right, args[0]->sym);
op.flags |= Op::_Impure;
} else {
auto left = args[0]->pre_compile(code);
code.emplace_back(here, Op::_Let, std::move(left), right);
}
return right;
return pre_compile_let(code, args.at(0), args.at(1), here);
}
case _LetFirst: {
auto rvect = new_tmp_vect(code);
auto right = args[1]->pre_compile(code);
auto left = args[0]->pre_compile(code);
auto left = args[0]->pre_compile(code, true);
left.push_back(rvect[0]);
code.emplace_back(here, Op::_Let, std::move(left), std::move(right));
return rvect;
}
case _MkTuple: {
auto left = new_tmp_vect(code);
auto right = args[0]->pre_compile(code);
code.emplace_back(here, Op::_Tuple, left, std::move(right));
return left;
}
case _CondExpr: {
auto cond = args[0]->pre_compile(code);
assert(cond.size() == 1);

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "func.h"
@ -46,6 +46,8 @@ void define_keywords() {
.add_kw_char(';')
.add_kw_char('(')
.add_kw_char(')')
.add_kw_char('[')
.add_kw_char(']')
.add_kw_char('{')
.add_kw_char('}')
.add_kw_char('=')
@ -118,6 +120,7 @@ void define_keywords() {
.add_keyword("impure", Kw::_Impure)
.add_keyword("inline", Kw::_Inline)
.add_keyword("inline_ref", Kw::_InlineRef)
.add_keyword("auto_apply", Kw::_AutoApply)
.add_keyword("method_id", Kw::_MethodId)
.add_keyword("operator", Kw::_Operator)
.add_keyword("infix", Kw::_Infix)

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "func.h"
@ -134,6 +134,16 @@ bool Optimizer::say(std::string str) const {
return true;
}
bool Optimizer::find_const_op(int* op_idx, int cst) {
for (int i = 0; i < l2_; i++) {
if (op_[i]->is_gconst() && tr_[i].get(0) == cst) {
*op_idx = i;
return true;
}
}
return false;
}
bool Optimizer::is_const_push_swap() const {
return l_ >= 3 && op_[0]->is_gconst() && op_[1]->is_push() && op_[1]->a >= 1 && op_[2]->is_swap();
}
@ -150,21 +160,44 @@ bool Optimizer::rewrite_const_push_swap() {
return true;
}
bool Optimizer::is_const_rot() const {
return pb_ >= 3 && pb_ <= l2_ && op_[0]->is_gconst() && tr_[pb_ - 1].is_const_rot();
bool Optimizer::is_const_rot(int* c) const {
return pb_ >= 3 && pb_ <= l2_ && tr_[pb_ - 1].is_const_rot(c);
}
bool Optimizer::rewrite_const_rot() {
bool Optimizer::rewrite_const_rot(int c) {
p_ = pb_;
q_ = 2;
int idx = -1;
if (!(p_ >= 2 && find_const_op(&idx, c) && idx < p_)) {
return false;
}
show_left();
oq_[0] = std::move(op_[0]);
oq_[1] = std::move(op_[1]);
oq_[0] = std::move(op_[idx]);
oq_[1] = std::move(op_[idx ? 0 : 1]);
*oq_[1] = AsmOp::Custom("ROT", 3, 3);
show_right();
return true;
}
bool Optimizer::is_const_pop(int* c, int* i) const {
return pb_ >= 3 && pb_ <= l2_ && tr_[pb_ - 1].is_const_pop(c, i);
}
bool Optimizer::rewrite_const_pop(int c, int i) {
p_ = pb_;
q_ = 2;
int idx = -1;
if (!(p_ >= 2 && find_const_op(&idx, c) && idx < p_)) {
return false;
}
show_left();
oq_[0] = std::move(op_[idx]);
oq_[1] = std::move(op_[idx ? 0 : 1]);
*oq_[1] = AsmOp::Pop(i);
show_right();
return true;
}
bool Optimizer::is_const_push_xchgs() {
if (!(pb_ >= 2 && pb_ <= l2_ && op_[0]->is_gconst())) {
return false;
@ -424,6 +457,10 @@ bool Optimizer::is_blkdrop(int* i) {
return is_pred([i](const auto& t) { return t.is_blkdrop(i) && *i > 0 && *i < 16; });
}
bool Optimizer::is_blkdrop2(int* i, int* j) {
return is_pred([i, j](const auto& t) { return t.is_blkdrop2(i, j) && *i > 0 && *i < 16 && *j > 0 && *j < 16; });
}
bool Optimizer::is_reverse(int* i, int* j) {
return is_pred([i, j](const auto& t) { return t.is_reverse(i, j) && *i >= 2 && *i <= 17 && *j < 16; });
}
@ -488,38 +525,42 @@ bool Optimizer::find_at_least(int pb) {
p_ = q_ = 0;
pb_ = pb;
// show_stack_transforms();
int i = -100, j = -100, k = -100;
int i = -100, j = -100, k = -100, c = 0;
return (is_const_push_swap() && 3 >= pb && rewrite_const_push_swap()) || (is_nop() && simple_rewrite_nop()) ||
(is_const_rot() && rewrite_const_rot()) || (is_const_push_xchgs() && rewrite_const_push_xchgs()) ||
(!(mode_ & 1) && is_const_rot(&c) && rewrite_const_rot(c)) ||
(is_const_push_xchgs() && rewrite_const_push_xchgs()) || (is_const_pop(&c, &i) && rewrite_const_pop(c, i)) ||
(is_xchg(&i, &j) && simple_rewrite(AsmOp::Xchg(i, j))) || (is_push(&i) && simple_rewrite(AsmOp::Push(i))) ||
(is_pop(&i) && simple_rewrite(AsmOp::Pop(i))) || (is_rot() && simple_rewrite(AsmOp::Custom("ROT", 3, 3))) ||
(is_rotrev() && simple_rewrite(AsmOp::Custom("-ROT", 3, 3))) ||
(is_2dup() && simple_rewrite(AsmOp::Custom("2DUP", 2, 4))) ||
(is_2swap() && simple_rewrite(AsmOp::Custom("2SWAP", 2, 4))) ||
(is_2over() && simple_rewrite(AsmOp::Custom("2OVER", 2, 4))) ||
(is_tuck() && simple_rewrite(AsmOp::Custom("TUCK", 2, 3))) ||
(is_2drop() && simple_rewrite(AsmOp::Custom("2DROP", 2, 0))) ||
(is_xchg2(&i, &j) && simple_rewrite(AsmOp::Xchg2(i, j))) ||
(is_xcpu(&i, &j) && simple_rewrite(AsmOp::XcPu(i, j))) ||
(is_puxc(&i, &j) && simple_rewrite(AsmOp::PuXc(i, j))) ||
(is_push2(&i, &j) && simple_rewrite(AsmOp::Push2(i, j))) ||
(is_blkswap(&i, &j) && simple_rewrite(AsmOp::BlkSwap(i, j))) ||
(is_blkpush(&i, &j) && simple_rewrite(AsmOp::BlkPush(i, j))) ||
(is_blkdrop(&i) && simple_rewrite(AsmOp::BlkDrop(i))) ||
(is_reverse(&i, &j) && simple_rewrite(AsmOp::BlkReverse(i, j))) ||
(is_nip_seq(&i, &j) && simple_rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) ||
(is_pop_blkdrop(&i, &k) && simple_rewrite(AsmOp::Pop(i), AsmOp::BlkDrop(k))) ||
(is_2pop_blkdrop(&i, &j, &k) && (k >= 3 && k <= 13 && i != j + 1 && i <= 15 && j <= 14
? simple_rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2))
: simple_rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) ||
(is_xchg3(&i, &j, &k) && simple_rewrite(AsmOp::Xchg3(i, j, k))) ||
(is_xc2pu(&i, &j, &k) && simple_rewrite(AsmOp::Xc2Pu(i, j, k))) ||
(is_xcpuxc(&i, &j, &k) && simple_rewrite(AsmOp::XcPuXc(i, j, k))) ||
(is_xcpu2(&i, &j, &k) && simple_rewrite(AsmOp::XcPu2(i, j, k))) ||
(is_puxc2(&i, &j, &k) && simple_rewrite(AsmOp::PuXc2(i, j, k))) ||
(is_puxcpu(&i, &j, &k) && simple_rewrite(AsmOp::PuXcPu(i, j, k))) ||
(is_pu2xc(&i, &j, &k) && simple_rewrite(AsmOp::Pu2Xc(i, j, k))) ||
(is_push3(&i, &j, &k) && simple_rewrite(AsmOp::Push3(i, j, k)));
(is_pop(&i) && simple_rewrite(AsmOp::Pop(i))) ||
(!(mode_ & 1) &&
((is_rot() && simple_rewrite(AsmOp::Custom("ROT", 3, 3))) ||
(is_rotrev() && simple_rewrite(AsmOp::Custom("-ROT", 3, 3))) ||
(is_2dup() && simple_rewrite(AsmOp::Custom("2DUP", 2, 4))) ||
(is_2swap() && simple_rewrite(AsmOp::Custom("2SWAP", 2, 4))) ||
(is_2over() && simple_rewrite(AsmOp::Custom("2OVER", 2, 4))) ||
(is_tuck() && simple_rewrite(AsmOp::Custom("TUCK", 2, 3))) ||
(is_2drop() && simple_rewrite(AsmOp::Custom("2DROP", 2, 0))) ||
(is_xchg2(&i, &j) && simple_rewrite(AsmOp::Xchg2(i, j))) ||
(is_xcpu(&i, &j) && simple_rewrite(AsmOp::XcPu(i, j))) ||
(is_puxc(&i, &j) && simple_rewrite(AsmOp::PuXc(i, j))) ||
(is_push2(&i, &j) && simple_rewrite(AsmOp::Push2(i, j))) ||
(is_blkswap(&i, &j) && simple_rewrite(AsmOp::BlkSwap(i, j))) ||
(is_blkpush(&i, &j) && simple_rewrite(AsmOp::BlkPush(i, j))) ||
(is_blkdrop(&i) && simple_rewrite(AsmOp::BlkDrop(i))) ||
(is_reverse(&i, &j) && simple_rewrite(AsmOp::BlkReverse(i, j))) ||
(is_nip_seq(&i, &j) && simple_rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) ||
(is_pop_blkdrop(&i, &k) && simple_rewrite(AsmOp::Pop(i), AsmOp::BlkDrop(k))) ||
(is_blkdrop2(&i, &j) && simple_rewrite(AsmOp::BlkDrop2(i, j))) ||
(is_2pop_blkdrop(&i, &j, &k) && (k >= 3 && k <= 13 && i != j + 1 && i <= 15 && j <= 14
? simple_rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2))
: simple_rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) ||
(is_xchg3(&i, &j, &k) && simple_rewrite(AsmOp::Xchg3(i, j, k))) ||
(is_xc2pu(&i, &j, &k) && simple_rewrite(AsmOp::Xc2Pu(i, j, k))) ||
(is_xcpuxc(&i, &j, &k) && simple_rewrite(AsmOp::XcPuXc(i, j, k))) ||
(is_xcpu2(&i, &j, &k) && simple_rewrite(AsmOp::XcPu2(i, j, k))) ||
(is_puxc2(&i, &j, &k) && simple_rewrite(AsmOp::PuXc2(i, j, k))) ||
(is_puxcpu(&i, &j, &k) && simple_rewrite(AsmOp::PuXcPu(i, j, k))) ||
(is_pu2xc(&i, &j, &k) && simple_rewrite(AsmOp::Pu2Xc(i, j, k))) ||
(is_push3(&i, &j, &k) && simple_rewrite(AsmOp::Push3(i, j, k)))));
}
bool Optimizer::find() {
@ -544,17 +585,17 @@ bool Optimizer::optimize() {
return f;
}
AsmOpConsList optimize_code_head(AsmOpConsList op_list) {
Optimizer opt(std::move(op_list), op_rewrite_comments);
AsmOpConsList optimize_code_head(AsmOpConsList op_list, int mode) {
Optimizer opt(std::move(op_list), op_rewrite_comments, mode);
opt.optimize();
return opt.extract_code();
}
AsmOpConsList optimize_code(AsmOpConsList op_list) {
AsmOpConsList optimize_code(AsmOpConsList op_list, int mode) {
std::vector<std::unique_ptr<AsmOp>> v;
while (op_list) {
if (!op_list->car->is_comment()) {
op_list = optimize_code_head(std::move(op_list));
op_list = optimize_code_head(std::move(op_list), mode);
}
if (op_list) {
v.push_back(std::move(op_list->car));
@ -568,11 +609,14 @@ AsmOpConsList optimize_code(AsmOpConsList op_list) {
}
void optimize_code(AsmOpList& ops) {
std::unique_ptr<AsmOpCons> op_list;
AsmOpConsList op_list;
for (auto it = ops.list_.rbegin(); it < ops.list_.rend(); ++it) {
op_list = AsmOpCons::cons(std::make_unique<AsmOp>(std::move(*it)), std::move(op_list));
}
op_list = optimize_code(std::move(op_list));
op_list = optimize_code(std::move(op_list), 1);
op_list = optimize_code(std::move(op_list), 1);
op_list = optimize_code(std::move(op_list), 0);
op_list = optimize_code(std::move(op_list), 0);
ops.list_.clear();
while (op_list) {
ops.list_.push_back(std::move(*(op_list->car)));

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "func.h"
#include "td/utils/crypto.h"
@ -100,14 +100,21 @@ TypeExpr* parse_type1(Lexer& lex) {
lex.cur().error_at("`", "` is not a type identifier");
}
}
lex.expect('(');
if (lex.tp() == ')') {
int c;
if (lex.tp() == '[') {
lex.next();
return TypeExpr::new_unit();
c = ']';
} else {
lex.expect('(');
c = ')';
}
if (lex.tp() == c) {
lex.next();
return c == ')' ? TypeExpr::new_unit() : TypeExpr::new_tuple({});
}
auto t1 = parse_type(lex);
if (lex.tp() != ',') {
lex.expect(')');
lex.expect(c);
return t1;
}
std::vector<TypeExpr*> tlist{1, t1};
@ -115,8 +122,8 @@ TypeExpr* parse_type1(Lexer& lex) {
lex.next();
tlist.push_back(parse_type(lex));
}
lex.expect(')');
return TypeExpr::new_tensor(std::move(tlist));
lex.expect(c);
return c == ')' ? TypeExpr::new_tensor(std::move(tlist)) : TypeExpr::new_tuple(std::move(tlist));
}
TypeExpr* parse_type(Lexer& lex) {
@ -302,7 +309,7 @@ bool check_global_func(const Lexem& cur, sym_idx_t func_name = 0) {
Expr* make_func_apply(Expr* fun, Expr* x) {
Expr* res;
if (fun->cls == Expr::_Glob) {
if (x->cls == Expr::_Tuple) {
if (x->cls == Expr::_Tensor) {
res = new Expr{Expr::_Apply, fun->sym, x->args};
} else {
res = new Expr{Expr::_Apply, fun->sym, {x}};
@ -317,28 +324,36 @@ Expr* make_func_apply(Expr* fun, Expr* x) {
Expr* parse_expr(Lexer& lex, CodeBlob& code, bool nv = false);
// parse ( E { , E } ) | () | id | num | _
// parse ( E { , E } ) | () | [ E { , E } ] | [] | id | num | _
Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
if (lex.tp() == '(') {
if (lex.tp() == '(' || lex.tp() == '[') {
bool tf = (lex.tp() == '[');
int clbr = (tf ? ']' : ')');
SrcLocation loc{lex.cur().loc};
lex.next();
if (lex.tp() == ')') {
if (lex.tp() == clbr) {
lex.next();
Expr* res = new Expr{Expr::_Tuple, {}};
Expr* res = new Expr{Expr::_Tensor, {}};
res->flags = Expr::_IsRvalue;
res->here = loc;
res->e_type = TypeExpr::new_unit();
if (tf) {
res = new Expr{Expr::_MkTuple, {res}};
res->flags = Expr::_IsRvalue;
res->here = loc;
res->e_type = TypeExpr::new_tuple(res->args.at(0)->e_type);
}
return res;
}
Expr* res = parse_expr(lex, code, nv);
if (lex.tp() != ',') {
lex.expect(')');
lex.expect(clbr);
return res;
}
std::vector<TypeExpr*> type_list;
type_list.push_back(res->e_type);
int f = res->flags;
res = new Expr{Expr::_Tuple, {res}};
res = new Expr{Expr::_Tensor, {res}};
while (lex.tp() == ',') {
lex.next();
auto x = parse_expr(lex, code, nv);
@ -351,8 +366,14 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
}
res->here = loc;
res->flags = f;
res->e_type = TypeExpr::new_tensor(std::move(type_list));
lex.expect(')');
res->e_type = TypeExpr::new_tensor(std::move(type_list), !tf);
if (tf) {
res = new Expr{Expr::_MkTuple, {res}};
res->flags = f;
res->here = loc;
res->e_type = TypeExpr::new_tuple(res->args.at(0)->e_type);
}
lex.expect(clbr);
return res;
}
int t = lex.tp();
@ -382,7 +403,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
lex.next();
return res;
}
if (t == _Int || t == _Cell || t == _Slice || t == _Builder || t == _Cont || t == _Type) {
if (t == _Int || t == _Cell || t == _Slice || t == _Builder || t == _Cont || t == _Type || t == _Tuple) {
Expr* res = new Expr{Expr::_Type, lex.cur().loc};
res->flags = Expr::_IsType;
res->e_type = TypeExpr::new_atomic(t);
@ -458,7 +479,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
// parse E { E }
Expr* parse_expr90(Lexer& lex, CodeBlob& code, bool nv) {
Expr* res = parse_expr100(lex, code, nv);
while (lex.tp() == '(' || (lex.tp() == _Ident && !is_special_ident(lex.cur().val))) {
while (lex.tp() == '(' || lex.tp() == '[' || (lex.tp() == _Ident && !is_special_ident(lex.cur().val))) {
if (res->is_type()) {
Expr* x = parse_expr100(lex, code, true);
x->chk_lvalue(lex.cur()); // chk_lrvalue() ?
@ -523,7 +544,7 @@ Expr* parse_expr80(Lexer& lex, CodeBlob& code, bool nv) {
lex.next();
auto x = parse_expr100(lex, code, false);
x->chk_rvalue(lex.cur());
if (x->cls == Expr::_Tuple) {
if (x->cls == Expr::_Tensor) {
res = new Expr{Expr::_Apply, name, {obj}};
res->args.insert(res->args.end(), x->args.begin(), x->args.end());
} else {
@ -1269,7 +1290,7 @@ void parse_func_def(Lexer& lex) {
bool parse_source(std::istream* is, const src::FileDescr* fdescr) {
src::SourceReader reader{is, fdescr};
Lexer lex{reader, true};
Lexer lex{reader, true, ";,()[] ~."};
while (lex.tp() != _Eof) {
if (lex.tp() == _Global) {
parse_global_var_decls(lex);

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "func.h"
@ -742,6 +742,28 @@ bool StackTransform::is_blkdrop(int *i) const {
return false;
}
// 0 1 .. j-1 j+i j+i+1 ...
bool StackTransform::is_blkdrop2(int i, int j) const {
if (!is_valid() || d != i || i <= 0 || j < 0 || dp < i + j || n != j || !is_trivial_after(j)) {
return false;
}
for (int s = 0; s < j; s++) {
if (get(s) != s) {
return false;
}
}
return true;
}
bool StackTransform::is_blkdrop2(int *i, int *j) const {
if (is_valid() && is_blkdrop2(d, n)) {
*i = d;
*j = n;
return true;
}
return false;
}
// equivalent to i times PUSH s(j)
bool StackTransform::is_blkpush(int *i, int *j) const {
if (!is_valid() || d >= 0) {
@ -846,8 +868,27 @@ bool StackTransform::is_2pop_blkdrop(int *i, int *j, int *k) const {
}
// PUSHCONST c ; ROT == 1 -1000 0 2 3
bool StackTransform::is_const_rot() const {
return is_valid() && d == -1 && is_trivial_after(3) && get(0) == 1 && get(1) <= c_start && get(2) == 0;
bool StackTransform::is_const_rot(int c) const {
return is_valid() && d == -1 && is_trivial_after(3) && get(0) == 1 && c <= c_start && get(1) == c && get(2) == 0;
}
bool StackTransform::is_const_rot(int *c) const {
return is_valid() && (*c = get(1)) <= c_start && is_const_rot(*c);
}
// PUSHCONST c ; POP s(i) == 0 1 .. i-1 -1000 i+1 ...
bool StackTransform::is_const_pop(int c, int i) const {
return is_valid() && !d && n == 1 && i > 0 && c <= c_start && get(i - 1) == c;
}
bool StackTransform::is_const_pop(int *c, int *i) const {
if (is_valid() && !d && n == 1 && A[0].second <= c_start) {
*i = A[0].first + 1;
*c = A[0].second;
return is_const_pop(*c, *i);
} else {
return false;
}
}
void StackTransform::show(std::ostream &os, int mode) const {

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "func.h"
@ -47,6 +47,12 @@ void TypeExpr::compute_width() {
maxw = w_inf;
}
break;
case te_Tuple:
minw = maxw = 1;
for (TypeExpr* arg : args) {
arg->compute_width();
}
break;
case te_Indirect:
minw = args[0]->minw;
maxw = args[0]->maxw;
@ -84,6 +90,14 @@ bool TypeExpr::recompute_width() {
}
return true;
}
case te_Tuple: {
for (TypeExpr* arg : args) {
if (arg->minw > 1 || arg->maxw < 1 || arg->minw > arg->maxw) {
return false;
}
}
return true;
}
default:
return false;
}
@ -233,7 +247,9 @@ std::ostream& TypeExpr::print(std::ostream& os, int lex_level) {
}
}
case te_Tensor: {
os << "(";
if (lex_level > -127) {
os << "(";
}
auto c = args.size();
if (c) {
for (const auto& x : args) {
@ -243,7 +259,25 @@ std::ostream& TypeExpr::print(std::ostream& os, int lex_level) {
}
}
}
return os << ")";
if (lex_level > -127) {
os << ")";
}
return os;
}
case te_Tuple: {
os << "[";
auto c = args.size();
if (c == 1 && args[0]->constr == te_Tensor) {
args[0]->print(os, -127);
} else if (c) {
for (const auto& x : args) {
x->print(os);
if (--c) {
os << ", ";
}
}
}
return os << "]";
}
case te_Map: {
assert(args.size() == 2);
@ -312,7 +346,7 @@ void check_update_widths(TypeExpr* te1, TypeExpr* te2) {
check_width_compat(te1, te2);
te1->minw = te2->minw = std::max(te1->minw, te2->minw);
te1->maxw = te2->maxw = std::min(te1->maxw, te2->maxw);
assert(te1->minw <= te2->minw);
assert(te1->minw <= te1->maxw);
}
void unify(TypeExpr*& te1, TypeExpr*& te2) {