mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Implement compilation and pre-computation of logical operations (#437)
* Implement compilation and pre-computation of logical operations (and, or, xor, not) * Fix emulate_and optimization * Fix variable flags in emulate_not * Rename co2.fc to co3.fc Co-authored-by: EmelyanenkoK <emelyanenko.kirill@gmail.com>
This commit is contained in:
parent
3b1d33f543
commit
3c380e0a7b
2 changed files with 150 additions and 7 deletions
|
@ -173,6 +173,74 @@ int emulate_mul(int a, int b) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int emulate_and(int a, int b) {
|
||||||
|
int both = a & b, any = a | b;
|
||||||
|
int r = VarDescr::_Int;
|
||||||
|
if (any & VarDescr::_Nan) {
|
||||||
|
return r | VarDescr::_Nan;
|
||||||
|
}
|
||||||
|
r |= VarDescr::_Finite;
|
||||||
|
if (any & VarDescr::_Zero) {
|
||||||
|
return VarDescr::ConstZero;
|
||||||
|
}
|
||||||
|
r |= both & (VarDescr::_Even | VarDescr::_Odd);
|
||||||
|
r |= both & (VarDescr::_Bit | VarDescr::_Bool);
|
||||||
|
if (both & VarDescr::_Odd) {
|
||||||
|
r |= VarDescr::_NonZero;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int emulate_or(int a, int b) {
|
||||||
|
if (b & VarDescr::_Zero) {
|
||||||
|
return a;
|
||||||
|
} else if (a & VarDescr::_Zero) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
int both = a & b, any = a | b;
|
||||||
|
int r = VarDescr::_Int;
|
||||||
|
if (any & VarDescr::_Nan) {
|
||||||
|
return r | VarDescr::_Nan;
|
||||||
|
}
|
||||||
|
r |= VarDescr::_Finite;
|
||||||
|
r |= any & VarDescr::_NonZero;
|
||||||
|
r |= any & VarDescr::_Odd;
|
||||||
|
r |= both & VarDescr::_Even;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int emulate_xor(int a, int b) {
|
||||||
|
if (b & VarDescr::_Zero) {
|
||||||
|
return a;
|
||||||
|
} else if (a & VarDescr::_Zero) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
int both = a & b, any = a | b;
|
||||||
|
int r = VarDescr::_Int;
|
||||||
|
if (any & VarDescr::_Nan) {
|
||||||
|
return r | VarDescr::_Nan;
|
||||||
|
}
|
||||||
|
r |= VarDescr::_Finite;
|
||||||
|
r |= both & VarDescr::_Even;
|
||||||
|
if (both & VarDescr::_Odd) {
|
||||||
|
r |= VarDescr::_Even;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int emulate_not(int a) {
|
||||||
|
int f = VarDescr::_Even | VarDescr::_Odd;
|
||||||
|
if ((a & f) && (~a & f)) {
|
||||||
|
a ^= f;
|
||||||
|
}
|
||||||
|
f = VarDescr::_Pos | VarDescr::_Neg;
|
||||||
|
if ((a & f) && (~a & f)) {
|
||||||
|
a ^= f;
|
||||||
|
}
|
||||||
|
a &= ~(VarDescr::_Zero | VarDescr::_NonZero | VarDescr::_Bit);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
int emulate_lshift(int a, int b) {
|
int emulate_lshift(int a, int b) {
|
||||||
if (((a | b) & VarDescr::_Nan) || !(~b & (VarDescr::_Neg | VarDescr::_NonZero))) {
|
if (((a | b) & VarDescr::_Nan) || !(~b & (VarDescr::_Neg | VarDescr::_NonZero))) {
|
||||||
return VarDescr::_Int | VarDescr::_Nan;
|
return VarDescr::_Int | VarDescr::_Nan;
|
||||||
|
@ -427,6 +495,57 @@ AsmOp compile_negate(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
|
||||||
return exec_op("NEGATE", 1);
|
return exec_op("NEGATE", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AsmOp compile_and(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
|
||||||
|
assert(res.size() == 1 && args.size() == 2);
|
||||||
|
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||||
|
if (x.is_int_const() && y.is_int_const()) {
|
||||||
|
r.set_const(x.int_const & y.int_const);
|
||||||
|
x.unused();
|
||||||
|
y.unused();
|
||||||
|
return push_const(r.int_const);
|
||||||
|
}
|
||||||
|
r.val = emulate_and(x.val, y.val);
|
||||||
|
return exec_op("AND", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
AsmOp compile_or(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
|
||||||
|
assert(res.size() == 1 && args.size() == 2);
|
||||||
|
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||||
|
if (x.is_int_const() && y.is_int_const()) {
|
||||||
|
r.set_const(x.int_const | y.int_const);
|
||||||
|
x.unused();
|
||||||
|
y.unused();
|
||||||
|
return push_const(r.int_const);
|
||||||
|
}
|
||||||
|
r.val = emulate_or(x.val, y.val);
|
||||||
|
return exec_op("OR", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
AsmOp compile_xor(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
|
||||||
|
assert(res.size() == 1 && args.size() == 2);
|
||||||
|
VarDescr &r = res[0], &x = args[0], &y = args[1];
|
||||||
|
if (x.is_int_const() && y.is_int_const()) {
|
||||||
|
r.set_const(x.int_const ^ y.int_const);
|
||||||
|
x.unused();
|
||||||
|
y.unused();
|
||||||
|
return push_const(r.int_const);
|
||||||
|
}
|
||||||
|
r.val = emulate_xor(x.val, y.val);
|
||||||
|
return exec_op("XOR", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
AsmOp compile_not(std::vector<VarDescr>& res, std::vector<VarDescr>& args) {
|
||||||
|
assert(res.size() == 1 && args.size() == 1);
|
||||||
|
VarDescr &r = res[0], &x = args[0];
|
||||||
|
if (x.is_int_const()) {
|
||||||
|
r.set_const(~x.int_const);
|
||||||
|
x.unused();
|
||||||
|
return push_const(r.int_const);
|
||||||
|
}
|
||||||
|
r.val = emulate_not(x.val);
|
||||||
|
return exec_op("NOT", 1);
|
||||||
|
}
|
||||||
|
|
||||||
AsmOp compile_mul_internal(VarDescr& r, VarDescr& x, VarDescr& y) {
|
AsmOp compile_mul_internal(VarDescr& r, VarDescr& x, VarDescr& y) {
|
||||||
if (x.is_int_const() && y.is_int_const()) {
|
if (x.is_int_const() && y.is_int_const()) {
|
||||||
r.set_const(x.int_const * y.int_const);
|
r.set_const(x.int_const * y.int_const);
|
||||||
|
@ -1000,10 +1119,10 @@ void define_builtins() {
|
||||||
define_builtin_func("_>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, -1));
|
define_builtin_func("_>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, -1));
|
||||||
define_builtin_func("_~>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, 0));
|
define_builtin_func("_~>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, 0));
|
||||||
define_builtin_func("_^>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, 1));
|
define_builtin_func("_^>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, 1));
|
||||||
define_builtin_func("_&_", arith_bin_op, AsmOp::Custom("AND", 2));
|
define_builtin_func("_&_", arith_bin_op, compile_and);
|
||||||
define_builtin_func("_|_", arith_bin_op, AsmOp::Custom("OR", 2));
|
define_builtin_func("_|_", arith_bin_op, compile_or);
|
||||||
define_builtin_func("_^_", arith_bin_op, AsmOp::Custom("XOR", 2));
|
define_builtin_func("_^_", arith_bin_op, compile_xor);
|
||||||
define_builtin_func("~_", arith_un_op, AsmOp::Custom("NOT", 1));
|
define_builtin_func("~_", arith_un_op, compile_not);
|
||||||
define_builtin_func("^_+=_", arith_bin_op, compile_add);
|
define_builtin_func("^_+=_", arith_bin_op, compile_add);
|
||||||
define_builtin_func("^_-=_", arith_bin_op, compile_sub);
|
define_builtin_func("^_-=_", arith_bin_op, compile_sub);
|
||||||
define_builtin_func("^_*=_", arith_bin_op, compile_mul);
|
define_builtin_func("^_*=_", arith_bin_op, compile_mul);
|
||||||
|
@ -1017,9 +1136,9 @@ void define_builtins() {
|
||||||
define_builtin_func("^_>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, -1));
|
define_builtin_func("^_>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, -1));
|
||||||
define_builtin_func("^_~>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, 0));
|
define_builtin_func("^_~>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, 0));
|
||||||
define_builtin_func("^_^>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, 1));
|
define_builtin_func("^_^>>=_", arith_bin_op, std::bind(compile_rshift, _1, _2, 1));
|
||||||
define_builtin_func("^_&=_", arith_bin_op, AsmOp::Custom("AND", 2));
|
define_builtin_func("^_&=_", arith_bin_op, compile_and);
|
||||||
define_builtin_func("^_|=_", arith_bin_op, AsmOp::Custom("OR", 2));
|
define_builtin_func("^_|=_", arith_bin_op, compile_or);
|
||||||
define_builtin_func("^_^=_", arith_bin_op, AsmOp::Custom("XOR", 2));
|
define_builtin_func("^_^=_", arith_bin_op, compile_xor);
|
||||||
define_builtin_func("muldiv", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, -1));
|
define_builtin_func("muldiv", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, -1));
|
||||||
define_builtin_func("muldivr", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, 0));
|
define_builtin_func("muldivr", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, 0));
|
||||||
define_builtin_func("muldivc", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, 1));
|
define_builtin_func("muldivc", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, 1));
|
||||||
|
|
24
crypto/func/test/co3.fc
Normal file
24
crypto/func/test/co3.fc
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
const val1 = 123456789;
|
||||||
|
const val2 = 987654321;
|
||||||
|
const val3 = 135792468;
|
||||||
|
const val4 = 246813579;
|
||||||
|
|
||||||
|
const prec_and = val1 & val2;
|
||||||
|
const prec_or = val1 | val2;
|
||||||
|
const prec_xor = val1 ^ val2;
|
||||||
|
const prec_logic = ((val1 & val2) | val3) ^ val4;
|
||||||
|
const prec_nand = val1 & (~ val2);
|
||||||
|
|
||||||
|
int get_and() { return prec_and; }
|
||||||
|
int get_or() { return prec_or; }
|
||||||
|
int get_xor() { return prec_xor; }
|
||||||
|
int get_logic() { return prec_logic; }
|
||||||
|
int get_nand() { return prec_nand; }
|
||||||
|
|
||||||
|
_ main() {
|
||||||
|
throw_unless(101, get_and() == 39471121);
|
||||||
|
throw_unless(102, get_or() == 1071639989);
|
||||||
|
throw_unless(103, get_xor() == 1032168868);
|
||||||
|
throw_unless(104, get_logic() == 82599134);
|
||||||
|
throw_unless(105, get_nand() == 83985668);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue