2
This file is part of TON Blockchain Library.
4
TON Blockchain Library is free software: you can redistribute it and/or modify
5
it under the terms of the GNU Lesser General Public License as published by
6
the Free Software Foundation, either version 2 of the License, or
7
(at your option) any later version.
9
TON Blockchain Library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU Lesser General Public License for more details.
14
You should have received a copy of the GNU Lesser General Public License
15
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
17
Copyright 2017-2020 Telegram Systems LLP
19
#include "parser/srcread.h"
27
* ASM-OP LIST FUNCTIONS
31
int is_pos_pow2(td::RefInt256 x) {
32
if (sgn(x) > 0 && !sgn(x & (x - 1))) {
33
return x->bit_size(false) - 1;
39
int is_neg_pow2(td::RefInt256 x) {
40
return sgn(x) < 0 ? is_pos_pow2(-x) : 0;
43
std::ostream& operator<<(std::ostream& os, AsmOp::SReg stack_reg) {
44
int i = stack_reg.idx;
47
return os << 's' << i;
49
return os << i << " s()";
52
return os << "s(" << i << ')';
54
return os << i << " s()";
58
AsmOp AsmOp::Const(int arg, std::string push_op, td::RefInt256 origin) {
59
std::ostringstream os;
60
os << arg << ' ' << push_op;
61
return AsmOp::Const(os.str(), origin);
64
AsmOp AsmOp::make_stk2(int a, int b, const char* str, int delta) {
65
std::ostringstream os;
66
os << SReg(a) << ' ' << SReg(b) << ' ' << str;
67
int c = std::max(a, b) + 1;
68
return AsmOp::Custom(os.str(), c, c + delta);
71
AsmOp AsmOp::make_stk3(int a, int b, int c, const char* str, int delta) {
72
std::ostringstream os;
73
os << SReg(a) << ' ' << SReg(b) << ' ' << SReg(c) << ' ' << str;
74
int m = std::max(a, std::max(b, c)) + 1;
75
return AsmOp::Custom(os.str(), m, m + delta);
78
AsmOp AsmOp::BlkSwap(int a, int b) {
79
std::ostringstream os;
80
if (a == 1 && b == 1) {
81
return AsmOp::Xchg(0, 1);
95
os << a << " " << b << " BLKSWAP";
97
return AsmOp::Custom(os.str(), a + b, a + b);
100
AsmOp AsmOp::BlkPush(int a, int b) {
101
std::ostringstream os;
103
return AsmOp::Push(b);
104
} else if (a == 2 && b == 1) {
107
os << a << " " << b << " BLKPUSH";
109
return AsmOp::Custom(os.str(), b + 1, a + b + 1);
112
AsmOp AsmOp::BlkDrop(int a) {
113
std::ostringstream os;
119
os << a << " BLKDROP";
121
return AsmOp::Custom(os.str(), a, 0);
124
AsmOp AsmOp::BlkDrop2(int a, int b) {
128
std::ostringstream os;
129
os << a << " " << b << " BLKDROP2";
130
return AsmOp::Custom(os.str(), a + b, b);
133
AsmOp AsmOp::BlkReverse(int a, int b) {
134
std::ostringstream os;
135
os << a << " " << b << " REVERSE";
136
return AsmOp::Custom(os.str(), a + b, a + b);
139
AsmOp AsmOp::Tuple(int a) {
142
return AsmOp::Custom("SINGLE", 1, 1);
144
return AsmOp::Custom("PAIR", 2, 1);
146
return AsmOp::Custom("TRIPLE", 3, 1);
148
std::ostringstream os;
150
return AsmOp::Custom(os.str(), a, 1);
153
AsmOp AsmOp::UnTuple(int a) {
156
return AsmOp::Custom("UNSINGLE", 1, 1);
158
return AsmOp::Custom("UNPAIR", 1, 2);
160
return AsmOp::Custom("UNTRIPLE", 1, 3);
162
std::ostringstream os;
163
os << a << " UNTUPLE";
164
return AsmOp::Custom(os.str(), 1, a);
167
AsmOp AsmOp::IntConst(td::RefInt256 x) {
168
if (x->signed_fits_bits(8)) {
169
return AsmOp::Const(dec_string(x) + " PUSHINT", x);
171
if (!x->is_valid()) {
172
return AsmOp::Const("PUSHNAN", x);
174
int k = is_pos_pow2(x);
176
return AsmOp::Const(k, "PUSHPOW2", x);
178
k = is_pos_pow2(x + 1);
180
return AsmOp::Const(k, "PUSHPOW2DEC", x);
184
return AsmOp::Const(k, "PUSHNEGPOW2", x);
186
if (!x->mod_pow2_short(23)) {
187
return AsmOp::Const(dec_string(x) + " PUSHINTX", x);
189
return AsmOp::Const(dec_string(x) + " PUSHINT", x);
192
AsmOp AsmOp::BoolConst(bool f) {
193
return AsmOp::Const(f ? "TRUE" : "FALSE");
196
AsmOp AsmOp::Parse(std::string custom_op) {
197
if (custom_op == "NOP") {
199
} else if (custom_op == "SWAP") {
200
return AsmOp::Xchg(1);
201
} else if (custom_op == "DROP") {
202
return AsmOp::Pop(0);
203
} else if (custom_op == "NIP") {
204
return AsmOp::Pop(1);
205
} else if (custom_op == "DUP") {
206
return AsmOp::Push(0);
207
} else if (custom_op == "OVER") {
208
return AsmOp::Push(1);
210
return AsmOp::Custom(custom_op);
214
AsmOp AsmOp::Parse(std::string custom_op, int args, int retv) {
215
auto res = Parse(custom_op);
216
if (res.is_custom()) {
223
void AsmOp::out(std::ostream& os) const {
232
if (!a && !(b & -2)) {
233
os << (b ? "SWAP" : "NOP");
236
os << SReg(a) << ' ' << SReg(b) << " XCHG";
240
os << (a ? "OVER" : "DUP");
243
os << SReg(a) << " PUSH";
247
os << (a ? "NIP" : "DROP");
250
os << SReg(a) << " POP";
253
throw src::Fatal{"unknown assembler operation"};
257
void AsmOp::out_indent_nl(std::ostream& os, bool no_eol) const {
258
for (int i = 0; i < indent; i++) {
267
std::string AsmOp::to_string() const {
271
std::ostringstream os;
277
bool AsmOpList::append(const std::vector<AsmOp>& ops) {
278
for (const auto& op : ops) {
286
const_idx_t AsmOpList::register_const(Const new_const) {
287
if (new_const.is_null()) {
291
for (idx = 0; idx < constants_.size(); idx++) {
292
if (!td::cmp(new_const, constants_[idx])) {
296
constants_.push_back(std::move(new_const));
297
return (const_idx_t)idx;
300
Const AsmOpList::get_const(const_idx_t idx) {
301
if ((unsigned)idx < constants_.size()) {
302
return constants_[idx];
308
void AsmOpList::show_var(std::ostream& os, var_idx_t idx) const {
309
if (!var_names_ || (unsigned)idx >= var_names_->size()) {
312
var_names_->at(idx).show(os, 2);
316
void AsmOpList::show_var_ext(std::ostream& os, std::pair<var_idx_t, const_idx_t> idx_pair) const {
317
auto i = idx_pair.first;
318
auto j = idx_pair.second;
319
if (!var_names_ || (unsigned)i >= var_names_->size()) {
322
var_names_->at(i).show(os, 2);
324
if ((unsigned)j < constants_.size() && constants_[j].not_null()) {
325
os << '=' << constants_[j];
329
void AsmOpList::out(std::ostream& os, int mode) const {
331
for (const auto& op : list_) {
332
op.out_indent_nl(os);
335
std::size_t n = list_.size();
336
for (std::size_t i = 0; i < n; i++) {
337
const auto& op = list_[i];
338
if (!op.is_comment() && i + 1 < n && list_[i + 1].is_comment()) {
339
op.out_indent_nl(os, true);
343
} while (i + 1 < n && list_[i + 1].is_comment());
347
op.out_indent_nl(os, false);
353
bool apply_op(StackTransform& trans, const AsmOp& op) {
354
if (!trans.is_valid()) {
361
return trans.apply_xchg(op.a, op.b, true);
363
return trans.apply_push(op.a);
365
return trans.apply_pop(op.a);
367
return !op.a && op.b == 1 && trans.apply_push_newconst();
368
case AsmOp::a_custom:
369
return op.is_gconst() && trans.apply_push_newconst();