/* * (c) 2022 Petr Ročkai * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #pragma once #include "opcodes.hpp" #include "types.hpp" #include "stack.hpp" namespace bast { template< builtin_type t > struct op< std::enable_if_t< bitvec_type< t >::value, exec_tag >, t > { using value_t = typename bitvec_type< t >::type; using signed_t = typename signed_type< t >::type; template< typename state_t, typename impl_t > static step binary( state_t &s, impl_t impl ) { value_t a = s.template pop< value_t >(), b = s.template pop< value_t >(); s.push( value_t( impl( b, a ) ) ); return next; } template< typename state_t > static step push_word( state_t &s, word w ) { s.push( w ); return next; } template< typename state_t > static step push_half( state_t &s, half h ) { s.push( h ); return next; } template< typename state_t > static step apply( state_t &s, word opcode ) { using namespace bast::opcodes; switch ( opcode ) { case bv_add<>: return binary( s, []( value_t a, value_t b ) { return a + b; } ); case bv_sub<>: return binary( s, []( value_t a, value_t b ) { return a - b; } ); case bv_mul<>: return binary( s, []( value_t a, value_t b ) { return a * b; } ); case bv_udiv<>: return binary( s, []( value_t a, value_t b ) { return a / b; } ); case bv_urem<>: return binary( s, []( value_t a, value_t b ) { return a % b; } ); case bv_sdiv<>: return binary( s, []( signed_t a, signed_t b ) { return a / b; } ); case bv_srem<>: return binary( s, []( signed_t a, signed_t b ) { return a % b; } ); case bv_and<>: return binary( s, []( value_t a, value_t b ) { return a & b; } ); case bv_or<>: return binary( s, []( value_t a, value_t b ) { return a | b; } ); case bv_xor<>: return binary( s, []( value_t a, value_t b ) { return a ^ b; } ); case bv_eq<>: return binary( s, []( value_t a, value_t b ) { return a == b; } ); case bv_neq<>: return binary( s, []( value_t a, value_t b ) { return a != b; } ); case bv_ult<>: return binary( s, []( value_t a, value_t b ) { return a < b; } ); case bv_ule<>: return binary( s, []( value_t a, value_t b ) { return a <= b; } ); case bv_ugt<>: return binary( s, []( value_t a, value_t b ) { return a > b; } ); case bv_uge<>: return binary( s, []( value_t a, value_t b ) { return a >= b; } ); case bv_slt<>: return binary( s, []( signed_t a, signed_t b ) { return a < b; } ); case bv_sle<>: return binary( s, []( signed_t a, signed_t b ) { return a <= b; } ); case bv_sgt<>: return binary( s, []( signed_t a, signed_t b ) { return a > b; } ); case bv_sge<>: return binary( s, []( signed_t a, signed_t b ) { return a >= b; } ); case bv_trunc_w<>: s.push( value_t( s.template pop< word >() ) ); return next; case bv_neg<>: s.push( ~s.template pop< value_t >() ); return next; case gen_drop<>: s.template pop< value_t >(); return next; case gen_dup<>: { value_t x = s.template pop< value_t >(); s.push( x ); s.push( x ); return next; } case bv_const<>: s.template push< value_t >( s.template pop< word >() ); return next; case bv_guard_nonzero<>: return s.template pop< value_t >() ? next : stop; case bv_guard_zero<>: return s.template pop< value_t >() ? stop : next; case bv_assert_nonzero<>: return s.template pop< value_t >() ? next : error; case bv_assert_zero<>: return s.template pop< value_t >() ? error : next; default: UNREACHABLE( std::hex, " op", opcode ); } } }; }