diff --git a/crypto/func/builtins.cpp b/crypto/func/builtins.cpp index 9a3c27e5..756de2f8 100644 --- a/crypto/func/builtins.cpp +++ b/crypto/func/builtins.cpp @@ -173,6 +173,74 @@ int emulate_mul(int a, int b) { 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) { if (((a | b) & VarDescr::_Nan) || !(~b & (VarDescr::_Neg | VarDescr::_NonZero))) { return VarDescr::_Int | VarDescr::_Nan; @@ -427,6 +495,57 @@ AsmOp compile_negate(std::vector& res, std::vector& args) { return exec_op("NEGATE", 1); } +AsmOp compile_and(std::vector& res, std::vector& 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& res, std::vector& 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& res, std::vector& 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& res, std::vector& 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) { if (x.is_int_const() && y.is_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, 0)); 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, AsmOp::Custom("OR", 2)); - define_builtin_func("_^_", arith_bin_op, AsmOp::Custom("XOR", 2)); - define_builtin_func("~_", arith_un_op, AsmOp::Custom("NOT", 1)); + define_builtin_func("_&_", arith_bin_op, compile_and); + define_builtin_func("_|_", arith_bin_op, compile_or); + define_builtin_func("_^_", arith_bin_op, compile_xor); + define_builtin_func("~_", arith_un_op, compile_not); define_builtin_func("^_+=_", arith_bin_op, compile_add); define_builtin_func("^_-=_", arith_bin_op, compile_sub); 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, 0)); 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, AsmOp::Custom("OR", 2)); - define_builtin_func("^_^=_", arith_bin_op, AsmOp::Custom("XOR", 2)); + define_builtin_func("^_&=_", arith_bin_op, compile_and); + define_builtin_func("^_|=_", arith_bin_op, compile_or); + 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("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)); diff --git a/crypto/func/test/co3.fc b/crypto/func/test/co3.fc new file mode 100644 index 00000000..398592d3 --- /dev/null +++ b/crypto/func/test/co3.fc @@ -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); +}