Ton

Форк
0
/
asmops.cpp 
375 строк · 8.6 Кб
1
/*
2
    This file is part of TON Blockchain Library.
3

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.
8

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.
13

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/>.
16

17
    Copyright 2017-2020 Telegram Systems LLP
18
*/
19
#include "parser/srcread.h"
20
#include "func.h"
21
#include <iostream>
22

23
namespace funC {
24

25
/*
26
 * 
27
 *   ASM-OP LIST FUNCTIONS
28
 * 
29
 */
30

31
int is_pos_pow2(td::RefInt256 x) {
32
  if (sgn(x) > 0 && !sgn(x & (x - 1))) {
33
    return x->bit_size(false) - 1;
34
  } else {
35
    return -1;
36
  }
37
}
38

39
int is_neg_pow2(td::RefInt256 x) {
40
  return sgn(x) < 0 ? is_pos_pow2(-x) : 0;
41
}
42

43
std::ostream& operator<<(std::ostream& os, AsmOp::SReg stack_reg) {
44
  int i = stack_reg.idx;
45
  if (i >= 0) {
46
    if (i < 16) {
47
      return os << 's' << i;
48
    } else {
49
      return os << i << " s()";
50
    }
51
  } else if (i >= -2) {
52
    return os << "s(" << i << ')';
53
  } else {
54
    return os << i << " s()";
55
  }
56
}
57

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);
62
}
63

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);
69
}
70

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);
76
}
77

78
AsmOp AsmOp::BlkSwap(int a, int b) {
79
  std::ostringstream os;
80
  if (a == 1 && b == 1) {
81
    return AsmOp::Xchg(0, 1);
82
  } else if (a == 1) {
83
    if (b == 2) {
84
      os << "ROT";
85
    } else {
86
      os << b << " ROLL";
87
    }
88
  } else if (b == 1) {
89
    if (a == 2) {
90
      os << "-ROT";
91
    } else {
92
      os << a << " -ROLL";
93
    }
94
  } else {
95
    os << a << " " << b << " BLKSWAP";
96
  }
97
  return AsmOp::Custom(os.str(), a + b, a + b);
98
}
99

100
AsmOp AsmOp::BlkPush(int a, int b) {
101
  std::ostringstream os;
102
  if (a == 1) {
103
    return AsmOp::Push(b);
104
  } else if (a == 2 && b == 1) {
105
    os << "2DUP";
106
  } else {
107
    os << a << " " << b << " BLKPUSH";
108
  }
109
  return AsmOp::Custom(os.str(), b + 1, a + b + 1);
110
}
111

112
AsmOp AsmOp::BlkDrop(int a) {
113
  std::ostringstream os;
114
  if (a == 1) {
115
    return AsmOp::Pop();
116
  } else if (a == 2) {
117
    os << "2DROP";
118
  } else {
119
    os << a << " BLKDROP";
120
  }
121
  return AsmOp::Custom(os.str(), a, 0);
122
}
123

124
AsmOp AsmOp::BlkDrop2(int a, int b) {
125
  if (!b) {
126
    return BlkDrop(a);
127
  }
128
  std::ostringstream os;
129
  os << a << " " << b << " BLKDROP2";
130
  return AsmOp::Custom(os.str(), a + b, b);
131
}
132

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);
137
}
138

139
AsmOp AsmOp::Tuple(int a) {
140
  switch (a) {
141
    case 1:
142
      return AsmOp::Custom("SINGLE", 1, 1);
143
    case 2:
144
      return AsmOp::Custom("PAIR", 2, 1);
145
    case 3:
146
      return AsmOp::Custom("TRIPLE", 3, 1);
147
  }
148
  std::ostringstream os;
149
  os << a << " TUPLE";
150
  return AsmOp::Custom(os.str(), a, 1);
151
}
152

153
AsmOp AsmOp::UnTuple(int a) {
154
  switch (a) {
155
    case 1:
156
      return AsmOp::Custom("UNSINGLE", 1, 1);
157
    case 2:
158
      return AsmOp::Custom("UNPAIR", 1, 2);
159
    case 3:
160
      return AsmOp::Custom("UNTRIPLE", 1, 3);
161
  }
162
  std::ostringstream os;
163
  os << a << " UNTUPLE";
164
  return AsmOp::Custom(os.str(), 1, a);
165
}
166

167
AsmOp AsmOp::IntConst(td::RefInt256 x) {
168
  if (x->signed_fits_bits(8)) {
169
    return AsmOp::Const(dec_string(x) + " PUSHINT", x);
170
  }
171
  if (!x->is_valid()) {
172
    return AsmOp::Const("PUSHNAN", x);
173
  }
174
  int k = is_pos_pow2(x);
175
  if (k >= 0) {
176
    return AsmOp::Const(k, "PUSHPOW2", x);
177
  }
178
  k = is_pos_pow2(x + 1);
179
  if (k >= 0) {
180
    return AsmOp::Const(k, "PUSHPOW2DEC", x);
181
  }
182
  k = is_pos_pow2(-x);
183
  if (k >= 0) {
184
    return AsmOp::Const(k, "PUSHNEGPOW2", x);
185
  }
186
  if (!x->mod_pow2_short(23)) {
187
    return AsmOp::Const(dec_string(x) + " PUSHINTX", x);
188
  }
189
  return AsmOp::Const(dec_string(x) + " PUSHINT", x);
190
}
191

