| 1880 | } |
| 1881 | |
| 1882 | static void emit_cmp_test_handler(X64Emitter& e, const VMConfig& vm, bool is_test) { |
| 1883 | const auto& r = vm.dispatcher_regs(); |
| 1884 | |
| 1885 | // op0: tag + payload |
| 1886 | emit_fetch_byte_dec(e, vm, r.scratch_a); |
| 1887 | auto lbl_op0_imm = e.new_label(), lbl_op0_done = e.new_label(); |
| 1888 | e.cmp_reg_imm32(r.scratch_a, 0); |
| 1889 | e.jcc_label(cc::nz, lbl_op0_imm); |
| 1890 | emit_fetch_byte_dec(e, vm, r.scratch_a); // slot |
| 1891 | emit_fetch_byte_dec(e, vm, r.scratch_b); // op0 width |
| 1892 | e.mov_reg_mem_sib( |
| 1893 | rx::rax, |
| 1894 | r.state_ptr, |
| 1895 | r.scratch_a, |
| 1896 | 3, |
| 1897 | static_cast<std::int32_t>(vm.state_layout().regs_base), |
| 1898 | true |
| 1899 | ); |
| 1900 | emit_extract_operand( |
| 1901 | e, |
| 1902 | vm, |
| 1903 | rx::rax, |
| 1904 | r.scratch_b |
| 1905 | ); |
| 1906 | e.jmp_label(lbl_op0_done); |
| 1907 | e.bind(lbl_op0_imm); |
| 1908 | e.sub_reg_imm32(rx::rsp, 16); |
| 1909 | emit_fetch_uN_dec( |
| 1910 | e, |
| 1911 | vm, |
| 1912 | rx::rax, |
| 1913 | 8 |
| 1914 | ); |
| 1915 | e.add_reg_imm32(rx::rsp, 16); |
| 1916 | |
| 1917 | // imm carries no per-operand width, gets masked by global width below. |
| 1918 | e.bind(lbl_op0_done); |
| 1919 | |
| 1920 | // op1 |
| 1921 | emit_fetch_byte_dec(e, vm, r.scratch_a); |
| 1922 | auto lbl_imm = e.new_label(), lbl_mem = e.new_label(), lbl_done = e.new_label(); |
| 1923 | e.cmp_reg_imm32(r.scratch_a, 1); |
| 1924 | e.jcc_label(cc::z, lbl_imm); |
| 1925 | e.cmp_reg_imm32(r.scratch_a, 2); |
| 1926 | e.jcc_label(cc::z, lbl_mem); |
| 1927 | emit_fetch_byte_dec(e, vm, r.scratch_a); // slot |
| 1928 | emit_fetch_byte_dec(e, vm, r.scratch_b); // op1 width |
| 1929 | e.mov_reg_mem_sib( |
| 1930 | rx::rcx, |
| 1931 | r.state_ptr, |
| 1932 | r.scratch_a, |
| 1933 | 3, |
| 1934 | static_cast<std::int32_t>(vm.state_layout().regs_base), |
| 1935 | true |
| 1936 | ); |
| 1937 | emit_extract_operand( |
| 1938 | e, |
| 1939 | vm, |
no test coverage detected