From 1c9f5fb5706e96deb896f048bd42688703257af4 Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Thu, 18 Jun 2026 01:11:25 -0400 Subject: [PATCH] goalc: fix errors --- goalc/build_level/common/FileInfo.cpp | 3 +- goalc/build_level/jak2/build_level.cpp | 2 +- goalc/build_level/jak3/build_level.cpp | 2 +- goalc/compiler/IR.cpp | 71 +- goalc/emitter/CodeTester.cpp | 4 +- goalc/emitter/IGen.cpp | 72 +- goalc/emitter/IGen.h | 68 +- goalc/emitter/IGenARM64.cpp | 14 +- goalc/emitter/IGenARM64.h | 8 +- goalc/emitter/IGenX86.cpp | 100 +- goalc/emitter/IGenX86.h | 86 +- goalc/emitter/Instruction.h | 15 +- test/goalc/test_CodeTester.cpp | 16 +- test/test_emitter.cpp | 7812 ++++++++++++------------ test/test_emitter_avx.cpp | 16 +- 15 files changed, 4153 insertions(+), 4136 deletions(-) diff --git a/goalc/build_level/common/FileInfo.cpp b/goalc/build_level/common/FileInfo.cpp index 2aa38da677..a499e005a4 100644 --- a/goalc/build_level/common/FileInfo.cpp +++ b/goalc/build_level/common/FileInfo.cpp @@ -5,7 +5,8 @@ #include "common/versions/versions.h" #include "goalc/data_compiler/DataObjectGenerator.h" -#include + +#include "fmt/chrono.h" std::string get_current_time_and_date() { auto const now = std::chrono::floor(std::chrono::system_clock::now()); diff --git a/goalc/build_level/jak2/build_level.cpp b/goalc/build_level/jak2/build_level.cpp index fd991b0c2d..fc41abc309 100644 --- a/goalc/build_level/jak2/build_level.cpp +++ b/goalc/build_level/jak2/build_level.cpp @@ -3,13 +3,13 @@ #include "common/util/gltf_util.h" #include "decompiler/extractor/extractor_util.h" +#include "decompiler/level_extractor/extract_collide_frags.h" #include "decompiler/level_extractor/extract_merc.h" #include "goalc/build_level/collide/jak2/collide.h" #include "goalc/build_level/common/Tfrag.h" #include "goalc/build_level/jak2/Entity.h" #include "goalc/build_level/jak2/FileInfo.h" #include "goalc/build_level/jak2/LevelFile.h" -#include namespace jak2 { bool run_build_level(const std::string& input_file, diff --git a/goalc/build_level/jak3/build_level.cpp b/goalc/build_level/jak3/build_level.cpp index 4501b910bb..3f2581e561 100644 --- a/goalc/build_level/jak3/build_level.cpp +++ b/goalc/build_level/jak3/build_level.cpp @@ -1,13 +1,13 @@ #include "build_level.h" #include "decompiler/extractor/extractor_util.h" +#include "decompiler/level_extractor/extract_collide_frags.h" #include "decompiler/level_extractor/extract_merc.h" #include "goalc/build_level/collide/jak3/collide.h" #include "goalc/build_level/common/Tfrag.h" #include "goalc/build_level/jak3/Entity.h" #include "goalc/build_level/jak3/FileInfo.h" #include "goalc/build_level/jak3/LevelFile.h" -#include namespace jak3 { bool run_build_level(const std::string& input_file, diff --git a/goalc/compiler/IR.cpp b/goalc/compiler/IR.cpp index bdf2110aef..ce4f98f91b 100644 --- a/goalc/compiler/IR.cpp +++ b/goalc/compiler/IR.cpp @@ -121,7 +121,7 @@ void regset_common(emitter::ObjectGenerator* gen, gen->count_eliminated_move(); gen->add_instr(IGen::null(*gen), irec); } else { - gen->add_instr(IGen::mov_xmm32_xmm32(*gen, dst_reg, src_reg), irec); + gen->add_instr(IGen::mov_f32_f32(*gen, dst_reg, src_reg), irec); } } else if (src_is_xmm128 && dst_is_xmm128) { if (src_reg == dst_reg) { @@ -133,20 +133,20 @@ void regset_common(emitter::ObjectGenerator* gen, } } else if (src_class == RegClass::FLOAT && dst_class == RegClass::GPR_64) { // xmm 1x -> gpr - gen->add_instr(IGen::movd_gpr32_xmm32(*gen, dst_reg, src_reg), irec); + gen->add_instr(IGen::movd_gpr32_f32(*gen, dst_reg, src_reg), irec); // don't forget to sign extend gen->add_instr(IGen::movsx_r64_r32(*gen, dst_reg, dst_reg), irec); } else if (src_class == RegClass::GPR_64 && dst_class == RegClass::FLOAT) { // gpr -> xmm 1x - gen->add_instr(IGen::movd_xmm32_gpr32(*gen, dst_reg, src_reg), irec); + gen->add_instr(IGen::movd_f32_gpr32(*gen, dst_reg, src_reg), irec); } else if (src_is_xmm128 && dst_class == RegClass::FLOAT) { - gen->add_instr(IGen::mov_xmm32_xmm32(*gen, dst_reg, src_reg), irec); + gen->add_instr(IGen::mov_f32_f32(*gen, dst_reg, src_reg), irec); } else if (src_class == RegClass::FLOAT && dst_is_xmm128) { - gen->add_instr(IGen::mov_xmm32_xmm32(*gen, dst_reg, src_reg), irec); + gen->add_instr(IGen::mov_f32_f32(*gen, dst_reg, src_reg), irec); } else if (src_class == RegClass::GPR_64 && dst_is_xmm128) { - gen->add_instr(IGen::movq_xmm64_gpr64(*gen, dst_reg, src_reg), irec); + gen->add_instr(IGen::movq_f64_gpr64(*gen, dst_reg, src_reg), irec); } else if (src_is_xmm128 && dst_class == RegClass::GPR_64) { - gen->add_instr(IGen::movq_gpr64_xmm64(*gen, dst_reg, src_reg), irec); + gen->add_instr(IGen::movq_gpr64_f64(*gen, dst_reg, src_reg), irec); } else { ASSERT(false); // unhandled move. } @@ -256,7 +256,7 @@ void IR_LoadSymbolPointer::do_codegen_x86(emitter::ObjectGenerator* gen, if (m_name == "#f") { static_assert(false_symbol_offset() == 0, "false symbol location"); if (dest_reg.is_xmm(gen->instr_set())) { - gen->add_instr(IGen::movq_xmm64_gpr64(*gen, dest_reg, gRegInfo.get_st_reg()), irec); + gen->add_instr(IGen::movq_f64_gpr64(*gen, dest_reg, gRegInfo.get_st_reg()), irec); } else { gen->add_instr(IGen::mov_gpr64_gpr64(*gen, dest_reg, gRegInfo.get_st_reg()), irec); } @@ -417,7 +417,7 @@ void IR_GotoLabel::do_codegen_x86(emitter::ObjectGenerator* gen, const AllocationResult& allocs, emitter::IR_Record irec) { (void)allocs; - auto instr = gen->add_instr(IGen::jmp_32(*gen), irec); + auto instr = gen->add_instr(IGen::jmp_imm(*gen), irec); // TODO ARM - have to patch this differently, encoding for the immediate is different gen->link_instruction_jump(instr, gen->get_future_ir_record_in_same_func(irec, m_dest->idx)); } @@ -712,18 +712,21 @@ void IR_IntegerMath::do_codegen_x86(emitter::ObjectGenerator* gen, ASSERT(!m_arg); break; case IntegerMathKind::SHLV_64: - gen->add_instr(IGen::shl_gpr64_reg(*gen, get_reg(m_dest, allocs, irec)), irec); + // TODO ARM - register provided but unused on x86 + gen->add_instr(IGen::shl_gpr64_reg(*gen, get_reg(m_dest, allocs, irec), 0), irec); // TODO ARM - x86 forces you to use CL, which is dumb, but the register allocator // has that logic baked in somewhere // ARM has no such constraint, so we should be able to use any register for the shift amount ASSERT(get_reg(m_arg, allocs, irec) == emitter::RCX); break; case IntegerMathKind::SHRV_64: - gen->add_instr(IGen::shr_gpr64_reg(*gen, get_reg(m_dest, allocs, irec)), irec); + // TODO ARM - register provided but unused on x86 + gen->add_instr(IGen::shr_gpr64_reg(*gen, get_reg(m_dest, allocs, irec), 0), irec); ASSERT(get_reg(m_arg, allocs, irec) == emitter::RCX); break; case IntegerMathKind::SARV_64: - gen->add_instr(IGen::sar_gpr64_reg(*gen, get_reg(m_dest, allocs, irec)), irec); + // TODO ARM - register provided but unused on x86 + gen->add_instr(IGen::sar_gpr64_reg(*gen, get_reg(m_dest, allocs, irec), 0), irec); ASSERT(get_reg(m_arg, allocs, irec) == emitter::RCX); break; case IntegerMathKind::SHL_64: @@ -827,37 +830,37 @@ void IR_FloatMath::do_codegen_x86(emitter::ObjectGenerator* gen, switch (m_kind) { case FloatMathKind::DIV_SS: gen->add_instr( - IGen::divss_xmm_xmm(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), + IGen::div_f32_f32(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); break; case FloatMathKind::MUL_SS: gen->add_instr( - IGen::mulss_xmm_xmm(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), + IGen::mul_f32_f32(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); break; case FloatMathKind::ADD_SS: gen->add_instr( - IGen::addss_xmm_xmm(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), + IGen::add_f32_f32(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); break; case FloatMathKind::SUB_SS: gen->add_instr( - IGen::subss_xmm_xmm(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), + IGen::sub_f32_f32(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); break; case FloatMathKind::MAX_SS: gen->add_instr( - IGen::maxss_xmm_xmm(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), + IGen::max_f32_f32(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); break; case FloatMathKind::MIN_SS: gen->add_instr( - IGen::minss_xmm_xmm(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), + IGen::min_f32_f32(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); break; case FloatMathKind::SQRT_SS: gen->add_instr( - IGen::sqrts_xmm(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); + IGen::sqrt_f32(*gen, get_reg(m_dest, allocs, irec), get_reg(m_arg, allocs, irec)), irec); break; default: ASSERT(false); @@ -899,7 +902,7 @@ void IR_StaticVarLoad::do_codegen_x86(emitter::ObjectGenerator* gen, ASSERT(load_info.requires_load == true); auto instr = - gen->add_instr(IGen::static_load_xmm32(*gen, get_reg(m_dest, allocs, irec), 0), irec); + gen->add_instr(IGen::static_load_f32(*gen, get_reg(m_dest, allocs, irec), 0), irec); gen->link_instruction_static(instr, m_src->rec, 0); } else if (m_dest->ireg().reg_class == RegClass::VECTOR_FLOAT) { // we don't check the load info intentionally because we want to allow loading an entire @@ -970,38 +973,38 @@ void IR_ConditionalBranch::do_codegen_x86(emitter::ObjectGenerator* gen, ASSERT(m_resolved); switch (condition.kind) { case ConditionKind::EQUAL: - jump_instr = IGen::je_32(*gen); + jump_instr = IGen::je_imm(*gen); break; case ConditionKind::NOT_EQUAL: - jump_instr = IGen::jne_32(*gen); + jump_instr = IGen::jne_imm(*gen); break; case ConditionKind::LEQ: if (condition.is_signed) { - jump_instr = IGen::jle_32(*gen); + jump_instr = IGen::jle_imm(*gen); } else { - jump_instr = IGen::jbe_32(*gen); + jump_instr = IGen::jbe_imm(*gen); } break; case ConditionKind::GEQ: if (condition.is_signed) { - jump_instr = IGen::jge_32(*gen); + jump_instr = IGen::jge_imm(*gen); } else { - jump_instr = IGen::jae_32(*gen); + jump_instr = IGen::jae_imm(*gen); } break; case ConditionKind::LT: if (condition.is_signed) { - jump_instr = IGen::jl_32(*gen); + jump_instr = IGen::jl_imm(*gen); } else { - jump_instr = IGen::jb_32(*gen); + jump_instr = IGen::jb_imm(*gen); } break; case ConditionKind::GT: if (condition.is_signed) { - jump_instr = IGen::jg_32(*gen); + jump_instr = IGen::jg_imm(*gen); } else { - jump_instr = IGen::ja_32(*gen); + jump_instr = IGen::ja_imm(*gen); } break; default: @@ -1009,7 +1012,7 @@ void IR_ConditionalBranch::do_codegen_x86(emitter::ObjectGenerator* gen, } if (condition.is_float) { - gen->add_instr(IGen::cmp_flt_flt(*gen, get_reg(condition.a, allocs, irec), + gen->add_instr(IGen::cmp_f32_f32(*gen, get_reg(condition.a, allocs, irec), get_reg(condition.b, allocs, irec)), irec); } else { @@ -1214,8 +1217,7 @@ void IR_FloatToInt::do_codegen_x86(emitter::ObjectGenerator* gen, const AllocationResult& allocs, emitter::IR_Record irec) { gen->add_instr( - IGen::float_to_int32(*gen, get_reg(m_dest, allocs, irec), get_reg(m_src, allocs, irec)), - irec); + IGen::f32_to_int32(*gen, get_reg(m_dest, allocs, irec), get_reg(m_src, allocs, irec)), irec); gen->add_instr( IGen::movsx_r64_r32(*gen, get_reg(m_dest, allocs, irec), get_reg(m_dest, allocs, irec)), irec); @@ -1248,8 +1250,7 @@ void IR_IntToFloat::do_codegen_x86(emitter::ObjectGenerator* gen, const AllocationResult& allocs, emitter::IR_Record irec) { gen->add_instr( - IGen::int32_to_float(*gen, get_reg(m_dest, allocs, irec), get_reg(m_src, allocs, irec)), - irec); + IGen::int32_to_f32(*gen, get_reg(m_dest, allocs, irec), get_reg(m_src, allocs, irec)), irec); } void IR_IntToFloat::do_codegen_arm64(emitter::ObjectGenerator* gen, diff --git a/goalc/emitter/CodeTester.cpp b/goalc/emitter/CodeTester.cpp index 1cefe8eb15..318a98d464 100644 --- a/goalc/emitter/CodeTester.cpp +++ b/goalc/emitter/CodeTester.cpp @@ -125,7 +125,7 @@ void CodeTester::emit_push_all_simd() { } else if (m_gen.instr_set() == InstructionSet::ARM64) { for (int i = 0; i < 16; i++) { emit(IGen::sub_gpr64_imm8s(m_gen, SP, 16)); - emit(IGen::store128_gpr64_simd128(m_gen, SP, Q0 + i)); + emit(IGen::store128_gpr64_simd128(m_gen, SP, V0 + i)); } } else { throw std::runtime_error("CodeTester::emit_push_all_simd unhandled instruction set"); @@ -144,7 +144,7 @@ void CodeTester::emit_pop_all_simd() { emit(IGen::add_gpr64_imm8s(m_gen, RSP, 8)); } else if (m_gen.instr_set() == InstructionSet::ARM64) { for (int i = 0; i < 16; i++) { - emit(IGen::load128_simd128_gpr64(m_gen, Q0 + i, SP)); + emit(IGen::load128_simd128_gpr64(m_gen, V0 + i, SP)); emit(IGen::add_gpr64_imm8s(m_gen, SP, 16)); } } else { diff --git a/goalc/emitter/IGen.cpp b/goalc/emitter/IGen.cpp index 99fad99b57..61e0d92100 100644 --- a/goalc/emitter/IGen.cpp +++ b/goalc/emitter/IGen.cpp @@ -31,23 +31,23 @@ Instruction mov_gpr64_s32(const ObjectGenerator& gen, Register dst, int64_t val) IGEN_DISPATCH(mov_gpr64_s32, dst, val); } -Instruction movd_gpr32_xmm32(const ObjectGenerator& gen, Register dst, Register src) { +Instruction movd_gpr32_f32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(movd_gpr32_f32, dst, src); } -Instruction movd_xmm32_gpr32(const ObjectGenerator& gen, Register dst, Register src) { +Instruction movd_f32_gpr32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(movd_f32_gpr32, dst, src); } -Instruction movq_gpr64_xmm64(const ObjectGenerator& gen, Register dst, Register src) { +Instruction movq_gpr64_f64(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(movq_gpr64_f64, dst, src); } -Instruction movq_xmm64_gpr64(const ObjectGenerator& gen, Register dst, Register src) { +Instruction movq_f64_gpr64(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(movq_f64_gpr64, dst, src); } -Instruction mov_xmm32_xmm32(const ObjectGenerator& gen, Register dst, Register src) { +Instruction mov_f32_f32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(mov_f32_f32, dst, src); } @@ -575,12 +575,12 @@ Instruction static_addr(const ObjectGenerator& gen, Register dst, s64 offset) { IGEN_DISPATCH(static_addr, dst, offset); } -Instruction static_load_xmm32(const ObjectGenerator& gen, Register simd_dest, s64 offset) { - IGEN_DISPATCH(static_load_fp32, simd_dest, offset); +Instruction static_load_f32(const ObjectGenerator& gen, Register simd_dest, s64 offset) { + IGEN_DISPATCH(static_load_f32, simd_dest, offset); } -Instruction static_store_xmm32(const ObjectGenerator& gen, Register xmm_value, s64 offset) { - IGEN_DISPATCH(static_store_xmm32, xmm_value, offset); +Instruction static_store_f32(const ObjectGenerator& gen, Register xmm_value, s64 offset) { + IGEN_DISPATCH(static_store_f32, xmm_value, offset); } Instruction load64_gpr64_plus_s32(const ObjectGenerator& gen, @@ -693,16 +693,16 @@ Instruction not_gpr64(const ObjectGenerator& gen, Register reg) { IGEN_DISPATCH(not_gpr64, reg); } -Instruction shl_gpr64_reg(const ObjectGenerator& gen, Register reg) { - IGEN_DISPATCH(shl_gpr64_reg, reg); +Instruction shl_gpr64_reg(const ObjectGenerator& gen, Register reg, Register shift_reg) { + IGEN_DISPATCH(shl_gpr64_reg, reg, shift_reg); } -Instruction shr_gpr64_reg(const ObjectGenerator& gen, Register reg) { - IGEN_DISPATCH(shr_gpr64_reg, reg); +Instruction shr_gpr64_reg(const ObjectGenerator& gen, Register reg, Register shift_reg) { + IGEN_DISPATCH(shr_gpr64_reg, reg, shift_reg); } -Instruction sar_gpr64_cl(const ObjectGenerator& gen, Register reg) { - IGEN_DISPATCH(sar_gpr64_cl, reg); +Instruction sar_gpr64_reg(const ObjectGenerator& gen, Register reg, Register shift_reg) { + IGEN_DISPATCH(sar_gpr64_reg, reg, shift_reg); } Instruction shl_gpr64_u8(const ObjectGenerator& gen, Register reg, uint8_t sa) { @@ -717,87 +717,87 @@ Instruction sar_gpr64_u8(const ObjectGenerator& gen, Register reg, uint8_t sa) { IGEN_DISPATCH(sar_gpr64_u8, reg, sa); } -Instruction jmp_32(const ObjectGenerator& gen) { +Instruction jmp_imm(const ObjectGenerator& gen) { IGEN_DISPATCH(jmp_imm); } -Instruction je_32(const ObjectGenerator& gen) { +Instruction je_imm(const ObjectGenerator& gen) { IGEN_DISPATCH(je_imm); } -Instruction jne_32(const ObjectGenerator& gen) { +Instruction jne_imm(const ObjectGenerator& gen) { IGEN_DISPATCH(jne_imm); } -Instruction jle_32(const ObjectGenerator& gen) { +Instruction jle_imm(const ObjectGenerator& gen) { IGEN_DISPATCH(jle_imm); } -Instruction jge_32(const ObjectGenerator& gen) { +Instruction jge_imm(const ObjectGenerator& gen) { IGEN_DISPATCH(jge_imm); } -Instruction jl_32(const ObjectGenerator& gen) { +Instruction jl_imm(const ObjectGenerator& gen) { IGEN_DISPATCH(jl_imm); } -Instruction jg_32(const ObjectGenerator& gen) { +Instruction jg_imm(const ObjectGenerator& gen) { IGEN_DISPATCH(jg_imm); } -Instruction jbe_32(const ObjectGenerator& gen) { +Instruction jbe_imm(const ObjectGenerator& gen) { IGEN_DISPATCH(jbe_imm); } -Instruction jae_32(const ObjectGenerator& gen) { +Instruction jae_imm(const ObjectGenerator& gen) { IGEN_DISPATCH(jae_imm); } -Instruction jb_32(const ObjectGenerator& gen) { +Instruction jb_imm(const ObjectGenerator& gen) { IGEN_DISPATCH(jb_imm); } -Instruction ja_32(const ObjectGenerator& gen) { +Instruction ja_imm(const ObjectGenerator& gen) { IGEN_DISPATCH(ja_imm); } -Instruction cmp_flt_flt(const ObjectGenerator& gen, Register a, Register b) { +Instruction cmp_f32_f32(const ObjectGenerator& gen, Register a, Register b) { IGEN_DISPATCH(cmp_f32_f32, a, b); } -Instruction sqrts_xmm(const ObjectGenerator& gen, Register dst, Register src) { +Instruction sqrt_f32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(sqrt_f32, dst, src); } -Instruction mulss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src) { +Instruction mul_f32_f32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(mul_f32_f32, dst, src); } -Instruction divss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src) { +Instruction div_f32_f32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(div_f32_f32, dst, src); } -Instruction subss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src) { +Instruction sub_f32_f32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(sub_f32_f32, dst, src); } -Instruction addss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src) { +Instruction add_f32_f32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(add_f32_f32, dst, src); } -Instruction minss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src) { +Instruction min_f32_f32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(min_f32_f32, dst, src); } -Instruction maxss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src) { +Instruction max_f32_f32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(max_f32_f32, dst, src); } -Instruction int32_to_float(const ObjectGenerator& gen, Register dst, Register src) { +Instruction int32_to_f32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(int32_to_f32, dst, src); } -Instruction float_to_int32(const ObjectGenerator& gen, Register dst, Register src) { +Instruction f32_to_int32(const ObjectGenerator& gen, Register dst, Register src) { IGEN_DISPATCH(f32_to_int32, dst, src); } diff --git a/goalc/emitter/IGen.h b/goalc/emitter/IGen.h index 7723dc58a2..27cbcc8c16 100644 --- a/goalc/emitter/IGen.h +++ b/goalc/emitter/IGen.h @@ -35,27 +35,27 @@ Instruction mov_gpr64_s32(const ObjectGenerator& gen, Register dst, int64_t val) /*! * Move 32-bits of xmm to 32 bits of gpr (no sign extension). */ -Instruction movd_gpr32_xmm32(const ObjectGenerator& gen, Register dst, Register src); +Instruction movd_gpr32_f32(const ObjectGenerator& gen, Register dst, Register src); /*! * Move 32-bits of gpr to 32-bits of xmm (no sign extension) */ -Instruction movd_xmm32_gpr32(const ObjectGenerator& gen, Register dst, Register src); +Instruction movd_f32_gpr32(const ObjectGenerator& gen, Register dst, Register src); /*! * Move 64-bits of xmm to 64 bits of gpr (no sign extension). */ -Instruction movq_gpr64_xmm64(const ObjectGenerator& gen, Register dst, Register src); +Instruction movq_gpr64_f64(const ObjectGenerator& gen, Register dst, Register src); /*! * Move 64-bits of gpr to 64-bits of xmm (no sign extension) */ -Instruction movq_xmm64_gpr64(const ObjectGenerator& gen, Register dst, Register src); +Instruction movq_f64_gpr64(const ObjectGenerator& gen, Register dst, Register src); /*! * Move 32-bits between xmm's */ -Instruction mov_xmm32_xmm32(const ObjectGenerator& gen, Register dst, Register src); +Instruction mov_f32_f32(const ObjectGenerator& gen, Register dst, Register src); // todo - GPR64 -> XMM64 (zext) // todo - XMM -> GPR64 @@ -486,9 +486,9 @@ Instruction static_store(const ObjectGenerator& gen, Register value, s64 offset, Instruction static_addr(const ObjectGenerator& gen, Register dst, s64 offset); -Instruction static_load_xmm32(const ObjectGenerator& gen, Register simd_dest, s64 offset); +Instruction static_load_f32(const ObjectGenerator& gen, Register simd_dest, s64 offset); -Instruction static_store_xmm32(const ObjectGenerator& gen, Register xmm_value, s64 offset); +Instruction static_store_f32(const ObjectGenerator& gen, Register xmm_value, s64 offset); // TODO, special load/stores of 128 bit values. @@ -656,57 +656,57 @@ Instruction sar_gpr64_u8(const ObjectGenerator& gen, Register reg, uint8_t sa); /*! * Jump, 32-bit constant offset. The offset is by default 0 and must be patched later. */ -Instruction jmp_32(const ObjectGenerator& gen); +Instruction jmp_imm(const ObjectGenerator& gen); /*! * Jump if equal. */ -Instruction je_32(const ObjectGenerator& gen); +Instruction je_imm(const ObjectGenerator& gen); /*! * Jump not equal. */ -Instruction jne_32(const ObjectGenerator& gen); +Instruction jne_imm(const ObjectGenerator& gen); /*! * Jump less than or equal. */ -Instruction jle_32(const ObjectGenerator& gen); +Instruction jle_imm(const ObjectGenerator& gen); /*! * Jump greater than or equal. */ -Instruction jge_32(const ObjectGenerator& gen); +Instruction jge_imm(const ObjectGenerator& gen); /*! * Jump less than */ -Instruction jl_32(const ObjectGenerator& gen); +Instruction jl_imm(const ObjectGenerator& gen); /*! * Jump greater than */ -Instruction jg_32(const ObjectGenerator& gen); +Instruction jg_imm(const ObjectGenerator& gen); /*! * Jump below or equal */ -Instruction jbe_32(const ObjectGenerator& gen); +Instruction jbe_imm(const ObjectGenerator& gen); /*! * Jump above or equal */ -Instruction jae_32(const ObjectGenerator& gen); +Instruction jae_imm(const ObjectGenerator& gen); /*! * Jump below */ -Instruction jb_32(const ObjectGenerator& gen); +Instruction jb_imm(const ObjectGenerator& gen); /*! * Jump above */ -Instruction ja_32(const ObjectGenerator& gen); +Instruction ja_imm(const ObjectGenerator& gen); //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; // FLOAT MATH @@ -715,49 +715,49 @@ Instruction ja_32(const ObjectGenerator& gen); /*! * Compare two floats and set flag register for jump (ucomiss) */ -Instruction cmp_flt_flt(const ObjectGenerator& gen, Register a, Register b); +Instruction cmp_f32_f32(const ObjectGenerator& gen, Register a, Register b); -Instruction sqrts_xmm(const ObjectGenerator& gen, Register dst, Register src); +Instruction sqrt_f32(const ObjectGenerator& gen, Register dst, Register src); /*! - * Multiply two floats in xmm's + * Multiply two floats in f32's */ -Instruction mulss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src); +Instruction mul_f32_f32(const ObjectGenerator& gen, Register dst, Register src); /*! - * Divide two floats in xmm's + * Divide two floats in f32's */ -Instruction divss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src); +Instruction div_f32_f32(const ObjectGenerator& gen, Register dst, Register src); /*! - * Subtract two floats in xmm's + * Subtract two floats in f32's */ -Instruction subss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src); +Instruction sub_f32_f32(const ObjectGenerator& gen, Register dst, Register src); /*! - * Add two floats in xmm's + * Add two floats in f32's */ -Instruction addss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src); +Instruction add_f32_f32(const ObjectGenerator& gen, Register dst, Register src); /*! * Floating point minimum. */ -Instruction minss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src); +Instruction min_f32_f32(const ObjectGenerator& gen, Register dst, Register src); /*! * Floating point maximum. */ -Instruction maxss_xmm_xmm(const ObjectGenerator& gen, Register dst, Register src); +Instruction max_f32_f32(const ObjectGenerator& gen, Register dst, Register src); /*! - * Convert GPR int32 to XMM float (single precision) + * Convert GPR int32 to float (single precision) */ -Instruction int32_to_float(const ObjectGenerator& gen, Register dst, Register src); +Instruction int32_to_f32(const ObjectGenerator& gen, Register dst, Register src); /*! - * Convert XMM float to GPR int32(single precision) (truncate) + * Convert float to GPR int32(single precision) (truncate) */ -Instruction float_to_int32(const ObjectGenerator& gen, Register dst, Register src); +Instruction f32_to_int32(const ObjectGenerator& gen, Register dst, Register src); Instruction nop(const ObjectGenerator& gen); diff --git a/goalc/emitter/IGenARM64.cpp b/goalc/emitter/IGenARM64.cpp index a1a2cdb0ea..e70d5eef54 100644 --- a/goalc/emitter/IGenARM64.cpp +++ b/goalc/emitter/IGenARM64.cpp @@ -1,6 +1,8 @@ #include "IGenARM64.h" +#include + #include "goalc/emitter/Instruction.h" #include "goalc/emitter/InstructionSet.h" #include "goalc/emitter/Register.h" @@ -693,7 +695,7 @@ InstructionARM64 static_addr(Register dest, s64 offset) { return InstructionARM64(Base(0b01011000, 8), Imm19(offset / 4), Rt(dest.id())); } -InstructionARM64 static_load_fp32(Register simd_dest, s64 offset) { +InstructionARM64 static_load_f32(Register simd_dest, s64 offset) { ASSERT(simd_dest.is_gpr(instr_set)); ASSERT_MSG(offset >= ARM64_LDR_MIN && offset <= ARM64_LDR_MAX, "PC Relative offset is too large for ARM64, fix it."); @@ -704,7 +706,7 @@ InstructionARM64 static_load_fp32(Register simd_dest, s64 offset) { // TODO ARM - no direct store instructions, gotta be two and involve a register -InstructionARM64 static_store_xmm32(Register xmm_value, s64 offset) { +InstructionARM64 static_store_f32(Register xmm_value, s64 offset) { ASSERT_MSG(false, "not yet implemented"); return InstructionARM64(0b0); } @@ -743,7 +745,7 @@ InstructionARM64 push_gpr64(Register reg) { // But we can't do either of these at this level, this is an optimization that has to come from // higher in the stack. Here we are concerned with just satisfying the need to push a GPR ASSERT(reg.is_gpr(instr_set)); - return InstructionARM64(Base(0b1111100000000000000011, 22), Imm9(-16), Rn(ARM64_REG::SP), + return InstructionARM64(Base(0b1111100000000000000011, 22), Imm9s(-16), Rn(ARM64_REG::SP), Rt(reg.id())); } @@ -751,7 +753,7 @@ InstructionARM64 pop_gpr64(Register reg) { // ldr reg, [sp], #16 // - https://www.scs.stanford.edu/~zyedidia/arm64/ldr_imm_gen.html ASSERT(reg.is_gpr(instr_set)); - return InstructionARM64(Base(0b1111100001000000000001, 22), Imm9(16), Rn(ARM64_REG::SP), + return InstructionARM64(Base(0b1111100001000000000001, 22), Imm9s(16), Rn(ARM64_REG::SP), Rt(reg.id())); } @@ -826,7 +828,7 @@ std::vector> decompose_into_imm12_chunks(u64 imm) { InstructionARM64 add_gpr64_imm(Register reg, int64_t imm) { ASSERT(reg.is_gpr(instr_set)); if (imm < 0) { - sub_gpr64_imm(reg, std::abs(imm)); + return sub_gpr64_imm(reg, std::abs(imm)); } // Check to see if we can represent this subtraction in a single instruction // if not, then we need to emit multiple partial instructions @@ -852,7 +854,7 @@ InstructionARM64 add_gpr64_imm(Register reg, int64_t imm) { InstructionARM64 sub_gpr64_imm(Register reg, int64_t imm) { ASSERT(reg.is_gpr(instr_set)); if (imm < 0) { - add_gpr64_imm(reg, std::abs(imm)); + return add_gpr64_imm(reg, std::abs(imm)); } // Check to see if we can represent this subtraction in a single instruction // if not, then we need to emit multiple partial instructions diff --git a/goalc/emitter/IGenARM64.h b/goalc/emitter/IGenARM64.h index 11041fba28..1bd210c7ae 100644 --- a/goalc/emitter/IGenARM64.h +++ b/goalc/emitter/IGenARM64.h @@ -351,9 +351,9 @@ InstructionARM64 static_store(Register value, s64 offset, int size); InstructionARM64 static_addr(Register dst, s64 offset); -InstructionARM64 static_load_fp32(Register simd_dest, s64 offset); +InstructionARM64 static_load_f32(Register simd_dest, s64 offset); -InstructionARM64 static_store_xmm32(Register xmm_value, s64 offset); +InstructionARM64 static_store_f32(Register xmm_value, s64 offset); // TODO, special load/stores of 128 bit values. @@ -609,12 +609,12 @@ InstructionARM64 min_f32_f32(Register dst, Register src); InstructionARM64 max_f32_f32(Register dst, Register src); /*! - * Convert GPR int32 to XMM float (single precision) + * Convert GPR int32 to float (single precision) */ InstructionARM64 int32_to_f32(Register dst, Register src); /*! - * Convert XMM float to GPR int32(single precision) (truncate) + * Convert float to GPR int32(single precision) (truncate) */ InstructionARM64 f32_to_int32(Register dst, Register src); diff --git a/goalc/emitter/IGenX86.cpp b/goalc/emitter/IGenX86.cpp index e146179906..6113d7b0ae 100644 --- a/goalc/emitter/IGenX86.cpp +++ b/goalc/emitter/IGenX86.cpp @@ -59,7 +59,7 @@ InstructionX86 mov_gpr64_s32(Register dst, int64_t val) { return instr; } -InstructionX86 movd_gpr32_xmm32(Register dst, Register src) { +InstructionX86 movd_gpr32_f32(Register dst, Register src) { ASSERT(dst.is_gpr(instr_set)); ASSERT(src.is_xmm(instr_set)); InstructionX86 instr(0x66); @@ -70,7 +70,7 @@ InstructionX86 movd_gpr32_xmm32(Register dst, Register src) { return instr; } -InstructionX86 movd_xmm32_gpr32(Register dst, Register src) { +InstructionX86 movd_f32_gpr32(Register dst, Register src) { ASSERT(dst.is_xmm(instr_set)); ASSERT(src.is_gpr(instr_set)); InstructionX86 instr(0x66); @@ -81,7 +81,7 @@ InstructionX86 movd_xmm32_gpr32(Register dst, Register src) { return instr; } -InstructionX86 movq_gpr64_xmm64(Register dst, Register src) { +InstructionX86 movq_gpr64_f64(Register dst, Register src) { ASSERT(dst.is_gpr(instr_set)); ASSERT(src.is_xmm(instr_set)); InstructionX86 instr(0x66); @@ -92,7 +92,7 @@ InstructionX86 movq_gpr64_xmm64(Register dst, Register src) { return instr; } -InstructionX86 movq_xmm64_gpr64(Register dst, Register src) { +InstructionX86 movq_f64_gpr64(Register dst, Register src) { ASSERT(dst.is_xmm(instr_set)); ASSERT(src.is_gpr(instr_set)); InstructionX86 instr(0x66); @@ -103,7 +103,7 @@ InstructionX86 movq_xmm64_gpr64(Register dst, Register src) { return instr; } -InstructionX86 mov_xmm32_xmm32(Register dst, Register src) { +InstructionX86 mov_f32_f32(Register dst, Register src) { ASSERT(dst.is_xmm(instr_set)); ASSERT(src.is_xmm(instr_set)); InstructionX86 instr(0xf3); @@ -1155,7 +1155,7 @@ InstructionX86 store128_xmm128_reg_offset(Register base, Register xmm_val, s64 o } } -InstructionX86 load64_rip_s32(Register dest, s64 offset) { +InstructionX86 load64_pcRel_s32(Register dest, s64 offset) { ASSERT(dest.is_gpr(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); InstructionX86 instr(0x8b); @@ -1163,7 +1163,7 @@ InstructionX86 load64_rip_s32(Register dest, s64 offset) { return instr; } -InstructionX86 load32s_rip_s32(Register dest, s64 offset) { +InstructionX86 load32s_pcRel_s32(Register dest, s64 offset) { ASSERT(dest.is_gpr(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); InstructionX86 instr(0x63); @@ -1171,7 +1171,7 @@ InstructionX86 load32s_rip_s32(Register dest, s64 offset) { return instr; } -InstructionX86 load32u_rip_s32(Register dest, s64 offset) { +InstructionX86 load32u_pcRel_s32(Register dest, s64 offset) { ASSERT(dest.is_gpr(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); InstructionX86 instr(0x8b); @@ -1179,7 +1179,7 @@ InstructionX86 load32u_rip_s32(Register dest, s64 offset) { return instr; } -InstructionX86 load16u_rip_s32(Register dest, s64 offset) { +InstructionX86 load16u_pcRel_s32(Register dest, s64 offset) { ASSERT(dest.is_gpr(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); InstructionX86 instr(0xf); @@ -1188,7 +1188,7 @@ InstructionX86 load16u_rip_s32(Register dest, s64 offset) { return instr; } -InstructionX86 load16s_rip_s32(Register dest, s64 offset) { +InstructionX86 load16s_pcRel_s32(Register dest, s64 offset) { ASSERT(dest.is_gpr(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); InstructionX86 instr(0xf); @@ -1197,7 +1197,7 @@ InstructionX86 load16s_rip_s32(Register dest, s64 offset) { return instr; } -InstructionX86 load8u_rip_s32(Register dest, s64 offset) { +InstructionX86 load8u_pcRel_s32(Register dest, s64 offset) { ASSERT(dest.is_gpr(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); InstructionX86 instr(0xf); @@ -1206,7 +1206,7 @@ InstructionX86 load8u_rip_s32(Register dest, s64 offset) { return instr; } -InstructionX86 load8s_rip_s32(Register dest, s64 offset) { +InstructionX86 load8s_pcRel_s32(Register dest, s64 offset) { ASSERT(dest.is_gpr(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); InstructionX86 instr(0xf); @@ -1219,33 +1219,33 @@ InstructionX86 static_load(Register dest, s64 offset, int size, bool sign_extend switch (size) { case 1: if (sign_extend) { - return load8s_rip_s32(dest, offset); + return load8s_pcRel_s32(dest, offset); } else { - return load8u_rip_s32(dest, offset); + return load8u_pcRel_s32(dest, offset); } break; case 2: if (sign_extend) { - return load16s_rip_s32(dest, offset); + return load16s_pcRel_s32(dest, offset); } else { - return load16u_rip_s32(dest, offset); + return load16u_pcRel_s32(dest, offset); } break; case 4: if (sign_extend) { - return load32s_rip_s32(dest, offset); + return load32s_pcRel_s32(dest, offset); } else { - return load32u_rip_s32(dest, offset); + return load32u_pcRel_s32(dest, offset); } break; case 8: - return load64_rip_s32(dest, offset); + return load64_pcRel_s32(dest, offset); default: ASSERT(false); } } -InstructionX86 store64_rip_s32(Register src, s64 offset) { +InstructionX86 store64_pcRel_s32(Register src, s64 offset) { ASSERT(src.is_gpr(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); @@ -1254,7 +1254,7 @@ InstructionX86 store64_rip_s32(Register src, s64 offset) { return instr; } -InstructionX86 store32_rip_s32(Register src, s64 offset) { +InstructionX86 store32_pcRel_s32(Register src, s64 offset) { ASSERT(src.is_gpr(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); @@ -1263,7 +1263,7 @@ InstructionX86 store32_rip_s32(Register src, s64 offset) { return instr; } -InstructionX86 store16_rip_s32(Register src, s64 offset) { +InstructionX86 store16_pcRel_s32(Register src, s64 offset) { ASSERT(src.is_gpr(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); @@ -1274,7 +1274,7 @@ InstructionX86 store16_rip_s32(Register src, s64 offset) { return instr; } -InstructionX86 store8_rip_s32(Register src, s64 offset) { +InstructionX86 store8_pcRel_s32(Register src, s64 offset) { ASSERT(src.is_gpr(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); @@ -1289,13 +1289,13 @@ InstructionX86 store8_rip_s32(Register src, s64 offset) { InstructionX86 static_store(Register value, s64 offset, int size) { switch (size) { case 1: - return store8_rip_s32(value, offset); + return store8_pcRel_s32(value, offset); case 2: - return store16_rip_s32(value, offset); + return store16_pcRel_s32(value, offset); case 4: - return store32_rip_s32(value, offset); + return store32_pcRel_s32(value, offset); case 8: - return store64_rip_s32(value, offset); + return store64_pcRel_s32(value, offset); default: ASSERT(false); } @@ -1309,7 +1309,7 @@ InstructionX86 static_addr(Register dst, s64 offset) { return instr; } -InstructionX86 static_load_xmm32(Register simd_dest, s64 offset) { +InstructionX86 static_load_f32(Register simd_dest, s64 offset) { ASSERT(simd_dest.is_xmm(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); @@ -1322,7 +1322,7 @@ InstructionX86 static_load_xmm32(Register simd_dest, s64 offset) { return instr; } -InstructionX86 static_store_xmm32(Register xmm_value, s64 offset) { +InstructionX86 static_store_f32(Register xmm_value, s64 offset) { ASSERT(xmm_value.is_xmm(instr_set)); ASSERT(offset >= INT32_MIN && offset <= INT32_MAX); @@ -1617,83 +1617,83 @@ InstructionX86 sar_gpr64_u8(Register reg, uint8_t sa) { return instr; } -InstructionX86 jmp_32() { +InstructionX86 jmp_imm() { InstructionX86 instr(0xe9); instr.set(Imm(4, 0)); return instr; } -InstructionX86 je_32() { +InstructionX86 je_imm() { InstructionX86 instr(0x0f); instr.set_op2(0x84); instr.set(Imm(4, 0)); return instr; } -InstructionX86 jne_32() { +InstructionX86 jne_imm() { InstructionX86 instr(0x0f); instr.set_op2(0x85); instr.set(Imm(4, 0)); return instr; } -InstructionX86 jle_32() { +InstructionX86 jle_imm() { InstructionX86 instr(0x0f); instr.set_op2(0x8e); instr.set(Imm(4, 0)); return instr; } -InstructionX86 jge_32() { +InstructionX86 jge_imm() { InstructionX86 instr(0x0f); instr.set_op2(0x8d); instr.set(Imm(4, 0)); return instr; } -InstructionX86 jl_32() { +InstructionX86 jl_imm() { InstructionX86 instr(0x0f); instr.set_op2(0x8c); instr.set(Imm(4, 0)); return instr; } -InstructionX86 jg_32() { +InstructionX86 jg_imm() { InstructionX86 instr(0x0f); instr.set_op2(0x8f); instr.set(Imm(4, 0)); return instr; } -InstructionX86 jbe_32() { +InstructionX86 jbe_imm() { InstructionX86 instr(0x0f); instr.set_op2(0x86); instr.set(Imm(4, 0)); return instr; } -InstructionX86 jae_32() { +InstructionX86 jae_imm() { InstructionX86 instr(0x0f); instr.set_op2(0x83); instr.set(Imm(4, 0)); return instr; } -InstructionX86 jb_32() { +InstructionX86 jb_imm() { InstructionX86 instr(0x0f); instr.set_op2(0x82); instr.set(Imm(4, 0)); return instr; } -InstructionX86 ja_32() { +InstructionX86 ja_imm() { InstructionX86 instr(0x0f); instr.set_op2(0x87); instr.set(Imm(4, 0)); return instr; } -InstructionX86 cmp_flt_flt(Register a, Register b) { +InstructionX86 cmp_f32_f32(Register a, Register b) { ASSERT(a.is_xmm(instr_set)); ASSERT(b.is_xmm(instr_set)); InstructionX86 instr(0x0f); @@ -1702,7 +1702,7 @@ InstructionX86 cmp_flt_flt(Register a, Register b) { return instr; } -InstructionX86 sqrts_xmm(Register dst, Register src) { +InstructionX86 sqrt_f32(Register dst, Register src) { ASSERT(dst.is_xmm(instr_set)); ASSERT(src.is_xmm(instr_set)); InstructionX86 instr(0xf3); @@ -1713,7 +1713,7 @@ InstructionX86 sqrts_xmm(Register dst, Register src) { return instr; } -InstructionX86 mulss_xmm_xmm(Register dst, Register src) { +InstructionX86 mul_f32_f32(Register dst, Register src) { ASSERT(dst.is_xmm(instr_set)); ASSERT(src.is_xmm(instr_set)); InstructionX86 instr(0xf3); @@ -1724,7 +1724,7 @@ InstructionX86 mulss_xmm_xmm(Register dst, Register src) { return instr; } -InstructionX86 divss_xmm_xmm(Register dst, Register src) { +InstructionX86 div_f32_f32(Register dst, Register src) { ASSERT(dst.is_xmm(instr_set)); ASSERT(src.is_xmm(instr_set)); InstructionX86 instr(0xf3); @@ -1735,7 +1735,7 @@ InstructionX86 divss_xmm_xmm(Register dst, Register src) { return instr; } -InstructionX86 subss_xmm_xmm(Register dst, Register src) { +InstructionX86 sub_f32_f32(Register dst, Register src) { ASSERT(dst.is_xmm(instr_set)); ASSERT(src.is_xmm(instr_set)); InstructionX86 instr(0xf3); @@ -1746,7 +1746,7 @@ InstructionX86 subss_xmm_xmm(Register dst, Register src) { return instr; } -InstructionX86 addss_xmm_xmm(Register dst, Register src) { +InstructionX86 add_f32_f32(Register dst, Register src) { ASSERT(dst.is_xmm(instr_set)); ASSERT(src.is_xmm(instr_set)); InstructionX86 instr(0xf3); @@ -1757,7 +1757,7 @@ InstructionX86 addss_xmm_xmm(Register dst, Register src) { return instr; } -InstructionX86 minss_xmm_xmm(Register dst, Register src) { +InstructionX86 min_f32_f32(Register dst, Register src) { ASSERT(dst.is_xmm(instr_set)); ASSERT(src.is_xmm(instr_set)); InstructionX86 instr(0xf3); @@ -1768,7 +1768,7 @@ InstructionX86 minss_xmm_xmm(Register dst, Register src) { return instr; } -InstructionX86 maxss_xmm_xmm(Register dst, Register src) { +InstructionX86 max_f32_f32(Register dst, Register src) { ASSERT(dst.is_xmm(instr_set)); ASSERT(src.is_xmm(instr_set)); InstructionX86 instr(0xf3); @@ -1779,7 +1779,7 @@ InstructionX86 maxss_xmm_xmm(Register dst, Register src) { return instr; } -InstructionX86 int32_to_float(Register dst, Register src) { +InstructionX86 int32_to_f32(Register dst, Register src) { ASSERT(dst.is_xmm(instr_set)); ASSERT(src.is_gpr(instr_set)); InstructionX86 instr(0xf3); @@ -1790,7 +1790,7 @@ InstructionX86 int32_to_float(Register dst, Register src) { return instr; } -InstructionX86 float_to_int32(Register dst, Register src) { +InstructionX86 f32_to_int32(Register dst, Register src) { ASSERT(dst.is_gpr(instr_set)); ASSERT(src.is_xmm(instr_set)); InstructionX86 instr(0xf3); diff --git a/goalc/emitter/IGenX86.h b/goalc/emitter/IGenX86.h index 50ed50f8ae..436fffce75 100644 --- a/goalc/emitter/IGenX86.h +++ b/goalc/emitter/IGenX86.h @@ -34,27 +34,27 @@ InstructionX86 mov_gpr64_s32(Register dst, int64_t val); /*! * Move 32-bits of xmm to 32 bits of gpr (no sign extension). */ -InstructionX86 movd_gpr32_xmm32(Register dst, Register src); +InstructionX86 movd_gpr32_f32(Register dst, Register src); /*! * Move 32-bits of gpr to 32-bits of xmm (no sign extension) */ -InstructionX86 movd_xmm32_gpr32(Register dst, Register src); +InstructionX86 movd_f32_gpr32(Register dst, Register src); /*! * Move 64-bits of xmm to 64 bits of gpr (no sign extension). */ -InstructionX86 movq_gpr64_xmm64(Register dst, Register src); +InstructionX86 movq_gpr64_f64(Register dst, Register src); /*! * Move 64-bits of gpr to 64-bits of xmm (no sign extension) */ -InstructionX86 movq_xmm64_gpr64(Register dst, Register src); +InstructionX86 movq_f64_gpr64(Register dst, Register src); /*! * Move 32-bits between xmm's */ -InstructionX86 mov_xmm32_xmm32(Register dst, Register src); +InstructionX86 mov_f32_f32(Register dst, Register src); // todo - GPR64 -> XMM64 (zext) // todo - XMM -> GPR64 @@ -323,37 +323,37 @@ InstructionX86 store128_xmm128_reg_offset(Register base, Register xmm_val, s64 o // RIP loads and stores //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -InstructionX86 load64_rip_s32(Register dest, s64 offset); +InstructionX86 load64_pcRel_s32(Register dest, s64 offset); -InstructionX86 load32s_rip_s32(Register dest, s64 offset); +InstructionX86 load32s_pcRel_s32(Register dest, s64 offset); -InstructionX86 load32u_rip_s32(Register dest, s64 offset); +InstructionX86 load32u_pcRel_s32(Register dest, s64 offset); -InstructionX86 load16u_rip_s32(Register dest, s64 offset); +InstructionX86 load16u_pcRel_s32(Register dest, s64 offset); -InstructionX86 load16s_rip_s32(Register dest, s64 offset); +InstructionX86 load16s_pcRel_s32(Register dest, s64 offset); -InstructionX86 load8u_rip_s32(Register dest, s64 offset); +InstructionX86 load8u_pcRel_s32(Register dest, s64 offset); -InstructionX86 load8s_rip_s32(Register dest, s64 offset); +InstructionX86 load8s_pcRel_s32(Register dest, s64 offset); InstructionX86 static_load(Register dest, s64 offset, int size, bool sign_extend); -InstructionX86 store64_rip_s32(Register src, s64 offset); +InstructionX86 store64_pcRel_s32(Register src, s64 offset); -InstructionX86 store32_rip_s32(Register src, s64 offset); +InstructionX86 store32_pcRel_s32(Register src, s64 offset); -InstructionX86 store16_rip_s32(Register src, s64 offset); +InstructionX86 store16_pcRel_s32(Register src, s64 offset); -InstructionX86 store8_rip_s32(Register src, s64 offset); +InstructionX86 store8_pcRel_s32(Register src, s64 offset); InstructionX86 static_store(Register value, s64 offset, int size); InstructionX86 static_addr(Register dst, s64 offset); -InstructionX86 static_load_xmm32(Register simd_dest, s64 offset); +InstructionX86 static_load_f32(Register simd_dest, s64 offset); -InstructionX86 static_store_xmm32(Register xmm_value, s64 offset); +InstructionX86 static_store_f32(Register xmm_value, s64 offset); // TODO, special load/stores of 128 bit values. @@ -515,57 +515,57 @@ InstructionX86 sar_gpr64_u8(Register reg, uint8_t sa); /*! * Jump, 32-bit constant offset. The offset is by default 0 and must be patched later. */ -InstructionX86 jmp_32(); +InstructionX86 jmp_imm(); /*! * Jump if equal. */ -InstructionX86 je_32(); +InstructionX86 je_imm(); /*! * Jump not equal. */ -InstructionX86 jne_32(); +InstructionX86 jne_imm(); /*! * Jump less than or equal. */ -InstructionX86 jle_32(); +InstructionX86 jle_imm(); /*! * Jump greater than or equal. */ -InstructionX86 jge_32(); +InstructionX86 jge_imm(); /*! * Jump less than */ -InstructionX86 jl_32(); +InstructionX86 jl_imm(); /*! * Jump greater than */ -InstructionX86 jg_32(); +InstructionX86 jg_imm(); /*! * Jump below or equal */ -InstructionX86 jbe_32(); +InstructionX86 jbe_imm(); /*! * Jump above or equal */ -InstructionX86 jae_32(); +InstructionX86 jae_imm(); /*! * Jump below */ -InstructionX86 jb_32(); +InstructionX86 jb_imm(); /*! * Jump above */ -InstructionX86 ja_32(); +InstructionX86 ja_imm(); //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; // FLOAT MATH @@ -574,49 +574,49 @@ InstructionX86 ja_32(); /*! * Compare two floats and set flag register for jump (ucomiss) */ -InstructionX86 cmp_flt_flt(Register a, Register b); +InstructionX86 cmp_f32_f32(Register a, Register b); -InstructionX86 sqrts_xmm(Register dst, Register src); +InstructionX86 sqrt_f32(Register dst, Register src); /*! - * Multiply two floats in xmm's + * Multiply two floats in f32's */ -InstructionX86 mulss_xmm_xmm(Register dst, Register src); +InstructionX86 mul_f32_f32(Register dst, Register src); /*! - * Divide two floats in xmm's + * Divide two floats in f32's */ -InstructionX86 divss_xmm_xmm(Register dst, Register src); +InstructionX86 div_f32_f32(Register dst, Register src); /*! - * Subtract two floats in xmm's + * Subtract two floats in f32's */ -InstructionX86 subss_xmm_xmm(Register dst, Register src); +InstructionX86 sub_f32_f32(Register dst, Register src); /*! - * Add two floats in xmm's + * Add two floats in f32's */ -InstructionX86 addss_xmm_xmm(Register dst, Register src); +InstructionX86 add_f32_f32(Register dst, Register src); /*! * Floating point minimum. */ -InstructionX86 minss_xmm_xmm(Register dst, Register src); +InstructionX86 min_f32_f32(Register dst, Register src); /*! * Floating point maximum. */ -InstructionX86 maxss_xmm_xmm(Register dst, Register src); +InstructionX86 max_f32_f32(Register dst, Register src); /*! * Convert GPR int32 to XMM float (single precision) */ -InstructionX86 int32_to_float(Register dst, Register src); +InstructionX86 int32_to_f32(Register dst, Register src); /*! * Convert XMM float to GPR int32(single precision) (truncate) */ -InstructionX86 float_to_int32(Register dst, Register src); +InstructionX86 f32_to_int32(Register dst, Register src); InstructionX86 nop(); diff --git a/goalc/emitter/Instruction.h b/goalc/emitter/Instruction.h index 6741fc96e4..8c691f1ce3 100644 --- a/goalc/emitter/Instruction.h +++ b/goalc/emitter/Instruction.h @@ -45,11 +45,18 @@ constexpr u32 Base(u32 value, u32 width) { return value << (32 - width); } +// TODO - consider passing in the instruction name to make debugging easier when an assertion is +// hit + // TODO NOW - fix below constexpr u64 pow2(u64 n) { return 1ull << n; } +constexpr s64 pow2s(u64 n) { + return 1ull << n; +} + constexpr Field Hw(u32 x) { ASSERT(x >= 0 && x <= (4 - 1)); return Field{(x & 4) << 21}; @@ -91,17 +98,17 @@ constexpr Field Imm4(u32 x) { } constexpr Field Imm6(u32 x) { - ASSERT(x >= 0 && x <= (64 - 1)); + ASSERT(x >= 0 && x <= ((2 ^ 6))); return Field{(x & 0b111111) << 10}; } -constexpr Field Imm9(s32 x) { - ASSERT(x >= 0 && x <= (512 - 1)); +constexpr Field Imm9s(s32 x) { + ASSERT(x >= (pow2s(9 - 1) * -1) && x <= (pow2s(9 - 1) - 1)); return Field{(static_cast(x) & 0b111111111) << 12}; } constexpr Field Imm12(u32 x) { - ASSERT(x >= 0 && x <= (4096 - 1)); + ASSERT(x >= 0 && x <= (pow2(12) - 1)); return Field{(static_cast(x) & 0b111111111111) << 10}; } diff --git a/test/goalc/test_CodeTester.cpp b/test/goalc/test_CodeTester.cpp index d1ffe56d63..738b49b131 100644 --- a/test/goalc/test_CodeTester.cpp +++ b/test/goalc/test_CodeTester.cpp @@ -150,10 +150,10 @@ TEST(CodeTester, simd_store_128_arm64) { CodeTester tester(emitter::InstructionSet::ARM64); tester.init_code_buffer(256); - tester.emit(IGen::store128_gpr64_simd128(tester.generator(), X2, Q3)); - tester.emit(IGen::store128_gpr64_simd128(tester.generator(), X14, Q3)); - tester.emit(IGen::store128_gpr64_simd128(tester.generator(), X2, Q14)); - tester.emit(IGen::store128_gpr64_simd128(tester.generator(), X14, Q13)); + tester.emit(IGen::store128_gpr64_simd128(tester.generator(), X2, V3)); + tester.emit(IGen::store128_gpr64_simd128(tester.generator(), X14, V3)); + tester.emit(IGen::store128_gpr64_simd128(tester.generator(), X2, V14)); + tester.emit(IGen::store128_gpr64_simd128(tester.generator(), X14, V13)); EXPECT_EQ(tester.dump_to_hex_string(), "43 00 80 3d c3 01 80 3d 4e 00 80 3d cd 01 80 3d"); } @@ -197,10 +197,10 @@ TEST(CodeTester, xmm_load_128_arm64) { CodeTester tester(emitter::InstructionSet::ARM64); tester.init_code_buffer(256); - tester.emit(IGen::load128_simd128_gpr64(tester.generator(), Q3, X1)); - tester.emit(IGen::load128_simd128_gpr64(tester.generator(), Q3, X14)); - tester.emit(IGen::load128_simd128_gpr64(tester.generator(), Q14, X1)); - tester.emit(IGen::load128_simd128_gpr64(tester.generator(), Q13, X14)); + tester.emit(IGen::load128_simd128_gpr64(tester.generator(), V3, X1)); + tester.emit(IGen::load128_simd128_gpr64(tester.generator(), V3, X14)); + tester.emit(IGen::load128_simd128_gpr64(tester.generator(), V14, X1)); + tester.emit(IGen::load128_simd128_gpr64(tester.generator(), V13, X14)); EXPECT_EQ(tester.dump_to_hex_string(), "23 00 c0 3d c3 01 c0 3d 2e 00 c0 3d cd 01 c0 3d"); } diff --git a/test/test_emitter.cpp b/test/test_emitter.cpp index 4538b1a7c1..fc4d05377d 100644 --- a/test/test_emitter.cpp +++ b/test/test_emitter.cpp @@ -1,3903 +1,3909 @@ -// #include "goalc/emitter/CodeTester.h" -// #include "goalc/emitter/IGen.h" -// #include "gtest/gtest.h" - -// using namespace emitter; - -// TEST(EmitterIntegerMath, add_gpr64_imm8s) { -// CodeTester tester; -// tester.init_code_buffer(256); - -// std::vector vals = {0, 1, -1, INT32_MIN, INT32_MAX, INT64_MIN, INT64_MAX}; -// std::vector imms = {0, 1, -1, INT8_MIN, INT8_MAX}; - -// // test the ones that aren't rsp -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (auto val : vals) { -// for (auto imm : imms) { -// auto expected = val + imm; - -// tester.clear(); -// tester.emit_push_all_gprs(true); - -// // move initial value to register -// tester.emit(IGen::mov_gpr64_gpr64(i, tester.get_c_abi_arg_reg(0))); -// // do the add -// tester.emit(IGen::add_gpr64_imm8s(i, imm)); -// // move for return -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); - -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// auto result = tester.execute_ret(val, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } - -// tester.clear(); -// tester.emit(IGen::add_gpr64_imm8s(RSP, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 83 c4 0c"); -// } - -// TEST(EmitterIntegerMath, add_gpr64_imm32s) { -// CodeTester tester; -// tester.init_code_buffer(256); - -// std::vector vals = {0, 1, -1, INT32_MIN, INT32_MAX, INT64_MIN, INT64_MAX}; -// std::vector imms = {0, 1, -1, INT8_MIN, INT8_MAX, INT32_MIN, INT32_MAX}; - -// // test the ones that aren't rsp -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (auto val : vals) { -// for (auto imm : imms) { -// auto expected = val + imm; - -// tester.clear(); -// tester.emit_push_all_gprs(true); - -// // move initial value to register -// tester.emit(IGen::mov_gpr64_gpr64(i, tester.get_c_abi_arg_reg(0))); -// // do the add -// tester.emit(IGen::add_gpr64_imm32s(i, imm)); -// // move for return -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); - -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// auto result = tester.execute_ret(val, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } - -// tester.clear(); -// tester.emit(IGen::add_gpr64_imm32s(RSP, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 81 c4 0c 00 00 00"); -// } - -// TEST(EmitterIntegerMath, sub_gpr64_imm8s) { -// CodeTester tester; -// tester.init_code_buffer(256); - -// std::vector vals = {0, 1, -1, INT32_MIN, INT32_MAX, INT64_MIN, INT64_MAX}; -// std::vector imms = {0, 1, -1, INT8_MIN, INT8_MAX}; - -// // test the ones that aren't rsp -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (auto val : vals) { -// for (auto imm : imms) { -// auto expected = val - imm; - -// tester.clear(); -// tester.emit_push_all_gprs(true); - -// // move initial value to register -// tester.emit(IGen::mov_gpr64_gpr64(i, tester.get_c_abi_arg_reg(0))); -// // do the add -// tester.emit(IGen::sub_gpr64_imm8s(i, imm)); -// // move for return -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); - -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// auto result = tester.execute_ret(val, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } - -// tester.clear(); -// tester.emit(IGen::sub_gpr64_imm8s(RSP, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 83 ec 0c"); -// } - -// TEST(EmitterIntegerMath, sub_gpr64_imm32s) { -// CodeTester tester; -// tester.init_code_buffer(256); - -// std::vector vals = {0, 1, -1, INT32_MIN, INT32_MAX, INT64_MIN, INT64_MAX}; -// std::vector imms = {0, 1, -1, INT8_MIN, INT8_MAX, INT32_MIN, INT32_MAX}; - -// // test the ones that aren't rsp -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (auto val : vals) { -// for (auto imm : imms) { -// auto expected = val - imm; - -// tester.clear(); -// tester.emit_push_all_gprs(true); - -// // move initial value to register -// tester.emit(IGen::mov_gpr64_gpr64(i, tester.get_c_abi_arg_reg(0))); -// // do the add -// tester.emit(IGen::sub_gpr64_imm32s(i, imm)); -// // move for return -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); - -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// auto result = tester.execute_ret(val, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } - -// tester.clear(); -// tester.emit(IGen::sub_gpr64_imm32s(RSP, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 81 ec 0c 00 00 00"); -// } - -// TEST(EmitterIntegerMath, add_gpr64_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, -// INT64_MAX, 117, 32, -348473, 83747382}; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } -// for (auto v1 : vals) { -// for (auto v2 : vals) { -// auto expected = v1 + v2; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v1)); -// tester.emit(IGen::mov_gpr64_u64(j, v2)); -// tester.emit(IGen::add_gpr64_gpr64(i, j)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, sub_gpr64_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, -// INT64_MAX, 117, 32, -348473, 83747382}; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } -// for (auto v1 : vals) { -// for (auto v2 : vals) { -// auto expected = v1 - v2; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v1)); -// tester.emit(IGen::mov_gpr64_u64(j, v2)); -// tester.emit(IGen::sub_gpr64_gpr64(i, j)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, mul_gpr32_gpr32) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = { -// 0, 1, -2, -20, 123123, INT32_MIN, INT32_MAX, INT32_MIN + 1, INT32_MAX - 1}; - -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } -// for (auto v1 : vals) { -// for (auto v2 : vals) { -// // this is kind of weird behavior, but it's what the PS2 CPU does, I think. -// // the lower 32-bits of the result are sign extended, even if this sign doesn't match -// // the sign of the real product. This is true for both signed and unsigned multiply. -// auto expected = ((s64(v1) * s64(v2)) << 32) >> 32; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, (s64)v1)); -// tester.emit(IGen::mov_gpr64_u64(j, (s64)v2)); -// tester.emit(IGen::imul_gpr32_gpr32(i, j)); -// tester.emit(IGen::movsx_r64_r32(RAX, i)); // weird PS2 sign extend. -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, or_gpr64_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, -// INT64_MAX, 117, 32, -348473, 83747382}; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } -// for (auto v1 : vals) { -// for (auto v2 : vals) { -// auto expected = v1 | v2; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v1)); -// tester.emit(IGen::mov_gpr64_u64(j, v2)); -// tester.emit(IGen::or_gpr64_gpr64(i, j)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, and_gpr64_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, -// INT64_MAX, 117, 32, -348473, 83747382}; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } -// for (auto v1 : vals) { -// for (auto v2 : vals) { -// auto expected = v1 & v2; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v1)); -// tester.emit(IGen::mov_gpr64_u64(j, v2)); -// tester.emit(IGen::and_gpr64_gpr64(i, j)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, xor_gpr64_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, -// INT64_MAX, 117, 32, -348473, 83747382}; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } -// for (auto v1 : vals) { -// for (auto v2 : vals) { -// auto expected = v1 ^ v2; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v1)); -// tester.emit(IGen::mov_gpr64_u64(j, v2)); -// tester.emit(IGen::xor_gpr64_gpr64(i, j)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, not_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, -// INT64_MAX, 117, 32, -348473, 83747382}; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (auto v1 : vals) { -// auto expected = ~v1; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v1)); -// tester.emit(IGen::not_gpr64(i)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } - -// TEST(EmitterIntegerMath, shl_gpr64_cl) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, -// INT64_MAX, 117, 32, -348473, 83747382}; -// std::vector sas = {0, 1, 23, 53, 64}; - -// for (int i = 0; i < 16; i++) { -// if (i == RSP || i == RCX) { -// continue; -// } -// for (auto v : vals) { -// for (auto sa : sas) { -// auto expected = v << sa; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v)); -// tester.emit(IGen::mov_gpr64_u64(RCX, sa)); -// tester.emit(IGen::shl_gpr64_cl(i)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, shr_gpr64_cl) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, u64(-2), u64(INT32_MIN), INT32_MAX, u64(INT64_MIN), -// INT64_MAX, 117, 32, u64(-348473), 83747382}; -// std::vector sas = {0, 1, 23, 53, 64}; - -// for (int i = 0; i < 16; i++) { -// if (i == RSP || i == RCX) { -// continue; -// } -// for (auto v : vals) { -// for (auto sa : sas) { -// auto expected = v >> sa; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v)); -// tester.emit(IGen::mov_gpr64_u64(RCX, sa)); -// tester.emit(IGen::shr_gpr64_cl(i)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, sar_gpr64_cl) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, -// INT64_MAX, 117, 32, -348473, 83747382}; -// std::vector sas = {0, 1, 23, 53, 64}; - -// for (int i = 0; i < 16; i++) { -// if (i == RSP || i == RCX) { -// continue; -// } -// for (auto v : vals) { -// for (auto sa : sas) { -// auto expected = v >> sa; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v)); -// tester.emit(IGen::mov_gpr64_u64(RCX, sa)); -// tester.emit(IGen::sar_gpr64_cl(i)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, shl_gpr64_u8) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, -// INT64_MAX, 117, 32, -348473, 83747382}; -// std::vector sas = {0, 1, 23, 53, 64}; - -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (auto v : vals) { -// for (auto sa : sas) { -// auto expected = v << sa; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v)); -// tester.emit(IGen::shl_gpr64_u8(i, sa)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, shr_gpr64_u8) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, u64(-2), u64(INT32_MIN), INT32_MAX, u64(INT64_MIN), -// INT64_MAX, 117, 32, u64(-348473), 83747382}; -// std::vector sas = {0, 1, 23, 53, 64}; - -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (auto v : vals) { -// for (auto sa : sas) { -// auto expected = v >> sa; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v)); -// tester.emit(IGen::shr_gpr64_u8(i, sa)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, sar_gpr64_u8) { -// CodeTester tester; -// tester.init_code_buffer(256); -// std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, -// INT64_MAX, 117, 32, -348473, 83747382}; -// std::vector sas = {0, 1, 23, 53, 64}; - -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (auto v : vals) { -// for (auto sa : sas) { -// auto expected = v >> sa; -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, v)); -// tester.emit(IGen::sar_gpr64_u8(i, sa)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } - -// TEST(EmitterIntegerMath, jumps) { -// CodeTester tester; -// tester.init_code_buffer(256); - -// std::vector reads; - -// auto x = IGen::jmp_32(); -// reads.push_back(tester.size() + x.offset_of_imm()); -// tester.emit(x); - -// x = IGen::je_32(); -// reads.push_back(tester.size() + x.offset_of_imm()); -// tester.emit(x); - -// x = IGen::jne_32(); -// reads.push_back(tester.size() + x.offset_of_imm()); -// tester.emit(x); - -// x = IGen::jle_32(); -// reads.push_back(tester.size() + x.offset_of_imm()); -// tester.emit(x); - -// x = IGen::jge_32(); -// reads.push_back(tester.size() + x.offset_of_imm()); -// tester.emit(x); - -// x = IGen::jl_32(); -// reads.push_back(tester.size() + x.offset_of_imm()); -// tester.emit(x); - -// x = IGen::jg_32(); -// reads.push_back(tester.size() + x.offset_of_imm()); -// tester.emit(x); - -// x = IGen::jbe_32(); -// reads.push_back(tester.size() + x.offset_of_imm()); -// tester.emit(x); - -// x = IGen::jae_32(); -// reads.push_back(tester.size() + x.offset_of_imm()); -// tester.emit(x); - -// x = IGen::jb_32(); -// reads.push_back(tester.size() + x.offset_of_imm()); -// tester.emit(x); - -// x = IGen::ja_32(); -// reads.push_back(tester.size() + x.offset_of_imm()); -// tester.emit(x); - -// for (auto off : reads) { -// EXPECT_EQ(0, tester.read(off)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "E9000000000F84000000000F85000000000F8E000000000F8D000000000F8C000000000F8F000000000F86" -// "000000000F83000000000F82000000000F8700000000"); -// } - -// TEST(EmitterIntegerMath, null) { -// auto instr = IGen::null(); -// EXPECT_EQ(0, instr.emit(nullptr)); -// } - -// TEST(EmitterLoadsAndStores, load_constant_64_and_move_gpr_gpr_64) { -// std::vector u64_constants = {0, UINT64_MAX, INT64_MAX, 7, 12}; - -// // test we can load a 64-bit constant into all gprs, move it to any other gpr, and return it. -// // rsp is skipping because that's the stack pointer and would prevent us from popping gprs -// after - -// CodeTester tester; -// tester.init_code_buffer(256); - -// for (auto constant : u64_constants) { -// for (int r1 = 0; r1 < 16; r1++) { -// if (r1 == RSP) { -// continue; -// } - -// for (int r2 = 0; r2 < 16; r2++) { -// if (r2 == RSP) { -// continue; -// } -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(r1, constant)); -// tester.emit(IGen::mov_gpr64_gpr64(r2, r1)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, r2)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// EXPECT_EQ(tester.execute(), constant); -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load_constant_32_unsigned) { -// std::vector u64_constants = {0, UINT32_MAX, INT32_MAX, 7, 12}; - -// // test loading 32-bit constants, with all upper 32-bits zero. -// // this uses a different opcode than 64-bit loads. -// CodeTester tester; -// tester.init_code_buffer(256); - -// for (auto constant : u64_constants) { -// for (int r1 = 0; r1 < 16; r1++) { -// if (r1 == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(r1, UINT64_MAX)); -// tester.emit(IGen::mov_gpr64_u32(r1, constant)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, r1)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// EXPECT_EQ(tester.execute(), constant); -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load_constant_32_signed) { -// std::vector s32_constants = {0, 1, INT32_MAX, INT32_MIN, 12, -1}; - -// // test loading signed 32-bit constants. for values < 0 this will sign extend. -// CodeTester tester; -// tester.init_code_buffer(256); - -// for (auto constant : s32_constants) { -// for (int r1 = 0; r1 < 16; r1++) { -// if (r1 == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_s32(r1, constant)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, r1)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); -// EXPECT_EQ(tester.execute(), constant); -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load8s_gpr64_goal_ptr_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(RAX, RBX, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f be 04 1e"); - -// tester.clear(); -// tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(R12, RBX, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4c 0f be 24 1e"); - -// tester.clear(); -// tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(R12, R15, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4e 0f be 24 3e"); - -// tester.clear(); -// tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(R12, R15, R14)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4f 0f be 24 3e"); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(k, i, j)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 3, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 2, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 5, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load8s_gpr64_gpr64_gpr64_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f be 44 1e fd"); - -// auto instr = IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s8(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 3 + 3, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 2 + 3, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 5 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load8s_gpr64_gpr64_gpr64_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f be 84 1e fd ff ff ff"); - -// auto instr = IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s32(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 3 + 3, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 2 + 3, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 5 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load8u_gpr64_goal_ptr_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64(RAX, RBX, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b6 04 1e"); - -// tester.clear(); -// tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64(R12, RBX, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4c 0f b6 24 1e"); - -// tester.clear(); -// tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64(R12, R15, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4e 0f b6 24 3e"); - -// tester.clear(); -// tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64(R12, R15, R14)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4f 0f b6 24 3e"); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(k, i, j)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 3, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 2, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 5, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load8u_gpr64_gpr64_gpr64_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b6 44 1e fd"); - -// auto instr = IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s8(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 3 + 3, 0, 0)), 0xfe); -// EXPECT_EQ(s64(tester.execute((u64)memory, 2 + 3, 0, 0)), 0xfd); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), 0xff); -// EXPECT_EQ(s64(tester.execute((u64)memory, 5 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load8u_gpr64_gpr64_gpr64_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b6 84 1e fd ff ff ff"); - -// auto instr = IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s32(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 3 + 3, 0, 0)), 0xfe); -// EXPECT_EQ(s64(tester.execute((u64)memory, 2 + 3, 0, 0)), 0xfd); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), 0xff); -// EXPECT_EQ(s64(tester.execute((u64)memory, 5 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load16s_gpr64_goal_ptr_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64(RAX, RBX, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f bf 04 1e"); - -// tester.clear(); -// tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64(R12, RBX, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4c 0f bf 24 1e"); - -// tester.clear(); -// tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64(R12, R15, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4e 0f bf 24 3e"); - -// tester.clear(); -// tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64(R12, R15, R14)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4f 0f bf 24 3e"); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64(k, i, j)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s16 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 6, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 10, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load16s_gpr64_gpr64_plus_gpr64_plus_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f bf 44 1e fd"); - -// auto instr = IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s8(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u16 memory[8] = {0, 0, 0xfffd, 0xfffe, 0xffff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 6 + 3, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 10 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load16s_gpr64_gpr64_plus_gpr64_plus_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f bf 84 1e fd ff ff ff"); - -// auto instr = IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s32(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u16 memory[8] = {0, 0, 0xfffd, 0xfffe, 0xffff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 6 + 3, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 10 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load16u_gpr64_goal_ptr_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64(RAX, RBX, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b7 04 1e"); - -// tester.clear(); -// tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64(R12, RBX, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4c 0f b7 24 1e"); - -// tester.clear(); -// tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64(R12, R15, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4e 0f b7 24 3e"); - -// tester.clear(); -// tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64(R12, R15, R14)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4f 0f b7 24 3e"); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64(k, i, j)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s16 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 6, 0, 0)), 0xfffe); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4, 0, 0)), 0xfffd); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8, 0, 0)), 0xffff); -// EXPECT_EQ(s64(tester.execute((u64)memory, 10, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load16u_gpr64_gpr64_plus_gpr64_plus_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b7 44 1e fd"); - -// auto instr = IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s8(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u16 memory[8] = {0, 0, 0xfffd, 0xfffe, 0xffff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 6 + 3, 0, 0)), 0xfffe); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), 0xfffd); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), 0xffff); -// EXPECT_EQ(s64(tester.execute((u64)memory, 10 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load16u_gpr64_gpr64_plus_gpr64_plus_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b7 84 1e fd ff ff ff"); - -// auto instr = IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s32(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u16 memory[8] = {0, 0, 0xfffd, 0xfffe, 0xffff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 6 + 3, 0, 0)), 0xfffe); -// EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), 0xfffd); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), 0xffff); -// EXPECT_EQ(s64(tester.execute((u64)memory, 10 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load32s_gpr64_goal_ptr_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64(RAX, RBX, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 63 04 1e"); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64(k, i, j)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s32 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 12, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 16, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 20, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load32s_gpr64_gpr64_plus_gpr64_plus_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 63 44 1e fd"); - -// auto instr = IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s8(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u32 memory[8] = {0, 0, 0xfffffffd, 0xfffffffe, 0xffffffff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 12 + 3, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 20 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load32s_gpr64_gpr64_plus_gpr64_plus_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 63 84 1e fd ff ff ff"); - -// auto instr = IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s32(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u32 memory[8] = {0, 0, 0xfffffffd, 0xfffffffe, 0xffffffff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 12 + 3, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 20 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load32u_gpr64_goal_ptr_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64(RAX, RBX, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "8b 04 1e"); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64(k, i, j)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s32 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 12, 0, 0)), 0xfffffffe); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8, 0, 0)), 0xfffffffd); -// EXPECT_EQ(s64(tester.execute((u64)memory, 16, 0, 0)), 0xffffffff); -// EXPECT_EQ(s64(tester.execute((u64)memory, 20, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load32u_gpr64_gpr64_plus_gpr64_plus_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "8b 44 1e fd"); - -// auto instr = IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s8(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s32 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 12 + 3, 0, 0)), 0xfffffffe); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), 0xfffffffd); -// EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), 0xffffffff); -// EXPECT_EQ(s64(tester.execute((u64)memory, 20 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load32u_gpr64_gpr64_plus_gpr64_plus_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "8b 84 1e fd ff ff ff"); - -// auto instr = IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s32(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// u32 memory[8] = {0, 0, 0xfffffffd, 0xfffffffe, 0xffffffff, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 12 + 3, 0, 0)), 0xfffffffe); -// EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), 0xfffffffd); -// EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), 0xffffffff); -// EXPECT_EQ(s64(tester.execute((u64)memory, 20 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load64_gpr64_goal_ptr_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64(RAX, RBX, RSI)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 8b 04 1e"); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64(k, i, j)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s64 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 24, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 16, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 32, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 40, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load64_gpr64_gpr64_plus_gpr64_plus_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 8b 44 1e fd"); - -// auto instr = IGen::load64_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64_plus_s8(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s64 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 24 + 3, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 32 + 3, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 40 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load64_gpr64_gpr64_plus_gpr64_plus_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3)); - -// EXPECT_EQ(tester.dump_to_hex_string(), "48 8b 84 1e fd ff ff ff"); - -// auto instr = IGen::load64_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // fill k with junk -// if (k != i && k != j) { -// tester.emit(IGen::mov_gpr64_u64(k, (iter & 1) ? 0 : UINT64_MAX)); -// } - -// // load into k -// tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64_plus_s32(k, i, j, -3)); - -// // move k to return register -// tester.emit(IGen::mov_gpr64_gpr64(RAX, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s64 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; - -// // run! -// EXPECT_EQ(s64(tester.execute((u64)memory, 24 + 3, 0, 0)), -2); -// EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), -3); -// EXPECT_EQ(s64(tester.execute((u64)memory, 32 + 3, 0, 0)), -1); -// EXPECT_EQ(s64(tester.execute((u64)memory, 40 + 3, 0, 0)), 0); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store8_gpr64_gpr64_plus_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64(RAX, RCX, RDX)); -// EXPECT_EQ(tester.dump_to_hex_string(), "88 14 01"); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store! -// tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64(i, j, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s8 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 3, 0xffffffffffffff07, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], 7); -// EXPECT_EQ(memory[4], 1); -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store8_gpr64_gpr64_plus_gpr64_plus_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, RDX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "88 54 01 0c"); - -// auto instr = IGen::store8_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, RDX, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store -// tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64_plus_s8(i, j, k, -3)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s8 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 6, 0xffffffffffffff07, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], 7); -// EXPECT_EQ(memory[4], 1); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store8_gpr64_gpr64_plus_gpr64_plus_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, RDX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "88 94 01 0c 00 00 00"); - -// auto instr = IGen::store8_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, RDX, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store -// tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64_plus_s32(i, j, k, -3)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s8 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 6, 0xffffffffffffff07, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], 7); -// EXPECT_EQ(memory[4], 1); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store16_gpr64_gpr64_plus_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64(RCX, RAX, R8)); -// EXPECT_EQ(tester.dump_to_hex_string(), "66 44 89 04 08"); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store! -// tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64(i, j, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s16 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 6, 0xffffffffffffff07, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], s16(0xff07)); -// EXPECT_EQ(memory[4], 1); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store16_gpr64_gpr64_plus_gpr64_plus_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, R8, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "66 44 89 44 01 0c"); - -// auto instr = IGen::store16_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, RDX, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store -// tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64_plus_s8(i, j, k, -3)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s16 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 6 + 3, 0xffffffffffffff07, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], s16(0xff07)); -// EXPECT_EQ(memory[4], 1); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store16_gpr64_gpr64_plus_gpr64_plus_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, R8, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "66 44 89 84 01 0c 00 00 00"); - -// auto instr = IGen::store16_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, RDX, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store -// tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64_plus_s32(i, j, k, -3)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s16 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 6 + 3, 0xffffffffffffff07, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], s16(0xff07)); -// EXPECT_EQ(memory[4], 1); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store32_gpr64_gpr64_plus_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64(RCX, RAX, R8)); -// EXPECT_EQ(tester.dump_to_hex_string(), "44 89 04 08"); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store! -// tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64(i, j, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s32 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 12, 0xffffffff12341234, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], 0x12341234); -// EXPECT_EQ(memory[4], 1); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store32_gpr64_gpr64_plus_gpr64_plus_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, R8, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "44 89 44 01 0c"); - -// auto instr = IGen::store32_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, RDX, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store -// tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s8(i, j, k, -3)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s32 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 12 + 3, 0xffffffffffffff07, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], s32(0xffffff07)); -// EXPECT_EQ(memory[4], 1); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store32_gpr64_gpr64_plus_gpr64_plus_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, R8, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "44 89 84 01 0c 00 00 00"); - -// auto instr = IGen::store32_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, RDX, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store -// tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s32(i, j, k, -3)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s32 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 12 + 3, 0xffffffffffffff07, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], s32(0xffffff07)); -// EXPECT_EQ(memory[4], 1); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store64_gpr64_gpr64_plus_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64(RCX, RAX, R8)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4c 89 04 08"); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store! -// tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64(i, j, k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s64 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 24, 0xffffffff12341234, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], 0xffffffff12341234); -// EXPECT_EQ(memory[4], 1); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store64_gpr64_gpr64_plus_gpr64_plus_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, R8, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4c 89 44 01 0c"); - -// auto instr = IGen::store64_gpr64_gpr64_plus_gpr64_plus_s8(RAX, RCX, RDX, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store -// tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s8(i, j, k, -3)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s64 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 24 + 3, 0xffffffffffffff07, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], s64(0xffffffffffffff07)); -// EXPECT_EQ(memory[4], 1); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, store64_gpr64_gpr64_plus_gpr64_plus_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// tester.clear(); -// tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, R8, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "4c 89 84 01 0c 00 00 00"); - -// auto instr = IGen::store64_gpr64_gpr64_plus_gpr64_plus_s32(RAX, RCX, RDX, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); - -// [[maybe_unused]] int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// if (k == RSP || k == j || k == i) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 -// tester.emit(IGen::pop_gpr64(k)); // k will have the value to store. - -// // store -// tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s32(i, j, k, -3)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// // prepare the memory: -// s64 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 24 + 3, 0xffffffffffffff07, 0); -// EXPECT_EQ(memory[2], 3); -// EXPECT_EQ(memory[3], s64(0xffffffffffffff07)); -// EXPECT_EQ(memory[4], 1); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterLoadsAndStores, load64_rip) { -// CodeTester tester; -// tester.init_code_buffer(256); -// tester.emit(IGen::load64_rip_s32(RAX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 8b 05 0c 00 00 00"); - -// tester.clear(); -// for (int i = 0; i < 16; i++) { -// tester.emit(IGen::load64_rip_s32(i, 12)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "488B050C000000488B0D0C000000488B150C000000488B1D0C000000488B250C000000488B2D0C00000048" -// "8B350C000000488B3D0C0000004C8B050C0000004C8B0D0C0000004C8B150C0000004C8B1D0C0000004C8B" -// "250C0000004C8B2D0C0000004C8B350C0000004C8B3D0C000000"); -// } - -// TEST(EmitterLoadsAndStores, load32s_rip) { -// CodeTester tester; -// tester.init_code_buffer(256); -// tester.emit(IGen::load32s_rip_s32(RAX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 63 05 0c 00 00 00"); - -// tester.clear(); -// for (int i = 0; i < 16; i++) { -// tester.emit(IGen::load32s_rip_s32(i, 12)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "4863050C00000048630D0C0000004863150C00000048631D0C0000004863250C00000048632D0C00000048" -// "63350C00000048633D0C0000004C63050C0000004C630D0C0000004C63150C0000004C631D0C0000004C63" -// "250C0000004C632D0C0000004C63350C0000004C633D0C000000"); -// } - -// TEST(EmitterLoadsAndStores, load32u_rip) { -// CodeTester tester; -// tester.init_code_buffer(256); -// tester.emit(IGen::load32u_rip_s32(RAX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "8b 05 0c 00 00 00"); - -// tester.clear(); -// for (int i = 0; i < 16; i++) { -// tester.emit(IGen::load32u_rip_s32(i, 12)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "8B050C0000008B0D0C0000008B150C0000008B1D0C0000008B250C0000008B2D0C0000008B350C0000008B" -// "3D0C000000448B050C000000448B0D0C000000448B150C000000448B1D0C000000448B250C000000448B2D" -// "0C000000448B350C000000448B3D0C000000"); -// } - -// TEST(EmitterLoadsAndStores, load16u_rip) { -// CodeTester tester; -// tester.init_code_buffer(256); -// tester.emit(IGen::load16u_rip_s32(RAX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b7 05 0c 00 00 00"); - -// tester.clear(); -// for (int i = 0; i < 16; i++) { -// tester.emit(IGen::load16u_rip_s32(i, 12)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "480FB7050C000000480FB70D0C000000480FB7150C000000480FB71D0C000000480FB7250C000000480FB7" -// "2D0C000000480FB7350C000000480FB73D0C0000004C0FB7050C0000004C0FB70D0C0000004C0FB7150C00" -// "00004C0FB71D0C0000004C0FB7250C0000004C0FB72D0C0000004C0FB7350C0000004C0FB73D0C000000"); -// } - -// TEST(EmitterLoadsAndStores, load16s_rip) { -// CodeTester tester; -// tester.init_code_buffer(256); -// tester.emit(IGen::load16s_rip_s32(RAX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f bf 05 0c 00 00 00"); - -// tester.clear(); -// for (int i = 0; i < 16; i++) { -// tester.emit(IGen::load16s_rip_s32(i, 12)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "480FBF050C000000480FBF0D0C000000480FBF150C000000480FBF1D0C000000480FBF250C000000480FBF" -// "2D0C000000480FBF350C000000480FBF3D0C0000004C0FBF050C0000004C0FBF0D0C0000004C0FBF150C00" -// "00004C0FBF1D0C0000004C0FBF250C0000004C0FBF2D0C0000004C0FBF350C0000004C0FBF3D0C000000"); -// } - -// TEST(EmitterLoadsAndStores, load8s_rip) { -// CodeTester tester; -// tester.init_code_buffer(256); -// tester.emit(IGen::load8s_rip_s32(RAX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f be 05 0c 00 00 00"); - -// tester.clear(); -// for (int i = 0; i < 16; i++) { -// tester.emit(IGen::load8s_rip_s32(i, 12)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "480FBE050C000000480FBE0D0C000000480FBE150C000000480FBE1D0C000000480FBE250C000000480FBE" -// "2D0C000000480FBE350C000000480FBE3D0C0000004C0FBE050C0000004C0FBE0D0C0000004C0FBE150C00" -// "00004C0FBE1D0C0000004C0FBE250C0000004C0FBE2D0C0000004C0FBE350C0000004C0FBE3D0C000000"); -// } - -// TEST(EmitterLoadsAndStores, load8u_rip) { -// CodeTester tester; -// tester.init_code_buffer(256); -// tester.emit(IGen::load8u_rip_s32(RAX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b6 05 0c 00 00 00"); - -// tester.clear(); -// for (int i = 0; i < 16; i++) { -// tester.emit(IGen::load8u_rip_s32(i, 12)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "480FB6050C000000480FB60D0C000000480FB6150C000000480FB61D0C000000480FB6250C000000480FB6" -// "2D0C000000480FB6350C000000480FB63D0C0000004C0FB6050C0000004C0FB60D0C0000004C0FB6150C00" -// "00004C0FB61D0C0000004C0FB6250C0000004C0FB62D0C0000004C0FB6350C0000004C0FB63D0C000000"); -// } - -// TEST(EmitterLoadsAndStores, store64_rip_s32) { -// CodeTester tester; -// tester.init_code_buffer(256); -// tester.emit(IGen::store64_rip_s32(RAX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "48 89 05 0c 00 00 00"); - -// tester.clear(); -// for (int i = 0; i < 16; i++) { -// tester.emit(IGen::store64_rip_s32(i, 12)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "4889050C00000048890D0C0000004889150C00000048891D0C0000004889250C00000048892D0C00000048" -// "89350C00000048893D0C0000004C89050C0000004C890D0C0000004C89150C0000004C891D0C0000004C89" -// "250C0000004C892D0C0000004C89350C0000004C893D0C000000"); -// } - -// TEST(EmitterLoadsAndStores, store32_rip_s32) { -// CodeTester tester; -// tester.init_code_buffer(256); -// tester.emit(IGen::store32_rip_s32(RAX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "89 05 0c 00 00 00"); - -// tester.clear(); -// for (int i = 0; i < 16; i++) { -// tester.emit(IGen::store32_rip_s32(i, 12)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "89050C000000890D0C00000089150C000000891D0C00000089250C000000892D0C00000089350C00000089" -// "3D0C0000004489050C00000044890D0C0000004489150C00000044891D0C0000004489250C00000044892D" -// "0C0000004489350C00000044893D0C000000"); -// } - -// TEST(EmitterLoadsAndStores, store16_rip_s32) { -// CodeTester tester; -// tester.init_code_buffer(256); -// tester.emit(IGen::store16_rip_s32(RAX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "66 89 05 0c 00 00 00"); - -// tester.clear(); -// for (int i = 0; i < 16; i++) { -// tester.emit(IGen::store16_rip_s32(i, 12)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "6689050C00000066890D0C0000006689150C00000066891D0C0000006689250C00000066892D0C00000066" -// "89350C00000066893D0C000000664489050C0000006644890D0C000000664489150C0000006644891D0C00" -// "0000664489250C0000006644892D0C000000664489350C0000006644893D0C000000"); -// } - -// TEST(EmitterLoadsAndStores, store8_rip_s32) { -// CodeTester tester; -// tester.init_code_buffer(256); -// tester.emit(IGen::store8_rip_s32(RAX, 12)); -// EXPECT_EQ(tester.dump_to_hex_string(), "88 05 0c 00 00 00"); - -// tester.clear(); -// for (int i = 0; i < 16; i++) { -// tester.emit(IGen::store8_rip_s32(i, 12)); -// } - -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "88050C000000880D0C00000088150C000000881D0C0000004088250C00000040882D0C0000004088350C00" -// "000040883D0C0000004488050C00000044880D0C0000004488150C00000044881D0C0000004488250C0000" -// "0044882D0C0000004488350C00000044883D0C000000"); -// } - -// TEST(EmitterLoadsAndStores, static_addr) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// tester.clear(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(i, 12345)); // load test reg with junk -// int start_of_lea = tester.size(); -// auto lea_instr = IGen::static_addr(i, INT32_MAX); -// tester.emit(lea_instr); -// // patch instruction to lea the start of this code + 1. -// tester.write(-start_of_lea - lea_instr.length() + 1, -// start_of_lea + lea_instr.offset_of_disp()); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_return(); - -// auto result = tester.execute(); -// EXPECT_EQ(result, (u64)(tester.data()) + 1); -// } -// } - -// #ifdef __linux__ -// TEST(EmitterXmm32, load32_xmm32_gpr64_plus_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); -// tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64(XMM3, RAX, RBX)); -// EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 10 1c 03"); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } -// for (int k = 0; k < 16; k++) { -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // fill k with junk -// tester.emit(IGen::mov_gpr64_u64(i, (iter & 1) ? 0 : UINT64_MAX)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i)); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // load into k -// tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64(XMM0 + k, i, j)); -// // move to return -// tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); - -// // prepare the memory: -// float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; - -// // run! -// EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 3 * sizeof(float), 0, 0), 3.45f); -// EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 2 * sizeof(float), 0, 0), 1.23f); -// EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 4 * sizeof(float), 0, 0), 5.67f); -// EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 5 * sizeof(float), 0, 0), 0); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterXmm32, load32_xmm32_gpr64_plus_gpr64_plus_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); -// tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64_plus_s8(XMM3, RAX, RBX, -1)); -// EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 10 5c 03 ff"); - -// auto instr = IGen::load32_xmm32_gpr64_plus_gpr64_plus_s8(XMM3, RBX, RSI, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } -// for (int k = 0; k < 16; k++) { -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // fill k with junk -// tester.emit(IGen::mov_gpr64_u64(i, (iter & 1) ? 0 : UINT64_MAX)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i)); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// // load into k -// tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64_plus_s8(XMM0 + k, i, j, -3)); -// // move to return -// tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); - -// // prepare the memory: -// float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; - -// // run! -// EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 3 * sizeof(float) + 3, 0, -// 0), 3.45f); EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 2 * sizeof(float) + 3, -// 0, 0), 1.23f); EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 4 * sizeof(float) + -// 3, 0, 0), 5.67f); EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 5 * -// sizeof(float) + 3, 0, 0), 0); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterXmm32, load32_xmm32_gpr64_plus_gpr64_plus_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); -// tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64_plus_s32(XMM3, RAX, RBX, -1)); -// EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 10 9c 03 ff ff ff ff"); - -// auto instr = IGen::load32_xmm32_gpr64_plus_gpr64_plus_s32(XMM3, RBX, RSI, -1234); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -1234); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } -// for (int k = 0; k < 16; k++) { -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); - -// // fill k with junk -// tester.emit(IGen::mov_gpr64_u64(i, (iter & 1) ? 0 : UINT64_MAX)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i)); - -// // pop args into appropriate register -// tester.emit(IGen::pop_gpr64(i)); // i will have offset 0 -// tester.emit(IGen::pop_gpr64(j)); // j will have offset 1 - -// s64 offset = (iter & 1) ? INT32_MAX : INT32_MIN; - -// // load into k -// tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64_plus_s32(XMM0 + k, i, j, offset)); -// // move to return -// tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); - -// // prepare the memory: -// float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; - -// // run! -// EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 3 * sizeof(float) - offset, 0, 0), -// 3.45f); -// EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 2 * sizeof(float) - offset, 0, 0), -// 1.23f); -// EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 4 * sizeof(float) - offset, 0, 0), -// 5.67f); -// EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 5 * sizeof(float) - offset, 0, 0), -// 0); -// iter++; -// } -// } -// } -// } - -// namespace { -// template -// float as_float(T x) { -// float result; -// memcpy(&result, &x, sizeof(float)); -// return result; -// } - -// u32 as_u32(float x) { -// u32 result; -// memcpy(&result, &x, 4); -// return result; -// } -// } // namespace - -// TEST(EmitterXmm32, store32_xmm32_gpr64_plus_gpr64) { -// CodeTester tester; -// tester.init_code_buffer(512); -// tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64(RAX, RBX, XMM7)); -// EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 11 3c 03"); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } - -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } - -// for (int k = 0; k < 16; k++) { -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// // push args to the stack - -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); // addr2 -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); // addr1 -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); // value - -// // pop value into addr1 GPR -// tester.emit(IGen::pop_gpr64(i)); -// // move to XMM -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i)); - -// // pop addrs -// tester.emit(IGen::pop_gpr64(i)); -// tester.emit(IGen::pop_gpr64(j)); - -// // store -// tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64(i, j, XMM0 + k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); - -// // prepare the memory: -// float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 12, as_u32(1.234f), 0); -// EXPECT_FLOAT_EQ(memory[2], 1.23f); -// EXPECT_FLOAT_EQ(memory[3], 1.234f); -// EXPECT_FLOAT_EQ(memory[4], 5.67f); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterXmm32, store32_xmm32_gpr64_plus_gpr64_plus_s8) { -// CodeTester tester; -// tester.init_code_buffer(512); -// tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64_plus_s8(RAX, RBX, XMM3, -1)); -// EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 11 5c 03 ff"); - -// auto instr = IGen::store32_xmm32_gpr64_plus_gpr64_plus_s8(RBX, RSI, XMM3, -3); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } -// for (int k = 0; k < 16; k++) { -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); // addr2 -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); // addr1 -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); // value - -// // pop value into addr1 GPR -// tester.emit(IGen::pop_gpr64(i)); -// // move to XMM -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i)); - -// // pop addrs -// tester.emit(IGen::pop_gpr64(i)); -// tester.emit(IGen::pop_gpr64(j)); - -// s64 offset = (iter & 1) ? INT8_MAX : INT8_MIN; - -// // load into k -// tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64_plus_s8(i, j, XMM0 + k, offset)); - -// // move to return -// tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); - -// // prepare the memory: -// float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 12 - offset, as_u32(1.234f), 0); -// EXPECT_FLOAT_EQ(memory[2], 1.23f); -// EXPECT_FLOAT_EQ(memory[3], 1.234f); -// EXPECT_FLOAT_EQ(memory[4], 5.67f); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterXmm32, store32_xmm32_gpr64_plus_gpr64_plus_s32) { -// CodeTester tester; -// tester.init_code_buffer(512); -// tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64_plus_s32(RAX, RBX, XMM3, -1)); -// EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 11 9c 03 ff ff ff ff"); - -// auto instr = IGen::store32_xmm32_gpr64_plus_gpr64_plus_s32(RBX, RSI, XMM3, -1234); -// u8 buff[256]; -// instr.emit(buff); -// EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -1234); - -// int iter = 0; -// for (int i = 0; i < 16; i++) { -// if (i == RSP) { -// continue; -// } -// for (int j = 0; j < 16; j++) { -// if (j == RSP || j == i) { -// continue; -// } -// for (int k = 0; k < 16; k++) { -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// // push args to the stack -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(1))); // addr2 -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(0))); // addr1 -// tester.emit(IGen::push_gpr64(tester.get_c_abi_arg_reg(2))); // value - -// // pop value into addr1 GPR -// tester.emit(IGen::pop_gpr64(i)); -// // move to XMM -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + k, i)); - -// // pop addrs -// tester.emit(IGen::pop_gpr64(i)); -// tester.emit(IGen::pop_gpr64(j)); - -// s64 offset = (iter & 1) ? INT32_MAX : INT32_MIN; - -// // load into k -// tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64_plus_s32(i, j, XMM0 + k, offset)); - -// // move to return -// tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + k)); - -// // return! -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); - -// // prepare the memory: -// float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; - -// // run! -// tester.execute((u64)memory, 12 - offset, as_u32(1.234f), 0); -// EXPECT_FLOAT_EQ(memory[2], 1.23f); -// EXPECT_FLOAT_EQ(memory[3], 1.234f); -// EXPECT_FLOAT_EQ(memory[4], 5.67f); - -// iter++; -// } -// } -// } -// } - -// TEST(EmitterXmm32, static_load_xmm32) { -// CodeTester tester; -// tester.init_code_buffer(512); -// for (int i = 0; i < 16; i++) { -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); - -// auto loc_of_load = tester.size(); -// auto load_instr = IGen::static_load_xmm32(XMM0 + i, INT32_MAX); - -// tester.emit(load_instr); -// tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); -// auto loc_of_float = tester.emit_data(float(1.2345f)); - -// // patch offset -// tester.write(loc_of_float - loc_of_load - load_instr.length(), -// loc_of_load + load_instr.offset_of_disp()); - -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_FLOAT_EQ(result, 1.2345f); -// } -// } - -// TEST(EmitterXmm32, static_store_xmm32) { -// CodeTester tester; -// tester.init_code_buffer(512); -// for (int i = 0; i < 16; i++) { -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + i, tester.get_c_abi_arg_reg(0))); - -// auto loc_of_store = tester.size(); -// auto store_instr = IGen::static_store_xmm32(XMM0 + i, INT32_MAX); - -// tester.emit(store_instr); -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); -// auto loc_of_float = tester.emit_data(float(1.2345f)); - -// tester.write(loc_of_float - loc_of_store - store_instr.length(), -// loc_of_store + store_instr.offset_of_disp()); -// tester.execute(as_u32(-44.567f), 0, 0, 0); -// EXPECT_FLOAT_EQ(-44.567f, tester.read(loc_of_float)); -// } -// } - -// TEST(EmitterXmm32, ucomiss) { -// CodeTester tester; -// tester.init_code_buffer(512); -// tester.emit(IGen::cmp_flt_flt(XMM13, XMM14)); -// EXPECT_EQ("45 0f 2e ee", tester.dump_to_hex_string()); -// } - -// TEST(EmitterXmm32, mul) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// std::vector vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f}; - -// for (auto f : vals) { -// for (auto g : vals) { -// for (int i = 0; i < 16; i++) { -// for (int j = 0; j < 16; j++) { -// if (i == j) { -// continue; -// } -// auto expected = f * g; -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// u64 val = 0; -// memcpy(&val, &f, sizeof(float)); -// tester.emit(IGen::mov_gpr64_u64(RAX, val)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + i, RAX)); -// memcpy(&val, &g, sizeof(float)); -// tester.emit(IGen::mov_gpr64_u64(RAX, val)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + j, RAX)); -// tester.emit(IGen::mulss_xmm_xmm(XMM0 + j, XMM0 + i)); -// tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + j)); -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_FLOAT_EQ(result, expected); -// } -// } -// } -// } -// } - -// TEST(EmitterXmm32, div) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// std::vector vals = {1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f}; - -// for (auto f : vals) { -// for (auto g : vals) { -// for (int i = 0; i < 16; i++) { -// for (int j = 0; j < 16; j++) { -// if (i == j) { -// continue; -// } -// auto expected = g / f; -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// u64 val = 0; -// memcpy(&val, &f, sizeof(float)); -// tester.emit(IGen::mov_gpr64_u64(RAX, val)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + i, RAX)); -// memcpy(&val, &g, sizeof(float)); -// tester.emit(IGen::mov_gpr64_u64(RAX, val)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + j, RAX)); -// tester.emit(IGen::divss_xmm_xmm(XMM0 + j, XMM0 + i)); -// tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + j)); -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_FLOAT_EQ(result, expected); -// } -// } -// } -// } -// } - -// TEST(EmitterXmm32, add) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// std::vector vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f}; -// for (auto f : vals) { -// for (auto g : vals) { -// for (int i = 0; i < 16; i++) { -// for (int j = 0; j < 16; j++) { -// if (i == j) { -// continue; -// } -// auto expected = g + f; -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// u64 val = 0; -// memcpy(&val, &f, sizeof(float)); -// tester.emit(IGen::mov_gpr64_u64(RAX, val)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + i, RAX)); -// memcpy(&val, &g, sizeof(float)); -// tester.emit(IGen::mov_gpr64_u64(RAX, val)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + j, RAX)); -// tester.emit(IGen::addss_xmm_xmm(XMM0 + j, XMM0 + i)); -// tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + j)); -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_FLOAT_EQ(result, expected); -// } -// } -// } -// } -// } - -// TEST(EmitterXmm32, sub) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// std::vector vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f}; - -// for (auto f : vals) { -// for (auto g : vals) { -// for (int i = 0; i < 16; i++) { -// for (int j = 0; j < 16; j++) { -// if (i == j) { -// continue; -// } -// auto expected = g - f; -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// u64 val = 0; -// memcpy(&val, &f, sizeof(float)); -// tester.emit(IGen::mov_gpr64_u64(RAX, val)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + i, RAX)); -// memcpy(&val, &g, sizeof(float)); -// tester.emit(IGen::mov_gpr64_u64(RAX, val)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + j, RAX)); -// tester.emit(IGen::subss_xmm_xmm(XMM0 + j, XMM0 + i)); -// tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + j)); -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_FLOAT_EQ(result, expected); -// } -// } -// } -// } -// } - -// TEST(EmitterXmm32, float_to_int) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// std::vector vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, -// 7.545f, 0.1f, 0.9f, -0.1f, -0.9f}; - -// for (auto g : vals) { -// for (int i = 0; i < 16; i++) { -// for (int j = 0; j < 16; j++) { -// if (j == RSP) { -// continue; -// } -// s32 expected = g; -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// u64 val = 0; -// memcpy(&val, &g, sizeof(float)); -// tester.emit(IGen::mov_gpr64_u64(RAX, val)); -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + i, RAX)); -// tester.emit(IGen::float_to_int32(j, XMM0 + i)); -// tester.emit(IGen::mov_gpr64_gpr64(RAX, j)); -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } - -// TEST(EmitterXmm32, int_to_float) { -// CodeTester tester; -// tester.init_code_buffer(512); - -// std::vector vals = {0, 1, -1, INT32_MAX, -3457343, 7, INT32_MIN}; - -// for (auto g : vals) { -// for (int i = 0; i < 16; i++) { -// for (int j = 0; j < 16; j++) { -// if (j == RSP) { -// continue; -// } -// float expected = g; -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// tester.emit(IGen::mov_gpr64_u64(j, g)); -// tester.emit(IGen::int32_to_float(XMM0 + i, j)); -// tester.emit(IGen::movd_gpr32_xmm32(RAX, XMM0 + i)); -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); -// auto result = tester.execute_ret(0, 0, 0, 0); -// EXPECT_EQ(result, expected); -// } -// } -// } -// } - -// TEST(EmitterSlow, xmm32_move) { -// std::vector u32_constants = {0, INT32_MAX, UINT32_MAX, 17}; - -// // test moving between xmms (32-bit) and gprs. -// CodeTester tester; -// tester.init_code_buffer(512); - -// for (auto constant : u32_constants) { -// for (int r1 = 0; r1 < 16; r1++) { -// if (r1 == RSP) { -// continue; -// } -// for (int r2 = 0; r2 < 16; r2++) { -// if (r2 == RSP) { -// continue; -// } -// for (int r3 = 0; r3 < 16; r3++) { -// for (int r4 = 0; r4 < 16; r4++) { -// tester.clear(); -// tester.emit_push_all_xmms(); -// tester.emit_push_all_gprs(true); -// // move constant to gpr -// tester.emit(IGen::mov_gpr64_u32(r1, constant)); -// // move gpr to xmm -// tester.emit(IGen::movd_xmm32_gpr32(XMM0 + r3, r1)); -// // move xmm to xmm -// tester.emit(IGen::mov_xmm32_xmm32(XMM0 + r4, XMM0 + r3)); -// // move xmm to gpr -// tester.emit(IGen::movd_gpr32_xmm32(r2, XMM0 + r4)); -// // return! -// tester.emit(IGen::mov_gpr64_gpr64(RAX, r2)); -// tester.emit_pop_all_gprs(true); -// tester.emit_pop_all_xmms(); -// tester.emit_return(); -// } -// } -// } -// } -// } -// // todo - finish this test -// } -// #endif - -// TEST(Emitter, LEA) { -// CodeTester tester; -// tester.init_code_buffer(1024); -// tester.emit(IGen::lea_reg_plus_off(RDI, RSP, -3)); -// tester.emit(IGen::lea_reg_plus_off(RDI, R12, -3)); -// tester.emit(IGen::lea_reg_plus_off(R13, RSP, -3)); -// tester.emit(IGen::lea_reg_plus_off(R13, R12, -3)); -// tester.emit(IGen::lea_reg_plus_off(RDI, RSP, -300)); -// tester.emit(IGen::lea_reg_plus_off(RDI, R12, -300)); -// tester.emit(IGen::lea_reg_plus_off(R13, RSP, -300)); -// tester.emit(IGen::lea_reg_plus_off(R13, R12, -300)); -// EXPECT_EQ(tester.dump_to_hex_string(true), -// "488D7C24FD498D7C24FD4C8D6C24FD4D8D6C24FD488DBC24D4FEFFFF498DBC24D4FEFFFF4C8DAC24D4FEFF" -// "FF4D8DAC24D4FEFFFF"); -// } - -// TEST(EmitterXMM, StackLoad32) { -// CodeTester tester; -// tester.init_code_buffer(1024); -// tester.emit(IGen::load32_xmm32_gpr64_plus_s32(XMM0 + 3, RSP, -1234)); -// tester.emit(IGen::load32_xmm32_gpr64_plus_s32(XMM0 + 13, RSP, -1234)); -// EXPECT_EQ(tester.dump_to_hex_string(true), "F30F109C242EFBFFFFF3440F10AC242EFBFFFF"); -// } - -// TEST(EmitterXMM, StackLoad8) { -// CodeTester tester; -// tester.init_code_buffer(1024); -// tester.emit(IGen::load32_xmm32_gpr64_plus_s8(XMM0 + 3, RSP, -12)); -// tester.emit(IGen::load32_xmm32_gpr64_plus_s8(XMM0 + 13, RSP, -12)); -// EXPECT_EQ(tester.dump_to_hex_string(true), "F30F105C24F4F3440F106C24F4"); -// } - -// TEST(EmitterXMM, StackLoadFull32) { -// CodeTester tester; -// tester.init_code_buffer(1024); -// tester.emit(IGen::load128_simd128_gpr64_s32(XMM0 + 3, RSP, -1234)); -// tester.emit(IGen::load128_simd128_gpr64_s32(XMM0 + 13, RSP, -1234)); -// EXPECT_EQ(tester.dump_to_hex_string(true), "660F6F9C242EFBFFFF66440F6FAC242EFBFFFF"); -// } - -// TEST(EmitterXMM, StackLoadFull8) { -// CodeTester tester; -// tester.init_code_buffer(1024); -// tester.emit(IGen::load128_simd128_gpr64_s8(XMM0 + 3, RSP, -12)); -// tester.emit(IGen::load128_simd128_gpr64_s8(XMM0 + 13, RSP, -12)); -// EXPECT_EQ(tester.dump_to_hex_string(true), "660F6F5C24F466440F6F6C24F4"); -// } - -// TEST(EmitterXMM, StackStore32) { -// CodeTester tester; -// tester.init_code_buffer(1024); -// tester.emit(IGen::store32_xmm32_gpr64_plus_s32(RSP, XMM0 + 3, -1234)); -// tester.emit(IGen::store32_xmm32_gpr64_plus_s32(RSP, XMM0 + 13, -1234)); -// EXPECT_EQ(tester.dump_to_hex_string(true), "F30F119C242EFBFFFFF3440F11AC242EFBFFFF"); -// } - -// TEST(EmitterXMM, StackStore8) { -// CodeTester tester; -// tester.init_code_buffer(1024); -// tester.emit(IGen::store32_xmm32_gpr64_plus_s8(RSP, XMM0 + 3, -12)); -// tester.emit(IGen::store32_xmm32_gpr64_plus_s8(RSP, XMM0 + 13, -12)); -// EXPECT_EQ(tester.dump_to_hex_string(true), "F30F115C24F4F3440F116C24F4"); -// } - -// TEST(EmitterXMM, StackStoreFull32) { -// CodeTester tester; -// tester.init_code_buffer(1024); -// tester.emit(IGen::store128_gpr64_simd128_s32(RSP, XMM0 + 3, -1234)); -// tester.emit(IGen::store128_gpr64_simd128_s32(RSP, XMM0 + 13, -1234)); -// EXPECT_EQ(tester.dump_to_hex_string(true), "660F7F9C242EFBFFFF66440F7FAC242EFBFFFF"); -// } - -// TEST(EmitterXMM, StackStoreFull8) { -// CodeTester tester; -// tester.init_code_buffer(1024); -// tester.emit(IGen::store128_gpr64_simd128_s8(RSP, XMM0 + 3, -12)); -// tester.emit(IGen::store128_gpr64_simd128_s8(RSP, XMM0 + 13, -12)); -// EXPECT_EQ(tester.dump_to_hex_string(true), "660F7F5C24F466440F7F6C24F4"); -// } - -// TEST(EmitterXMM, SqrtS) { -// CodeTester tester; -// tester.init_code_buffer(1024); -// tester.emit(IGen::sqrts_xmm(XMM0 + 1, XMM0 + 2)); -// tester.emit(IGen::sqrts_xmm(XMM0 + 11, XMM0 + 2)); -// tester.emit(IGen::sqrts_xmm(XMM0 + 1, XMM0 + 12)); -// tester.emit(IGen::sqrts_xmm(XMM0 + 11, XMM0 + 12)); -// EXPECT_EQ(tester.dump_to_hex_string(true), "F30F51CAF3440F51DAF3410F51CCF3450F51DC"); -// } +#include "goalc/emitter/CodeTester.h" +#include "goalc/emitter/IGen.h" +#include "gtest/gtest.h" + +using namespace emitter; + +TEST(EmitterIntegerMath, add_gpr64_imm8s) { + CodeTester tester; + tester.init_code_buffer(256); + + std::vector vals = {0, 1, -1, INT32_MIN, INT32_MAX, INT64_MIN, INT64_MAX}; + std::vector imms = {0, 1, -1, INT8_MIN, INT8_MAX}; + + // test the ones that aren't rsp + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (auto val : vals) { + for (auto imm : imms) { + auto expected = val + imm; + + tester.clear(); + tester.emit_push_all_gprs(true); + + // move initial value to register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), i, tester.get_c_abi_arg_reg(0))); + // do the add + tester.emit(IGen::add_gpr64_imm8s(tester.generator(), i, imm)); + // move for return + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + auto result = tester.execute_ret(val, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } + + tester.clear(); + tester.emit(IGen::add_gpr64_imm8s(tester.generator(), RSP, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 83 c4 0c"); +} + +TEST(EmitterIntegerMath, add_gpr64_imm32s) { + CodeTester tester; + tester.init_code_buffer(256); + + std::vector vals = {0, 1, -1, INT32_MIN, INT32_MAX, INT64_MIN, INT64_MAX}; + std::vector imms = {0, 1, -1, INT8_MIN, INT8_MAX, INT32_MIN, INT32_MAX}; + + // test the ones that aren't rsp + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (auto val : vals) { + for (auto imm : imms) { + auto expected = val + imm; + + tester.clear(); + tester.emit_push_all_gprs(true); + + // move initial value to register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), i, tester.get_c_abi_arg_reg(0))); + // do the add + tester.emit(IGen::add_gpr64_imm32s(tester.generator(), i, imm)); + // move for return + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + auto result = tester.execute_ret(val, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } + + tester.clear(); + tester.emit(IGen::add_gpr64_imm32s(tester.generator(), RSP, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 81 c4 0c 00 00 00"); +} + +TEST(EmitterIntegerMath, sub_gpr64_imm8s) { + CodeTester tester; + tester.init_code_buffer(256); + + std::vector vals = {0, 1, -1, INT32_MIN, INT32_MAX, INT64_MIN, INT64_MAX}; + std::vector imms = {0, 1, -1, INT8_MIN, INT8_MAX}; + + // test the ones that aren't rsp + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (auto val : vals) { + for (auto imm : imms) { + auto expected = val - imm; + + tester.clear(); + tester.emit_push_all_gprs(true); + + // move initial value to register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), i, tester.get_c_abi_arg_reg(0))); + // do the add + tester.emit(IGen::sub_gpr64_imm8s(tester.generator(), i, imm)); + // move for return + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + auto result = tester.execute_ret(val, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } + + tester.clear(); + tester.emit(IGen::sub_gpr64_imm8s(tester.generator(), RSP, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 83 ec 0c"); +} + +TEST(EmitterIntegerMath, sub_gpr64_imm32s) { + CodeTester tester; + tester.init_code_buffer(256); + + std::vector vals = {0, 1, -1, INT32_MIN, INT32_MAX, INT64_MIN, INT64_MAX}; + std::vector imms = {0, 1, -1, INT8_MIN, INT8_MAX, INT32_MIN, INT32_MAX}; + + // test the ones that aren't rsp + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (auto val : vals) { + for (auto imm : imms) { + auto expected = val - imm; + + tester.clear(); + tester.emit_push_all_gprs(true); + + // move initial value to register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), i, tester.get_c_abi_arg_reg(0))); + // do the add + tester.emit(IGen::sub_gpr64_imm32s(tester.generator(), i, imm)); + // move for return + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + auto result = tester.execute_ret(val, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } + + tester.clear(); + tester.emit(IGen::sub_gpr64_imm32s(tester.generator(), RSP, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 81 ec 0c 00 00 00"); +} + +TEST(EmitterIntegerMath, add_gpr64_gpr64) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, + INT64_MAX, 117, 32, -348473, 83747382}; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + for (auto v1 : vals) { + for (auto v2 : vals) { + auto expected = v1 + v2; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v1)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), j, v2)); + tester.emit(IGen::add_gpr64_gpr64(tester.generator(), i, j)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } + } +} + +TEST(EmitterIntegerMath, sub_gpr64_gpr64) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, + INT64_MAX, 117, 32, -348473, 83747382}; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + for (auto v1 : vals) { + for (auto v2 : vals) { + auto expected = v1 - v2; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v1)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), j, v2)); + tester.emit(IGen::sub_gpr64_gpr64(tester.generator(), i, j)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } + } +} + +TEST(EmitterIntegerMath, mul_gpr32_gpr32) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = { + 0, 1, -2, -20, 123123, INT32_MIN, INT32_MAX, INT32_MIN + 1, INT32_MAX - 1}; + + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + for (auto v1 : vals) { + for (auto v2 : vals) { + // this is kind of weird behavior, but it's what the PS2 CPU does, I think. + // the lower 32-bits of the result are sign extended, even if this sign doesn't match + // the sign of the real product. This is true for both signed and unsigned multiply. + auto expected = ((s64(v1) * s64(v2)) << 32) >> 32; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, (s64)v1)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), j, (s64)v2)); + tester.emit(IGen::imul_gpr32_gpr32(tester.generator(), i, j)); + tester.emit(IGen::movsx_r64_r32(tester.generator(), RAX, i)); // weird PS2 sign extend. + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } + } +} + +TEST(EmitterIntegerMath, or_gpr64_gpr64) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, + INT64_MAX, 117, 32, -348473, 83747382}; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + for (auto v1 : vals) { + for (auto v2 : vals) { + auto expected = v1 | v2; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v1)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), j, v2)); + tester.emit(IGen::or_gpr64_gpr64(tester.generator(), i, j)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } + } +} + +TEST(EmitterIntegerMath, and_gpr64_gpr64) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, + INT64_MAX, 117, 32, -348473, 83747382}; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + for (auto v1 : vals) { + for (auto v2 : vals) { + auto expected = v1 & v2; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v1)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), j, v2)); + tester.emit(IGen::and_gpr64_gpr64(tester.generator(), i, j)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } + } +} + +TEST(EmitterIntegerMath, xor_gpr64_gpr64) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, + INT64_MAX, 117, 32, -348473, 83747382}; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + for (auto v1 : vals) { + for (auto v2 : vals) { + auto expected = v1 ^ v2; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v1)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), j, v2)); + tester.emit(IGen::xor_gpr64_gpr64(tester.generator(), i, j)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } + } +} + +TEST(EmitterIntegerMath, not_gpr64) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, + INT64_MAX, 117, 32, -348473, 83747382}; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (auto v1 : vals) { + auto expected = ~v1; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v1)); + tester.emit(IGen::not_gpr64(tester.generator(), i)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } +} + +TEST(EmitterIntegerMath, shl_gpr64_cl) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, + INT64_MAX, 117, 32, -348473, 83747382}; + std::vector sas = {0, 1, 23, 53, 64}; + + for (int i = 0; i < 16; i++) { + if (i == RSP || i == RCX) { + continue; + } + for (auto v : vals) { + for (auto sa : sas) { + auto expected = v << sa; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RCX, sa)); + tester.emit(IGen::shl_gpr64_reg(tester.generator(), i, 0)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } +} + +TEST(EmitterIntegerMath, shr_gpr64_cl) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, u64(-2), u64(INT32_MIN), INT32_MAX, u64(INT64_MIN), + INT64_MAX, 117, 32, u64(-348473), 83747382}; + std::vector sas = {0, 1, 23, 53, 64}; + + for (int i = 0; i < 16; i++) { + if (i == RSP || i == RCX) { + continue; + } + for (auto v : vals) { + for (auto sa : sas) { + auto expected = v >> sa; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RCX, sa)); + tester.emit(IGen::shr_gpr64_reg(tester.generator(), i, 0)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } +} + +TEST(EmitterIntegerMath, sar_gpr64_cl) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, + INT64_MAX, 117, 32, -348473, 83747382}; + std::vector sas = {0, 1, 23, 53, 64}; + + for (int i = 0; i < 16; i++) { + if (i == RSP || i == RCX) { + continue; + } + for (auto v : vals) { + for (auto sa : sas) { + auto expected = v >> sa; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RCX, sa)); + tester.emit(IGen::sar_gpr64_reg(tester.generator(), i, 0)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } +} + +TEST(EmitterIntegerMath, shl_gpr64_u8) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, + INT64_MAX, 117, 32, -348473, 83747382}; + std::vector sas = {0, 1, 23, 53, 64}; + + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (auto v : vals) { + for (auto sa : sas) { + auto expected = v << sa; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v)); + tester.emit(IGen::shl_gpr64_u8(tester.generator(), i, sa)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } +} + +TEST(EmitterIntegerMath, shr_gpr64_u8) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, u64(-2), u64(INT32_MIN), INT32_MAX, u64(INT64_MIN), + INT64_MAX, 117, 32, u64(-348473), 83747382}; + std::vector sas = {0, 1, 23, 53, 64}; + + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (auto v : vals) { + for (auto sa : sas) { + auto expected = v >> sa; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v)); + tester.emit(IGen::shr_gpr64_u8(tester.generator(), i, sa)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } +} + +TEST(EmitterIntegerMath, sar_gpr64_u8) { + CodeTester tester; + tester.init_code_buffer(256); + std::vector vals = {0, 1, -2, INT32_MIN, INT32_MAX, INT64_MIN, + INT64_MAX, 117, 32, -348473, 83747382}; + std::vector sas = {0, 1, 23, 53, 64}; + + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (auto v : vals) { + for (auto sa : sas) { + auto expected = v >> sa; + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, v)); + tester.emit(IGen::sar_gpr64_u8(tester.generator(), i, sa)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } +} + +TEST(EmitterIntegerMath, jumps) { + CodeTester tester; + tester.init_code_buffer(256); + + std::vector reads; + + auto x = IGen::jmp_imm(tester.generator()); + reads.push_back(tester.size() + x.offset_of_imm()); + tester.emit(x); + + x = IGen::je_imm(tester.generator()); + reads.push_back(tester.size() + x.offset_of_imm()); + tester.emit(x); + + x = IGen::jne_imm(tester.generator()); + reads.push_back(tester.size() + x.offset_of_imm()); + tester.emit(x); + + x = IGen::jle_imm(tester.generator()); + reads.push_back(tester.size() + x.offset_of_imm()); + tester.emit(x); + + x = IGen::jge_imm(tester.generator()); + reads.push_back(tester.size() + x.offset_of_imm()); + tester.emit(x); + + x = IGen::jl_imm(tester.generator()); + reads.push_back(tester.size() + x.offset_of_imm()); + tester.emit(x); + + x = IGen::jg_imm(tester.generator()); + reads.push_back(tester.size() + x.offset_of_imm()); + tester.emit(x); + + x = IGen::jbe_imm(tester.generator()); + reads.push_back(tester.size() + x.offset_of_imm()); + tester.emit(x); + + x = IGen::jae_imm(tester.generator()); + reads.push_back(tester.size() + x.offset_of_imm()); + tester.emit(x); + + x = IGen::jb_imm(tester.generator()); + reads.push_back(tester.size() + x.offset_of_imm()); + tester.emit(x); + + x = IGen::ja_imm(tester.generator()); + reads.push_back(tester.size() + x.offset_of_imm()); + tester.emit(x); + + for (auto off : reads) { + EXPECT_EQ(0, tester.read(off)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "E9000000000F84000000000F85000000000F8E000000000F8D000000000F8C000000000F8F000000000F86" + "000000000F83000000000F82000000000F8700000000"); +} + +TEST(EmitterIntegerMath, null) { + CodeTester tester; + auto instr = IGen::null(tester.generator()); + EXPECT_EQ(0, instr.emit(nullptr)); +} + +TEST(EmitterLoadsAndStores, load_constant_64_and_move_gpr_gpr_64) { + std::vector u64_constants = {0, UINT64_MAX, INT64_MAX, 7, 12}; + + // test we can load a 64-bit constant into all gprs, move it to any other gpr, and return it. + // rsp is skipping because that's the stack pointer and would prevent us from popping gprs after + + CodeTester tester; + tester.init_code_buffer(256); + + for (auto constant : u64_constants) { + for (int r1 = 0; r1 < 16; r1++) { + if (r1 == RSP) { + continue; + } + + for (int r2 = 0; r2 < 16; r2++) { + if (r2 == RSP) { + continue; + } + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), r1, constant)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), r2, r1)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, r2)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + EXPECT_EQ(tester.execute(), constant); + } + } + } +} + +TEST(EmitterLoadsAndStores, load_constant_32_unsigned) { + std::vector u64_constants = {0, UINT32_MAX, INT32_MAX, 7, 12}; + + // test loading 32-bit constants, with all upper 32-bits zero. + // this uses a different opcode than 64-bit loads. + CodeTester tester; + tester.init_code_buffer(256); + + for (auto constant : u64_constants) { + for (int r1 = 0; r1 < 16; r1++) { + if (r1 == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), r1, UINT64_MAX)); + tester.emit(IGen::mov_gpr64_u32(tester.generator(), r1, constant)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, r1)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + EXPECT_EQ(tester.execute(), constant); + } + } +} + +TEST(EmitterLoadsAndStores, load_constant_32_signed) { + std::vector s32_constants = {0, 1, INT32_MAX, INT32_MIN, 12, -1}; + + // test loading signed 32-bit constants. for values < 0 this will sign extend. + CodeTester tester; + tester.init_code_buffer(256); + + for (auto constant : s32_constants) { + for (int r1 = 0; r1 < 16; r1++) { + if (r1 == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_s32(tester.generator(), r1, constant)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, r1)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + EXPECT_EQ(tester.execute(), constant); + } + } +} + +TEST(EmitterLoadsAndStores, load8s_gpr64_goal_ptr_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(tester.generator(), RAX, RBX, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f be 04 1e"); + + tester.clear(); + tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(tester.generator(), R12, RBX, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "4c 0f be 24 1e"); + + tester.clear(); + tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(tester.generator(), R12, R15, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "4e 0f be 24 3e"); + + tester.clear(); + tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(tester.generator(), R12, R15, R14)); + EXPECT_EQ(tester.dump_to_hex_string(), "4f 0f be 24 3e"); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(tester.generator(), k, i, j)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 3, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 2, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 4, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 5, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load8s_gpr64_gpr64_gpr64_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f be 44 1e fd"); + + auto instr = IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 3 + 3, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 2 + 3, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 5 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load8s_gpr64_gpr64_gpr64_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f be 84 1e fd ff ff ff"); + + auto instr = IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 3 + 3, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 2 + 3, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 5 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load8u_gpr64_goal_ptr_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64(tester.generator(), RAX, RBX, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b6 04 1e"); + + tester.clear(); + tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64(tester.generator(), R12, RBX, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "4c 0f b6 24 1e"); + + tester.clear(); + tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64(tester.generator(), R12, R15, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "4e 0f b6 24 3e"); + + tester.clear(); + tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64(tester.generator(), R12, R15, R14)); + EXPECT_EQ(tester.dump_to_hex_string(), "4f 0f b6 24 3e"); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load8s_gpr64_gpr64_plus_gpr64(tester.generator(), k, i, j)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 3, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 2, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 4, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 5, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load8u_gpr64_gpr64_gpr64_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b6 44 1e fd"); + + auto instr = IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 3 + 3, 0, 0)), 0xfe); + EXPECT_EQ(s64(tester.execute((u64)memory, 2 + 3, 0, 0)), 0xfd); + EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), 0xff); + EXPECT_EQ(s64(tester.execute((u64)memory, 5 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load8u_gpr64_gpr64_gpr64_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b6 84 1e fd ff ff ff"); + + auto instr = IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load8u_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u8 memory[8] = {0, 0, 0xfd, 0xfe, 0xff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 3 + 3, 0, 0)), 0xfe); + EXPECT_EQ(s64(tester.execute((u64)memory, 2 + 3, 0, 0)), 0xfd); + EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), 0xff); + EXPECT_EQ(s64(tester.execute((u64)memory, 5 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load16s_gpr64_goal_ptr_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64(tester.generator(), RAX, RBX, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f bf 04 1e"); + + tester.clear(); + tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64(tester.generator(), R12, RBX, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "4c 0f bf 24 1e"); + + tester.clear(); + tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64(tester.generator(), R12, R15, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "4e 0f bf 24 3e"); + + tester.clear(); + tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64(tester.generator(), R12, R15, R14)); + EXPECT_EQ(tester.dump_to_hex_string(), "4f 0f bf 24 3e"); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64(tester.generator(), k, i, j)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s16 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 6, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 4, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 8, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 10, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load16s_gpr64_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f bf 44 1e fd"); + + auto instr = IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u16 memory[8] = {0, 0, 0xfffd, 0xfffe, 0xffff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 6 + 3, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 10 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load16s_gpr64_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f bf 84 1e fd ff ff ff"); + + auto instr = IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load16s_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u16 memory[8] = {0, 0, 0xfffd, 0xfffe, 0xffff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 6 + 3, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 10 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load16u_gpr64_goal_ptr_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64(tester.generator(), RAX, RBX, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b7 04 1e"); + + tester.clear(); + tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64(tester.generator(), R12, RBX, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "4c 0f b7 24 1e"); + + tester.clear(); + tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64(tester.generator(), R12, R15, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "4e 0f b7 24 3e"); + + tester.clear(); + tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64(tester.generator(), R12, R15, R14)); + EXPECT_EQ(tester.dump_to_hex_string(), "4f 0f b7 24 3e"); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64(tester.generator(), k, i, j)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s16 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 6, 0, 0)), 0xfffe); + EXPECT_EQ(s64(tester.execute((u64)memory, 4, 0, 0)), 0xfffd); + EXPECT_EQ(s64(tester.execute((u64)memory, 8, 0, 0)), 0xffff); + EXPECT_EQ(s64(tester.execute((u64)memory, 10, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load16u_gpr64_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b7 44 1e fd"); + + auto instr = IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u16 memory[8] = {0, 0, 0xfffd, 0xfffe, 0xffff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 6 + 3, 0, 0)), 0xfffe); + EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), 0xfffd); + EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), 0xffff); + EXPECT_EQ(s64(tester.execute((u64)memory, 10 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load16u_gpr64_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b7 84 1e fd ff ff ff"); + + auto instr = IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load16u_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u16 memory[8] = {0, 0, 0xfffd, 0xfffe, 0xffff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 6 + 3, 0, 0)), 0xfffe); + EXPECT_EQ(s64(tester.execute((u64)memory, 4 + 3, 0, 0)), 0xfffd); + EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), 0xffff); + EXPECT_EQ(s64(tester.execute((u64)memory, 10 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load32s_gpr64_goal_ptr_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64(tester.generator(), RAX, RBX, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 63 04 1e"); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64(tester.generator(), k, i, j)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s32 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 12, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 8, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 16, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 20, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load32s_gpr64_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 63 44 1e fd"); + + auto instr = IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u32 memory[8] = {0, 0, 0xfffffffd, 0xfffffffe, 0xffffffff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 12 + 3, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 20 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load32s_gpr64_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 63 84 1e fd ff ff ff"); + + auto instr = IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load32s_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u32 memory[8] = {0, 0, 0xfffffffd, 0xfffffffe, 0xffffffff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 12 + 3, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 20 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load32u_gpr64_goal_ptr_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64(tester.generator(), RAX, RBX, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "8b 04 1e"); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64(tester.generator(), k, i, j)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s32 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 12, 0, 0)), 0xfffffffe); + EXPECT_EQ(s64(tester.execute((u64)memory, 8, 0, 0)), 0xfffffffd); + EXPECT_EQ(s64(tester.execute((u64)memory, 16, 0, 0)), 0xffffffff); + EXPECT_EQ(s64(tester.execute((u64)memory, 20, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load32u_gpr64_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "8b 44 1e fd"); + + auto instr = IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s32 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 12 + 3, 0, 0)), 0xfffffffe); + EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), 0xfffffffd); + EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), 0xffffffff); + EXPECT_EQ(s64(tester.execute((u64)memory, 20 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load32u_gpr64_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "8b 84 1e fd ff ff ff"); + + auto instr = IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load32u_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + u32 memory[8] = {0, 0, 0xfffffffd, 0xfffffffe, 0xffffffff, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 12 + 3, 0, 0)), 0xfffffffe); + EXPECT_EQ(s64(tester.execute((u64)memory, 8 + 3, 0, 0)), 0xfffffffd); + EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), 0xffffffff); + EXPECT_EQ(s64(tester.execute((u64)memory, 20 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load64_gpr64_goal_ptr_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64(tester.generator(), RAX, RBX, RSI)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 8b 04 1e"); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64(tester.generator(), k, i, j)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s64 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 24, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 16, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 32, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 40, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load64_gpr64_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 8b 44 1e fd"); + + auto instr = IGen::load64_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s64 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 24 + 3, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 32 + 3, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 40 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load64_gpr64_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3)); + + EXPECT_EQ(tester.dump_to_hex_string(), "48 8b 84 1e fd ff ff ff"); + + auto instr = IGen::load64_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // fill k with junk + if (k != i && k != j) { + tester.emit(IGen::mov_gpr64_u64(tester.generator(), k, (iter & 1) ? 0 : UINT64_MAX)); + } + + // load into k + tester.emit(IGen::load64_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), k, i, j, -3)); + + // move k to return register + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s64 memory[8] = {0, 0, -3, -2, -1, 0, 0, 0}; + + // run! + EXPECT_EQ(s64(tester.execute((u64)memory, 24 + 3, 0, 0)), -2); + EXPECT_EQ(s64(tester.execute((u64)memory, 16 + 3, 0, 0)), -3); + EXPECT_EQ(s64(tester.execute((u64)memory, 32 + 3, 0, 0)), -1); + EXPECT_EQ(s64(tester.execute((u64)memory, 40 + 3, 0, 0)), 0); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store8_gpr64_gpr64_plus_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64(tester.generator(), RAX, RCX, RDX)); + EXPECT_EQ(tester.dump_to_hex_string(), "88 14 01"); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store! + tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64(tester.generator(), i, j, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s8 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 3, 0xffffffffffffff07, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], 7); + EXPECT_EQ(memory[4], 1); + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store8_gpr64_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RCX, RDX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "88 54 01 0c"); + + auto instr = IGen::store8_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RCX, RDX, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store + tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s8 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 6, 0xffffffffffffff07, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], 7); + EXPECT_EQ(memory[4], 1); + + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store8_gpr64_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RCX, RDX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "88 94 01 0c 00 00 00"); + + auto instr = IGen::store8_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RCX, RDX, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -3); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store + tester.emit(IGen::store8_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s8 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 6, 0xffffffffffffff07, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], 7); + EXPECT_EQ(memory[4], 1); + + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store16_gpr64_gpr64_plus_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64(tester.generator(), RCX, RAX, R8)); + EXPECT_EQ(tester.dump_to_hex_string(), "66 44 89 04 08"); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store! + tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64(tester.generator(), i, j, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s16 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 6, 0xffffffffffffff07, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], s16(0xff07)); + EXPECT_EQ(memory[4], 1); + + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store16_gpr64_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RCX, R8, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "66 44 89 44 01 0c"); + + auto instr = IGen::store16_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RCX, RDX, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store + tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s16 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 6 + 3, 0xffffffffffffff07, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], s16(0xff07)); + EXPECT_EQ(memory[4], 1); + + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store16_gpr64_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RCX, R8, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "66 44 89 84 01 0c 00 00 00"); + + auto instr = IGen::store16_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RCX, RDX, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store + tester.emit(IGen::store16_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s16 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 6 + 3, 0xffffffffffffff07, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], s16(0xff07)); + EXPECT_EQ(memory[4], 1); + + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store32_gpr64_gpr64_plus_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64(tester.generator(), RCX, RAX, R8)); + EXPECT_EQ(tester.dump_to_hex_string(), "44 89 04 08"); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store! + tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64(tester.generator(), i, j, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s32 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 12, 0xffffffff12341234, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], 0x12341234); + EXPECT_EQ(memory[4], 1); + + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store32_gpr64_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RCX, R8, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "44 89 44 01 0c"); + + auto instr = IGen::store32_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RCX, RDX, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store + tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s32 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 12 + 3, 0xffffffffffffff07, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], s32(0xffffff07)); + EXPECT_EQ(memory[4], 1); + + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store32_gpr64_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RCX, R8, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "44 89 84 01 0c 00 00 00"); + + auto instr = IGen::store32_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RCX, RDX, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store + tester.emit(IGen::store32_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s32 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 12 + 3, 0xffffffffffffff07, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], s32(0xffffff07)); + EXPECT_EQ(memory[4], 1); + + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store64_gpr64_gpr64_plus_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64(tester.generator(), RCX, RAX, R8)); + EXPECT_EQ(tester.dump_to_hex_string(), "4c 89 04 08"); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store! + tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64(tester.generator(), i, j, k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s64 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 24, 0xffffffff12341234, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], 0xffffffff12341234); + EXPECT_EQ(memory[4], 1); + + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store64_gpr64_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RCX, R8, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "4c 89 44 01 0c"); + + auto instr = IGen::store64_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RCX, RDX, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store + tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s8(tester.generator(), i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s64 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 24 + 3, 0xffffffffffffff07, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], s64(0xffffffffffffff07)); + EXPECT_EQ(memory[4], 1); + + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, store64_gpr64_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + + tester.clear(); + tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RCX, R8, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "4c 89 84 01 0c 00 00 00"); + + auto instr = IGen::store64_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RCX, RDX, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s8*)(buff + instr.offset_of_disp()), -3); + + [[maybe_unused]] int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + if (k == RSP || k == j || k == i) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + tester.emit(IGen::pop_gpr64(tester.generator(), k)); // k will have the value to store. + + // store + tester.emit(IGen::store64_gpr64_gpr64_plus_gpr64_plus_s32(tester.generator(), i, j, k, -3)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + // prepare the memory: + s64 memory[8] = {0, 0, 3, -2, 1, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 24 + 3, 0xffffffffffffff07, 0); + EXPECT_EQ(memory[2], 3); + EXPECT_EQ(memory[3], s64(0xffffffffffffff07)); + EXPECT_EQ(memory[4], 1); + + iter++; + } + } + } +} + +TEST(EmitterLoadsAndStores, load64_rip) { + CodeTester tester; + tester.init_code_buffer(256); + tester.emit(IGen::load64_rip_s32(tester.generator(), RAX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 8b 05 0c 00 00 00"); + + tester.clear(); + for (int i = 0; i < 16; i++) { + tester.emit(IGen::load64_rip_s32(tester.generator(), i, 12)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "488B050C000000488B0D0C000000488B150C000000488B1D0C000000488B250C000000488B2D0C00000048" + "8B350C000000488B3D0C0000004C8B050C0000004C8B0D0C0000004C8B150C0000004C8B1D0C0000004C8B" + "250C0000004C8B2D0C0000004C8B350C0000004C8B3D0C000000"); +} + +TEST(EmitterLoadsAndStores, load32s_rip) { + CodeTester tester; + tester.init_code_buffer(256); + tester.emit(IGen::load32s_rip_s32(tester.generator(), RAX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 63 05 0c 00 00 00"); + + tester.clear(); + for (int i = 0; i < 16; i++) { + tester.emit(IGen::load32s_rip_s32(tester.generator(), i, 12)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "4863050C00000048630D0C0000004863150C00000048631D0C0000004863250C00000048632D0C00000048" + "63350C00000048633D0C0000004C63050C0000004C630D0C0000004C63150C0000004C631D0C0000004C63" + "250C0000004C632D0C0000004C63350C0000004C633D0C000000"); +} + +TEST(EmitterLoadsAndStores, load32u_rip) { + CodeTester tester; + tester.init_code_buffer(256); + tester.emit(IGen::load32u_rip_s32(tester.generator(), RAX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "8b 05 0c 00 00 00"); + + tester.clear(); + for (int i = 0; i < 16; i++) { + tester.emit(IGen::load32u_rip_s32(tester.generator(), i, 12)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "8B050C0000008B0D0C0000008B150C0000008B1D0C0000008B250C0000008B2D0C0000008B350C0000008B" + "3D0C000000448B050C000000448B0D0C000000448B150C000000448B1D0C000000448B250C000000448B2D" + "0C000000448B350C000000448B3D0C000000"); +} + +TEST(EmitterLoadsAndStores, load16u_rip) { + CodeTester tester; + tester.init_code_buffer(256); + tester.emit(IGen::load16u_rip_s32(tester.generator(), RAX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b7 05 0c 00 00 00"); + + tester.clear(); + for (int i = 0; i < 16; i++) { + tester.emit(IGen::load16u_rip_s32(tester.generator(), i, 12)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "480FB7050C000000480FB70D0C000000480FB7150C000000480FB71D0C000000480FB7250C000000480FB7" + "2D0C000000480FB7350C000000480FB73D0C0000004C0FB7050C0000004C0FB70D0C0000004C0FB7150C00" + "00004C0FB71D0C0000004C0FB7250C0000004C0FB72D0C0000004C0FB7350C0000004C0FB73D0C000000"); +} + +TEST(EmitterLoadsAndStores, load16s_rip) { + CodeTester tester; + tester.init_code_buffer(256); + tester.emit(IGen::load16s_rip_s32(tester.generator(), RAX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f bf 05 0c 00 00 00"); + + tester.clear(); + for (int i = 0; i < 16; i++) { + tester.emit(IGen::load16s_rip_s32(tester.generator(), i, 12)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "480FBF050C000000480FBF0D0C000000480FBF150C000000480FBF1D0C000000480FBF250C000000480FBF" + "2D0C000000480FBF350C000000480FBF3D0C0000004C0FBF050C0000004C0FBF0D0C0000004C0FBF150C00" + "00004C0FBF1D0C0000004C0FBF250C0000004C0FBF2D0C0000004C0FBF350C0000004C0FBF3D0C000000"); +} + +TEST(EmitterLoadsAndStores, load8s_rip) { + CodeTester tester; + tester.init_code_buffer(256); + tester.emit(IGen::load8s_rip_s32(tester.generator(), RAX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f be 05 0c 00 00 00"); + + tester.clear(); + for (int i = 0; i < 16; i++) { + tester.emit(IGen::load8s_rip_s32(tester.generator(), i, 12)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "480FBE050C000000480FBE0D0C000000480FBE150C000000480FBE1D0C000000480FBE250C000000480FBE" + "2D0C000000480FBE350C000000480FBE3D0C0000004C0FBE050C0000004C0FBE0D0C0000004C0FBE150C00" + "00004C0FBE1D0C0000004C0FBE250C0000004C0FBE2D0C0000004C0FBE350C0000004C0FBE3D0C000000"); +} + +TEST(EmitterLoadsAndStores, load8u_rip) { + CodeTester tester; + tester.init_code_buffer(256); + tester.emit(IGen::load8u_rip_s32(tester.generator(), RAX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 0f b6 05 0c 00 00 00"); + + tester.clear(); + for (int i = 0; i < 16; i++) { + tester.emit(IGen::load8u_rip_s32(tester.generator(), i, 12)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "480FB6050C000000480FB60D0C000000480FB6150C000000480FB61D0C000000480FB6250C000000480FB6" + "2D0C000000480FB6350C000000480FB63D0C0000004C0FB6050C0000004C0FB60D0C0000004C0FB6150C00" + "00004C0FB61D0C0000004C0FB6250C0000004C0FB62D0C0000004C0FB6350C0000004C0FB63D0C000000"); +} + +TEST(EmitterLoadsAndStores, store64_rip_s32) { + CodeTester tester; + tester.init_code_buffer(256); + tester.emit(IGen::store64_rip_s32(tester.generator(), RAX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "48 89 05 0c 00 00 00"); + + tester.clear(); + for (int i = 0; i < 16; i++) { + tester.emit(IGen::store64_rip_s32(tester.generator(), i, 12)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "4889050C00000048890D0C0000004889150C00000048891D0C0000004889250C00000048892D0C00000048" + "89350C00000048893D0C0000004C89050C0000004C890D0C0000004C89150C0000004C891D0C0000004C89" + "250C0000004C892D0C0000004C89350C0000004C893D0C000000"); +} + +TEST(EmitterLoadsAndStores, store32_rip_s32) { + CodeTester tester; + tester.init_code_buffer(256); + tester.emit(IGen::store32_rip_s32(tester.generator(), RAX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "89 05 0c 00 00 00"); + + tester.clear(); + for (int i = 0; i < 16; i++) { + tester.emit(IGen::store32_rip_s32(tester.generator(), i, 12)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "89050C000000890D0C00000089150C000000891D0C00000089250C000000892D0C00000089350C00000089" + "3D0C0000004489050C00000044890D0C0000004489150C00000044891D0C0000004489250C00000044892D" + "0C0000004489350C00000044893D0C000000"); +} + +TEST(EmitterLoadsAndStores, store16_rip_s32) { + CodeTester tester; + tester.init_code_buffer(256); + tester.emit(IGen::store16_rip_s32(tester.generator(), RAX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "66 89 05 0c 00 00 00"); + + tester.clear(); + for (int i = 0; i < 16; i++) { + tester.emit(IGen::store16_rip_s32(tester.generator(), i, 12)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "6689050C00000066890D0C0000006689150C00000066891D0C0000006689250C00000066892D0C00000066" + "89350C00000066893D0C000000664489050C0000006644890D0C000000664489150C0000006644891D0C00" + "0000664489250C0000006644892D0C000000664489350C0000006644893D0C000000"); +} + +TEST(EmitterLoadsAndStores, store8_rip_s32) { + CodeTester tester; + tester.init_code_buffer(256); + tester.emit(IGen::store8_rip_s32(tester.generator(), RAX, 12)); + EXPECT_EQ(tester.dump_to_hex_string(), "88 05 0c 00 00 00"); + + tester.clear(); + for (int i = 0; i < 16; i++) { + tester.emit(IGen::store8_rip_s32(tester.generator(), i, 12)); + } + + EXPECT_EQ(tester.dump_to_hex_string(true), + "88050C000000880D0C00000088150C000000881D0C0000004088250C00000040882D0C0000004088350C00" + "000040883D0C0000004488050C00000044880D0C0000004488150C00000044881D0C0000004488250C0000" + "0044882D0C0000004488350C00000044883D0C000000"); +} + +TEST(EmitterLoadsAndStores, static_addr) { + CodeTester tester; + tester.init_code_buffer(512); + + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + tester.clear(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, 12345)); // load test reg with junk + int start_of_lea = tester.size(); + auto lea_instr = IGen::static_addr(tester.generator(), i, INT32_MAX); + tester.emit(lea_instr); + // patch instruction to lea the start of this code + 1. + tester.write(-start_of_lea - lea_instr.length() + 1, + start_of_lea + lea_instr.offset_of_disp()); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, i)); + tester.emit_pop_all_gprs(true); + tester.emit_return(); + + auto result = tester.execute(); + EXPECT_EQ(result, (u64)(tester.data()) + 1); + } +} + +#ifdef __linux__ +TEST(EmitterXmm32, load32_xmm32_gpr64_plus_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64(tester.generator(), XMM3, RAX, RBX)); + EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 10 1c 03"); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + for (int k = 0; k < 16; k++) { + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // fill k with junk + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, (iter & 1) ? 0 : UINT64_MAX)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + k, i)); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // load into k + tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64(tester.generator(), XMM0 + k, i, j)); + // move to return + tester.emit(IGen::movd_gpr32_f32(tester.generator(), RAX, XMM0 + k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + + // prepare the memory: + float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; + + // run! + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 3 * sizeof(float), 0, 0), 3.45f); + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 2 * sizeof(float), 0, 0), 1.23f); + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 4 * sizeof(float), 0, 0), 5.67f); + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 5 * sizeof(float), 0, 0), 0); + + iter++; + } + } + } +} + +TEST(EmitterXmm32, load32_xmm32_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64_plus_s8(tester.generator(), XMM3, RAX, RBX, -1)); + EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 10 5c 03 ff"); + + auto instr = IGen::load32_xmm32_gpr64_plus_gpr64_plus_s8(tester.generator(), XMM3, RBX, RSI, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + for (int k = 0; k < 16; k++) { + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // fill k with junk + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, (iter & 1) ? 0 : UINT64_MAX)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + k, i)); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + // load into k + tester.emit( + IGen::load32_xmm32_gpr64_plus_gpr64_plus_s8(tester.generator(), XMM0 + k, i, j, -3)); + // move to return + tester.emit(IGen::movd_gpr32_f32(tester.generator(), RAX, XMM0 + k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + + // prepare the memory: + float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; + + // run! + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 3 * sizeof(float) + 3, 0, 0), 3.45f); + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 2 * sizeof(float) + 3, 0, 0), 1.23f); + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 4 * sizeof(float) + 3, 0, 0), 5.67f); + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 5 * sizeof(float) + 3, 0, 0), 0); + + iter++; + } + } + } +} + +TEST(EmitterXmm32, load32_xmm32_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64_plus_s32(tester.generator(), XMM3, RAX, RBX, -1)); + EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 10 9c 03 ff ff ff ff"); + + auto instr = + IGen::load32_xmm32_gpr64_plus_gpr64_plus_s32(tester.generator(), XMM3, RBX, RSI, -1234); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -1234); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + for (int k = 0; k < 16; k++) { + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); + + // fill k with junk + tester.emit(IGen::mov_gpr64_u64(tester.generator(), i, (iter & 1) ? 0 : UINT64_MAX)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + k, i)); + + // pop args into appropriate register + tester.emit(IGen::pop_gpr64(tester.generator(), i)); // i will have offset 0 + tester.emit(IGen::pop_gpr64(tester.generator(), j)); // j will have offset 1 + + s64 offset = (iter & 1) ? INT32_MAX : INT32_MIN; + + // load into k + tester.emit(IGen::load32_xmm32_gpr64_plus_gpr64_plus_s32(tester.generator(), XMM0 + k, i, j, + offset)); + // move to return + tester.emit(IGen::movd_gpr32_f32(tester.generator(), RAX, XMM0 + k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + + // prepare the memory: + float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; + + // run! + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 3 * sizeof(float) - offset, 0, 0), + 3.45f); + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 2 * sizeof(float) - offset, 0, 0), + 1.23f); + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 4 * sizeof(float) - offset, 0, 0), + 5.67f); + EXPECT_FLOAT_EQ(tester.execute_ret((u64)memory, 5 * sizeof(float) - offset, 0, 0), + 0); + iter++; + } + } + } +} + +namespace { +template +float as_float(T x) { + float result; + memcpy(&result, &x, sizeof(float)); + return result; +} + +u32 as_u32(float x) { + u32 result; + memcpy(&result, &x, 4); + return result; +} +} // namespace + +TEST(EmitterXmm32, store32_xmm32_gpr64_plus_gpr64) { + CodeTester tester; + tester.init_code_buffer(512); + tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64(tester.generator(), RAX, RBX, XMM7)); + EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 11 3c 03"); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + + for (int k = 0; k < 16; k++) { + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + // push args to the stack + + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); // addr2 + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); // addr1 + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); // value + + // pop value into addr1 GPR + tester.emit(IGen::pop_gpr64(tester.generator(), i)); + // move to XMM + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + k, i)); + + // pop addrs + tester.emit(IGen::pop_gpr64(tester.generator(), i)); + tester.emit(IGen::pop_gpr64(tester.generator(), j)); + + // store + tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64(tester.generator(), i, j, XMM0 + k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + + // prepare the memory: + float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 12, as_u32(1.234f), 0); + EXPECT_FLOAT_EQ(memory[2], 1.23f); + EXPECT_FLOAT_EQ(memory[3], 1.234f); + EXPECT_FLOAT_EQ(memory[4], 5.67f); + + iter++; + } + } + } +} + +TEST(EmitterXmm32, store32_xmm32_gpr64_plus_gpr64_plus_s8) { + CodeTester tester; + tester.init_code_buffer(512); + tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64_plus_s8(tester.generator(), RAX, RBX, XMM3, -1)); + EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 11 5c 03 ff"); + + auto instr = IGen::store32_xmm32_gpr64_plus_gpr64_plus_s8(tester.generator(), RBX, RSI, XMM3, -3); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(s8(buff[instr.offset_of_disp()]), -3); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + for (int k = 0; k < 16; k++) { + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); // addr2 + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); // addr1 + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); // value + + // pop value into addr1 GPR + tester.emit(IGen::pop_gpr64(tester.generator(), i)); + // move to XMM + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + k, i)); + + // pop addrs + tester.emit(IGen::pop_gpr64(tester.generator(), i)); + tester.emit(IGen::pop_gpr64(tester.generator(), j)); + + s64 offset = (iter & 1) ? INT8_MAX : INT8_MIN; + + // load into k + tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64_plus_s8(tester.generator(), i, j, XMM0 + k, + offset)); + + // move to return + tester.emit(IGen::movd_gpr32_f32(tester.generator(), RAX, XMM0 + k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + + // prepare the memory: + float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 12 - offset, as_u32(1.234f), 0); + EXPECT_FLOAT_EQ(memory[2], 1.23f); + EXPECT_FLOAT_EQ(memory[3], 1.234f); + EXPECT_FLOAT_EQ(memory[4], 5.67f); + + iter++; + } + } + } +} + +TEST(EmitterXmm32, store32_xmm32_gpr64_plus_gpr64_plus_s32) { + CodeTester tester; + tester.init_code_buffer(512); + tester.emit( + IGen::store32_xmm32_gpr64_plus_gpr64_plus_s32(tester.generator(), RAX, RBX, XMM3, -1)); + EXPECT_EQ(tester.dump_to_hex_string(), "f3 0f 11 9c 03 ff ff ff ff"); + + auto instr = + IGen::store32_xmm32_gpr64_plus_gpr64_plus_s32(tester.generator(), RBX, RSI, XMM3, -1234); + u8 buff[256]; + instr.emit(buff); + EXPECT_EQ(*(s32*)(buff + instr.offset_of_disp()), -1234); + + int iter = 0; + for (int i = 0; i < 16; i++) { + if (i == RSP) { + continue; + } + for (int j = 0; j < 16; j++) { + if (j == RSP || j == i) { + continue; + } + for (int k = 0; k < 16; k++) { + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + // push args to the stack + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(1))); // addr2 + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(0))); // addr1 + tester.emit(IGen::push_gpr64(tester.generator(), tester.get_c_abi_arg_reg(2))); // value + + // pop value into addr1 GPR + tester.emit(IGen::pop_gpr64(tester.generator(), i)); + // move to XMM + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + k, i)); + + // pop addrs + tester.emit(IGen::pop_gpr64(tester.generator(), i)); + tester.emit(IGen::pop_gpr64(tester.generator(), j)); + + s64 offset = (iter & 1) ? INT32_MAX : INT32_MIN; + + // load into k + tester.emit(IGen::store32_xmm32_gpr64_plus_gpr64_plus_s32(tester.generator(), i, j, + XMM0 + k, offset)); + + // move to return + tester.emit(IGen::movd_gpr32_f32(tester.generator(), RAX, XMM0 + k)); + + // return! + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + + // prepare the memory: + float memory[8] = {0, 0, 1.23f, 3.45f, 5.67f, 0, 0, 0}; + + // run! + tester.execute((u64)memory, 12 - offset, as_u32(1.234f), 0); + EXPECT_FLOAT_EQ(memory[2], 1.23f); + EXPECT_FLOAT_EQ(memory[3], 1.234f); + EXPECT_FLOAT_EQ(memory[4], 5.67f); + + iter++; + } + } + } +} + +TEST(EmitterXmm32, static_load_xmm32) { + CodeTester tester; + tester.init_code_buffer(512); + for (int i = 0; i < 16; i++) { + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + + auto loc_of_load = tester.size(); + auto load_instr = IGen::static_load_f32(tester.generator(), XMM0 + i, INT32_MAX); + + tester.emit(load_instr); + tester.emit(IGen::movd_gpr32_f32(tester.generator(), RAX, XMM0 + i)); + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + auto loc_of_float = tester.emit_data(float(1.2345f)); + + // patch offset + tester.write(loc_of_float - loc_of_load - load_instr.length(), + loc_of_load + load_instr.offset_of_disp()); + + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_FLOAT_EQ(result, 1.2345f); + } +} + +TEST(EmitterXmm32, static_store_xmm32) { + CodeTester tester; + tester.init_code_buffer(512); + for (int i = 0; i < 16; i++) { + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + i, tester.get_c_abi_arg_reg(0))); + + auto loc_of_store = tester.size(); + auto store_instr = IGen::static_store_f32(tester.generator(), XMM0 + i, INT32_MAX); + + tester.emit(store_instr); + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + auto loc_of_float = tester.emit_data(float(1.2345f)); + + tester.write(loc_of_float - loc_of_store - store_instr.length(), + loc_of_store + store_instr.offset_of_disp()); + tester.execute(as_u32(-44.567f), 0, 0, 0); + EXPECT_FLOAT_EQ(-44.567f, tester.read(loc_of_float)); + } +} + +TEST(EmitterXmm32, ucomiss) { + CodeTester tester; + tester.init_code_buffer(512); + tester.emit(IGen::cmp_f32_f32(tester.generator(), XMM13, XMM14)); + EXPECT_EQ("45 0f 2e ee", tester.dump_to_hex_string()); +} + +TEST(EmitterXmm32, mul) { + CodeTester tester; + tester.init_code_buffer(512); + + std::vector vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f}; + + for (auto f : vals) { + for (auto g : vals) { + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + if (i == j) { + continue; + } + auto expected = f * g; + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + u64 val = 0; + memcpy(&val, &f, sizeof(float)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RAX, val)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + i, RAX)); + memcpy(&val, &g, sizeof(float)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RAX, val)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + j, RAX)); + tester.emit(IGen::mul_f32_f32(tester.generator(), XMM0 + j, XMM0 + i)); + tester.emit(IGen::movd_gpr32_f32(tester.generator(), RAX, XMM0 + j)); + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_FLOAT_EQ(result, expected); + } + } + } + } +} + +TEST(EmitterXmm32, div) { + CodeTester tester; + tester.init_code_buffer(512); + + std::vector vals = {1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f}; + + for (auto f : vals) { + for (auto g : vals) { + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + if (i == j) { + continue; + } + auto expected = g / f; + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + u64 val = 0; + memcpy(&val, &f, sizeof(float)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RAX, val)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + i, RAX)); + memcpy(&val, &g, sizeof(float)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RAX, val)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + j, RAX)); + tester.emit(IGen::div_f32_f32(tester.generator(), XMM0 + j, XMM0 + i)); + tester.emit(IGen::movd_gpr32_f32(tester.generator(), RAX, XMM0 + j)); + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_FLOAT_EQ(result, expected); + } + } + } + } +} + +TEST(EmitterXmm32, add) { + CodeTester tester; + tester.init_code_buffer(512); + + std::vector vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f}; + for (auto f : vals) { + for (auto g : vals) { + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + if (i == j) { + continue; + } + auto expected = g + f; + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + u64 val = 0; + memcpy(&val, &f, sizeof(float)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RAX, val)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + i, RAX)); + memcpy(&val, &g, sizeof(float)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RAX, val)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + j, RAX)); + tester.emit(IGen::add_f32_f32(tester.generator(), XMM0 + j, XMM0 + i)); + tester.emit(IGen::movd_gpr32_f32(tester.generator(), RAX, XMM0 + j)); + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_FLOAT_EQ(result, expected); + } + } + } + } +} + +TEST(EmitterXmm32, sub) { + CodeTester tester; + tester.init_code_buffer(512); + + std::vector vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, 7.545f}; + + for (auto f : vals) { + for (auto g : vals) { + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + if (i == j) { + continue; + } + auto expected = g - f; + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + u64 val = 0; + memcpy(&val, &f, sizeof(float)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RAX, val)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + i, RAX)); + memcpy(&val, &g, sizeof(float)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RAX, val)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + j, RAX)); + tester.emit(IGen::sub_f32_f32(tester.generator(), XMM0 + j, XMM0 + i)); + tester.emit(IGen::movd_gpr32_f32(tester.generator(), RAX, XMM0 + j)); + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_FLOAT_EQ(result, expected); + } + } + } + } +} + +TEST(EmitterXmm32, float_to_int) { + CodeTester tester; + tester.init_code_buffer(512); + + std::vector vals = {0.f, 1.f, 0.2f, -1.f, 1235423.2f, -3457343.3f, + 7.545f, 0.1f, 0.9f, -0.1f, -0.9f}; + + for (auto g : vals) { + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + if (j == RSP) { + continue; + } + s32 expected = g; + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + u64 val = 0; + memcpy(&val, &g, sizeof(float)); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), RAX, val)); + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + i, RAX)); + tester.emit(IGen::f32_to_int32(tester.generator(), j, XMM0 + i)); + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, j)); + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } +} + +TEST(EmitterXmm32, int_to_float) { + CodeTester tester; + tester.init_code_buffer(512); + + std::vector vals = {0, 1, -1, INT32_MAX, -3457343, 7, INT32_MIN}; + + for (auto g : vals) { + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + if (j == RSP) { + continue; + } + float expected = g; + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + tester.emit(IGen::mov_gpr64_u64(tester.generator(), j, g)); + tester.emit(IGen::int32_to_f32(tester.generator(), XMM0 + i, j)); + tester.emit(IGen::movd_gpr32_f32(tester.generator(), RAX, XMM0 + i)); + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + auto result = tester.execute_ret(0, 0, 0, 0); + EXPECT_EQ(result, expected); + } + } + } +} + +TEST(EmitterSlow, xmm32_move) { + std::vector u32_constants = {0, INT32_MAX, UINT32_MAX, 17}; + + // test moving between xmms (32-bit) and gprs. + CodeTester tester; + tester.init_code_buffer(512); + + for (auto constant : u32_constants) { + for (int r1 = 0; r1 < 16; r1++) { + if (r1 == RSP) { + continue; + } + for (int r2 = 0; r2 < 16; r2++) { + if (r2 == RSP) { + continue; + } + for (int r3 = 0; r3 < 16; r3++) { + for (int r4 = 0; r4 < 16; r4++) { + tester.clear(); + tester.emit_push_all_simd(); + tester.emit_push_all_gprs(true); + // move constant to gpr + tester.emit(IGen::mov_gpr64_u32(tester.generator(), r1, constant)); + // move gpr to xmm + tester.emit(IGen::movd_f32_gpr32(tester.generator(), XMM0 + r3, r1)); + // move xmm to xmm + tester.emit(IGen::mov_f32_f32(tester.generator(), XMM0 + r4, XMM0 + r3)); + // move xmm to gpr + tester.emit(IGen::movd_gpr32_f32(tester.generator(), r2, XMM0 + r4)); + // return! + tester.emit(IGen::mov_gpr64_gpr64(tester.generator(), RAX, r2)); + tester.emit_pop_all_gprs(true); + tester.emit_pop_all_simd(); + tester.emit_return(); + } + } + } + } + } + // todo - finish this test +} +#endif + +TEST(Emitter, LEA) { + CodeTester tester; + tester.init_code_buffer(1024); + tester.emit(IGen::lea_reg_plus_off(tester.generator(), RDI, RSP, -3)); + tester.emit(IGen::lea_reg_plus_off(tester.generator(), RDI, R12, -3)); + tester.emit(IGen::lea_reg_plus_off(tester.generator(), R13, RSP, -3)); + tester.emit(IGen::lea_reg_plus_off(tester.generator(), R13, R12, -3)); + tester.emit(IGen::lea_reg_plus_off(tester.generator(), RDI, RSP, -300)); + tester.emit(IGen::lea_reg_plus_off(tester.generator(), RDI, R12, -300)); + tester.emit(IGen::lea_reg_plus_off(tester.generator(), R13, RSP, -300)); + tester.emit(IGen::lea_reg_plus_off(tester.generator(), R13, R12, -300)); + EXPECT_EQ(tester.dump_to_hex_string(true), + "488D7C24FD498D7C24FD4C8D6C24FD4D8D6C24FD488DBC24D4FEFFFF498DBC24D4FEFFFF4C8DAC24D4FEFF" + "FF4D8DAC24D4FEFFFF"); +} + +TEST(EmitterXMM, StackLoad32) { + CodeTester tester; + tester.init_code_buffer(1024); + tester.emit(IGen::load32_xmm32_gpr64_plus_s32(tester.generator(), XMM0 + 3, RSP, -1234)); + tester.emit(IGen::load32_xmm32_gpr64_plus_s32(tester.generator(), XMM0 + 13, RSP, -1234)); + EXPECT_EQ(tester.dump_to_hex_string(true), "F30F109C242EFBFFFFF3440F10AC242EFBFFFF"); +} + +TEST(EmitterXMM, StackLoad8) { + CodeTester tester; + tester.init_code_buffer(1024); + tester.emit(IGen::load32_xmm32_gpr64_plus_s8(tester.generator(), XMM0 + 3, RSP, -12)); + tester.emit(IGen::load32_xmm32_gpr64_plus_s8(tester.generator(), XMM0 + 13, RSP, -12)); + EXPECT_EQ(tester.dump_to_hex_string(true), "F30F105C24F4F3440F106C24F4"); +} + +TEST(EmitterXMM, StackLoadFull32) { + CodeTester tester; + tester.init_code_buffer(1024); + tester.emit(IGen::load128_simd128_gpr64_s32(tester.generator(), XMM0 + 3, RSP, -1234)); + tester.emit(IGen::load128_simd128_gpr64_s32(tester.generator(), XMM0 + 13, RSP, -1234)); + EXPECT_EQ(tester.dump_to_hex_string(true), "660F6F9C242EFBFFFF66440F6FAC242EFBFFFF"); +} + +TEST(EmitterXMM, StackLoadFull8) { + CodeTester tester; + tester.init_code_buffer(1024); + tester.emit(IGen::load128_simd128_gpr64_s8(tester.generator(), XMM0 + 3, RSP, -12)); + tester.emit(IGen::load128_simd128_gpr64_s8(tester.generator(), XMM0 + 13, RSP, -12)); + EXPECT_EQ(tester.dump_to_hex_string(true), "660F6F5C24F466440F6F6C24F4"); +} + +TEST(EmitterXMM, StackStore32) { + CodeTester tester; + tester.init_code_buffer(1024); + tester.emit(IGen::store32_xmm32_gpr64_plus_s32(tester.generator(), RSP, XMM0 + 3, -1234)); + tester.emit(IGen::store32_xmm32_gpr64_plus_s32(tester.generator(), RSP, XMM0 + 13, -1234)); + EXPECT_EQ(tester.dump_to_hex_string(true), "F30F119C242EFBFFFFF3440F11AC242EFBFFFF"); +} + +TEST(EmitterXMM, StackStore8) { + CodeTester tester; + tester.init_code_buffer(1024); + tester.emit(IGen::store32_xmm32_gpr64_plus_s8(tester.generator(), RSP, XMM0 + 3, -12)); + tester.emit(IGen::store32_xmm32_gpr64_plus_s8(tester.generator(), RSP, XMM0 + 13, -12)); + EXPECT_EQ(tester.dump_to_hex_string(true), "F30F115C24F4F3440F116C24F4"); +} + +TEST(EmitterXMM, StackStoreFull32) { + CodeTester tester; + tester.init_code_buffer(1024); + tester.emit(IGen::store128_gpr64_simd128_s32(tester.generator(), RSP, XMM0 + 3, -1234)); + tester.emit(IGen::store128_gpr64_simd128_s32(tester.generator(), RSP, XMM0 + 13, -1234)); + EXPECT_EQ(tester.dump_to_hex_string(true), "660F7F9C242EFBFFFF66440F7FAC242EFBFFFF"); +} + +TEST(EmitterXMM, StackStoreFull8) { + CodeTester tester; + tester.init_code_buffer(1024); + tester.emit(IGen::store128_gpr64_simd128_s8(tester.generator(), RSP, XMM0 + 3, -12)); + tester.emit(IGen::store128_gpr64_simd128_s8(tester.generator(), RSP, XMM0 + 13, -12)); + EXPECT_EQ(tester.dump_to_hex_string(true), "660F7F5C24F466440F7F6C24F4"); +} + +TEST(EmitterXMM, SqrtS) { + CodeTester tester; + tester.init_code_buffer(1024); + tester.emit(IGen::sqrt_f32(tester.generator(), XMM0 + 1, XMM0 + 2)); + tester.emit(IGen::sqrt_f32(tester.generator(), XMM0 + 11, XMM0 + 2)); + tester.emit(IGen::sqrt_f32(tester.generator(), XMM0 + 1, XMM0 + 12)); + tester.emit(IGen::sqrt_f32(tester.generator(), XMM0 + 11, XMM0 + 12)); + EXPECT_EQ(tester.dump_to_hex_string(true), "F30F51CAF3440F51DAF3410F51CCF3450F51DC"); +} diff --git a/test/test_emitter_avx.cpp b/test/test_emitter_avx.cpp index 4558dc85e8..b98cfade6a 100644 --- a/test/test_emitter_avx.cpp +++ b/test/test_emitter_avx.cpp @@ -634,20 +634,20 @@ TEST(EmitterAVX, VPSHUFHW) { TEST(EmitterAVX, movq_to_gpr_from_xmm) { CodeTester tester; tester.init_code_buffer(1024); - tester.emit(IGen::movq_gpr64_xmm64(tester.generator(), RSP, XMM0 + 3)); - tester.emit(IGen::movq_gpr64_xmm64(tester.generator(), RSP, XMM0 + 13)); - tester.emit(IGen::movq_gpr64_xmm64(tester.generator(), R12, XMM0 + 3)); - tester.emit(IGen::movq_gpr64_xmm64(tester.generator(), R12, XMM0 + 13)); + tester.emit(IGen::movq_gpr64_f64(tester.generator(), RSP, XMM0 + 3)); + tester.emit(IGen::movq_gpr64_f64(tester.generator(), RSP, XMM0 + 13)); + tester.emit(IGen::movq_gpr64_f64(tester.generator(), R12, XMM0 + 3)); + tester.emit(IGen::movq_gpr64_f64(tester.generator(), R12, XMM0 + 13)); EXPECT_EQ(tester.dump_to_hex_string(true), "66480F7EDC664C0F7EEC66490F7EDC664D0F7EEC"); } TEST(EmitterAVX, movq_to_xmm_from_gpr) { CodeTester tester; tester.init_code_buffer(1024); - tester.emit(IGen::movq_xmm64_gpr64(tester.generator(), XMM0 + 3, RSP)); - tester.emit(IGen::movq_xmm64_gpr64(tester.generator(), XMM0 + 13, RSP)); - tester.emit(IGen::movq_xmm64_gpr64(tester.generator(), XMM0 + 3, R12)); - tester.emit(IGen::movq_xmm64_gpr64(tester.generator(), XMM0 + 13, R12)); + tester.emit(IGen::movq_f64_gpr64(tester.generator(), XMM0 + 3, RSP)); + tester.emit(IGen::movq_f64_gpr64(tester.generator(), XMM0 + 13, RSP)); + tester.emit(IGen::movq_f64_gpr64(tester.generator(), XMM0 + 3, R12)); + tester.emit(IGen::movq_f64_gpr64(tester.generator(), XMM0 + 13, R12)); EXPECT_EQ(tester.dump_to_hex_string(true), "66480F6EDC664C0F6EEC66490F6EDC664D0F6EEC"); }