192
AsmOp AsmOp::BoolConst(bool f) {
193
  return AsmOp::Const(f ? "TRUE" : "FALSE");
194
}
195

196
AsmOp AsmOp::Parse(std::string custom_op) {
197
  if (custom_op == "NOP") {
198
    return AsmOp::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);
209
  } else {
210
    return AsmOp::Custom(custom_op);
211
  }
212
}
213

214
AsmOp AsmOp::Parse(std::string custom_op, int args, int retv) {
215
  auto res = Parse(custom_op);
216
  if (res.is_custom()) {
217
    res.a = args;
218
    res.b = retv;
219
  }
220
  return res;
221
}
222

223
void AsmOp::out(std::ostream& os) const {
224
  if (!op.empty()) {
225
    os << op;
226
    return;
227
  }
228
  switch (t) {
229
    case a_none:
230
      break;
231
    case a_xchg:
232
      if (!a && !(b & -2)) {
233
        os << (b ? "SWAP" : "NOP");
234
        break;
235
      }
236
      os << SReg(a) << ' ' << SReg(b) << " XCHG";
237
      break;
238
    case a_push:
239
      if (!(a & -2)) {
240
        os << (a ? "OVER" : "DUP");
241
        break;
242
      }
243
      os << SReg(a) << " PUSH";
244
      break;
245
    case a_pop:
246
      if (!(a & -2)) {
247
        os << (a ? "NIP" : "DROP");
248
        break;
249
      }
250
      os << SReg(a) << " POP";
251
      break;
252
    default:
253
      throw src::Fatal{"unknown assembler operation"};
254
  }
255
}
256

257
void AsmOp::out_indent_nl(std::ostream& os, bool no_eol) const {
258
  for (int i = 0; i < indent; i++) {
259
    os << "  ";
260
  }
261
  out(os);
262
  if (!no_eol) {
263
    os << std::endl;
264
  }
265
}
266

267
std::string AsmOp::to_string() const {
268
  if (!op.empty()) {
269
    return op;
270
  } else {
271
    std::ostringstream os;
272
    out(os);
273
    return os.str();
274
  }
275
}
276

277
bool AsmOpList::append(const std::vector<AsmOp>& ops) {
278
  for (const auto& op : ops) {
279
    if (!append(op)) {
280
      return false;
281
    }
282
  }
283
  return true;
284
}
285

286
const_idx_t AsmOpList::register_const(Const new_const) {
287
  if (new_const.is_null()) {
288
    return not_const;
289
  }
290
  unsigned idx;
291
  for (idx = 0; idx < constants_.size(); idx++) {
292
    if (!td::cmp(new_const, constants_[idx])) {
293
      return idx;
294
    }
295
  }
296
  constants_.push_back(std::move(new_const));
297
  return (const_idx_t)idx;
298
}
299

300
Const AsmOpList::get_const(const_idx_t idx) {
301
  if ((unsigned)idx < constants_.size()) {
302
    return constants_[idx];
303
  } else {
304
    return {};
305
  }
306
}
307

308
void AsmOpList::show_var(std::ostream& os, var_idx_t idx) const {
309
  if (!var_names_ || (unsigned)idx >= var_names_->size()) {
310
    os << '_' << idx;
311
  } else {
312
    var_names_->at(idx).show(os, 2);
313
  }
314
}
315

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()) {
320
    os << '_' << i;
321
  } else {
322
    var_names_->at(i).show(os, 2);
323
  }
324
  if ((unsigned)j < constants_.size() && constants_[j].not_null()) {
325
    os << '=' << constants_[j];
326
  }
327
}
328

329
void AsmOpList::out(std::ostream& os, int mode) const {
330
  if (!(mode & 2)) {
331
    for (const auto& op : list_) {
332
      op.out_indent_nl(os);
333
    }
334
  } else {
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);
340
        os << '\t';
341
        do {
342
          i++;
343
        } while (i + 1 < n && list_[i + 1].is_comment());
344
        list_[i].out(os);
345
        os << std::endl;
346
      } else {
347
        op.out_indent_nl(os, false);
348
      }
349
    }
350
  }
351
}
352

353
bool apply_op(StackTransform& trans, const AsmOp& op) {
354
  if (!trans.is_valid()) {
355
    return false;
356
  }
357
  switch (op.t) {
358
    case AsmOp::a_none:
359
      return true;
360
    case AsmOp::a_xchg:
361
      return trans.apply_xchg(op.a, op.b, true);
362
    case AsmOp::a_push:
363
      return trans.apply_push(op.a);
364
    case AsmOp::a_pop:
365
      return trans.apply_pop(op.a);
366
    case AsmOp::a_const:
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();
370
    default:
371
      return false;
372
  }
373
}
374

375
}  // namespace funC
376

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.