From fdb6a5cfa36e81569c5e89d8c26bb48c0a09ad96 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Fri, 6 Dec 2013 22:57:16 -0800 Subject: [PATCH] Initial Alloy implementation. This is a regression in functionality and performance, but a much better foundation for the future of the project (I think). It can run basic apps under an SSA interpreter but doesn't support some of the features required to do real 360 apps yet. --- .../cpu/ppc.h => alloy/alloy-private.h} | 16 +- src/alloy/alloy.h | 31 + src/alloy/arena.cc | 92 + src/alloy/arena.h | 56 + src/alloy/backend/assembler.cc | 32 + src/alloy/backend/assembler.h | 55 + src/alloy/backend/backend.cc | 35 + src/alloy/backend/backend.h | 45 + src/alloy/backend/ivm/ivm_assembler.cc | 95 + src/alloy/backend/ivm/ivm_assembler.h | 47 + src/alloy/backend/ivm/ivm_backend.cc | 44 + src/alloy/backend/ivm/ivm_backend.h | 42 + src/alloy/backend/ivm/ivm_function.cc | 66 + src/alloy/backend/ivm/ivm_function.h | 50 + src/alloy/backend/ivm/ivm_intcode.cc | 2651 ++++++++++++ src/alloy/backend/ivm/ivm_intcode.h | 104 + src/alloy/backend/ivm/sources.gypi | 13 + src/alloy/backend/sources.gypi | 15 + src/alloy/backend/tracing.h | 54 + src/alloy/backend/x64/sources.gypi | 5 + src/alloy/compiler/compiler.cc | 53 + src/alloy/compiler/compiler.h | 44 + .../cpu/sdb.h => alloy/compiler/pass.cc} | 17 +- src/alloy/compiler/pass.h | 31 + src/alloy/compiler/passes.h | 15 + src/alloy/compiler/passes/mem2reg_pass.cc | 22 + src/alloy/compiler/passes/mem2reg_pass.h | 33 + src/alloy/compiler/passes/sources.gypi | 7 + src/alloy/compiler/sources.gypi | 15 + src/alloy/compiler/tracing.h | 43 + src/alloy/core.h | 51 + src/alloy/frontend/frontend.cc | 33 + src/alloy/frontend/frontend.h | 52 + .../frontend/ppc/ppc_context.cc} | 13 +- .../frontend/ppc/ppc_context.h} | 193 +- .../frontend/ppc/ppc_disasm-private.h} | 28 +- src/alloy/frontend/ppc/ppc_disasm.h | 33 + .../frontend/ppc/ppc_disasm_altivec.cc} | 3790 ++++++++--------- .../frontend/ppc/ppc_disasm_alu.cc} | 12 +- .../frontend/ppc/ppc_disasm_control.cc} | 23 +- .../frontend/ppc/ppc_disasm_fpu.cc} | 12 +- .../frontend/ppc/ppc_disasm_memory.cc} | 12 +- .../frontend/ppc/ppc_emit-private.h} | 34 +- src/alloy/frontend/ppc/ppc_emit.h | 33 + src/alloy/frontend/ppc/ppc_emit_altivec.cc | 2170 ++++++++++ src/alloy/frontend/ppc/ppc_emit_alu.cc | 1394 ++++++ src/alloy/frontend/ppc/ppc_emit_control.cc | 577 +++ src/alloy/frontend/ppc/ppc_emit_fpu.cc | 543 +++ src/alloy/frontend/ppc/ppc_emit_memory.cc | 1349 ++++++ src/alloy/frontend/ppc/ppc_frontend.cc | 96 + src/alloy/frontend/ppc/ppc_frontend.h | 48 + .../frontend/ppc/ppc_function_builder.cc | 306 ++ src/alloy/frontend/ppc/ppc_function_builder.h | 86 + .../frontend/ppc/ppc_instr.cc} | 38 +- .../frontend/ppc/ppc_instr.h} | 30 +- .../frontend/ppc/ppc_instr_tables.h} | 16 +- src/alloy/frontend/ppc/ppc_scanner.cc | 278 ++ src/alloy/frontend/ppc/ppc_scanner.h | 44 + src/alloy/frontend/ppc/ppc_translator.cc | 101 + src/alloy/frontend/ppc/ppc_translator.h | 52 + src/alloy/frontend/ppc/sources.gypi | 32 + src/alloy/frontend/sources.gypi | 12 + src/alloy/frontend/tracing.h | 43 + src/alloy/hir/block.cc | 13 + .../x64/x64_backend.h => alloy/hir/block.h} | 35 +- src/alloy/hir/function_builder.cc | 2110 +++++++++ src/alloy/hir/function_builder.h | 225 + src/alloy/hir/instr.cc | 13 + src/alloy/hir/instr.h | 55 + src/alloy/hir/label.cc | 13 + src/alloy/hir/label.h | 39 + src/alloy/hir/opcodes.h | 219 + src/alloy/hir/sources.gypi | 17 + src/alloy/hir/tracing.h | 35 + src/alloy/hir/value.cc | 195 + src/alloy/hir/value.h | 188 + src/alloy/memory.cc | 68 + src/alloy/memory.h | 62 + src/alloy/mutex.h | 32 + src/alloy/mutex_posix.cc | 65 + src/alloy/mutex_win.cc | 55 + src/alloy/runtime/entry_table.cc | 74 + src/alloy/runtime/entry_table.h | 56 + src/alloy/runtime/function.cc | 62 + src/alloy/runtime/function.h | 85 + src/alloy/runtime/module.cc | 154 + src/alloy/runtime/module.h | 64 + src/alloy/runtime/raw_module.cc | 61 + src/alloy/runtime/raw_module.h | 43 + .../runtime/register_access.h} | 26 +- src/alloy/runtime/runtime.cc | 218 + src/alloy/runtime/runtime.h | 68 + src/alloy/runtime/simple/sources.gypi | 13 + src/alloy/runtime/sources.gypi | 25 + src/alloy/runtime/symbol_info.cc | 37 + src/alloy/runtime/symbol_info.h | 84 + src/alloy/runtime/thread_state.cc | 56 + src/alloy/runtime/thread_state.h | 52 + src/alloy/runtime/tracing.h | 94 + src/alloy/sources.gypi | 46 + src/alloy/string_buffer.cc | 57 + .../cpu/backend.h => alloy/string_buffer.h} | 41 +- src/alloy/tracing/channel.cc | 20 + src/alloy/tracing/channel.h | 36 + src/alloy/tracing/channels/file_channel.cc | 51 + src/alloy/tracing/channels/file_channel.h | 46 + src/alloy/tracing/channels/sources.gypi | 7 + src/alloy/tracing/event_type.h | 49 + src/alloy/tracing/sources.gypi | 16 + src/alloy/tracing/tracer.cc | 51 + src/alloy/tracing/tracer.h | 43 + src/alloy/tracing/tracing.cc | 94 + src/alloy/tracing/tracing.h | 46 + src/alloy/type_pool.h | 71 + src/xenia/apu/audio_driver.cc | 5 +- src/xenia/apu/audio_driver.h | 6 +- src/xenia/apu/audio_system.cc | 13 +- src/xenia/apu/audio_system.h | 16 +- src/xenia/apu/nop/nop_audio_driver.cc | 2 +- src/xenia/apu/nop/nop_audio_driver.h | 2 +- src/xenia/core.h | 6 +- src/xenia/cpu/cpu.h | 6 +- src/xenia/cpu/exec_module.cc | 160 - src/xenia/cpu/exec_module.h | 62 - src/xenia/cpu/global_exports.cc | 289 -- src/xenia/cpu/global_exports.h | 60 - src/xenia/cpu/jit.h | 58 - src/xenia/cpu/ppc/sources.gypi | 17 - src/xenia/cpu/processor.cc | 271 +- src/xenia/cpu/processor.h | 65 +- src/xenia/cpu/sdb/raw_symbol_database.cc | 41 - src/xenia/cpu/sdb/raw_symbol_database.h | 43 - src/xenia/cpu/sdb/sources.gypi | 15 - src/xenia/cpu/sdb/symbol.cc | 127 - src/xenia/cpu/sdb/symbol.h | 170 - src/xenia/cpu/sdb/symbol_database.cc | 826 ---- src/xenia/cpu/sdb/symbol_database.h | 81 - src/xenia/cpu/sdb/symbol_table.cc | 41 - src/xenia/cpu/sdb/xex_symbol_database.cc | 772 ---- src/xenia/cpu/sdb/xex_symbol_database.h | 49 - src/xenia/cpu/sources.gypi | 23 +- src/xenia/cpu/thread_state.cc | 49 - src/xenia/cpu/thread_state.h | 53 - src/xenia/cpu/x64/sources.gypi | 17 - src/xenia/cpu/x64/x64_backend.cc | 58 - src/xenia/cpu/x64/x64_emit_altivec.cc | 2475 ----------- src/xenia/cpu/x64/x64_emit_alu.cc | 1995 --------- src/xenia/cpu/x64/x64_emit_control.cc | 730 ---- src/xenia/cpu/x64/x64_emit_fpu.cc | 952 ----- src/xenia/cpu/x64/x64_emit_memory.cc | 1738 -------- src/xenia/cpu/x64/x64_emitter.cc | 2306 ---------- src/xenia/cpu/x64/x64_emitter.h | 186 - src/xenia/cpu/x64/x64_jit.cc | 191 - src/xenia/cpu/x64/x64_jit.h | 56 - src/xenia/{memory.cc => cpu/xenon_memory.cc} | 538 ++- src/xenia/cpu/xenon_memory.h | 69 + src/xenia/cpu/xenon_runtime.cc | 48 + .../{sdb/symbol_table.h => xenon_runtime.h} | 89 +- src/xenia/cpu/xenon_thread_state.cc | 57 + src/xenia/cpu/xenon_thread_state.h | 49 + src/xenia/cpu/xex_module.cc | 488 +++ src/xenia/cpu/xex_module.h | 56 + src/xenia/emulator.cc | 16 +- src/xenia/emulator.h | 8 +- src/xenia/gpu/d3d11/d3d11_graphics_driver.cc | 10 +- src/xenia/gpu/d3d11/d3d11_graphics_driver.h | 2 +- src/xenia/gpu/graphics_driver.cc | 7 +- src/xenia/gpu/graphics_driver.h | 6 +- src/xenia/gpu/graphics_system.cc | 13 +- src/xenia/gpu/graphics_system.h | 16 +- src/xenia/gpu/nop/nop_graphics_driver.cc | 4 +- src/xenia/gpu/nop/nop_graphics_driver.h | 2 +- src/xenia/gpu/ring_buffer_worker.cc | 8 +- src/xenia/gpu/ring_buffer_worker.h | 6 +- src/xenia/hid/input_system.cc | 4 +- src/xenia/hid/input_system.h | 4 +- src/xenia/kernel/kernel_module.cc | 4 +- src/xenia/kernel/kernel_module.h | 6 +- src/xenia/kernel/shim_utils.h | 6 +- src/xenia/kernel/xam/xam_content.cc | 2 +- src/xenia/kernel/xam/xam_info.cc | 6 +- src/xenia/kernel/xam/xam_input.cc | 6 +- src/xenia/kernel/xam/xam_net.cc | 4 +- src/xenia/kernel/xam/xam_state.cc | 6 +- src/xenia/kernel/xam/xam_state.h | 4 +- src/xenia/kernel/xam/xam_user.cc | 4 +- src/xenia/kernel/xam/xam_video.cc | 2 +- src/xenia/kernel/xboxkrnl/kernel_state.cc | 5 +- src/xenia/kernel/xboxkrnl/kernel_state.h | 4 +- src/xenia/kernel/xboxkrnl/objects/xmodule.cc | 11 +- src/xenia/kernel/xboxkrnl/objects/xthread.cc | 34 +- src/xenia/kernel/xboxkrnl/objects/xthread.h | 4 +- src/xenia/kernel/xboxkrnl/xboxkrnl_audio.cc | 4 +- src/xenia/kernel/xboxkrnl/xboxkrnl_debug.cc | 4 +- src/xenia/kernel/xboxkrnl/xboxkrnl_hal.cc | 2 +- src/xenia/kernel/xboxkrnl/xboxkrnl_io.cc | 14 +- src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc | 30 +- src/xenia/kernel/xboxkrnl/xboxkrnl_misc.cc | 4 +- src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc | 19 +- src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc | 10 +- src/xenia/kernel/xboxkrnl/xboxkrnl_nt.cc | 2 +- src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc | 4 +- src/xenia/kernel/xboxkrnl/xboxkrnl_rtl.cc | 32 +- .../kernel/xboxkrnl/xboxkrnl_threading.cc | 44 +- src/xenia/kernel/xboxkrnl/xboxkrnl_video.cc | 42 +- src/xenia/kernel/xboxkrnl/xobject.cc | 4 +- src/xenia/kernel/xboxkrnl/xobject.h | 2 +- src/xenia/kernel/xex2.cc | 48 +- src/xenia/kernel/xex2.h | 3 +- src/xenia/memory.h | 67 - src/xenia/sources.gypi | 2 - tools/alloy-sandbox/alloy-sandbox.cc | 61 + tools/alloy-sandbox/alloy-sandbox.gypi | 22 + tools/tools.gypi | 1 + xenia.gyp | 63 + 215 files changed, 20167 insertions(+), 16704 deletions(-) rename src/{xenia/cpu/ppc.h => alloy/alloy-private.h} (70%) create mode 100644 src/alloy/alloy.h create mode 100644 src/alloy/arena.cc create mode 100644 src/alloy/arena.h create mode 100644 src/alloy/backend/assembler.cc create mode 100644 src/alloy/backend/assembler.h create mode 100644 src/alloy/backend/backend.cc create mode 100644 src/alloy/backend/backend.h create mode 100644 src/alloy/backend/ivm/ivm_assembler.cc create mode 100644 src/alloy/backend/ivm/ivm_assembler.h create mode 100644 src/alloy/backend/ivm/ivm_backend.cc create mode 100644 src/alloy/backend/ivm/ivm_backend.h create mode 100644 src/alloy/backend/ivm/ivm_function.cc create mode 100644 src/alloy/backend/ivm/ivm_function.h create mode 100644 src/alloy/backend/ivm/ivm_intcode.cc create mode 100644 src/alloy/backend/ivm/ivm_intcode.h create mode 100644 src/alloy/backend/ivm/sources.gypi create mode 100644 src/alloy/backend/sources.gypi create mode 100644 src/alloy/backend/tracing.h create mode 100644 src/alloy/backend/x64/sources.gypi create mode 100644 src/alloy/compiler/compiler.cc create mode 100644 src/alloy/compiler/compiler.h rename src/{xenia/cpu/sdb.h => alloy/compiler/pass.cc} (62%) create mode 100644 src/alloy/compiler/pass.h create mode 100644 src/alloy/compiler/passes.h create mode 100644 src/alloy/compiler/passes/mem2reg_pass.cc create mode 100644 src/alloy/compiler/passes/mem2reg_pass.h create mode 100644 src/alloy/compiler/passes/sources.gypi create mode 100644 src/alloy/compiler/sources.gypi create mode 100644 src/alloy/compiler/tracing.h create mode 100644 src/alloy/core.h create mode 100644 src/alloy/frontend/frontend.cc create mode 100644 src/alloy/frontend/frontend.h rename src/{xenia/cpu/ppc/state.cc => alloy/frontend/ppc/ppc_context.cc} (82%) rename src/{xenia/cpu/ppc/state.h => alloy/frontend/ppc/ppc_context.h} (53%) rename src/{xenia/cpu/ppc/disasm.h => alloy/frontend/ppc/ppc_disasm-private.h} (60%) create mode 100644 src/alloy/frontend/ppc/ppc_disasm.h rename src/{xenia/cpu/ppc/disasm_altivec.cc => alloy/frontend/ppc/ppc_disasm_altivec.cc} (97%) rename src/{xenia/cpu/ppc/disasm_alu.cc => alloy/frontend/ppc/ppc_disasm_alu.cc} (99%) rename src/{xenia/cpu/ppc/disasm_control.cc => alloy/frontend/ppc/ppc_disasm_control.cc} (94%) rename src/{xenia/cpu/ppc/disasm_fpu.cc => alloy/frontend/ppc/ppc_disasm_fpu.cc} (98%) rename src/{xenia/cpu/ppc/disasm_memory.cc => alloy/frontend/ppc/ppc_disasm_memory.cc} (99%) rename src/{xenia/cpu/x64/x64_emit.h => alloy/frontend/ppc/ppc_emit-private.h} (53%) create mode 100644 src/alloy/frontend/ppc/ppc_emit.h create mode 100644 src/alloy/frontend/ppc/ppc_emit_altivec.cc create mode 100644 src/alloy/frontend/ppc/ppc_emit_alu.cc create mode 100644 src/alloy/frontend/ppc/ppc_emit_control.cc create mode 100644 src/alloy/frontend/ppc/ppc_emit_fpu.cc create mode 100644 src/alloy/frontend/ppc/ppc_emit_memory.cc create mode 100644 src/alloy/frontend/ppc/ppc_frontend.cc create mode 100644 src/alloy/frontend/ppc/ppc_frontend.h create mode 100644 src/alloy/frontend/ppc/ppc_function_builder.cc create mode 100644 src/alloy/frontend/ppc/ppc_function_builder.h rename src/{xenia/cpu/ppc/instr.cc => alloy/frontend/ppc/ppc_instr.cc} (90%) rename src/{xenia/cpu/ppc/instr.h => alloy/frontend/ppc/ppc_instr.h} (96%) rename src/{xenia/cpu/ppc/instr_tables.h => alloy/frontend/ppc/ppc_instr_tables.h} (99%) create mode 100644 src/alloy/frontend/ppc/ppc_scanner.cc create mode 100644 src/alloy/frontend/ppc/ppc_scanner.h create mode 100644 src/alloy/frontend/ppc/ppc_translator.cc create mode 100644 src/alloy/frontend/ppc/ppc_translator.h create mode 100644 src/alloy/frontend/ppc/sources.gypi create mode 100644 src/alloy/frontend/sources.gypi create mode 100644 src/alloy/frontend/tracing.h create mode 100644 src/alloy/hir/block.cc rename src/{xenia/cpu/x64/x64_backend.h => alloy/hir/block.h} (53%) create mode 100644 src/alloy/hir/function_builder.cc create mode 100644 src/alloy/hir/function_builder.h create mode 100644 src/alloy/hir/instr.cc create mode 100644 src/alloy/hir/instr.h create mode 100644 src/alloy/hir/label.cc create mode 100644 src/alloy/hir/label.h create mode 100644 src/alloy/hir/opcodes.h create mode 100644 src/alloy/hir/sources.gypi create mode 100644 src/alloy/hir/tracing.h create mode 100644 src/alloy/hir/value.cc create mode 100644 src/alloy/hir/value.h create mode 100644 src/alloy/memory.cc create mode 100644 src/alloy/memory.h create mode 100644 src/alloy/mutex.h create mode 100644 src/alloy/mutex_posix.cc create mode 100644 src/alloy/mutex_win.cc create mode 100644 src/alloy/runtime/entry_table.cc create mode 100644 src/alloy/runtime/entry_table.h create mode 100644 src/alloy/runtime/function.cc create mode 100644 src/alloy/runtime/function.h create mode 100644 src/alloy/runtime/module.cc create mode 100644 src/alloy/runtime/module.h create mode 100644 src/alloy/runtime/raw_module.cc create mode 100644 src/alloy/runtime/raw_module.h rename src/{xenia/cpu/ppc/registers.h => alloy/runtime/register_access.h} (62%) create mode 100644 src/alloy/runtime/runtime.cc create mode 100644 src/alloy/runtime/runtime.h create mode 100644 src/alloy/runtime/simple/sources.gypi create mode 100644 src/alloy/runtime/sources.gypi create mode 100644 src/alloy/runtime/symbol_info.cc create mode 100644 src/alloy/runtime/symbol_info.h create mode 100644 src/alloy/runtime/thread_state.cc create mode 100644 src/alloy/runtime/thread_state.h create mode 100644 src/alloy/runtime/tracing.h create mode 100644 src/alloy/sources.gypi create mode 100644 src/alloy/string_buffer.cc rename src/{xenia/cpu/backend.h => alloy/string_buffer.h} (54%) create mode 100644 src/alloy/tracing/channel.cc create mode 100644 src/alloy/tracing/channel.h create mode 100644 src/alloy/tracing/channels/file_channel.cc create mode 100644 src/alloy/tracing/channels/file_channel.h create mode 100644 src/alloy/tracing/channels/sources.gypi create mode 100644 src/alloy/tracing/event_type.h create mode 100644 src/alloy/tracing/sources.gypi create mode 100644 src/alloy/tracing/tracer.cc create mode 100644 src/alloy/tracing/tracer.h create mode 100644 src/alloy/tracing/tracing.cc create mode 100644 src/alloy/tracing/tracing.h create mode 100644 src/alloy/type_pool.h delete mode 100644 src/xenia/cpu/exec_module.cc delete mode 100644 src/xenia/cpu/exec_module.h delete mode 100644 src/xenia/cpu/global_exports.cc delete mode 100644 src/xenia/cpu/global_exports.h delete mode 100644 src/xenia/cpu/jit.h delete mode 100644 src/xenia/cpu/ppc/sources.gypi delete mode 100644 src/xenia/cpu/sdb/raw_symbol_database.cc delete mode 100644 src/xenia/cpu/sdb/raw_symbol_database.h delete mode 100644 src/xenia/cpu/sdb/sources.gypi delete mode 100644 src/xenia/cpu/sdb/symbol.cc delete mode 100644 src/xenia/cpu/sdb/symbol.h delete mode 100644 src/xenia/cpu/sdb/symbol_database.cc delete mode 100644 src/xenia/cpu/sdb/symbol_database.h delete mode 100644 src/xenia/cpu/sdb/symbol_table.cc delete mode 100644 src/xenia/cpu/sdb/xex_symbol_database.cc delete mode 100644 src/xenia/cpu/sdb/xex_symbol_database.h delete mode 100644 src/xenia/cpu/thread_state.cc delete mode 100644 src/xenia/cpu/thread_state.h delete mode 100644 src/xenia/cpu/x64/sources.gypi delete mode 100644 src/xenia/cpu/x64/x64_backend.cc delete mode 100644 src/xenia/cpu/x64/x64_emit_altivec.cc delete mode 100644 src/xenia/cpu/x64/x64_emit_alu.cc delete mode 100644 src/xenia/cpu/x64/x64_emit_control.cc delete mode 100644 src/xenia/cpu/x64/x64_emit_fpu.cc delete mode 100644 src/xenia/cpu/x64/x64_emit_memory.cc delete mode 100644 src/xenia/cpu/x64/x64_emitter.cc delete mode 100644 src/xenia/cpu/x64/x64_emitter.h delete mode 100644 src/xenia/cpu/x64/x64_jit.cc delete mode 100644 src/xenia/cpu/x64/x64_jit.h rename src/xenia/{memory.cc => cpu/xenon_memory.cc} (52%) create mode 100644 src/xenia/cpu/xenon_memory.h create mode 100644 src/xenia/cpu/xenon_runtime.cc rename src/xenia/cpu/{sdb/symbol_table.h => xenon_runtime.h} (51%) create mode 100644 src/xenia/cpu/xenon_thread_state.cc create mode 100644 src/xenia/cpu/xenon_thread_state.h create mode 100644 src/xenia/cpu/xex_module.cc create mode 100644 src/xenia/cpu/xex_module.h delete mode 100644 src/xenia/memory.h create mode 100644 tools/alloy-sandbox/alloy-sandbox.cc create mode 100644 tools/alloy-sandbox/alloy-sandbox.gypi diff --git a/src/xenia/cpu/ppc.h b/src/alloy/alloy-private.h similarity index 70% rename from src/xenia/cpu/ppc.h rename to src/alloy/alloy-private.h index b8ae0d21a..11e849cee 100644 --- a/src/xenia/cpu/ppc.h +++ b/src/alloy/alloy-private.h @@ -7,13 +7,15 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_PPC_H_ -#define XENIA_CPU_PPC_H_ +#ifndef ALLOY_ALLOY_PRIVATE_H_ +#define ALLOY_ALLOY_PRIVATE_H_ -#include +#include -#include -#include -#include -#endif // XENIA_CPU_PPC_H_ +namespace alloy { + +} // namespace alloy + + +#endif // ALLOY_ALLOY_PRIVATE_H_ diff --git a/src/alloy/alloy.h b/src/alloy/alloy.h new file mode 100644 index 000000000..f65e8d5a6 --- /dev/null +++ b/src/alloy/alloy.h @@ -0,0 +1,31 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_ALLOY_H_ +#define ALLOY_ALLOY_H_ + +#include + +#include +#include +#include +#include +#include + + +// TODO(benvanik): based on platform/config/etc. +#include + + +namespace alloy { + +} // namespace alloy + + +#endif // ALLOY_ALLOY_H_ diff --git a/src/alloy/arena.cc b/src/alloy/arena.cc new file mode 100644 index 000000000..4ca1a3cec --- /dev/null +++ b/src/alloy/arena.cc @@ -0,0 +1,92 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +using namespace alloy; + + +Arena::Arena(size_t chunk_size) : + chunk_size_(chunk_size), + head_chunk_(NULL), active_chunk_(NULL) { +} + +Arena::~Arena() { + Reset(); + Chunk* chunk = head_chunk_; + while (chunk) { + Chunk* next = chunk->next; + delete chunk; + chunk = next; + } + head_chunk_ = NULL; +} + +void Arena::Reset() { + active_chunk_ = head_chunk_; + if (active_chunk_) { + active_chunk_->offset = 0; + } +} + +void* Arena::Alloc(size_t size) { + if (active_chunk_) { + if (active_chunk_->capacity - active_chunk_->offset < size) { + Chunk* next = active_chunk_->next; + if (!next) { + XEASSERT(size < size); // need to support larger chunks + next = new Chunk(chunk_size_); + active_chunk_->next = next; + } + active_chunk_ = next; + } + } else { + head_chunk_ = active_chunk_ = new Chunk(chunk_size_); + } + + uint8_t* p = active_chunk_->buffer + active_chunk_->offset; + active_chunk_->offset += size; + return p; +} + +void* Arena::CloneContents() { + size_t total_length = 0; + Chunk* chunk = head_chunk_; + while (chunk) { + total_length += chunk->offset; + if (chunk == active_chunk_) { + break; + } + chunk = chunk->next; + } + void* result = xe_malloc(total_length); + uint8_t* p = (uint8_t*)result; + chunk = head_chunk_; + while (chunk) { + xe_copy_struct(p, chunk->buffer, chunk->offset); + p += chunk->offset; + if (chunk == active_chunk_) { + break; + } + chunk = chunk->next; + } + return result; +} + +Arena::Chunk::Chunk(size_t chunk_size) : + next(NULL), + capacity(chunk_size), buffer(0), offset(0) { + buffer = (uint8_t*)xe_malloc(capacity); +} + +Arena::Chunk::~Chunk() { + if (buffer) { + xe_free(buffer); + } +} diff --git a/src/alloy/arena.h b/src/alloy/arena.h new file mode 100644 index 000000000..4375a12b2 --- /dev/null +++ b/src/alloy/arena.h @@ -0,0 +1,56 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_ARENA_H_ +#define ALLOY_ARENA_H_ + +#include + + +namespace alloy { + + +class Arena { +public: + Arena(size_t chunk_size = 4 * 1024 * 1024); + ~Arena(); + + void Reset(); + + void* Alloc(size_t size); + template T* Alloc() { + return (T*)Alloc(sizeof(T)); + } + + void* CloneContents(); + +private: + class Chunk { + public: + Chunk(size_t chunk_size); + ~Chunk(); + + Chunk* next; + + size_t capacity; + uint8_t* buffer; + size_t offset; + }; + +private: + size_t chunk_size_; + Chunk* head_chunk_; + Chunk* active_chunk_; +}; + + +} // namespace alloy + + +#endif // ALLOY_ARENA_H_ diff --git a/src/alloy/backend/assembler.cc b/src/alloy/backend/assembler.cc new file mode 100644 index 000000000..54e32c76a --- /dev/null +++ b/src/alloy/backend/assembler.cc @@ -0,0 +1,32 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include + +using namespace alloy; +using namespace alloy::backend; +using namespace alloy::runtime; + + +Assembler::Assembler(Backend* backend) : + backend_(backend) { +} + +Assembler::~Assembler() { + Reset(); +} + +int Assembler::Initialize() { + return 0; +} + +void Assembler::Reset() { +} diff --git a/src/alloy/backend/assembler.h b/src/alloy/backend/assembler.h new file mode 100644 index 000000000..c42512ab1 --- /dev/null +++ b/src/alloy/backend/assembler.h @@ -0,0 +1,55 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_BACKEND_ASSEMBLER_H_ +#define ALLOY_BACKEND_ASSEMBLER_H_ + +#include + + +namespace alloy { +namespace hir { +class FunctionBuilder; +} +namespace runtime { +class Function; +class FunctionInfo; +class Runtime; +} +} + +namespace alloy { +namespace backend { + +class Backend; + + +class Assembler { +public: + Assembler(Backend* backend); + virtual ~Assembler(); + + virtual int Initialize(); + + virtual void Reset(); + + virtual int Assemble( + runtime::FunctionInfo* symbol_info, hir::FunctionBuilder* builder, + runtime::Function** out_function) = 0; + +protected: + Backend* backend_; +}; + + +} // namespace backend +} // namespace alloy + + +#endif // ALLOY_BACKEND_ASSEMBLER_H_ diff --git a/src/alloy/backend/backend.cc b/src/alloy/backend/backend.cc new file mode 100644 index 000000000..2f6531fb5 --- /dev/null +++ b/src/alloy/backend/backend.cc @@ -0,0 +1,35 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include + +using namespace alloy; +using namespace alloy::backend; +using namespace alloy::runtime; + + +Backend::Backend(Runtime* runtime) : + runtime_(runtime) { +} + +Backend::~Backend() { +} + +int Backend::Initialize() { + return 0; +} + +void* Backend::AllocThreadData() { + return NULL; +} + +void Backend::FreeThreadData(void* thread_data) { +} diff --git a/src/alloy/backend/backend.h b/src/alloy/backend/backend.h new file mode 100644 index 000000000..292195478 --- /dev/null +++ b/src/alloy/backend/backend.h @@ -0,0 +1,45 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_BACKEND_BACKEND_H_ +#define ALLOY_BACKEND_BACKEND_H_ + +#include + + +namespace alloy { namespace runtime { class Runtime; } } + +namespace alloy { +namespace backend { + +class Assembler; + + +class Backend { +public: + Backend(runtime::Runtime* runtime); + virtual ~Backend(); + + virtual int Initialize(); + + virtual void* AllocThreadData(); + virtual void FreeThreadData(void* thread_data); + + virtual Assembler* CreateAssembler() = 0; + +protected: + runtime::Runtime* runtime_; +}; + + +} // namespace backend +} // namespace alloy + + +#endif // ALLOY_BACKEND_BACKEND_H_ diff --git a/src/alloy/backend/ivm/ivm_assembler.cc b/src/alloy/backend/ivm/ivm_assembler.cc new file mode 100644 index 000000000..3a39c9cb1 --- /dev/null +++ b/src/alloy/backend/ivm/ivm_assembler.cc @@ -0,0 +1,95 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include +#include +#include + +using namespace alloy; +using namespace alloy::backend; +using namespace alloy::backend::ivm; +using namespace alloy::hir; +using namespace alloy::runtime; + + +IVMAssembler::IVMAssembler(Backend* backend) : + Assembler(backend) { +} + +IVMAssembler::~IVMAssembler() { + alloy::tracing::WriteEvent(EventType::AssemblerDeinit({ + })); +} + +int IVMAssembler::Initialize() { + int result = Assembler::Initialize(); + if (result) { + return result; + } + + alloy::tracing::WriteEvent(EventType::AssemblerInit({ + })); + + return result; +} + +void IVMAssembler::Reset() { + intcode_arena_.Reset(); + scratch_arena_.Reset(); + Assembler::Reset(); +} + +int IVMAssembler::Assemble( + FunctionInfo* symbol_info, FunctionBuilder* builder, + Function** out_function) { + IVMFunction* fn = new IVMFunction(symbol_info); + + TranslationContext ctx; + ctx.register_count = 0; + ctx.intcode_count = 0; + ctx.intcode_arena = &intcode_arena_; + ctx.scratch_arena = &scratch_arena_; + ctx.label_ref_head = NULL; + + // Function prologue. + + Block* block = builder->first_block(); + while (block) { + Label* label = block->label_head; + while (label) { + label->tag = (void*)(0x80000000 | ctx.intcode_count); + label = label->next; + } + + Instr* i = block->instr_head; + while (i) { + int result = TranslateIntCodes(ctx, i); + i = i->next; + } + block = block->next; + } + + // Function epilogue. + + // Fixup label references. + LabelRef* label_ref = ctx.label_ref_head; + while (label_ref) { + label_ref->instr->src1_reg = (uint32_t)label_ref->label->tag & ~0x80000000; + label_ref = label_ref->next; + } + + fn->Setup(ctx); + + *out_function = fn; + return 0; +} diff --git a/src/alloy/backend/ivm/ivm_assembler.h b/src/alloy/backend/ivm/ivm_assembler.h new file mode 100644 index 000000000..37e77853a --- /dev/null +++ b/src/alloy/backend/ivm/ivm_assembler.h @@ -0,0 +1,47 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_BACKEND_IVM_IVM_ASSEMBLER_H_ +#define ALLOY_BACKEND_IVM_IVM_ASSEMBLER_H_ + +#include + +#include + + +namespace alloy { +namespace backend { +namespace ivm { + + +class IVMAssembler : public Assembler { +public: + IVMAssembler(Backend* backend); + virtual ~IVMAssembler(); + + virtual int Initialize(); + + virtual void Reset(); + + virtual int Assemble( + runtime::FunctionInfo* symbol_info, hir::FunctionBuilder* builder, + runtime::Function** out_function); + +private: + Arena intcode_arena_; + Arena scratch_arena_; +}; + + +} // namespace ivm +} // namespace backend +} // namespace alloy + + +#endif // ALLOY_BACKEND_IVM_IVM_ASSEMBLER_H_ diff --git a/src/alloy/backend/ivm/ivm_backend.cc b/src/alloy/backend/ivm/ivm_backend.cc new file mode 100644 index 000000000..83546ae10 --- /dev/null +++ b/src/alloy/backend/ivm/ivm_backend.cc @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include + +using namespace alloy; +using namespace alloy::backend; +using namespace alloy::backend::ivm; +using namespace alloy::runtime; + + +IVMBackend::IVMBackend(Runtime* runtime) : + Backend(runtime) { +} + +IVMBackend::~IVMBackend() { + alloy::tracing::WriteEvent(EventType::Deinit({ + })); +} + +int IVMBackend::Initialize() { + int result = Backend::Initialize(); + if (result) { + return result; + } + + alloy::tracing::WriteEvent(EventType::Init({ + })); + + return result; +} + +Assembler* IVMBackend::CreateAssembler() { + return new IVMAssembler(this); +} diff --git a/src/alloy/backend/ivm/ivm_backend.h b/src/alloy/backend/ivm/ivm_backend.h new file mode 100644 index 000000000..5cfa4b900 --- /dev/null +++ b/src/alloy/backend/ivm/ivm_backend.h @@ -0,0 +1,42 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_BACKEND_IVM_IVM_BACKEND_H_ +#define ALLOY_BACKEND_IVM_IVM_BACKEND_H_ + +#include + +#include + + +namespace alloy { +namespace backend { +namespace ivm { + + +#define ALLOY_HAS_IVM_BACKEND 1 + + +class IVMBackend : public Backend { +public: + IVMBackend(runtime::Runtime* runtime); + virtual ~IVMBackend(); + + virtual int Initialize(); + + virtual Assembler* CreateAssembler(); +}; + + +} // namespace ivm +} // namespace backend +} // namespace alloy + + +#endif // ALLOY_BACKEND_IVM_IVM_BACKEND_H_ diff --git a/src/alloy/backend/ivm/ivm_function.cc b/src/alloy/backend/ivm/ivm_function.cc new file mode 100644 index 000000000..33fa4be1d --- /dev/null +++ b/src/alloy/backend/ivm/ivm_function.cc @@ -0,0 +1,66 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include + +using namespace alloy; +using namespace alloy::backend; +using namespace alloy::backend::ivm; +using namespace alloy::runtime; + + +IVMFunction::IVMFunction(FunctionInfo* symbol_info) : + register_count_(0), intcode_count_(0), intcodes_(0), + GuestFunction(symbol_info) { +} + +IVMFunction::~IVMFunction() { + xe_free(intcodes_); +} + +void IVMFunction::Setup(TranslationContext& ctx) { + register_count_ = ctx.register_count; + intcode_count_ = ctx.intcode_count; + intcodes_ = (IntCode*)ctx.intcode_arena->CloneContents(); +} + +int IVMFunction::CallImpl(ThreadState* thread_state) { + // Setup register file on stack. + size_t register_file_size = register_count_ * sizeof(Register); + Register* register_file = (Register*)alloca(register_file_size); + + IntCodeState ics; + ics.rf = register_file; + ics.context = (uint8_t*)thread_state->raw_context(); + ics.membase = thread_state->memory()->membase(); + ics.did_carry = 0; + ics.thread_state = thread_state; + ics.return_address = 0xBEBEBEBE; + + // TODO(benvanik): DID_CARRY -- need HIR to set a OPCODE_FLAG_SET_CARRY + // or something so the fns can set an ics flag. + + uint32_t ia = 0; + while (true) { + const IntCode* i = &intcodes_[ia]; + uint32_t new_ia = i->intcode_fn(ics, i); + if (new_ia == IA_NEXT) { + ia++; + } else if (new_ia == IA_RETURN) { + break; + } else { + ia = new_ia; + } + } + + return 0; +} diff --git a/src/alloy/backend/ivm/ivm_function.h b/src/alloy/backend/ivm/ivm_function.h new file mode 100644 index 000000000..c9fde00f3 --- /dev/null +++ b/src/alloy/backend/ivm/ivm_function.h @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_BACKEND_IVM_IVM_FUNCTION_H_ +#define ALLOY_BACKEND_IVM_IVM_FUNCTION_H_ + +#include +#include +#include +#include + + +namespace alloy { +namespace backend { +namespace ivm { + + +class IVMFunction : public runtime::GuestFunction { +public: + IVMFunction(runtime::FunctionInfo* symbol_info); + virtual ~IVMFunction(); + + void Setup(TranslationContext& ctx); + +protected: + virtual int CallImpl(runtime::ThreadState* thread_state); + +private: + +private: + size_t register_count_; + Register* constant_regiters_; + size_t intcode_count_; + IntCode* intcodes_; + // ... source_map_; +}; + + +} // namespace ivm +} // namespace backend +} // namespace alloy + + +#endif // ALLOY_BACKEND_IVM_IVM_FUNCTION_H_ diff --git a/src/alloy/backend/ivm/ivm_intcode.cc b/src/alloy/backend/ivm/ivm_intcode.cc new file mode 100644 index 000000000..0e0b86f1d --- /dev/null +++ b/src/alloy/backend/ivm/ivm_intcode.cc @@ -0,0 +1,2651 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include +#include + +using namespace alloy; +using namespace alloy::backend; +using namespace alloy::backend::ivm; +using namespace alloy::hir; +using namespace alloy::runtime; + + +namespace alloy { +namespace backend { +namespace ivm { + + +//#define DPRINT printf +//#define DFLUSH() fflush(stdout) +#define DPRINT +#define DFLUSH() +//#define IPRINT printf +//#define IFLUSH() fflush(stdout) +#define IPRINT +#define IFLUSH() + + +uint32_t IntCode_INT_LOAD_CONSTANT(IntCodeState& ics, const IntCode* i) { + // TODO(benvanik): optimize on type to avoid 16b copy per load. + ics.rf[i->dest_reg].v128 = i->constant.v128; + return IA_NEXT; +} + +uint32_t AllocConstant(TranslationContext& ctx, uint64_t value, + IntCode** out_ic = NULL) { + ctx.intcode_count++; + IntCode* ic = ctx.intcode_arena->Alloc(); + ic->intcode_fn = IntCode_INT_LOAD_CONSTANT; + ic->flags = 0; + ic->dest_reg = ctx.register_count++; + ic->constant.u64 = value; + if (out_ic) { + *out_ic = ic; + } + return ic->dest_reg; +} + +uint32_t AllocConstant(TranslationContext& ctx, Value* value) { + ctx.intcode_count++; + IntCode* ic = ctx.intcode_arena->Alloc(); + ic->intcode_fn = IntCode_INT_LOAD_CONSTANT; + ic->flags = 0; + ic->dest_reg = ctx.register_count++; + ic->constant.v128 = value->constant.v128; + return ic->dest_reg; +} + +uint32_t AllocLabel(TranslationContext& ctx, Label* label) { + // If it's a back-branch to an already tagged label avoid setting up + // a reference. + uint32_t value = (uint32_t)label->tag; + if (value & 0x80000000) { + // Already set. + return AllocConstant(ctx, value & ~0x80000000); + } + + // Allocate a constant - it will be updated later. + IntCode* ic; + uint32_t reg = AllocConstant(ctx, 0, &ic); + + // Setup a label reference. After assembly is complete this will + // run through and fix up the constant with the IA. + LabelRef* label_ref = ctx.scratch_arena->Alloc(); + label_ref->next = ctx.label_ref_head; + ctx.label_ref_head = label_ref; + label_ref->label = label; + label_ref->instr = ic; + + return reg; +} + +uint32_t AllocDynamicRegister(TranslationContext& ctx, Value* value) { + int32_t reg = (int32_t)value->tag - 1; + if (reg == -1) { + reg = ctx.register_count++; + value->tag = (void*)(reg + 1); + } + return (uint32_t)reg; +} + +uint32_t AllocOpRegister( + TranslationContext& ctx, OpcodeSignatureType sig_type, Instr::Op* op) { + switch (sig_type) { + case OPCODE_SIG_TYPE_X: + // Nothing. + return 0; + case OPCODE_SIG_TYPE_L: + return AllocLabel(ctx, op->label); + case OPCODE_SIG_TYPE_O: + return AllocConstant(ctx, (uint64_t)op->offset); + case OPCODE_SIG_TYPE_S: + return AllocConstant(ctx, (uint64_t)op->symbol_info); + case OPCODE_SIG_TYPE_V: + Value* value = op->value; + if (value->IsConstant()) { + return AllocConstant(ctx, value); + } else { + return AllocDynamicRegister(ctx, value); + } + } + return 0; +} + +uint32_t IntCode_INVALID(IntCodeState& ics, const IntCode* i); +uint32_t IntCode_INVALID_TYPE(IntCodeState& ics, const IntCode* i); +int DispatchToC(TranslationContext& ctx, Instr* i, IntCodeFn fn) { + XEASSERT(fn != IntCode_INVALID); + XEASSERT(fn != IntCode_INVALID_TYPE); + + const OpcodeInfo* op = i->opcode; + uint32_t sig = op->signature; + OpcodeSignatureType dest_type = GET_OPCODE_SIG_TYPE_DEST(sig); + OpcodeSignatureType src1_type = GET_OPCODE_SIG_TYPE_SRC1(sig); + OpcodeSignatureType src2_type = GET_OPCODE_SIG_TYPE_SRC2(sig); + OpcodeSignatureType src3_type = GET_OPCODE_SIG_TYPE_SRC3(sig); + + // Setup arguments. + uint32_t dest_reg = 0; + if (dest_type == OPCODE_SIG_TYPE_V) { + // Allocate dest register. + dest_reg = AllocDynamicRegister(ctx, i->dest); + } + uint32_t src1_reg = AllocOpRegister(ctx, src1_type, &i->src1); + uint32_t src2_reg = AllocOpRegister(ctx, src2_type, &i->src2); + uint32_t src3_reg = AllocOpRegister(ctx, src3_type, &i->src3); + + // Allocate last (in case we had any setup instructions for args). + ctx.intcode_count++; + IntCode* ic = ctx.intcode_arena->Alloc(); + ic->intcode_fn = fn; + ic->flags = i->flags; + ic->dest_reg = dest_reg; + ic->src1_reg = src1_reg; + ic->src2_reg = src2_reg; + ic->src3_reg = src3_reg; + + return 0; +} + + +uint32_t IntCode_INVALID(IntCodeState& ics, const IntCode* i) { + XEASSERTALWAYS(); + return IA_NEXT; +} +uint32_t IntCode_INVALID_TYPE(IntCodeState& ics, const IntCode* i) { + XEASSERTALWAYS(); + return IA_NEXT; +} +int TranslateInvalid(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_INVALID); +} + +uint32_t IntCode_COMMENT(IntCodeState& ics, const IntCode* i) { + char* value = (char*)(i->src1_reg | ((uint64_t)i->src2_reg << 32)); + IPRINT("%s\n", value); + IFLUSH(); + return IA_NEXT; +} +int Translate_COMMENT(TranslationContext& ctx, Instr* i) { + ctx.intcode_count++; + IntCode* ic = ctx.intcode_arena->Alloc(); + ic->intcode_fn = IntCode_COMMENT; + ic->flags = i->flags; + // HACK HACK HACK + char* src = xestrdupa((char*)i->src1.offset); + uint64_t src_p = (uint64_t)src; + ic->src1_reg = (uint32_t)src_p; + ic->src2_reg = (uint32_t)(src_p >> 32); + return 0; +} + +uint32_t IntCode_NOP(IntCodeState& ics, const IntCode* i) { + return IA_NEXT; +} +int Translate_NOP(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_NOP); +} + +uint32_t IntCode_DEBUG_BREAK(IntCodeState& ics, const IntCode* i) { + DFLUSH(); + __debugbreak(); + return IA_NEXT; +} +int Translate_DEBUG_BREAK(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_DEBUG_BREAK); +} + +uint32_t IntCode_DEBUG_BREAK_TRUE_I8(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u8) { + return IntCode_DEBUG_BREAK(ics, i); + } + return IA_NEXT; +} +uint32_t IntCode_DEBUG_BREAK_TRUE_I16(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u16) { + return IntCode_DEBUG_BREAK(ics, i); + } + return IA_NEXT; +} +uint32_t IntCode_DEBUG_BREAK_TRUE_I32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u32) { + return IntCode_DEBUG_BREAK(ics, i); + } + return IA_NEXT; +} +uint32_t IntCode_DEBUG_BREAK_TRUE_I64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u64) { + return IntCode_DEBUG_BREAK(ics, i); + } + return IA_NEXT; +} +uint32_t IntCode_DEBUG_BREAK_TRUE_F32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f32) { + return IntCode_DEBUG_BREAK(ics, i); + } + return IA_NEXT; +} +uint32_t IntCode_DEBUG_BREAK_TRUE_F64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f64) { + return IntCode_DEBUG_BREAK(ics, i); + } + return IA_NEXT; +} +int Translate_DEBUG_BREAK_TRUE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_DEBUG_BREAK_TRUE_I8, + IntCode_DEBUG_BREAK_TRUE_I16, + IntCode_DEBUG_BREAK_TRUE_I32, + IntCode_DEBUG_BREAK_TRUE_I64, + IntCode_DEBUG_BREAK_TRUE_F32, + IntCode_DEBUG_BREAK_TRUE_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_TRAP(IntCodeState& ics, const IntCode* i) { + __debugbreak(); + return IA_NEXT; +} +int Translate_TRAP(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_TRAP); +} + +uint32_t IntCode_TRAP_TRUE_I8(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u8) { + return IntCode_TRAP(ics, i); + } + return IA_NEXT; +} +uint32_t IntCode_TRAP_TRUE_I16(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u16) { + return IntCode_TRAP(ics, i); + } + return IA_NEXT; +} +uint32_t IntCode_TRAP_TRUE_I32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u32) { + return IntCode_TRAP(ics, i); + } + return IA_NEXT; +} +uint32_t IntCode_TRAP_TRUE_I64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u64) { + return IntCode_TRAP(ics, i); + } + return IA_NEXT; +} +uint32_t IntCode_TRAP_TRUE_F32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f32) { + return IntCode_TRAP(ics, i); + } + return IA_NEXT; +} +uint32_t IntCode_TRAP_TRUE_F64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f64) { + return IntCode_TRAP(ics, i); + } + return IA_NEXT; +} +int Translate_TRAP_TRUE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_TRAP_TRUE_I8, + IntCode_TRAP_TRUE_I16, + IntCode_TRAP_TRUE_I32, + IntCode_TRAP_TRUE_I64, + IntCode_TRAP_TRUE_F32, + IntCode_TRAP_TRUE_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_CALL_XX(IntCodeState& ics, const IntCode* i, uint32_t reg) { + FunctionInfo* symbol_info = (FunctionInfo*)ics.rf[reg].u64; + Function* fn; + ics.thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn); + // TODO(benvanik): proper tail call support, somehow. + fn->Call(ics.thread_state); + if (i->flags & CALL_TAIL) { + return IA_RETURN; + } + return IA_NEXT; +} +uint32_t IntCode_CALL(IntCodeState& ics, const IntCode* i) { + return IntCode_CALL_XX(ics, i, i->src1_reg); +} +int Translate_CALL(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_CALL); +} + +uint32_t IntCode_CALL_TRUE_I8(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u8) { + return IntCode_CALL_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_CALL_TRUE_I16(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u16) { + return IntCode_CALL_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_CALL_TRUE_I32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u32) { + return IntCode_CALL_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_CALL_TRUE_I64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u64) { + return IntCode_CALL_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_CALL_TRUE_F32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f32) { + return IntCode_CALL_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_CALL_TRUE_F64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f64) { + return IntCode_CALL_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +int Translate_CALL_TRUE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_CALL_TRUE_I8, + IntCode_CALL_TRUE_I16, + IntCode_CALL_TRUE_I32, + IntCode_CALL_TRUE_I64, + IntCode_CALL_TRUE_F32, + IntCode_CALL_TRUE_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_CALL_INDIRECT_XX(IntCodeState& ics, const IntCode* i, uint32_t reg) { + // Check if return address - if so, return. + /*if (ics.rf[reg].u64 == ics.return_address) { + return IA_RETURN; + }*/ + + // Real call. + Function* fn; + ics.thread_state->runtime()->ResolveFunction(ics.rf[reg].u64, &fn); + // TODO(benvanik): proper tail call support, somehow. + fn->Call(ics.thread_state); + if (i->flags & CALL_TAIL) { + return IA_RETURN; + } + return IA_NEXT; +} +uint32_t IntCode_CALL_INDIRECT(IntCodeState& ics, const IntCode* i) { + return IntCode_CALL_INDIRECT_XX(ics, i, i->src1_reg); +} +int Translate_CALL_INDIRECT(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_CALL_INDIRECT); +} + +uint32_t IntCode_CALL_INDIRECT_TRUE_I8(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u8) { + return IntCode_CALL_INDIRECT_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_CALL_INDIRECT_TRUE_I16(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u16) { + return IntCode_CALL_INDIRECT_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_CALL_INDIRECT_TRUE_I32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u32) { + return IntCode_CALL_INDIRECT_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_CALL_INDIRECT_TRUE_I64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u64) { + return IntCode_CALL_INDIRECT_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_CALL_INDIRECT_TRUE_F32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f32) { + return IntCode_CALL_INDIRECT_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_CALL_INDIRECT_TRUE_F64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f64) { + return IntCode_CALL_INDIRECT_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +int Translate_CALL_INDIRECT_TRUE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_CALL_INDIRECT_TRUE_I8, + IntCode_CALL_INDIRECT_TRUE_I16, + IntCode_CALL_INDIRECT_TRUE_I32, + IntCode_CALL_INDIRECT_TRUE_I64, + IntCode_CALL_INDIRECT_TRUE_F32, + IntCode_CALL_INDIRECT_TRUE_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_RETURN(IntCodeState& ics, const IntCode* i) { + return IA_RETURN; +} +int Translate_RETURN(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_RETURN); +} + +uint32_t IntCode_BRANCH_XX(IntCodeState& ics, const IntCode* i, uint32_t reg) { + return ics.rf[reg].u32; +} +uint32_t IntCode_BRANCH(IntCodeState& ics, const IntCode* i) { + return IntCode_BRANCH_XX(ics, i, i->src1_reg); +} +int Translate_BRANCH(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_BRANCH); +} + +uint32_t IntCode_BRANCH_IF_I8(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u8) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } else { + return IntCode_BRANCH_XX(ics, i, i->src3_reg); + } +} +uint32_t IntCode_BRANCH_IF_I16(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u16) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } else { + return IntCode_BRANCH_XX(ics, i, i->src3_reg); + } +} +uint32_t IntCode_BRANCH_IF_I32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u32) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } else { + return IntCode_BRANCH_XX(ics, i, i->src3_reg); + } +} +uint32_t IntCode_BRANCH_IF_I64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u64) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } else { + return IntCode_BRANCH_XX(ics, i, i->src3_reg); + } +} +uint32_t IntCode_BRANCH_IF_F32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f32) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } else { + return IntCode_BRANCH_XX(ics, i, i->src3_reg); + } +} +uint32_t IntCode_BRANCH_IF_F64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f64) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } else { + return IntCode_BRANCH_XX(ics, i, i->src3_reg); + } +} +int Translate_BRANCH_IF(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_BRANCH_IF_I8, + IntCode_BRANCH_IF_I16, + IntCode_BRANCH_IF_I32, + IntCode_BRANCH_IF_I64, + IntCode_BRANCH_IF_F32, + IntCode_BRANCH_IF_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_BRANCH_TRUE_I8(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u8) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_BRANCH_TRUE_I16(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u16) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_BRANCH_TRUE_I32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u32) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_BRANCH_TRUE_I64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].u64) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_BRANCH_TRUE_F32(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f32) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_BRANCH_TRUE_F64(IntCodeState& ics, const IntCode* i) { + if (ics.rf[i->src1_reg].f64) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +int Translate_BRANCH_TRUE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_BRANCH_TRUE_I8, + IntCode_BRANCH_TRUE_I16, + IntCode_BRANCH_TRUE_I32, + IntCode_BRANCH_TRUE_I64, + IntCode_BRANCH_TRUE_F32, + IntCode_BRANCH_TRUE_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_BRANCH_FALSE_I8(IntCodeState& ics, const IntCode* i) { + if (!ics.rf[i->src1_reg].u8) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_BRANCH_FALSE_I16(IntCodeState& ics, const IntCode* i) { + if (!ics.rf[i->src1_reg].u16) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_BRANCH_FALSE_I32(IntCodeState& ics, const IntCode* i) { + if (!ics.rf[i->src1_reg].u32) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_BRANCH_FALSE_I64(IntCodeState& ics, const IntCode* i) { + if (!ics.rf[i->src1_reg].u64) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_BRANCH_FALSE_F32(IntCodeState& ics, const IntCode* i) { + if (!ics.rf[i->src1_reg].f32) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +uint32_t IntCode_BRANCH_FALSE_F64(IntCodeState& ics, const IntCode* i) { + if (!ics.rf[i->src1_reg].f64) { + return IntCode_BRANCH_XX(ics, i, i->src2_reg); + } + return IA_NEXT; +} +int Translate_BRANCH_FALSE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_BRANCH_FALSE_I8, + IntCode_BRANCH_FALSE_I16, + IntCode_BRANCH_FALSE_I32, + IntCode_BRANCH_FALSE_I64, + IntCode_BRANCH_FALSE_F32, + IntCode_BRANCH_FALSE_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_ASSIGN_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_ASSIGN_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_ASSIGN_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_ASSIGN_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_ASSIGN_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = ics.rf[i->src1_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_ASSIGN_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = ics.rf[i->src1_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_ASSIGN_V128(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].v128 = ics.rf[i->src1_reg].v128; + return IA_NEXT; +} +int Translate_ASSIGN(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_ASSIGN_I8, + IntCode_ASSIGN_I16, + IntCode_ASSIGN_I32, + IntCode_ASSIGN_I64, + IntCode_ASSIGN_F32, + IntCode_ASSIGN_F64, + IntCode_ASSIGN_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_CAST(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].v128 = ics.rf[i->src1_reg].v128; + return IA_NEXT; +} +int Translate_CAST(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_CAST); +} + +uint32_t IntCode_ZERO_EXTEND_I8_TO_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = (uint8_t)ics.rf[i->src1_reg].u8; + return IA_NEXT; +} +uint32_t IntCode_ZERO_EXTEND_I8_TO_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = (uint16_t)ics.rf[i->src1_reg].u8; + return IA_NEXT; +} +uint32_t IntCode_ZERO_EXTEND_I8_TO_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = (uint64_t)ics.rf[i->src1_reg].u8; + return IA_NEXT; +} +uint32_t IntCode_ZERO_EXTEND_I16_TO_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = (uint32_t)ics.rf[i->src1_reg].u16; + return IA_NEXT; +} +uint32_t IntCode_ZERO_EXTEND_I16_TO_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = (uint64_t)ics.rf[i->src1_reg].u16; + return IA_NEXT; +} +uint32_t IntCode_ZERO_EXTEND_I32_TO_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = (uint64_t)ics.rf[i->src1_reg].u32; + return IA_NEXT; +} +int Translate_ZERO_EXTEND(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_ASSIGN_I8, IntCode_ZERO_EXTEND_I8_TO_I16, IntCode_ZERO_EXTEND_I8_TO_I32, IntCode_ZERO_EXTEND_I8_TO_I64, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_ASSIGN_I16, IntCode_ZERO_EXTEND_I16_TO_I32, IntCode_ZERO_EXTEND_I16_TO_I64, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_ASSIGN_I32, IntCode_ZERO_EXTEND_I32_TO_I64, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_ASSIGN_I64, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + }; + IntCodeFn fn = fns[i->src1.value->type * MAX_TYPENAME + i->dest->type]; + return DispatchToC(ctx, i, fn); +} + +uint32_t IntCode_SIGN_EXTEND_I8_TO_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = (int8_t)ics.rf[i->src1_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SIGN_EXTEND_I8_TO_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = (int16_t)ics.rf[i->src1_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SIGN_EXTEND_I8_TO_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = (int64_t)ics.rf[i->src1_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SIGN_EXTEND_I16_TO_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = (int32_t)ics.rf[i->src1_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_SIGN_EXTEND_I16_TO_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = (int64_t)ics.rf[i->src1_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_SIGN_EXTEND_I32_TO_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = (int64_t)ics.rf[i->src1_reg].i32; + return IA_NEXT; +} +int Translate_SIGN_EXTEND(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_ASSIGN_I8, IntCode_SIGN_EXTEND_I8_TO_I16, IntCode_SIGN_EXTEND_I8_TO_I32, IntCode_SIGN_EXTEND_I8_TO_I64, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_ASSIGN_I16, IntCode_SIGN_EXTEND_I16_TO_I32, IntCode_SIGN_EXTEND_I16_TO_I64, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_ASSIGN_I32, IntCode_SIGN_EXTEND_I32_TO_I64, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_ASSIGN_I64, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + }; + IntCodeFn fn = fns[i->src1.value->type * MAX_TYPENAME + i->dest->type]; + return DispatchToC(ctx, i, fn); +} + +uint32_t IntCode_TRUNCATE_I16_TO_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = (int8_t)ics.rf[i->src1_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_TRUNCATE_I32_TO_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = (int8_t)ics.rf[i->src1_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_TRUNCATE_I32_TO_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = (int16_t)ics.rf[i->src1_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_TRUNCATE_I64_TO_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = (int8_t)ics.rf[i->src1_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_TRUNCATE_I64_TO_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = (int16_t)ics.rf[i->src1_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_TRUNCATE_I64_TO_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = (int32_t)ics.rf[i->src1_reg].i64; + return IA_NEXT; +} +int Translate_TRUNCATE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_ASSIGN_I8, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_TRUNCATE_I16_TO_I8, IntCode_ASSIGN_I16, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_TRUNCATE_I32_TO_I8, IntCode_TRUNCATE_I32_TO_I16, IntCode_ASSIGN_I32, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_TRUNCATE_I64_TO_I8, IntCode_TRUNCATE_I64_TO_I16, IntCode_TRUNCATE_I64_TO_I32, IntCode_ASSIGN_I64, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + }; + IntCodeFn fn = fns[i->src1.value->type * MAX_TYPENAME + i->dest->type]; + return DispatchToC(ctx, i, fn); +} + +uint32_t IntCode_CONVERT_I32_TO_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = (float)ics.rf[i->src1_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_CONVERT_I64_TO_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = (double)ics.rf[i->src1_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_CONVERT_F32_TO_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = (int32_t)ics.rf[i->src1_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_CONVERT_F32_TO_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = (double)ics.rf[i->src1_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_CONVERT_F64_TO_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = (int64_t)ics.rf[i->src1_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_CONVERT_F64_TO_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = (float)ics.rf[i->src1_reg].f64; + return IA_NEXT; +} +int Translate_CONVERT(TranslationContext& ctx, Instr* i) { + // Can do more as needed. + static IntCodeFn fns[] = { + IntCode_ASSIGN_I8, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_ASSIGN_I16, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_ASSIGN_I32, IntCode_INVALID_TYPE, IntCode_CONVERT_I32_TO_F32, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_ASSIGN_I64, IntCode_INVALID_TYPE, IntCode_CONVERT_I64_TO_F64, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_CONVERT_F32_TO_I32, IntCode_INVALID_TYPE, IntCode_ASSIGN_F32, IntCode_CONVERT_F32_TO_F64, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_CONVERT_F64_TO_I64, IntCode_CONVERT_F64_TO_F32, IntCode_ASSIGN_F64, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_ASSIGN_V128, + }; + IntCodeFn fn = fns[i->src1.value->type * MAX_TYPENAME + i->dest->type]; + return DispatchToC(ctx, i, fn); +} + + +uint32_t IntCode_VECTOR_CONVERT_I2F(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + dest.f4[0] = (float)(int32_t)dest.i4[0]; + dest.f4[1] = (float)(int32_t)dest.i4[1]; + dest.f4[2] = (float)(int32_t)dest.i4[2]; + dest.f4[3] = (float)(int32_t)dest.i4[3]; + return IA_NEXT; +} +int Translate_VECTOR_CONVERT_I2F(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_VECTOR_CONVERT_I2F); +} + +uint32_t IntCode_LOAD_CONTEXT_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = *((int8_t*)(ics.context + ics.rf[i->src1_reg].u64)); + DPRINT("%d (%.X) = ctx i8 +%d\n", ics.rf[i->dest_reg].i8, ics.rf[i->dest_reg].u8, ics.rf[i->src1_reg].u64); + return IA_NEXT; +} +uint32_t IntCode_LOAD_CONTEXT_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = *((int16_t*)(ics.context + ics.rf[i->src1_reg].u64)); + DPRINT("%d (%.X) = ctx i16 +%d\n", ics.rf[i->dest_reg].i16, ics.rf[i->dest_reg].u16, ics.rf[i->src1_reg].u64); + return IA_NEXT; +} +uint32_t IntCode_LOAD_CONTEXT_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = *((int32_t*)(ics.context + ics.rf[i->src1_reg].u64)); + DPRINT("%d (%.X) = ctx i32 +%d\n", ics.rf[i->dest_reg].i32, ics.rf[i->dest_reg].u32, ics.rf[i->src1_reg].u64); + return IA_NEXT; +} +uint32_t IntCode_LOAD_CONTEXT_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = *((int64_t*)(ics.context + ics.rf[i->src1_reg].u64)); + DPRINT("%d (%.X) = ctx i64 +%d\n", ics.rf[i->dest_reg].i64, ics.rf[i->dest_reg].u64, ics.rf[i->src1_reg].u64); + return IA_NEXT; +} +uint32_t IntCode_LOAD_CONTEXT_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = *((float*)(ics.context + ics.rf[i->src1_reg].u64)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_CONTEXT_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = *((double*)(ics.context + ics.rf[i->src1_reg].u64)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_CONTEXT_V128(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].v128 = *((vec128_t*)(ics.context + ics.rf[i->src1_reg].u64)); + return IA_NEXT; +} +int Translate_LOAD_CONTEXT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_LOAD_CONTEXT_I8, + IntCode_LOAD_CONTEXT_I16, + IntCode_LOAD_CONTEXT_I32, + IntCode_LOAD_CONTEXT_I64, + IntCode_LOAD_CONTEXT_F32, + IntCode_LOAD_CONTEXT_F64, + IntCode_LOAD_CONTEXT_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_STORE_CONTEXT_I8(IntCodeState& ics, const IntCode* i) { + *((int8_t*)(ics.context + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].i8; + DPRINT("ctx i8 +%d = %d (%.X)\n", ics.rf[i->src1_reg].u64, ics.rf[i->src2_reg].i8, ics.rf[i->src2_reg].u8); + return IA_NEXT; +} +uint32_t IntCode_STORE_CONTEXT_I16(IntCodeState& ics, const IntCode* i) { + *((int16_t*)(ics.context + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].i16; + DPRINT("ctx i16 +%d = %d (%.X)\n", ics.rf[i->src1_reg].u64, ics.rf[i->src2_reg].i16, ics.rf[i->src2_reg].u16); + return IA_NEXT; +} +uint32_t IntCode_STORE_CONTEXT_I32(IntCodeState& ics, const IntCode* i) { + *((int32_t*)(ics.context + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].i32; + DPRINT("ctx i32 +%d = %d (%.X)\n", ics.rf[i->src1_reg].u64, ics.rf[i->src2_reg].i32, ics.rf[i->src2_reg].u32); + return IA_NEXT; +} +uint32_t IntCode_STORE_CONTEXT_I64(IntCodeState& ics, const IntCode* i) { + *((int64_t*)(ics.context + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].i64; + DPRINT("ctx i64 +%d = %d (%.X)\n", ics.rf[i->src1_reg].u64, ics.rf[i->src2_reg].i64, ics.rf[i->src2_reg].u64); + return IA_NEXT; +} +uint32_t IntCode_STORE_CONTEXT_F32(IntCodeState& ics, const IntCode* i) { + *((float*)(ics.context + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_STORE_CONTEXT_F64(IntCodeState& ics, const IntCode* i) { + *((double*)(ics.context + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_STORE_CONTEXT_V128(IntCodeState& ics, const IntCode* i) { + *((vec128_t*)(ics.context + ics.rf[i->src1_reg].u64)) = ics.rf[i->src2_reg].v128; + return IA_NEXT; +} +int Translate_STORE_CONTEXT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_STORE_CONTEXT_I8, + IntCode_STORE_CONTEXT_I16, + IntCode_STORE_CONTEXT_I32, + IntCode_STORE_CONTEXT_I64, + IntCode_STORE_CONTEXT_F32, + IntCode_STORE_CONTEXT_F64, + IntCode_STORE_CONTEXT_V128, + }; + return DispatchToC(ctx, i, fns[i->src2.value->type]); +} + +uint32_t IntCode_LOAD_I8(IntCodeState& ics, const IntCode* i) { + DPRINT("%d (%X) = load.i8 %.8X\n", + *((int8_t*)(ics.membase + ics.rf[i->src1_reg].u32)), + *((uint8_t*)(ics.membase + ics.rf[i->src1_reg].u32)), + ics.rf[i->src1_reg].u32); + DFLUSH(); + ics.rf[i->dest_reg].i8 = *((int8_t*)(ics.membase + ics.rf[i->src1_reg].u32)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_I16(IntCodeState& ics, const IntCode* i) { + DPRINT("%d (%X) = load.i16 %.8X\n", + *((int16_t*)(ics.membase + ics.rf[i->src1_reg].u32)), + *((uint16_t*)(ics.membase + ics.rf[i->src1_reg].u32)), + ics.rf[i->src1_reg].u32); + DFLUSH(); + ics.rf[i->dest_reg].i16 = *((int16_t*)(ics.membase + ics.rf[i->src1_reg].u32)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_I32(IntCodeState& ics, const IntCode* i) { + DFLUSH(); + DPRINT("%d (%X) = load.i32 %.8X\n", + *((int32_t*)(ics.membase + ics.rf[i->src1_reg].u32)), + *((uint32_t*)(ics.membase + ics.rf[i->src1_reg].u32)), + ics.rf[i->src1_reg].u32); + DFLUSH(); + ics.rf[i->dest_reg].i32 = *((int32_t*)(ics.membase + ics.rf[i->src1_reg].u32)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_I64(IntCodeState& ics, const IntCode* i) { + DPRINT("%d (%X) = load.i64 %.8X\n", + *((int64_t*)(ics.membase + ics.rf[i->src1_reg].u32)), + *((uint64_t*)(ics.membase + ics.rf[i->src1_reg].u32)), + ics.rf[i->src1_reg].u32); + DFLUSH(); + ics.rf[i->dest_reg].i64 = *((int64_t*)(ics.membase + ics.rf[i->src1_reg].u32)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = *((float*)(ics.membase + ics.rf[i->src1_reg].u32)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = *((double*)(ics.membase + ics.rf[i->src1_reg].u32)); + return IA_NEXT; +} +uint32_t IntCode_LOAD_V128(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].v128 = *((vec128_t*)(ics.membase + (ics.rf[i->src1_reg].u32 & ~0xF))); + return IA_NEXT; +} +int Translate_LOAD(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_LOAD_I8, + IntCode_LOAD_I16, + IntCode_LOAD_I32, + IntCode_LOAD_I64, + IntCode_LOAD_F32, + IntCode_LOAD_F64, + IntCode_LOAD_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_STORE_I8(IntCodeState& ics, const IntCode* i) { + DPRINT("store.i8 %.8X = %d (%X)\n", + ics.rf[i->src1_reg].u32, ics.rf[i->src2_reg].i8, ics.rf[i->src2_reg].i8); + DFLUSH(); + *((int8_t*)(ics.membase + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_STORE_I16(IntCodeState& ics, const IntCode* i) { + DPRINT("store.i16 %.8X = %d (%X)\n", + ics.rf[i->src1_reg].u32, ics.rf[i->src2_reg].i16, ics.rf[i->src2_reg].i16); + DFLUSH(); + *((int16_t*)(ics.membase + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_STORE_I32(IntCodeState& ics, const IntCode* i) { + DPRINT("store.i32 %.8X = %d (%X)\n", + ics.rf[i->src1_reg].u32, ics.rf[i->src2_reg].i32, ics.rf[i->src2_reg].i32); + DFLUSH(); + *((int32_t*)(ics.membase + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_STORE_I64(IntCodeState& ics, const IntCode* i) { + DPRINT("store.i64 %.8X = %d (%X)\n", + ics.rf[i->src1_reg].u32, ics.rf[i->src2_reg].i64, ics.rf[i->src2_reg].i64); + DFLUSH(); + *((int64_t*)(ics.membase + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_STORE_F32(IntCodeState& ics, const IntCode* i) { + *((float*)(ics.membase + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_STORE_F64(IntCodeState& ics, const IntCode* i) { + *((double*)(ics.membase + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_STORE_V128(IntCodeState& ics, const IntCode* i) { + *((vec128_t*)(ics.membase + (ics.rf[i->src1_reg].u32 & ~0xF))) = ics.rf[i->src2_reg].v128; + return IA_NEXT; +} +int Translate_STORE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_STORE_I8, + IntCode_STORE_I16, + IntCode_STORE_I32, + IntCode_STORE_I64, + IntCode_STORE_F32, + IntCode_STORE_F64, + IntCode_STORE_V128, + }; + return DispatchToC(ctx, i, fns[i->src2.value->type]); +} + +uint32_t IntCode_PREFETCH(IntCodeState& ics, const IntCode* i) { + return IA_NEXT; +} +int Translate_PREFETCH(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_PREFETCH); +} + +uint32_t IntCode_SELECT_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 ? + ics.rf[i->src2_reg].i8 : ics.rf[i->src3_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SELECT_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].i8 ? + ics.rf[i->src2_reg].i16 : ics.rf[i->src3_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_SELECT_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].i8 ? + ics.rf[i->src2_reg].i32 : ics.rf[i->src3_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_SELECT_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].i8 ? + ics.rf[i->src2_reg].i64 : ics.rf[i->src3_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_SELECT_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = ics.rf[i->src1_reg].i8 ? + ics.rf[i->src2_reg].f32 : ics.rf[i->src3_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_SELECT_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = ics.rf[i->src1_reg].i8 ? + ics.rf[i->src2_reg].f64 : ics.rf[i->src3_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_SELECT_V128(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].v128 = ics.rf[i->src1_reg].i8 ? + ics.rf[i->src2_reg].v128 : ics.rf[i->src3_reg].v128; + return IA_NEXT; +} +int Translate_SELECT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_SELECT_I8, + IntCode_SELECT_I16, + IntCode_SELECT_I32, + IntCode_SELECT_I64, + IntCode_SELECT_F32, + IntCode_SELECT_F64, + IntCode_SELECT_V128, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_IS_TRUE_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !!ics.rf[i->src1_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_IS_TRUE_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !!ics.rf[i->src1_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_IS_TRUE_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !!ics.rf[i->src1_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_IS_TRUE_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !!ics.rf[i->src1_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_IS_TRUE_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !!ics.rf[i->src1_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_IS_TRUE_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !!ics.rf[i->src1_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_IS_TRUE_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + ics.rf[i->dest_reg].i8 = src1.high && src1.low; + return IA_NEXT; +} +int Translate_IS_TRUE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_IS_TRUE_I8, + IntCode_IS_TRUE_I16, + IntCode_IS_TRUE_I32, + IntCode_IS_TRUE_I64, + IntCode_IS_TRUE_F32, + IntCode_IS_TRUE_F64, + IntCode_IS_TRUE_V128, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_IS_FALSE_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !ics.rf[i->src1_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_IS_FALSE_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !ics.rf[i->src1_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_IS_FALSE_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !ics.rf[i->src1_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_IS_FALSE_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !ics.rf[i->src1_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_IS_FALSE_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !ics.rf[i->src1_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_IS_FALSE_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = !ics.rf[i->src1_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_IS_FALSE_V128(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = + !(ics.rf[i->src1_reg].v128.high && ics.rf[i->src1_reg].v128.low); + return IA_NEXT; +} +int Translate_IS_FALSE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_IS_FALSE_I8, + IntCode_IS_FALSE_I16, + IntCode_IS_FALSE_I32, + IntCode_IS_FALSE_I64, + IntCode_IS_FALSE_F32, + IntCode_IS_FALSE_F64, + IntCode_IS_FALSE_V128, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_COMPARE_EQ_I8_I8(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 == ics.rf[i->src2_reg].i8; return IA_NEXT; } +uint32_t IntCode_COMPARE_EQ_I16_I16(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i16 == ics.rf[i->src2_reg].i16; return IA_NEXT; } +uint32_t IntCode_COMPARE_EQ_I32_I32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i32 == ics.rf[i->src2_reg].i32; return IA_NEXT; } +uint32_t IntCode_COMPARE_EQ_I64_I64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i64 == ics.rf[i->src2_reg].i64; return IA_NEXT; } +uint32_t IntCode_COMPARE_EQ_F32_F32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f32 == ics.rf[i->src2_reg].f32; return IA_NEXT; } +uint32_t IntCode_COMPARE_EQ_F64_F64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f64 == ics.rf[i->src2_reg].f64; return IA_NEXT; } +int Translate_COMPARE_EQ(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_COMPARE_EQ_I8_I8, + IntCode_COMPARE_EQ_I16_I16, + IntCode_COMPARE_EQ_I32_I32, + IntCode_COMPARE_EQ_I64_I64, + IntCode_COMPARE_EQ_F32_F32, + IntCode_COMPARE_EQ_F64_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_COMPARE_NE_I8_I8(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 != ics.rf[i->src2_reg].i8; return IA_NEXT; } +uint32_t IntCode_COMPARE_NE_I16_I16(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i16 != ics.rf[i->src2_reg].i16; return IA_NEXT; } +uint32_t IntCode_COMPARE_NE_I32_I32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i32 != ics.rf[i->src2_reg].i32; return IA_NEXT; } +uint32_t IntCode_COMPARE_NE_I64_I64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i64 != ics.rf[i->src2_reg].i64; return IA_NEXT; } +uint32_t IntCode_COMPARE_NE_F32_F32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f32 != ics.rf[i->src2_reg].f32; return IA_NEXT; } +uint32_t IntCode_COMPARE_NE_F64_F64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f64 != ics.rf[i->src2_reg].f64; return IA_NEXT; } +int Translate_COMPARE_NE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_COMPARE_NE_I8_I8, + IntCode_COMPARE_NE_I16_I16, + IntCode_COMPARE_NE_I32_I32, + IntCode_COMPARE_NE_I64_I64, + IntCode_COMPARE_NE_F32_F32, + IntCode_COMPARE_NE_F64_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_COMPARE_SLT_I8_I8(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 < ics.rf[i->src2_reg].i8; return IA_NEXT; } +uint32_t IntCode_COMPARE_SLT_I16_I16(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i16 < ics.rf[i->src2_reg].i16; return IA_NEXT; } +uint32_t IntCode_COMPARE_SLT_I32_I32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i32 < ics.rf[i->src2_reg].i32; return IA_NEXT; } +uint32_t IntCode_COMPARE_SLT_I64_I64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i64 < ics.rf[i->src2_reg].i64; return IA_NEXT; } +uint32_t IntCode_COMPARE_SLT_F32_F32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f32 < ics.rf[i->src2_reg].f32; return IA_NEXT; } +uint32_t IntCode_COMPARE_SLT_F64_F64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f64 < ics.rf[i->src2_reg].f64; return IA_NEXT; } +int Translate_COMPARE_SLT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_COMPARE_SLT_I8_I8, + IntCode_COMPARE_SLT_I16_I16, + IntCode_COMPARE_SLT_I32_I32, + IntCode_COMPARE_SLT_I64_I64, + IntCode_COMPARE_SLT_F32_F32, + IntCode_COMPARE_SLT_F64_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_COMPARE_SLE_I8_I8(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 <= ics.rf[i->src2_reg].i8; return IA_NEXT; } +uint32_t IntCode_COMPARE_SLE_I16_I16(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i16 <= ics.rf[i->src2_reg].i16; return IA_NEXT; } +uint32_t IntCode_COMPARE_SLE_I32_I32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i32 <= ics.rf[i->src2_reg].i32; return IA_NEXT; } +uint32_t IntCode_COMPARE_SLE_I64_I64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i64 <= ics.rf[i->src2_reg].i64; return IA_NEXT; } +uint32_t IntCode_COMPARE_SLE_F32_F32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f32 <= ics.rf[i->src2_reg].f32; return IA_NEXT; } +uint32_t IntCode_COMPARE_SLE_F64_F64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f64 <= ics.rf[i->src2_reg].f64; return IA_NEXT; } +int Translate_COMPARE_SLE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_COMPARE_SLE_I8_I8, + IntCode_COMPARE_SLE_I16_I16, + IntCode_COMPARE_SLE_I32_I32, + IntCode_COMPARE_SLE_I64_I64, + IntCode_COMPARE_SLE_F32_F32, + IntCode_COMPARE_SLE_F64_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_COMPARE_SGT_I8_I8(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 > ics.rf[i->src2_reg].i8; return IA_NEXT; } +uint32_t IntCode_COMPARE_SGT_I16_I16(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i16 > ics.rf[i->src2_reg].i16; return IA_NEXT; } +uint32_t IntCode_COMPARE_SGT_I32_I32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i32 > ics.rf[i->src2_reg].i32; return IA_NEXT; } +uint32_t IntCode_COMPARE_SGT_I64_I64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i64 > ics.rf[i->src2_reg].i64; return IA_NEXT; } +uint32_t IntCode_COMPARE_SGT_F32_F32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f32 > ics.rf[i->src2_reg].f32; return IA_NEXT; } +uint32_t IntCode_COMPARE_SGT_F64_F64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f64 > ics.rf[i->src2_reg].f64; return IA_NEXT; } +int Translate_COMPARE_SGT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_COMPARE_SGT_I8_I8, + IntCode_COMPARE_SGT_I16_I16, + IntCode_COMPARE_SGT_I32_I32, + IntCode_COMPARE_SGT_I64_I64, + IntCode_COMPARE_SGT_F32_F32, + IntCode_COMPARE_SGT_F64_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_COMPARE_SGE_I8_I8(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 >= ics.rf[i->src2_reg].i8; return IA_NEXT; } +uint32_t IntCode_COMPARE_SGE_I16_I16(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i16 >= ics.rf[i->src2_reg].i16; return IA_NEXT; } +uint32_t IntCode_COMPARE_SGE_I32_I32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i32 >= ics.rf[i->src2_reg].i32; return IA_NEXT; } +uint32_t IntCode_COMPARE_SGE_I64_I64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i64 >= ics.rf[i->src2_reg].i64; return IA_NEXT; } +uint32_t IntCode_COMPARE_SGE_F32_F32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f32 >= ics.rf[i->src2_reg].f32; return IA_NEXT; } +uint32_t IntCode_COMPARE_SGE_F64_F64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f64 >= ics.rf[i->src2_reg].f64; return IA_NEXT; } +int Translate_COMPARE_SGE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_COMPARE_SGE_I8_I8, + IntCode_COMPARE_SGE_I16_I16, + IntCode_COMPARE_SGE_I32_I32, + IntCode_COMPARE_SGE_I64_I64, + IntCode_COMPARE_SGE_F32_F32, + IntCode_COMPARE_SGE_F64_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_COMPARE_ULT_I8_I8(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u8 < ics.rf[i->src2_reg].u8; return IA_NEXT; } +uint32_t IntCode_COMPARE_ULT_I16_I16(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u16 < ics.rf[i->src2_reg].u16; return IA_NEXT; } +uint32_t IntCode_COMPARE_ULT_I32_I32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u32 < ics.rf[i->src2_reg].u32; return IA_NEXT; } +uint32_t IntCode_COMPARE_ULT_I64_I64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u64 < ics.rf[i->src2_reg].u64; return IA_NEXT; } +uint32_t IntCode_COMPARE_ULT_F32_F32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f32 < ics.rf[i->src2_reg].f32; return IA_NEXT; } +uint32_t IntCode_COMPARE_ULT_F64_F64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f64 < ics.rf[i->src2_reg].f64; return IA_NEXT; } +int Translate_COMPARE_ULT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_COMPARE_ULT_I8_I8, + IntCode_COMPARE_ULT_I16_I16, + IntCode_COMPARE_ULT_I32_I32, + IntCode_COMPARE_ULT_I64_I64, + IntCode_COMPARE_ULT_F32_F32, + IntCode_COMPARE_ULT_F64_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_COMPARE_ULE_I8_I8(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u8 <= ics.rf[i->src2_reg].u8; return IA_NEXT; } +uint32_t IntCode_COMPARE_ULE_I16_I16(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u16 <= ics.rf[i->src2_reg].u16; return IA_NEXT; } +uint32_t IntCode_COMPARE_ULE_I32_I32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u32 <= ics.rf[i->src2_reg].u32; return IA_NEXT; } +uint32_t IntCode_COMPARE_ULE_I64_I64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u64 <= ics.rf[i->src2_reg].u64; return IA_NEXT; } +uint32_t IntCode_COMPARE_ULE_F32_F32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f32 <= ics.rf[i->src2_reg].f32; return IA_NEXT; } +uint32_t IntCode_COMPARE_ULE_F64_F64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f64 <= ics.rf[i->src2_reg].f64; return IA_NEXT; } +int Translate_COMPARE_ULE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_COMPARE_ULE_I8_I8, + IntCode_COMPARE_ULE_I16_I16, + IntCode_COMPARE_ULE_I32_I32, + IntCode_COMPARE_ULE_I64_I64, + IntCode_COMPARE_ULE_F32_F32, + IntCode_COMPARE_ULE_F64_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_COMPARE_UGT_I8_I8(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u8 > ics.rf[i->src2_reg].u8; return IA_NEXT; } +uint32_t IntCode_COMPARE_UGT_I16_I16(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u16 > ics.rf[i->src2_reg].u16; return IA_NEXT; } +uint32_t IntCode_COMPARE_UGT_I32_I32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u32 > ics.rf[i->src2_reg].u32; return IA_NEXT; } +uint32_t IntCode_COMPARE_UGT_I64_I64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u64 > ics.rf[i->src2_reg].u64; return IA_NEXT; } +uint32_t IntCode_COMPARE_UGT_F32_F32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f32 > ics.rf[i->src2_reg].f32; return IA_NEXT; } +uint32_t IntCode_COMPARE_UGT_F64_F64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f64 > ics.rf[i->src2_reg].f64; return IA_NEXT; } +int Translate_COMPARE_UGT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_COMPARE_UGT_I8_I8, + IntCode_COMPARE_UGT_I16_I16, + IntCode_COMPARE_UGT_I32_I32, + IntCode_COMPARE_UGT_I64_I64, + IntCode_COMPARE_UGT_F32_F32, + IntCode_COMPARE_UGT_F64_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_COMPARE_UGE_I8_I8(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u8 >= ics.rf[i->src2_reg].u8; return IA_NEXT; } +uint32_t IntCode_COMPARE_UGE_I16_I16(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u16 >= ics.rf[i->src2_reg].u16; return IA_NEXT; } +uint32_t IntCode_COMPARE_UGE_I32_I32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u32 >= ics.rf[i->src2_reg].u32; return IA_NEXT; } +uint32_t IntCode_COMPARE_UGE_I64_I64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u64 >= ics.rf[i->src2_reg].u64; return IA_NEXT; } +uint32_t IntCode_COMPARE_UGE_F32_F32(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f32 >= ics.rf[i->src2_reg].f32; return IA_NEXT; } +uint32_t IntCode_COMPARE_UGE_F64_F64(IntCodeState& ics, const IntCode* i) { ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].f64 >= ics.rf[i->src2_reg].f64; return IA_NEXT; } +int Translate_COMPARE_UGE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_COMPARE_UGE_I8_I8, + IntCode_COMPARE_UGE_I16_I16, + IntCode_COMPARE_UGE_I32_I32, + IntCode_COMPARE_UGE_I64_I64, + IntCode_COMPARE_UGE_F32_F32, + IntCode_COMPARE_UGE_F64_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_DID_CARRY(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.did_carry; + return IA_NEXT; +} +int Translate_DID_CARRY(TranslationContext& ctx, Instr* i) { + return DispatchToC(ctx, i, IntCode_DID_CARRY); +} + +#define VECTOR_COMPARER(type, value, count, op) \ + const vec128_t& src1 = ics.rf[i->src1_reg].v128; \ + const vec128_t& src2 = ics.rf[i->src2_reg].v128; \ + vec128_t& dest = ics.rf[i->dest_reg].v128; \ + for (int n = 0; n < count; n++) { \ + dest.value[n] = (type)src1.value[n] op (type)src1.value[n]; \ + } \ + return IA_NEXT; + +uint32_t IntCode_VECTOR_COMPARE_EQ_I8(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(uint8_t, b16, 16, ==) }; +uint32_t IntCode_VECTOR_COMPARE_EQ_I16(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(uint16_t, s8, 8, ==) }; +uint32_t IntCode_VECTOR_COMPARE_EQ_I32(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(uint32_t, i4, 4, ==) }; +uint32_t IntCode_VECTOR_COMPARE_EQ_F32(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(float, f4, 4, ==) }; +int Translate_VECTOR_COMPARE_EQ(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_VECTOR_COMPARE_EQ_I8, + IntCode_VECTOR_COMPARE_EQ_I16, + IntCode_VECTOR_COMPARE_EQ_I32, + IntCode_INVALID_TYPE, + IntCode_VECTOR_COMPARE_EQ_F32, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->flags]); +} + +uint32_t IntCode_VECTOR_COMPARE_SGT_I8(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(int8_t, b16, 16, >) }; +uint32_t IntCode_VECTOR_COMPARE_SGT_I16(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(int16_t, s8, 8, >) }; +uint32_t IntCode_VECTOR_COMPARE_SGT_I32(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(int32_t, i4, 4, >) }; +uint32_t IntCode_VECTOR_COMPARE_SGT_F32(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(float, f4, 4, >) }; +int Translate_VECTOR_COMPARE_SGT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_VECTOR_COMPARE_SGT_I8, + IntCode_VECTOR_COMPARE_SGT_I16, + IntCode_VECTOR_COMPARE_SGT_I32, + IntCode_INVALID_TYPE, + IntCode_VECTOR_COMPARE_SGT_F32, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->flags]); +} + +uint32_t IntCode_VECTOR_COMPARE_SGE_I8(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(int8_t, b16, 16, >=) }; +uint32_t IntCode_VECTOR_COMPARE_SGE_I16(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(int16_t, s8, 8, >=) }; +uint32_t IntCode_VECTOR_COMPARE_SGE_I32(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(int32_t, i4, 4, >=) }; +uint32_t IntCode_VECTOR_COMPARE_SGE_F32(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(float, f4, 4, >=) }; +int Translate_VECTOR_COMPARE_SGE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_VECTOR_COMPARE_SGE_I8, + IntCode_VECTOR_COMPARE_SGE_I16, + IntCode_VECTOR_COMPARE_SGE_I32, + IntCode_INVALID_TYPE, + IntCode_VECTOR_COMPARE_SGE_F32, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->flags]); +} + +uint32_t IntCode_VECTOR_COMPARE_UGT_I8(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(uint8_t, b16, 16, >) }; +uint32_t IntCode_VECTOR_COMPARE_UGT_I16(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(uint16_t, s8, 8, >) }; +uint32_t IntCode_VECTOR_COMPARE_UGT_I32(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(uint32_t, i4, 4, >) }; +uint32_t IntCode_VECTOR_COMPARE_UGT_F32(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(float, f4, 4, >) }; +int Translate_VECTOR_COMPARE_UGT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_VECTOR_COMPARE_UGT_I8, + IntCode_VECTOR_COMPARE_UGT_I16, + IntCode_VECTOR_COMPARE_UGT_I32, + IntCode_INVALID_TYPE, + IntCode_VECTOR_COMPARE_UGT_F32, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->flags]); +} + +uint32_t IntCode_VECTOR_COMPARE_UGE_I8(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(uint8_t, b16, 16, >=) }; +uint32_t IntCode_VECTOR_COMPARE_UGE_I16(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(uint16_t, s8, 8, >=) }; +uint32_t IntCode_VECTOR_COMPARE_UGE_I32(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(uint32_t, i4, 4, >=) }; +uint32_t IntCode_VECTOR_COMPARE_UGE_F32(IntCodeState& ics, const IntCode* i) { VECTOR_COMPARER(float, f4, 4, >=) }; +int Translate_VECTOR_COMPARE_UGE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_VECTOR_COMPARE_UGE_I8, + IntCode_VECTOR_COMPARE_UGE_I16, + IntCode_VECTOR_COMPARE_UGE_I32, + IntCode_INVALID_TYPE, + IntCode_VECTOR_COMPARE_UGE_F32, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->flags]); +} + +#define CHECK_DID_CARRY(v1, v2) ((v2) > ~(v1)) +#define ADD_DID_CARRY(a, b) CHECK_DID_CARRY(a, b) +uint32_t IntCode_ADD_I8_I8(IntCodeState& ics, const IntCode* i) { + int8_t a = ics.rf[i->src1_reg].i8; int8_t b = ics.rf[i->src2_reg].i8; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = ADD_DID_CARRY(a, b); + } + ics.rf[i->dest_reg].i8 = a + b; + return IA_NEXT; +} +uint32_t IntCode_ADD_I16_I16(IntCodeState& ics, const IntCode* i) { + int16_t a = ics.rf[i->src1_reg].i16; int16_t b = ics.rf[i->src2_reg].i16; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = ADD_DID_CARRY(a, b); + } + ics.rf[i->dest_reg].i16 = a + b; + return IA_NEXT; +} +uint32_t IntCode_ADD_I32_I32(IntCodeState& ics, const IntCode* i) { + int32_t a = ics.rf[i->src1_reg].i32; int32_t b = ics.rf[i->src2_reg].i32; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = ADD_DID_CARRY(a, b); + } + ics.rf[i->dest_reg].i32 = a + b; + return IA_NEXT; +} +uint32_t IntCode_ADD_I64_I64(IntCodeState& ics, const IntCode* i) { + int64_t a = ics.rf[i->src1_reg].i64; int64_t b = ics.rf[i->src2_reg].i64; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = ADD_DID_CARRY(a, b); + } + ics.rf[i->dest_reg].i64 = a + b; + return IA_NEXT; +} +uint32_t IntCode_ADD_F32_F32(IntCodeState& ics, const IntCode* i) { + XEASSERT(!i->flags); + ics.rf[i->dest_reg].f32 = ics.rf[i->src1_reg].f32 + ics.rf[i->src2_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_ADD_F64_F64(IntCodeState& ics, const IntCode* i) { + XEASSERT(!i->flags); + ics.rf[i->dest_reg].f64 = ics.rf[i->src1_reg].f64 + ics.rf[i->src2_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_ADD_V128_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.f4[n] = src1.f4[n] + src2.f4[n]; + } + return IA_NEXT; +} +int Translate_ADD(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_ADD_I8_I8, + IntCode_ADD_I16_I16, + IntCode_ADD_I32_I32, + IntCode_ADD_I64_I64, + IntCode_ADD_F32_F32, + IntCode_ADD_F64_F64, + IntCode_ADD_V128_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +#define ADD_CARRY_DID_CARRY(a, b, c) \ + (CHECK_DID_CARRY(a, b) || ((c) != 0) && CHECK_DID_CARRY((a) + (b), c)) +uint32_t IntCode_ADD_CARRY_I8_I8(IntCodeState& ics, const IntCode* i) { + int8_t a = ics.rf[i->src1_reg].i8; int8_t b = ics.rf[i->src2_reg].i8; uint8_t c = ics.rf[i->src3_reg].u8; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = ADD_CARRY_DID_CARRY(a, b, c); + } + ics.rf[i->dest_reg].i8 = a + b + c; + return IA_NEXT; +} +uint32_t IntCode_ADD_CARRY_I16_I16(IntCodeState& ics, const IntCode* i) { + int16_t a = ics.rf[i->src1_reg].i16; int16_t b = ics.rf[i->src2_reg].i16; uint8_t c = ics.rf[i->src3_reg].u8; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = ADD_CARRY_DID_CARRY(a, b, c); + } + ics.rf[i->dest_reg].i16 = a + b + c; + return IA_NEXT; +} +uint32_t IntCode_ADD_CARRY_I32_I32(IntCodeState& ics, const IntCode* i) { + int32_t a = ics.rf[i->src1_reg].i32; int32_t b = ics.rf[i->src2_reg].i32; uint8_t c = ics.rf[i->src3_reg].u8; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = ADD_CARRY_DID_CARRY(a, b, c); + } + ics.rf[i->dest_reg].i32 = a + b + c; + return IA_NEXT; +} +uint32_t IntCode_ADD_CARRY_I64_I64(IntCodeState& ics, const IntCode* i) { + int64_t a = ics.rf[i->src1_reg].i64; int64_t b = ics.rf[i->src2_reg].i64; uint8_t c = ics.rf[i->src3_reg].u8; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = ADD_CARRY_DID_CARRY(a, b, c); + } + ics.rf[i->dest_reg].i64 = a + b + c; + return IA_NEXT; +} +uint32_t IntCode_ADD_CARRY_F32_F32(IntCodeState& ics, const IntCode* i) { + XEASSERT(!i->flags); + ics.rf[i->dest_reg].f32 = ics.rf[i->src1_reg].f32 + ics.rf[i->src2_reg].f32 + ics.rf[i->src3_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_ADD_CARRY_F64_F64(IntCodeState& ics, const IntCode* i) { + XEASSERT(!i->flags); + ics.rf[i->dest_reg].f64 = ics.rf[i->src1_reg].f64 + ics.rf[i->src2_reg].f64 + ics.rf[i->src3_reg].i8; + return IA_NEXT; +} +int Translate_ADD_CARRY(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_ADD_CARRY_I8_I8, + IntCode_ADD_CARRY_I16_I16, + IntCode_ADD_CARRY_I32_I32, + IntCode_ADD_CARRY_I64_I64, + IntCode_ADD_CARRY_F32_F32, + IntCode_ADD_CARRY_F64_F64, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +#define SUB_DID_CARRY(a, b) \ + ((b) == 0) || CHECK_DID_CARRY(a, 0 - b) +uint32_t IntCode_SUB_I8_I8(IntCodeState& ics, const IntCode* i) { + int8_t a = ics.rf[i->src1_reg].i8; int8_t b = ics.rf[i->src2_reg].i8; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = SUB_DID_CARRY(a, b); + } + ics.rf[i->dest_reg].i8 = a - b; + return IA_NEXT; +} +uint32_t IntCode_SUB_I16_I16(IntCodeState& ics, const IntCode* i) { + int16_t a = ics.rf[i->src1_reg].i16; int16_t b = ics.rf[i->src2_reg].i16; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = SUB_DID_CARRY(a, b); + } + ics.rf[i->dest_reg].i16 = a - b; + return IA_NEXT; +} +uint32_t IntCode_SUB_I32_I32(IntCodeState& ics, const IntCode* i) { + int32_t a = ics.rf[i->src1_reg].i32; int32_t b = ics.rf[i->src2_reg].i32; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = a < ~b; + } + ics.did_carry = SUB_DID_CARRY(a, b); + return IA_NEXT; +} +uint32_t IntCode_SUB_I64_I64(IntCodeState& ics, const IntCode* i) { + int64_t a = ics.rf[i->src1_reg].i64; int64_t b = ics.rf[i->src2_reg].i64; + if (i->flags == ARITHMETIC_SET_CARRY) { + ics.did_carry = SUB_DID_CARRY(a, b); + } + ics.rf[i->dest_reg].i64 = a - b; + return IA_NEXT; +} +uint32_t IntCode_SUB_F32_F32(IntCodeState& ics, const IntCode* i) { + XEASSERT(!i->flags); + ics.rf[i->dest_reg].f32 = ics.rf[i->src1_reg].f32 - ics.rf[i->src2_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_SUB_F64_F64(IntCodeState& ics, const IntCode* i) { + XEASSERT(!i->flags); + ics.rf[i->dest_reg].f64 = ics.rf[i->src1_reg].f64 - ics.rf[i->src2_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_SUB_V128_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.f4[n] = src1.f4[n] - src2.f4[n]; + } + return IA_NEXT; +} +int Translate_SUB(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_SUB_I8_I8, + IntCode_SUB_I16_I16, + IntCode_SUB_I32_I32, + IntCode_SUB_I64_I64, + IntCode_SUB_F32_F32, + IntCode_SUB_F64_F64, + IntCode_SUB_V128_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_MUL_I8_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 * ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_MUL_I16_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].i16 * ics.rf[i->src2_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_MUL_I32_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].i32 * ics.rf[i->src2_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_MUL_I64_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].i64 * ics.rf[i->src2_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_MUL_F32_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = ics.rf[i->src1_reg].f32 * ics.rf[i->src2_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_MUL_F64_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = ics.rf[i->src1_reg].f64 * ics.rf[i->src2_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_MUL_V128_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.f4[n] = src1.f4[n] * src2.f4[n]; + } + return IA_NEXT; +} +int Translate_MUL(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_MUL_I8_I8, + IntCode_MUL_I16_I16, + IntCode_MUL_I32_I32, + IntCode_MUL_I64_I64, + IntCode_MUL_F32_F32, + IntCode_MUL_F64_F64, + IntCode_MUL_V128_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_DIV_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 / ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_DIV_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].i16 / ics.rf[i->src2_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_DIV_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].i32 / ics.rf[i->src2_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_DIV_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].i64 / ics.rf[i->src2_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_DIV_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = ics.rf[i->src1_reg].f32 / ics.rf[i->src2_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_DIV_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = ics.rf[i->src1_reg].f64 / ics.rf[i->src2_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_DIV_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.f4[n] = src1.f4[n] / src2.f4[n]; + } + return IA_NEXT; +} +int Translate_DIV(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_DIV_I8, + IntCode_DIV_I16, + IntCode_DIV_I32, + IntCode_DIV_I64, + IntCode_DIV_F32, + IntCode_DIV_F64, + IntCode_DIV_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +// TODO(benvanik): use intrinsics or something +uint32_t IntCode_MULADD_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 * ics.rf[i->src2_reg].i8 + ics.rf[i->src3_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_MULADD_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].i16 * ics.rf[i->src2_reg].i16 + ics.rf[i->src3_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_MULADD_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].i32 * ics.rf[i->src2_reg].i32 + ics.rf[i->src3_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_MULADD_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].i64 * ics.rf[i->src2_reg].i64 + ics.rf[i->src3_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_MULADD_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = ics.rf[i->src1_reg].f32 * ics.rf[i->src2_reg].f32 + ics.rf[i->src3_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_MULADD_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = ics.rf[i->src1_reg].f64 * ics.rf[i->src2_reg].f64 + ics.rf[i->src3_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_MULADD_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + const vec128_t& src3 = ics.rf[i->src3_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.f4[n] = src1.f4[n] * src2.f4[n] + src3.f4[n]; + } + return IA_NEXT; +} +int Translate_MULADD(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_MULADD_I8, + IntCode_MULADD_I16, + IntCode_MULADD_I32, + IntCode_MULADD_I64, + IntCode_MULADD_F32, + IntCode_MULADD_F64, + IntCode_MULADD_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +// TODO(benvanik): use intrinsics or something +uint32_t IntCode_MULSUB_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 * ics.rf[i->src2_reg].i8 - ics.rf[i->src3_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_MULSUB_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].i16 * ics.rf[i->src2_reg].i16 - ics.rf[i->src3_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_MULSUB_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].i32 * ics.rf[i->src2_reg].i32 - ics.rf[i->src3_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_MULSUB_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].i64 * ics.rf[i->src2_reg].i64 - ics.rf[i->src3_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_MULSUB_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = ics.rf[i->src1_reg].f32 * ics.rf[i->src2_reg].f32 - ics.rf[i->src3_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_MULSUB_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = ics.rf[i->src1_reg].f64 * ics.rf[i->src2_reg].f64 - ics.rf[i->src3_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_MULSUB_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + const vec128_t& src3 = ics.rf[i->src3_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.f4[n] = src1.f4[n] * src2.f4[n] - src3.f4[n]; + } + return IA_NEXT; +} +int Translate_MULSUB(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_MULSUB_I8, + IntCode_MULSUB_I16, + IntCode_MULSUB_I32, + IntCode_MULSUB_I64, + IntCode_MULSUB_F32, + IntCode_MULSUB_F64, + IntCode_MULSUB_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_NEG_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = -ics.rf[i->src1_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_NEG_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = -ics.rf[i->src1_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_NEG_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = -ics.rf[i->src1_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_NEG_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = -ics.rf[i->src1_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_NEG_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = -ics.rf[i->src1_reg].f32; + return IA_NEXT; +} +uint32_t IntCode_NEG_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = -ics.rf[i->src1_reg].f64; + return IA_NEXT; +} +uint32_t IntCode_NEG_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (size_t i = 0; i < 4; i++) { + dest.f4[i] = -src1.f4[i]; + } + return IA_NEXT; +} +int Translate_NEG(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_NEG_I8, + IntCode_NEG_I16, + IntCode_NEG_I32, + IntCode_NEG_I64, + IntCode_NEG_F32, + IntCode_NEG_F64, + IntCode_NEG_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_ABS_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = abs(ics.rf[i->src1_reg].i8); + return IA_NEXT; +} +uint32_t IntCode_ABS_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = abs(ics.rf[i->src1_reg].i16); + return IA_NEXT; +} +uint32_t IntCode_ABS_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = abs(ics.rf[i->src1_reg].i32); + return IA_NEXT; +} +uint32_t IntCode_ABS_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = abs(ics.rf[i->src1_reg].i64); + return IA_NEXT; +} +uint32_t IntCode_ABS_F32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f32 = abs(ics.rf[i->src1_reg].f32); + return IA_NEXT; +} +uint32_t IntCode_ABS_F64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].f64 = abs(ics.rf[i->src1_reg].f64); + return IA_NEXT; +} +uint32_t IntCode_ABS_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (size_t i = 0; i < 4; i++) { + dest.f4[i] = abs(src1.f4[i]); + } + return IA_NEXT; +} +int Translate_ABS(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_ABS_I8, + IntCode_ABS_I16, + IntCode_ABS_I32, + IntCode_ABS_I64, + IntCode_ABS_F32, + IntCode_ABS_F64, + IntCode_ABS_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_DOT_PRODUCT_3_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src1_reg].v128; + ics.rf[i->dest_reg].f32 = + (src1.x * src2.x) + (src1.y * src2.y) + (src1.z * src2.z); + return IA_NEXT; +} +int Translate_DOT_PRODUCT_3(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_DOT_PRODUCT_3_V128, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_DOT_PRODUCT_4_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src1_reg].v128; + ics.rf[i->dest_reg].f32 = + (src1.x * src2.x) + (src1.y * src2.y) + (src1.z * src2.z) + (src1.w * src2.w); + return IA_NEXT; +} +int Translate_DOT_PRODUCT_4(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_DOT_PRODUCT_4_V128, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_RSQRT_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.f4[n] = 1 / sqrtf(src1.f4[n]); + } + return IA_NEXT; +} +int Translate_RSQRT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_RSQRT_V128, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_AND_I8_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 & ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_AND_I16_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].i16 & ics.rf[i->src2_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_AND_I32_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].i32 & ics.rf[i->src2_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_AND_I64_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].i64 & ics.rf[i->src2_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_AND_V128_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.i4[n] = src1.i4[n] & src2.i4[n]; + } + return IA_NEXT; +} +int Translate_AND(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_AND_I8_I8, + IntCode_AND_I16_I16, + IntCode_AND_I32_I32, + IntCode_AND_I64_I64, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_AND_V128_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_OR_I8_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 | ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_OR_I16_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].i16 | ics.rf[i->src2_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_OR_I32_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].i32 | ics.rf[i->src2_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_OR_I64_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].i64 | ics.rf[i->src2_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_OR_V128_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.i4[n] = src1.i4[n] | src2.i4[n]; + } + return IA_NEXT; +} +int Translate_OR(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_OR_I8_I8, + IntCode_OR_I16_I16, + IntCode_OR_I32_I32, + IntCode_OR_I64_I64, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_OR_V128_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_XOR_I8_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 ^ ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_XOR_I16_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].i16 ^ ics.rf[i->src2_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_XOR_I32_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].i32 ^ ics.rf[i->src2_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_XOR_I64_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].i64 ^ ics.rf[i->src2_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_XOR_V128_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.i4[n] = src1.i4[n] ^ src2.i4[n]; + } + return IA_NEXT; +} +int Translate_XOR(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_XOR_I8_I8, + IntCode_XOR_I16_I16, + IntCode_XOR_I32_I32, + IntCode_XOR_I64_I64, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_XOR_V128_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_NOT_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ~ics.rf[i->src1_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_NOT_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ~ics.rf[i->src1_reg].i16; + return IA_NEXT; +} +uint32_t IntCode_NOT_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ~ics.rf[i->src1_reg].i32; + return IA_NEXT; +} +uint32_t IntCode_NOT_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ~ics.rf[i->src1_reg].i64; + return IA_NEXT; +} +uint32_t IntCode_NOT_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.i4[n] = ~src1.i4[n]; + } + return IA_NEXT; +} +int Translate_NOT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_NOT_I8, + IntCode_NOT_I16, + IntCode_NOT_I32, + IntCode_NOT_I64, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_NOT_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_SHL_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 << ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SHL_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].i16 << ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SHL_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].i32 << ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SHL_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].i64 << ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +int Translate_SHL(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_SHL_I8, + IntCode_SHL_I16, + IntCode_SHL_I32, + IntCode_SHL_I64, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_VECTOR_SHL_I8(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 16; n++) { + dest.b16[n] = src1.b16[n] << src2.b16[n] & 0x7; + } + return IA_NEXT; +} +uint32_t IntCode_VECTOR_SHL_I16(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 8; n++) { + dest.s8[n] = src1.s8[n] << src2.s8[n] & 0xF; + } + return IA_NEXT; +} +uint32_t IntCode_VECTOR_SHL_I32(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (int n = 0; n < 4; n++) { + dest.i4[n] = src1.i4[n] << src2.i4[n] & 0x1F; + } + return IA_NEXT; +} +int Translate_VECTOR_SHL(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_VECTOR_SHL_I8, + IntCode_VECTOR_SHL_I16, + IntCode_VECTOR_SHL_I32, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->flags]); +} + +uint32_t IntCode_SHR_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].u8 >> ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SHR_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].u16 >> ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SHR_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].u32 >> ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SHR_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].u64 >> ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +int Translate_SHR(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_SHR_I8, + IntCode_SHR_I16, + IntCode_SHR_I32, + IntCode_SHR_I64, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_SHA_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ics.rf[i->src1_reg].i8 >> ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SHA_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ics.rf[i->src1_reg].i16 >> ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SHA_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ics.rf[i->src1_reg].i32 >> ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +uint32_t IntCode_SHA_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ics.rf[i->src1_reg].i64 >> ics.rf[i->src2_reg].i8; + return IA_NEXT; +} +int Translate_SHA(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_SHA_I8, + IntCode_SHA_I16, + IntCode_SHA_I32, + IntCode_SHA_I64, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +#define ROTL8(v, n) \ + (uint8_t((v) << (n)) | ((v) >> (8 - (n)))) +#define ROTL16(v, n) \ + (uint16_t((v) << (n)) | ((v) >> (16 - (n)))) +#define ROTL32(v, n) \ + (uint32_t((v) << (n)) | ((v) >> (32 - (n)))) +#define ROTL64(v, n) \ + (uint64_t((v) << (n)) | ((v) >> (64 - (n)))) +uint32_t IntCode_ROTATE_LEFT_I8(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i8 = ROTL8(ics.rf[i->src1_reg].i8, ics.rf[i->src2_reg].i8); + return IA_NEXT; +} +uint32_t IntCode_ROTATE_LEFT_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = ROTL16(ics.rf[i->src1_reg].i16, ics.rf[i->src2_reg].i8); + return IA_NEXT; +} +uint32_t IntCode_ROTATE_LEFT_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = ROTL32(ics.rf[i->src1_reg].i32, ics.rf[i->src2_reg].i8); + return IA_NEXT; +} +uint32_t IntCode_ROTATE_LEFT_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = ROTL64(ics.rf[i->src1_reg].i64, ics.rf[i->src2_reg].i8); + return IA_NEXT; +} +int Translate_ROTATE_LEFT(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_ROTATE_LEFT_I8, + IntCode_ROTATE_LEFT_I16, + IntCode_ROTATE_LEFT_I32, + IntCode_ROTATE_LEFT_I64, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_BYTE_SWAP_I16(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i16 = XESWAP16(ics.rf[i->src1_reg].i16); + return IA_NEXT; +} +uint32_t IntCode_BYTE_SWAP_I32(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i32 = XESWAP32(ics.rf[i->src1_reg].i32); + return IA_NEXT; +} +uint32_t IntCode_BYTE_SWAP_I64(IntCodeState& ics, const IntCode* i) { + ics.rf[i->dest_reg].i64 = XESWAP64(ics.rf[i->src1_reg].i64); + return IA_NEXT; +} +uint32_t IntCode_BYTE_SWAP_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + dest.low = XESWAP64(src1.high); + dest.high = XESWAP64(src1.low); + return IA_NEXT; +} +int Translate_BYTE_SWAP(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_INVALID_TYPE, + IntCode_BYTE_SWAP_I16, + IntCode_BYTE_SWAP_I32, + IntCode_BYTE_SWAP_I64, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_BYTE_SWAP_V128, + }; + return DispatchToC(ctx, i, fns[i->dest->type]); +} + +uint32_t IntCode_CNTLZ_I8(IntCodeState& ics, const IntCode* i) { + // CHECK + XEASSERTALWAYS(); + DWORD index; + DWORD mask = ics.rf[i->src1_reg].i16; + BOOLEAN is_nonzero = _BitScanReverse(&index, mask); + ics.rf[i->dest_reg].i8 = is_nonzero ? (int8_t)(index - 24) ^ 0x7 : 0x7; + return IA_NEXT; +} +uint32_t IntCode_CNTLZ_I16(IntCodeState& ics, const IntCode* i) { + // CHECK + XEASSERTALWAYS(); + DWORD index; + DWORD mask = ics.rf[i->src1_reg].i16; + BOOLEAN is_nonzero = _BitScanReverse(&index, mask); + ics.rf[i->dest_reg].i8 = is_nonzero ? (int8_t)(index - 16) ^ 0xF : 0xF; + return IA_NEXT; +} +uint32_t IntCode_CNTLZ_I32(IntCodeState& ics, const IntCode* i) { + DWORD index; + DWORD mask = ics.rf[i->src1_reg].i32; + BOOLEAN is_nonzero = _BitScanReverse(&index, mask); + ics.rf[i->dest_reg].i8 = is_nonzero ? (int8_t)index ^ 0x1F : 0x1F; + return IA_NEXT; +} +uint32_t IntCode_CNTLZ_I64(IntCodeState& ics, const IntCode* i) { + DWORD index; + DWORD64 mask = ics.rf[i->src1_reg].i64; + BOOLEAN is_nonzero = _BitScanReverse64(&index, mask); + ics.rf[i->dest_reg].i8 = is_nonzero ? (int8_t)index ^ 0x3F : 0x3F; + return IA_NEXT; +} +int Translate_CNTLZ(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_CNTLZ_I8, + IntCode_CNTLZ_I16, + IntCode_CNTLZ_I32, + IntCode_CNTLZ_I64, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +uint32_t IntCode_EXTRACT_INT8_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + ics.rf[i->dest_reg].i8 = src1.b16[ics.rf[i->src2_reg].i64]; + return IA_NEXT; +} +uint32_t IntCode_EXTRACT_INT16_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + ics.rf[i->dest_reg].i16 = src1.s8[ics.rf[i->src2_reg].i64]; + return IA_NEXT; +} +uint32_t IntCode_EXTRACT_INT32_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + ics.rf[i->dest_reg].i32 = src1.i4[ics.rf[i->src2_reg].i64]; + return IA_NEXT; +} +int Translate_EXTRACT(TranslationContext& ctx, Instr* i) { + // Can do more as needed. + static IntCodeFn fns[] = { + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_EXTRACT_INT8_V128, IntCode_EXTRACT_INT16_V128, IntCode_EXTRACT_INT32_V128, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + }; + IntCodeFn fn = fns[i->src1.value->type * MAX_TYPENAME + i->dest->type]; + return DispatchToC(ctx, i, fn); +} + +uint32_t IntCode_SPLAT_V128_INT8(IntCodeState& ics, const IntCode* i) { + int8_t src1 = ics.rf[i->src1_reg].i8; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (size_t i = 0; i < 16; i++) { + dest.b16[i] = src1; + } + return IA_NEXT; +} +uint32_t IntCode_SPLAT_V128_INT16(IntCodeState& ics, const IntCode* i) { + int16_t src1 = ics.rf[i->src1_reg].i16; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (size_t i = 0; i < 8; i++) { + dest.s8[i] = src1; + } + return IA_NEXT; +} +uint32_t IntCode_SPLAT_V128_INT32(IntCodeState& ics, const IntCode* i) { + int32_t src1 = ics.rf[i->src1_reg].i32; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (size_t i = 0; i < 4; i++) { + dest.i4[i] = src1; + } + return IA_NEXT; +} +uint32_t IntCode_SPLAT_V128_FLOAT32(IntCodeState& ics, const IntCode* i) { + float src1 = ics.rf[i->src1_reg].f32; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (size_t i = 0; i < 4; i++) { + dest.f4[i] = src1; + } + return IA_NEXT; +} +int Translate_SPLAT(TranslationContext& ctx, Instr* i) { + // Can do more as needed. + static IntCodeFn fns[] = { + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_SPLAT_V128_INT8, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_SPLAT_V128_INT16, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_SPLAT_V128_INT32, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_SPLAT_V128_FLOAT32, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + }; + IntCodeFn fn = fns[i->src1.value->type * MAX_TYPENAME + i->dest->type]; + return DispatchToC(ctx, i, fn); +} + +uint32_t IntCode_PERMUTE_V128_BY_INT32(IntCodeState& ics, const IntCode* i) { + uint32_t src1 = ics.rf[i->src1_reg].i32; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + const vec128_t& src3 = ics.rf[i->src3_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (size_t i = 0; i < 4; i++) { +#define SWAP_INLINE(x) (((x) & ~0x3) + (3 - ((x) % 4))) + size_t m = SWAP_INLINE(i); + size_t b = (src1 >> (m * 8)) & 0x3; + dest.i4[m] = b < 4 ? + src2.i4[SWAP_INLINE(b)] : + src3.i4[SWAP_INLINE(b - 4)]; + } + return IA_NEXT; +} +uint32_t IntCode_PERMUTE_V128_BY_VEC128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + const vec128_t& src2 = ics.rf[i->src2_reg].v128; + const vec128_t& src3 = ics.rf[i->src3_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + for (size_t i = 0; i < 16; i++) { +#define SWAP_INLINE(x) (((x) & ~0x3) + (3 - ((x) % 4))) + size_t m = SWAP_INLINE(i); + size_t b = src1.b16[m] & 0x1F; + dest.b16[m] = b < 16 ? + src2.b16[SWAP_INLINE(b)] : + src3.b16[SWAP_INLINE(b - 16)]; + } + return IA_NEXT; +} +int Translate_PERMUTE(TranslationContext& ctx, Instr* i) { + // Can do more as needed. + static IntCodeFn fns[] = { + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_PERMUTE_V128_BY_INT32, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_PERMUTE_V128_BY_VEC128, + }; + IntCodeFn fn = fns[i->src1.value->type * MAX_TYPENAME + i->dest->type]; + return DispatchToC(ctx, i, fn); +} + +uint32_t IntCode_SWIZZLE_V128(IntCodeState& ics, const IntCode* i) { + const vec128_t& src1 = ics.rf[i->src1_reg].v128; + vec128_t& dest = ics.rf[i->dest_reg].v128; + uint32_t swizzle_mask = i->flags; + dest.i4[0] = src1.i4[swizzle_mask & 0x3]; + dest.i4[1] = src1.i4[(swizzle_mask >> 2) & 0x3]; + dest.i4[2] = src1.i4[(swizzle_mask >> 4) & 0x3]; + dest.i4[3] = src1.i4[(swizzle_mask >> 6) & 0x3]; + return IA_NEXT; +} +int Translate_SWIZZLE(TranslationContext& ctx, Instr* i) { + static IntCodeFn fns[] = { + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_INVALID_TYPE, + IntCode_SWIZZLE_V128, + }; + return DispatchToC(ctx, i, fns[i->src1.value->type]); +} + +typedef int (*TranslateFn)(TranslationContext& ctx, Instr* i); +static const TranslateFn dispatch_table[] = { + Translate_COMMENT, + + Translate_NOP, + + Translate_DEBUG_BREAK, + Translate_DEBUG_BREAK_TRUE, + + Translate_TRAP, + Translate_TRAP_TRUE, + + Translate_CALL, + Translate_CALL_TRUE, + Translate_CALL_INDIRECT, + Translate_CALL_INDIRECT_TRUE, + Translate_RETURN, + + Translate_BRANCH, + Translate_BRANCH_IF, + Translate_BRANCH_TRUE, + Translate_BRANCH_FALSE, + + Translate_ASSIGN, + Translate_CAST, + Translate_ZERO_EXTEND, + Translate_SIGN_EXTEND, + Translate_TRUNCATE, + Translate_CONVERT, + TranslateInvalid, //Translate_ROUND, + Translate_VECTOR_CONVERT_I2F, + TranslateInvalid, //Translate_VECTOR_CONVERT_F2I, + + Translate_LOAD_CONTEXT, + Translate_STORE_CONTEXT, + + Translate_LOAD, + TranslateInvalid, //Translate_LOAD_ACQUIRE, + Translate_STORE, + TranslateInvalid, //Translate_STORE_RELEASE, + Translate_PREFETCH, + + TranslateInvalid, //Translate_MAX, + TranslateInvalid, //Translate_MIN, + Translate_SELECT, + Translate_IS_TRUE, + Translate_IS_FALSE, + Translate_COMPARE_EQ, + Translate_COMPARE_NE, + Translate_COMPARE_SLT, + Translate_COMPARE_SLE, + Translate_COMPARE_SGT, + Translate_COMPARE_SGE, + Translate_COMPARE_ULT, + Translate_COMPARE_ULE, + Translate_COMPARE_UGT, + Translate_COMPARE_UGE, + Translate_DID_CARRY, + TranslateInvalid, //Translate_DID_OVERFLOW, + Translate_VECTOR_COMPARE_EQ, + Translate_VECTOR_COMPARE_SGT, + Translate_VECTOR_COMPARE_SGE, + Translate_VECTOR_COMPARE_UGT, + Translate_VECTOR_COMPARE_UGE, + + Translate_ADD, + Translate_ADD_CARRY, + Translate_SUB, + Translate_MUL, + Translate_DIV, + TranslateInvalid, //Translate_REM, + Translate_MULADD, + Translate_MULSUB, + Translate_NEG, + Translate_ABS, + TranslateInvalid, //Translate_SQRT, + Translate_RSQRT, + Translate_DOT_PRODUCT_3, + Translate_DOT_PRODUCT_4, + + Translate_AND, + Translate_OR, + Translate_XOR, + Translate_NOT, + Translate_SHL, + Translate_VECTOR_SHL, + Translate_SHR, + Translate_SHA, + Translate_ROTATE_LEFT, + Translate_BYTE_SWAP, + Translate_CNTLZ, + TranslateInvalid, //Translate_INSERT + Translate_EXTRACT, + Translate_SPLAT, + Translate_PERMUTE, + Translate_SWIZZLE, + + TranslateInvalid, //Translate_COMPARE_EXCHANGE, + TranslateInvalid, //Translate_ATOMIC_ADD, + TranslateInvalid, //Translate_ATOMIC_SUB, +}; + +int TranslateIntCodes(TranslationContext& ctx, Instr* i) { + TranslateFn fn = dispatch_table[i->opcode->num]; + return fn(ctx, i); +} + + +} // namespace ivm +} // namespace backend +} // namespace alloy diff --git a/src/alloy/backend/ivm/ivm_intcode.h b/src/alloy/backend/ivm/ivm_intcode.h new file mode 100644 index 000000000..34eec0f5e --- /dev/null +++ b/src/alloy/backend/ivm/ivm_intcode.h @@ -0,0 +1,104 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_BACKEND_IVM_INTCODE_H_ +#define ALLOY_BACKEND_IVM_INTCODE_H_ + +#include + +#include +#include + +namespace alloy { namespace runtime { class ThreadState; } } + + +namespace alloy { +namespace backend { +namespace ivm { + + +typedef union { + int8_t i8; + uint8_t u8; + int16_t i16; + uint16_t u16; + int32_t i32; + uint32_t u32; + int64_t i64; + uint64_t u64; + float f32; + double f64; + vec128_t v128; +} Register; + + +typedef struct { + Register* rf; + uint8_t* context; + uint8_t* membase; + int8_t did_carry; + runtime::ThreadState* thread_state; + uint64_t return_address; +} IntCodeState; + + +struct IntCode_s; +typedef uint32_t (*IntCodeFn)( + IntCodeState& ics, const struct IntCode_s* i); + +#define IA_RETURN 0xA0000000 +#define IA_NEXT 0xB0000000 + + +typedef struct IntCode_s { + IntCodeFn intcode_fn; + uint16_t flags; + + uint32_t dest_reg; + union { + struct { + uint32_t src1_reg; + uint32_t src2_reg; + uint32_t src3_reg; + // <4 bytes available> + }; + struct { + Register constant; + }; + }; + + // debugging info/etc +} IntCode; + + +typedef struct LabelRef_s { + hir::Label* label; + IntCode* instr; + LabelRef_s* next; +} LabelRef; + + +typedef struct { + uint32_t register_count; + size_t intcode_count; + Arena* intcode_arena; + Arena* scratch_arena; + LabelRef* label_ref_head; +} TranslationContext; + + +int TranslateIntCodes(TranslationContext& ctx, hir::Instr* i); + + +} // namespace ivm +} // namespace backend +} // namespace alloy + + +#endif // ALLOY_BACKEND_IVM_INTCODE_H_ diff --git a/src/alloy/backend/ivm/sources.gypi b/src/alloy/backend/ivm/sources.gypi new file mode 100644 index 000000000..0e9c55d1c --- /dev/null +++ b/src/alloy/backend/ivm/sources.gypi @@ -0,0 +1,13 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'ivm_intcode.cc', + 'ivm_intcode.h', + 'ivm_assembler.cc', + 'ivm_assembler.h', + 'ivm_backend.cc', + 'ivm_backend.h', + 'ivm_function.cc', + 'ivm_function.h', + ], +} diff --git a/src/alloy/backend/sources.gypi b/src/alloy/backend/sources.gypi new file mode 100644 index 000000000..154cd75ad --- /dev/null +++ b/src/alloy/backend/sources.gypi @@ -0,0 +1,15 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'assembler.cc', + 'assembler.h', + 'backend.cc', + 'backend.h', + 'tracing.h', + ], + + 'includes': [ + 'ivm/sources.gypi', + 'x64/sources.gypi', + ], +} diff --git a/src/alloy/backend/tracing.h b/src/alloy/backend/tracing.h new file mode 100644 index 000000000..c137f633c --- /dev/null +++ b/src/alloy/backend/tracing.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_BACKEND_TRACING_H_ +#define ALLOY_BACKEND_TRACING_H_ + +#include +#include + + +namespace alloy { +namespace backend { + +const uint32_t ALLOY_BACKEND = alloy::tracing::EventType::ALLOY_BACKEND; + + +class EventType { +public: + enum { + ALLOY_BACKEND_INIT = ALLOY_BACKEND | (1), + ALLOY_BACKEND_DEINIT = ALLOY_BACKEND | (2), + + ALLOY_BACKEND_ASSEMBLER = ALLOY_BACKEND | (1 << 25), + ALLOY_BACKEND_ASSEMBLER_INIT = ALLOY_BACKEND_ASSEMBLER | (1), + ALLOY_BACKEND_ASSEMBLER_DEINIT = ALLOY_BACKEND_ASSEMBLER | (2), + }; + + typedef struct { + static const uint32_t event_type = ALLOY_BACKEND_INIT; + } Init; + typedef struct { + static const uint32_t event_type = ALLOY_BACKEND_DEINIT; + } Deinit; + + typedef struct { + static const uint32_t event_type = ALLOY_BACKEND_ASSEMBLER_INIT; + } AssemblerInit; + typedef struct { + static const uint32_t event_type = ALLOY_BACKEND_ASSEMBLER_DEINIT; + } AssemblerDeinit; +}; + + +} // namespace backend +} // namespace alloy + + +#endif // ALLOY_BACKEND_TRACING_H_ diff --git a/src/alloy/backend/x64/sources.gypi b/src/alloy/backend/x64/sources.gypi new file mode 100644 index 000000000..230679df4 --- /dev/null +++ b/src/alloy/backend/x64/sources.gypi @@ -0,0 +1,5 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + ], +} diff --git a/src/alloy/compiler/compiler.cc b/src/alloy/compiler/compiler.cc new file mode 100644 index 000000000..6a1f4d2b9 --- /dev/null +++ b/src/alloy/compiler/compiler.cc @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include + +using namespace alloy; +using namespace alloy::compiler; +using namespace alloy::hir; + + +Compiler::Compiler() { + alloy::tracing::WriteEvent(EventType::Init({ + })); +} + +Compiler::~Compiler() { + Reset(); + + for (PassList::iterator it = passes_.begin(); it != passes_.end(); ++it) { + Pass* pass = *it; + delete pass; + } + + alloy::tracing::WriteEvent(EventType::Deinit({ + })); +} + +void Compiler::AddPass(Pass* pass) { + passes_.push_back(pass); +} + +void Compiler::Reset() { +} + +int Compiler::Compile(FunctionBuilder* builder) { + // TODO(benvanik): sophisticated stuff. Run passes in parallel, run until they + // stop changing things, etc. + for (PassList::iterator it = passes_.begin(); it != passes_.end(); ++it) { + Pass* pass = *it; + // + } + + return 0; +} \ No newline at end of file diff --git a/src/alloy/compiler/compiler.h b/src/alloy/compiler/compiler.h new file mode 100644 index 000000000..d4f45c86d --- /dev/null +++ b/src/alloy/compiler/compiler.h @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_COMPILER_COMPILER_H_ +#define ALLOY_COMPILER_COMPILER_H_ + +#include +#include + + +namespace alloy { +namespace compiler { + +class Pass; + + +class Compiler { +public: + Compiler(); + ~Compiler(); + + void AddPass(Pass* pass); + + void Reset(); + + int Compile(hir::FunctionBuilder* builder); + +private: + typedef std::vector PassList; + PassList passes_; +}; + + +} // namespace compiler +} // namespace alloy + + +#endif // ALLOY_COMPILER_COMPILER_H_ diff --git a/src/xenia/cpu/sdb.h b/src/alloy/compiler/pass.cc similarity index 62% rename from src/xenia/cpu/sdb.h rename to src/alloy/compiler/pass.cc index 24df9ec17..2920bf002 100644 --- a/src/xenia/cpu/sdb.h +++ b/src/alloy/compiler/pass.cc @@ -7,13 +7,14 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_SDB_H_ -#define XENIA_CPU_SDB_H_ +#include -#include -#include -#include -#include -#include +using namespace alloy; +using namespace alloy::compiler; -#endif // XENIA_CPU_SDB_H_ + +Pass::Pass() { +} + +Pass::~Pass() { +} diff --git a/src/alloy/compiler/pass.h b/src/alloy/compiler/pass.h new file mode 100644 index 000000000..8cfa96f04 --- /dev/null +++ b/src/alloy/compiler/pass.h @@ -0,0 +1,31 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_COMPILER_PASS_H_ +#define ALLOY_COMPILER_PASS_H_ + +#include + + +namespace alloy { +namespace compiler { + + +class Pass { +public: + Pass(); + virtual ~Pass(); +}; + + +} // namespace compiler +} // namespace alloy + + +#endif // ALLOY_COMPILER_PASS_H_ diff --git a/src/alloy/compiler/passes.h b/src/alloy/compiler/passes.h new file mode 100644 index 000000000..314400f63 --- /dev/null +++ b/src/alloy/compiler/passes.h @@ -0,0 +1,15 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_COMPILER_PASSES_H_ +#define ALLOY_COMPILER_PASSES_H_ + +#include + +#endif // ALLOY_COMPILER_PASSES_H_ diff --git a/src/alloy/compiler/passes/mem2reg_pass.cc b/src/alloy/compiler/passes/mem2reg_pass.cc new file mode 100644 index 000000000..58dbb205f --- /dev/null +++ b/src/alloy/compiler/passes/mem2reg_pass.cc @@ -0,0 +1,22 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +using namespace alloy; +using namespace alloy::compiler; +using namespace alloy::compiler::passes; + + +Mem2RegPass::Mem2RegPass() : + Pass() { +} + +Mem2RegPass::~Mem2RegPass() { +} diff --git a/src/alloy/compiler/passes/mem2reg_pass.h b/src/alloy/compiler/passes/mem2reg_pass.h new file mode 100644 index 000000000..cafe9b046 --- /dev/null +++ b/src/alloy/compiler/passes/mem2reg_pass.h @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_COMPILER_PASSES_MEM2REG_PASS_H_ +#define ALLOY_COMPILER_PASSES_MEM2REG_PASS_H_ + +#include + + +namespace alloy { +namespace compiler { +namespace passes { + + +class Mem2RegPass : public Pass { +public: + Mem2RegPass(); + virtual ~Mem2RegPass(); +}; + + +} // namespace passes +} // namespace compiler +} // namespace alloy + + +#endif // ALLOY_COMPILER_PASSES_MEM2REG_PASS_H_ diff --git a/src/alloy/compiler/passes/sources.gypi b/src/alloy/compiler/passes/sources.gypi new file mode 100644 index 000000000..3b8cc1e59 --- /dev/null +++ b/src/alloy/compiler/passes/sources.gypi @@ -0,0 +1,7 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'mem2reg_pass.cc', + 'mem2reg_pass.h', + ], +} diff --git a/src/alloy/compiler/sources.gypi b/src/alloy/compiler/sources.gypi new file mode 100644 index 000000000..fb372f558 --- /dev/null +++ b/src/alloy/compiler/sources.gypi @@ -0,0 +1,15 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'compiler.cc', + 'compiler.h', + 'pass.cc', + 'pass.h', + 'passes.h', + 'tracing.h', + ], + + 'includes': [ + 'passes/sources.gypi', + ], +} diff --git a/src/alloy/compiler/tracing.h b/src/alloy/compiler/tracing.h new file mode 100644 index 000000000..04da6d9ee --- /dev/null +++ b/src/alloy/compiler/tracing.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_COMPILER_TRACING_H_ +#define ALLOY_COMPILER_TRACING_H_ + +#include +#include + + +namespace alloy { +namespace compiler { + +const uint32_t ALLOY_COMPILER = alloy::tracing::EventType::ALLOY_COMPILER; + + +class EventType { +public: + enum { + ALLOY_COMPILER_INIT = ALLOY_COMPILER | (1), + ALLOY_COMPILER_DEINIT = ALLOY_COMPILER | (2), + }; + + typedef struct { + static const uint32_t event_type = ALLOY_COMPILER_INIT; + } Init; + typedef struct { + static const uint32_t event_type = ALLOY_COMPILER_DEINIT; + } Deinit; +}; + + +} // namespace compiler +} // namespace alloy + + +#endif // ALLOY_COMPILER_TRACING_H_ diff --git a/src/alloy/core.h b/src/alloy/core.h new file mode 100644 index 000000000..421718e7a --- /dev/null +++ b/src/alloy/core.h @@ -0,0 +1,51 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_CORE_H_ +#define ALLOY_CORE_H_ + +// TODO(benvanik): move the common stuff into here? +#include + +#include +#include +#include + + +namespace alloy { + +typedef struct XECACHEALIGN vec128_s { + union { + struct { + float x; + float y; + float z; + float w; + }; + struct { + uint32_t ix; + uint32_t iy; + uint32_t iz; + uint32_t iw; + }; + float f4[4]; + uint32_t i4[4]; + uint16_t s8[8]; + uint8_t b16[16]; + struct { + uint64_t low; + uint64_t high; + }; + }; +} vec128_t; + +} // namespace alloy + + +#endif // ALLOY_CORE_H_ diff --git a/src/alloy/frontend/frontend.cc b/src/alloy/frontend/frontend.cc new file mode 100644 index 000000000..30c480a0a --- /dev/null +++ b/src/alloy/frontend/frontend.cc @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include + +using namespace alloy; +using namespace alloy::frontend; +using namespace alloy::runtime; + + +Frontend::Frontend(Runtime* runtime) : + runtime_(runtime) { +} + +Frontend::~Frontend() { +} + +Memory* Frontend::memory() const { + return runtime_->memory(); +} + +int Frontend::Initialize() { + return 0; +} diff --git a/src/alloy/frontend/frontend.h b/src/alloy/frontend/frontend.h new file mode 100644 index 000000000..8e5cd1e5a --- /dev/null +++ b/src/alloy/frontend/frontend.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_FRONTEND_FRONTEND_H_ +#define ALLOY_FRONTEND_FRONTEND_H_ + +#include +#include +#include +#include + + +namespace alloy { namespace runtime { + class Runtime; +} } + +namespace alloy { +namespace frontend { + + +class Frontend { +public: + Frontend(runtime::Runtime* runtime); + virtual ~Frontend(); + + runtime::Runtime* runtime() const { return runtime_; } + Memory* memory() const; + + virtual int Initialize(); + + virtual int DeclareFunction( + runtime::FunctionInfo* symbol_info) = 0; + virtual int DefineFunction( + runtime::FunctionInfo* symbol_info, + runtime::Function** out_function) = 0; + +protected: + runtime::Runtime* runtime_; +}; + + +} // namespace frontend +} // namespace alloy + + +#endif // ALLOY_FRONTEND_FRONTEND_H_ diff --git a/src/xenia/cpu/ppc/state.cc b/src/alloy/frontend/ppc/ppc_context.cc similarity index 82% rename from src/xenia/cpu/ppc/state.cc rename to src/alloy/frontend/ppc/ppc_context.cc index 6e744ff50..8b3344bf6 100644 --- a/src/xenia/cpu/ppc/state.cc +++ b/src/alloy/frontend/ppc/ppc_context.cc @@ -7,9 +7,11 @@ ****************************************************************************** */ -#include -#include -#include +#include + +using namespace alloy; +using namespace alloy::frontend; +using namespace alloy::frontend::ppc; namespace { @@ -20,7 +22,8 @@ uint64_t ParseInt64(const char* value) { } -void xe_ppc_state::SetRegFromString(const char* name, const char* value) { + +void PPCContext::SetRegFromString(const char* name, const char* value) { int n; if (sscanf(name, "r%d", &n) == 1) { this->r[n] = ParseInt64(value); @@ -29,7 +32,7 @@ void xe_ppc_state::SetRegFromString(const char* name, const char* value) { } } -bool xe_ppc_state::CompareRegWithString( +bool PPCContext::CompareRegWithString( const char* name, const char* value, char* out_value, size_t out_value_size) { int n; diff --git a/src/xenia/cpu/ppc/state.h b/src/alloy/frontend/ppc/ppc_context.h similarity index 53% rename from src/xenia/cpu/ppc/state.h rename to src/alloy/frontend/ppc/ppc_context.h index ba8619282..a16901ea0 100644 --- a/src/xenia/cpu/ppc/state.h +++ b/src/alloy/frontend/ppc/ppc_context.h @@ -7,99 +7,133 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_PPC_STATE_H_ -#define XENIA_CPU_PPC_STATE_H_ +#ifndef ALLOY_FRONTEND_PPC_PPC_CONTEXT_H_ +#define ALLOY_FRONTEND_PPC_PPC_CONTEXT_H_ -#include +#include -XEDECLARECLASS2(xe, cpu, Processor); -XEDECLARECLASS2(xe, cpu, ThreadState); +namespace alloy { namespace runtime { + class Runtime; + class ThreadState; +} } -// namespace FPRF { -// enum FPRF_e { -// QUIET_NAN = 0x00088000, -// NEG_INFINITY = 0x00090000, -// NEG_NORMALIZED = 0x00010000, -// NEG_DENORMALIZED = 0x00018000, -// NEG_ZERO = 0x00048000, -// POS_ZERO = 0x00040000, -// POS_DENORMALIZED = 0x00028000, -// POS_NORMALIZED = 0x00020000, -// POS_INFINITY = 0x000A0000, -// }; -// } // FPRF +namespace alloy { +namespace frontend { +namespace ppc { -#define kXEPPCRegLR 0xFFFF0001 -#define kXEPPCRegCTR 0xFFFF0002 +using vec128_t = alloy::vec128_t; -typedef struct XECACHEALIGN xe_float4 { - union { - struct { - float x; - float y; - float z; - float w; - }; - struct { - uint32_t ix; - uint32_t iy; - uint32_t iz; - uint32_t iw; - }; - float f4[4]; - uint32_t i4[4]; - struct { - uint64_t low; - uint64_t high; - }; - }; -} xe_float4_t; +typedef union { + uint32_t value; + struct { + uint8_t lt :1; // Negative (LT) - result is negative + uint8_t gt :1; // Positive (GT) - result is positive (and not zero) + uint8_t eq :1; // Zero (EQ) - result is zero or a stwcx/stdcx completed successfully + uint8_t so :1; // Summary Overflow (SO) - copy of XER[SO] + } cr0; + struct { + uint8_t fx :1; // FP exception summary - copy of FPSCR[FX] + uint8_t fex :1; // FP enabled exception summary - copy of FPSCR[FEX] + uint8_t vx :1; // FP invalid operation exception summary - copy of FPSCR[VX] + uint8_t ox :1; // FP overflow exception - copy of FPSCR[OX] + } cr1; + struct { + uint8_t value :4; + } cr2; + struct { + uint8_t value :4; + } cr3; + struct { + uint8_t value :4; + } cr4; + struct { + uint8_t value :4; + } cr5; + struct { + uint8_t value :4; + } cr6; + struct { + uint8_t value :4; + } cr7; +} PPCCR; -typedef struct XECACHEALIGN64 xe_ppc_state { - uint32_t cia; // Current PC (CIA) - uint32_t nia; // Next PC (NIA) - uint64_t xer; // XER register +#pragma pack(push, 4) +typedef struct XECACHEALIGN64 PPCContext_s { + // Most frequently used registers first. + uint64_t r[32]; // General purpose registers uint64_t lr; // Link register uint64_t ctr; // Count register + // XER register + // Split to make it easier to do individual updates. + uint8_t xer_ca; + uint8_t xer_ov; + uint8_t xer_so; + + // Condition registers + // These are split to make it easier to do DCE on unused stores. union { uint32_t value; struct { - uint8_t lt :1; // Negative (LT) - result is negative - uint8_t gt :1; // Positive (GT) - result is positive (and not zero) - uint8_t eq :1; // Zero (EQ) - result is zero or a stwcx/stdcx completed successfully - uint8_t so :1; // Summary Overflow (SO) - copy of XER[SO] - } cr0; + uint8_t cr0_lt; // Negative (LT) - result is negative + uint8_t cr0_gt; // Positive (GT) - result is positive (and not zero) + uint8_t cr0_eq; // Zero (EQ) - result is zero or a stwcx/stdcx completed successfully + uint8_t cr0_so; // Summary Overflow (SO) - copy of XER[SO] + }; + } cr0; + union { + uint32_t value; struct { - uint8_t fx :1; // FP exception summary - copy of FPSCR[FX] - uint8_t fex :1; // FP enabled exception summary - copy of FPSCR[FEX] - uint8_t vx :1; // FP invalid operation exception summary - copy of FPSCR[VX] - uint8_t ox :1; // FP overflow exception - copy of FPSCR[OX] - } cr1; + uint8_t cr1_fx; // FP exception summary - copy of FPSCR[FX] + uint8_t cr1_fex; // FP enabled exception summary - copy of FPSCR[FEX] + uint8_t cr1_vx; // FP invalid operation exception summary - copy of FPSCR[VX] + uint8_t cr1_ox; // FP overflow exception - copy of FPSCR[OX] + }; + } cr1; + union { + uint32_t value; struct { - uint8_t value :4; - } cr2; + uint8_t cr2_0; uint8_t cr2_1; uint8_t cr2_2; uint8_t cr2_3; + }; + } cr2; + union { + uint32_t value; struct { - uint8_t value :4; - } cr3; + uint8_t cr3_0; uint8_t cr3_1; uint8_t cr3_2; uint8_t cr3_3; + }; + } cr3; + union { + uint32_t value; struct { - uint8_t value :4; - } cr4; + uint8_t cr4_0; uint8_t cr4_1; uint8_t cr4_2; uint8_t cr4_3; + }; + } cr4; + union { + uint32_t value; struct { - uint8_t value :4; - } cr5; + uint8_t cr5_0; uint8_t cr5_1; uint8_t cr5_2; uint8_t cr5_3; + }; + } cr5; + union { + uint32_t value; struct { - uint8_t value :4; - } cr6; + uint8_t cr6_0; + uint8_t cr6_none_equal; + uint8_t cr6_2; + uint8_t cr6_all_equal; + }; + } cr6; + union { + uint32_t value; struct { - uint8_t value :4; - } cr7; - } cr; // Condition register + uint8_t cr7_0; uint8_t cr7_1; uint8_t cr7_2; uint8_t cr7_3; + }; + } cr7; union { uint32_t value; @@ -141,9 +175,8 @@ typedef struct XECACHEALIGN64 xe_ppc_state { } bits; } fpscr; // Floating-point status and control register - uint64_t r[32]; // General purpose registers - xe_float4_t v[128]; // VMX128 vector registers - double f[32]; // Floating-point registers + double f[32]; // Floating-point registers + vec128_t v[128]; // VMX128 vector registers // uint32_t get_fprf() { // return fpscr.value & 0x000F8000; @@ -154,14 +187,20 @@ typedef struct XECACHEALIGN64 xe_ppc_state { // Runtime-specific data pointer. Used on callbacks to get access to the // current runtime and its data. - uint8_t* membase; - xe::cpu::Processor* processor; - xe::cpu::ThreadState* thread_state; + uint8_t* membase; + runtime::Runtime* runtime; + runtime::ThreadState* thread_state; void SetRegFromString(const char* name, const char* value); bool CompareRegWithString(const char* name, const char* value, char* out_value, size_t out_value_size); -} xe_ppc_state_t; +} PPCContext; +#pragma pack(pop) -#endif // XENIA_CPU_PPC_STATE_H_ +} // namespace ppc +} // namespace frontend +} // namespace alloy + + +#endif // ALLOY_FRONTEND_PPC_PPC_CONTEXT_H_ diff --git a/src/xenia/cpu/ppc/disasm.h b/src/alloy/frontend/ppc/ppc_disasm-private.h similarity index 60% rename from src/xenia/cpu/ppc/disasm.h rename to src/alloy/frontend/ppc/ppc_disasm-private.h index ec7552563..974a1dc75 100644 --- a/src/xenia/cpu/ppc/disasm.h +++ b/src/alloy/frontend/ppc/ppc_disasm-private.h @@ -7,36 +7,30 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_PPC_DISASM_H_ -#define XENIA_CPU_PPC_DISASM_H_ +#ifndef ALLOY_FRONTEND_PPC_PPC_DISASM_PRIVATE_H_ +#define ALLOY_FRONTEND_PPC_PPC_DISASM_PRIVATE_H_ -#include +#include +#include -namespace xe { -namespace cpu { +namespace alloy { +namespace frontend { namespace ppc { -void RegisterDisasmCategoryAltivec(); -void RegisterDisasmCategoryALU(); -void RegisterDisasmCategoryControl(); -void RegisterDisasmCategoryFPU(); -void RegisterDisasmCategoryMemory(); - - #define XEDISASMR(name, opcode, format) int InstrDisasm_##name #define XEREGISTERINSTR(name, opcode) \ RegisterInstrDisassemble(opcode, (InstrDisassembleFn)InstrDisasm_##name); -#define XEINSTRNOTIMPLEMENTED() -//#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS +//#define XEINSTRNOTIMPLEMENTED() +#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS } // namespace ppc -} // namespace cpu -} // namespace xe +} // namespace frontend +} // namespace alloy -#endif // XENIA_CPU_PPC_DISASM_H_ +#endif // ALLOY_FRONTEND_PPC_PPC_DISASM_PRIVATE_H_ diff --git a/src/alloy/frontend/ppc/ppc_disasm.h b/src/alloy/frontend/ppc/ppc_disasm.h new file mode 100644 index 000000000..ee78f0706 --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_disasm.h @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_FRONTEND_PPC_PPC_DISASM_H_ +#define ALLOY_FRONTEND_PPC_PPC_DISASM_H_ + +#include + + +namespace alloy { +namespace frontend { +namespace ppc { + + +void RegisterDisasmCategoryAltivec(); +void RegisterDisasmCategoryALU(); +void RegisterDisasmCategoryControl(); +void RegisterDisasmCategoryFPU(); +void RegisterDisasmCategoryMemory(); + + +} // namespace ppc +} // namespace frontend +} // namespace alloy + + +#endif // ALLOY_FRONTEND_PPC_PPC_DISASM_H_ diff --git a/src/xenia/cpu/ppc/disasm_altivec.cc b/src/alloy/frontend/ppc/ppc_disasm_altivec.cc similarity index 97% rename from src/xenia/cpu/ppc/disasm_altivec.cc rename to src/alloy/frontend/ppc/ppc_disasm_altivec.cc index 8bd9b9787..6672ea16e 100644 --- a/src/xenia/cpu/ppc/disasm_altivec.cc +++ b/src/alloy/frontend/ppc/ppc_disasm_altivec.cc @@ -1,1895 +1,1895 @@ -/* - ****************************************************************************** - * Xenia : Xbox 360 Emulator Research Project * - ****************************************************************************** - * Copyright 2013 Ben Vanik. All rights reserved. * - * Released under the BSD license - see LICENSE in the root for more details. * - ****************************************************************************** - */ - -#include - - -using namespace xe::cpu::ppc; - - -namespace xe { -namespace cpu { -namespace ppc { - - -// Most of this file comes from: -// http://biallas.net/doc/vmx128/vmx128.txt -// https://github.com/kakaroto/ps3ida/blob/master/plugins/PPCAltivec/src/main.cpp - - -#define OP(x) ((((uint32_t)(x)) & 0x3f) << 26) -#define VX128(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x3d0)) -#define VX128_1(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x7f3)) -#define VX128_2(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x210)) -#define VX128_3(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x7f0)) -#define VX128_4(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x730)) -#define VX128_5(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x10)) -#define VX128_P(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x630)) - - -namespace { - -int GeneralVXA(InstrData& i, InstrDisasm& d) { - d.AddRegOperand(InstrRegister::kVMX, i.VXA.VD, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, i.VXA.VA, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, i.VXA.VB, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, i.VXA.VC, InstrRegister::kRead); - return d.Finish(); -} - -int GeneralVX128(InstrData& i, InstrDisasm& d) { - const uint32_t vd = i.VX128.VD128l | (i.VX128.VD128h << 5); - const uint32_t va = i.VX128.VA128l | (i.VX128.VA128h << 5) | - (i.VX128.VA128H << 6); - const uint32_t vb = i.VX128.VB128l | (i.VX128.VB128h << 5); - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, va, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); - return d.Finish(); -} - -int GeneralX(InstrData& i, InstrDisasm& d, bool store) { - d.AddRegOperand(InstrRegister::kVMX, i.X.RT, - store ? InstrRegister::kRead : InstrRegister::kWrite); - if (i.X.RA) { - d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead); - } else { - d.AddUImmOperand(0, 1); - } - d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead); - return d.Finish(); -} - -int GeneralVX128_1(InstrData& i, InstrDisasm& d, bool store) { - const uint32_t vd = i.VX128_1.VD128l | (i.VX128_1.VD128h << 5); - d.AddRegOperand(InstrRegister::kVMX, vd, - store ? InstrRegister::kRead : InstrRegister::kWrite); - if (i.VX128_1.RA) { - d.AddRegOperand(InstrRegister::kGPR, i.VX128_1.RA, InstrRegister::kRead); - } else { - d.AddUImmOperand(0, 1); - } - d.AddRegOperand(InstrRegister::kGPR, i.VX128_1.RB, InstrRegister::kRead); - return d.Finish(); -} - -int GeneralVX128_3(InstrData& i, InstrDisasm& d) { - const uint32_t vd = i.VX128_3.VD128l | (i.VX128_3.VD128h << 5); - const uint32_t vb = i.VX128_3.VB128l | (i.VX128_3.VB128h << 5); - const uint32_t uimm = i.VX128_3.IMM; - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); - d.AddUImmOperand(uimm, 1); - return d.Finish(); -} - -} - - -XEDISASMR(dst, 0x7C0002AC, XDSS)(InstrData& i, InstrDisasm& d) { - d.Init("dst", "Data Stream Touch", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(dstst, 0x7C0002EC, XDSS)(InstrData& i, InstrDisasm& d) { - d.Init("dstst", "Data Stream Touch for Store", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(dss, 0x7C00066C, XDSS)(InstrData& i, InstrDisasm& d) { - d.Init("dss", "Data Stream Stop", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(lvebx, 0x7C00000E, X )(InstrData& i, InstrDisasm& d) { - d.Init("lvebx", "Load Vector Element Byte Indexed", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(lvehx, 0x7C00004E, X )(InstrData& i, InstrDisasm& d) { - d.Init("lvehx", "Load Vector Element Half Word Indexed", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(lvewx, 0x7C00008E, X )(InstrData& i, InstrDisasm& d) { - d.Init("lvewx", "Load Vector Element Word Indexed", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(lvewx128, VX128_1(4, 131), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("lvewx128", "Load Vector128 Element Word Indexed", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(lvsl, 0x7C00000C, X )(InstrData& i, InstrDisasm& d) { - d.Init("lvsl", "Load Vector for Shift Left", - InstrDisasm::kVMX); - return GeneralX(i, d, false); -} - -XEDISASMR(lvsl128, VX128_1(4, 3), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("lvsl128", "Load Vector128 for Shift Left", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, false); -} - -XEDISASMR(lvsr, 0x7C00004C, X )(InstrData& i, InstrDisasm& d) { - d.Init("lvsr", "Load Vector for Shift Right", - InstrDisasm::kVMX); - return GeneralX(i, d, false); -} - -XEDISASMR(lvsr128, VX128_1(4, 67), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("lvsr128", "Load Vector128 for Shift Right", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, false); -} - -XEDISASMR(lvx, 0x7C0000CE, X )(InstrData& i, InstrDisasm& d) { - d.Init("lvx", "Load Vector Indexed", - InstrDisasm::kVMX); - return GeneralX(i, d, false); -} - -XEDISASMR(lvx128, VX128_1(4, 195), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("lvx128", "Load Vector128 Indexed", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, false); -} - -XEDISASMR(lvxl, 0x7C0002CE, X )(InstrData& i, InstrDisasm& d) { - d.Init("lvxl", "Load Vector Indexed LRU", - InstrDisasm::kVMX); - return GeneralX(i, d, false); -} - -XEDISASMR(lvxl128, VX128_1(4, 707), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("lvxl128", "Load Vector128 Left Indexed", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, false); -} - -XEDISASMR(stvebx, 0x7C00010E, X )(InstrData& i, InstrDisasm& d) { - d.Init("stvebx", "Store Vector Element Byte Indexed", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(stvehx, 0x7C00014E, X )(InstrData& i, InstrDisasm& d) { - d.Init("stvehx", "Store Vector Element Half Word Indexed", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(stvewx, 0x7C00018E, X )(InstrData& i, InstrDisasm& d) { - d.Init("stvewx", "Store Vector Element Word Indexed", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(stvewx128, VX128_1(4, 387), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("stvewx128", "Store Vector128 Element Word Indexed", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, true); -} - -XEDISASMR(stvx, 0x7C0001CE, X )(InstrData& i, InstrDisasm& d) { - d.Init("stvx", "Store Vector Indexed", - InstrDisasm::kVMX); - return GeneralX(i, d, true); -} - -XEDISASMR(stvx128, VX128_1(4, 451), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("stvx128", "Store Vector128 Indexed", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, true); -} - -XEDISASMR(stvxl, 0x7C0003CE, X )(InstrData& i, InstrDisasm& d) { - d.Init("stvxl", "Store Vector Indexed LRU", - InstrDisasm::kVMX); - return GeneralX(i, d, true); -} - -XEDISASMR(stvxl128, VX128_1(4, 963), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("stvxl128", "Store Vector128 Indexed LRU", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, true); -} - -XEDISASMR(lvlx, 0x7C00040E, X )(InstrData& i, InstrDisasm& d) { - d.Init("lvlx", "Load Vector Indexed", - InstrDisasm::kVMX); - return GeneralX(i, d, false); -} - -XEDISASMR(lvlx128, VX128_1(4, 1027), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("lvlx128", "Load Vector128 Left Indexed LRU", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, false); -} - -XEDISASMR(lvlxl, 0x7C00060E, X )(InstrData& i, InstrDisasm& d) { - d.Init("lvlxl", "Load Vector Indexed LRU", - InstrDisasm::kVMX); - return GeneralX(i, d, false); -} - -XEDISASMR(lvlxl128, VX128_1(4, 1539), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("lvlxl128", "Load Vector128 Indexed LRU", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, false); -} - -XEDISASMR(lvrx, 0x7C00044E, X )(InstrData& i, InstrDisasm& d) { - d.Init("lvrx", "Load Vector Right Indexed", - InstrDisasm::kVMX); - return GeneralX(i, d, false); -} - -XEDISASMR(lvrx128, VX128_1(4, 1091), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("lvrx128", "Load Vector128 Right Indexed", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, false); -} - -XEDISASMR(lvrxl, 0x7C00064E, X )(InstrData& i, InstrDisasm& d) { - d.Init("lvrxl", "Load Vector Right Indexed LRU", - InstrDisasm::kVMX); - return GeneralX(i, d, false); -} - -XEDISASMR(lvrxl128, VX128_1(4, 1603), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("lvrxl128", "Load Vector128 Right Indexed LRU", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, false); -} - -XEDISASMR(stvlx, 0x7C00050E, X )(InstrData& i, InstrDisasm& d) { - d.Init("stvlx", "Store Vector Left Indexed", - InstrDisasm::kVMX); - return GeneralX(i, d, true); -} - -XEDISASMR(stvlx128, VX128_1(4, 1283), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("stvlx128", "Store Vector128 Left Indexed", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, true); -} - -XEDISASMR(stvlxl, 0x7C00070E, X )(InstrData& i, InstrDisasm& d) { - d.Init("stvlxl", "Store Vector Left Indexed LRU", - InstrDisasm::kVMX); - return GeneralX(i, d, true); -} - -XEDISASMR(stvlxl128, VX128_1(4, 1795), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("stvlxl128", "Store Vector128 Left Indexed LRU", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, true); -} - -XEDISASMR(stvrx, 0x7C00054E, X )(InstrData& i, InstrDisasm& d) { - d.Init("stvrx", "Store Vector Right Indexed", - InstrDisasm::kVMX); - return GeneralX(i, d, true); -} - -XEDISASMR(stvrx128, VX128_1(4, 1347), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("stvrx128", "Store Vector128 Right Indexed", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, true); -} - -XEDISASMR(stvrxl, 0x7C00074E, X )(InstrData& i, InstrDisasm& d) { - d.Init("stvrxl", "Store Vector Right Indexed LRU", - InstrDisasm::kVMX); - return GeneralX(i, d, true); -} - -XEDISASMR(stvrxl128, VX128_1(4, 1859), VX128_1)(InstrData& i, InstrDisasm& d) { - d.Init("stvrxl128", "Store Vector128 Right Indexed LRU", - InstrDisasm::kVMX); - return GeneralVX128_1(i, d, true); -} - -XEDISASMR(mfvscr, 0x10000604, VX )(InstrData& i, InstrDisasm& d) { - d.Init("mfvscr", "Move from Vector Status and Control Register", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(mtvscr, 0x10000644, VX )(InstrData& i, InstrDisasm& d) { - d.Init("mtvscr", "Move to Vector Status and Control Register", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vaddcuw, 0x10000180, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vaddcuw", "Vector Add Carryout Unsigned Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vaddfp, 0x1000000A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vaddfp", "Vector Add Floating Point", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vaddfp128, VX128(5, 16), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vaddfp128", "Vector128 Add Floating Point", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vaddsbs, 0x10000300, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vaddsbs", "Vector Add Signed Byte Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vaddshs, 0x10000340, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vaddshs", "Vector Add Signed Half Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vaddsws, 0x10000380, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vaddsws", "Vector Add Signed Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vaddubm, 0x10000000, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vaddubm", "Vector Add Unsigned Byte Modulo", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vaddubs, 0x10000200, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vaddubs", "Vector Add Unsigned Byte Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vadduhm, 0x10000040, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vadduhm", "Vector Add Unsigned Half Word Modulo", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vadduhs, 0x10000240, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vadduhs", "Vector Add Unsigned Half Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vadduwm, 0x10000080, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vadduwm", "Vector Add Unsigned Word Modulo", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vadduws, 0x10000280, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vadduws", "Vector Add Unsigned Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vand, 0x10000404, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vand", "Vector Logical AND", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vand128, VX128(5, 528), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vand128", "Vector128 Logical AND", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vandc, 0x10000444, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vandc", "Vector Logical AND with Complement", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vandc128, VX128(5, 592), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vandc128", "Vector128 Logical AND with Complement", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vavgsb, 0x10000502, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vavgsb", "Vector Average Signed Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vavgsh, 0x10000542, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vavgsh", "Vector Average Signed Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vavgsw, 0x10000582, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vavgsw", "Vector Average Signed Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vavgub, 0x10000402, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vavgub", "Vector Average Unsigned Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vavguh, 0x10000442, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vavguh", "Vector Average Unsigned Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vavguw, 0x10000482, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vavguw", "Vector Average Unsigned Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vcfsx, 0x1000034A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vcfsx", "Vector Convert from Signed Fixed-Point Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vcsxwfp128, VX128_3(6, 688), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vcsxwfp128", "Vector128 Convert From Signed Fixed-Point Word to Floating-Point", - InstrDisasm::kVMX); - return GeneralVX128_3(i, d); -} - -XEDISASMR(vcfpsxws128, VX128_3(6, 560), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vcfpsxws128", "Vector128 Convert From Floating-Point to Signed Fixed-Point Word Saturate", - InstrDisasm::kVMX); - return GeneralVX128_3(i, d); -} - -XEDISASMR(vcfux, 0x1000030A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vcfux", "Vector Convert from Unsigned Fixed-Point Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vcuxwfp128, VX128_3(6, 752), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vcuxwfp128", "Vector128 Convert From Unsigned Fixed-Point Word to Floating-Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vcfpuxws128, VX128_3(6, 624), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vcfpuxws128", "Vector128 Convert From Floating-Point to Unsigned Fixed-Point Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vcmpbfp, 0x100003C6, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpbfp", "Vector Compare Bounds Floating Point", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpbfp128, VX128(6, 384), VX128_R)(InstrData& i, InstrDisasm& d) { - d.Init("vcmpbfp128", "Vector128 Compare Bounds Floating Point", - InstrDisasm::kVMX | (i.VX128_R.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpeqfp, 0x100000C6, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpeqfp", "Vector Compare Equal-to Floating Point", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpeqfp128, VX128(6, 0), VX128_R)(InstrData& i, InstrDisasm& d) { - d.Init("vcmpeqfp128", "Vector128 Compare Equal-to Floating Point", - InstrDisasm::kVMX | (i.VX128_R.Rc ? InstrDisasm::kRc : 0)); - return GeneralVX128(i, d); -} - -XEDISASMR(vcmpequb, 0x10000006, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpequb", "Vector Compare Equal-to Unsigned Byte", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpequh, 0x10000046, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpequh", "Vector Compare Equal-to Unsigned Half Word", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpequw, 0x10000086, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpequw", "Vector Compare Equal-to Unsigned Word", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpequw128, VX128(6, 512), VX128_R)(InstrData& i, InstrDisasm& d) { - d.Init("vcmpequw128", "Vector128 Compare Equal-to Unsigned Word", - InstrDisasm::kVMX | (i.VX128_R.Rc ? InstrDisasm::kRc : 0)); - return GeneralVX128(i, d); -} - -XEDISASMR(vcmpgefp, 0x100001C6, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpgefp", "Vector Compare Greater-Than-or-Equal-to Floating Point", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpgefp128, VX128(6, 128), VX128_R)(InstrData& i, InstrDisasm& d) { - d.Init("vcmpgefp128", "Vector128 Compare Greater-Than-or-Equal-to Floating Point", - InstrDisasm::kVMX | (i.VX128_R.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpgtfp, 0x100002C6, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpgtfp", "Vector Compare Greater-Than Floating Point", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpgtfp128, VX128(6, 256), VX128_R)(InstrData& i, InstrDisasm& d) { - d.Init("vcmpgtfp128", "Vector128 Compare Greater-Than Floating-Point", - InstrDisasm::kVMX | (i.VX128_R.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpgtsb, 0x10000306, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpgtsb", "Vector Compare Greater-Than Signed Byte", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpgtsh, 0x10000346, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpgtsh", "Vector Compare Greater-Than Signed Half Word", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpgtsw, 0x10000386, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpgtsw", "Vector Compare Greater-Than Signed Word", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpgtub, 0x10000206, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpgtub", "Vector Compare Greater-Than Unsigned Byte", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpgtuh, 0x10000246, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpgtuh", "Vector Compare Greater-Than Unsigned Half Word", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vcmpgtuw, 0x10000286, VXR )(InstrData& i, InstrDisasm& d) { - d.Init("vcmpgtuw", "Vector Compare Greater-Than Unsigned Word", - InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); - return 1; -} - -XEDISASMR(vctsxs, 0x100003CA, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vctsxs", "Vector Convert to Signed Fixed-Point Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vctuxs, 0x1000038A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vctuxs", "Vector Convert to Unsigned Fixed-Point Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vexptefp, 0x1000018A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vexptefp", "Vector 2 Raised to the Exponent Estimate Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vexptefp128, VX128_3(6, 1712), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vexptefp128", "Vector128 2 Raised to the Exponent Estimate Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vlogefp, 0x100001CA, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vlogefp", "Vector Log2 Estimate Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vlogefp128, VX128_3(6, 1776), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vlogefp128", "Vector128 Log2 Estimate Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmaddfp, 0x1000002E, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vmaddfp", "Vector Multiply-Add Floating Point", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vmaddfp128, VX128(5, 208), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vmaddfp128", "Vector128 Multiply Add Floating Point", - InstrDisasm::kVMX); - const uint32_t vd = i.VX128.VD128l | (i.VX128.VD128h << 5); - const uint32_t va = i.VX128.VA128l | (i.VX128.VA128h << 5) | - (i.VX128.VA128H << 6); - const uint32_t vb = i.VX128.VB128l | (i.VX128.VB128h << 5); - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, va, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vmaddcfp128, VX128(5, 272), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vmaddcfp128", "Vector128 Multiply Add Floating Point", - InstrDisasm::kVMX); - const uint32_t vd = i.VX128.VD128l | (i.VX128.VD128h << 5); - const uint32_t va = i.VX128.VA128l | (i.VX128.VA128h << 5) | - (i.VX128.VA128H << 6); - const uint32_t vb = i.VX128.VB128l | (i.VX128.VB128h << 5); - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, va, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vmaxfp, 0x1000040A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmaxfp", "Vector Maximum Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmaxfp128, VX128(6, 640), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vmaxfp128", "Vector128 Maximum Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmaxsb, 0x10000102, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmaxsb", "Vector Maximum Signed Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmaxsh, 0x10000142, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmaxsh", "Vector Maximum Signed Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmaxsw, 0x10000182, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmaxsw", "Vector Maximum Signed Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmaxub, 0x10000002, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmaxub", "Vector Maximum Unsigned Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmaxuh, 0x10000042, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmaxuh", "Vector Maximum Unsigned Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmaxuw, 0x10000082, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmaxuw", "Vector Maximum Unsigned Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmhaddshs, 0x10000020, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vmhaddshs", "Vector Multiply-High and Add Signed Signed Half Word Saturate", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vmhraddshs, 0x10000021, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vmhraddshs", "Vector Multiply-High Round and Add Signed Signed Half Word Saturate", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vminfp, 0x1000044A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vminfp", "Vector Minimum Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vminfp128, VX128(6, 704), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vminfp128", "Vector128 Minimum Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vminsb, 0x10000302, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vminsb", "Vector Minimum Signed Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vminsh, 0x10000342, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vminsh", "Vector Minimum Signed Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vminsw, 0x10000382, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vminsw", "Vector Minimum Signed Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vminub, 0x10000202, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vminub", "Vector Minimum Unsigned Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vminuh, 0x10000242, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vminuh", "Vector Minimum Unsigned Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vminuw, 0x10000282, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vminuw", "Vector Minimum Unsigned Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmladduhm, 0x10000022, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vmladduhm", "Vector Multiply-Low and Add Unsigned Half Word Modulo", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vmrghb, 0x1000000C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmrghb", "Vector Merge High Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmrghh, 0x1000004C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmrghh", "Vector Merge High Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmrghw, 0x1000008C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmrghw", "Vector Merge High Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmrghw128, VX128(6, 768), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vmrghw128", "Vector128 Merge High Word", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vmrglb, 0x1000010C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmrglb", "Vector Merge Low Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmrglh, 0x1000014C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmrglh", "Vector Merge Low Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmrglw, 0x1000018C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmrglw", "Vector Merge Low Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmrglw128, VX128(6, 832), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vmrglw128", "Vector128 Merge Low Word", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vmsummbm, 0x10000025, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vmsummbm", "Vector Multiply-Sum Mixed-Sign Byte Modulo", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vmsumshm, 0x10000028, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vmsumshm", "Vector Multiply-Sum Signed Half Word Modulo", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vmsumshs, 0x10000029, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vmsumshs", "Vector Multiply-Sum Signed Half Word Saturate", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vmsumubm, 0x10000024, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vmsumubm", "Vector Multiply-Sum Unsigned Byte Modulo", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vmsumuhm, 0x10000026, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vmsumuhm", "Vector Multiply-Sum Unsigned Half Word Modulo", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vmsumuhs, 0x10000027, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vmsumuhs", "Vector Multiply-Sum Unsigned Half Word Saturate", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vmsum3fp128, VX128(5, 400), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vmsum3fp128", "Vector128 Multiply Sum 3-way Floating Point", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vmsum4fp128, VX128(5, 464), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vmsum4fp128", "Vector128 Multiply Sum 4-way Floating-Point", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vmulesb, 0x10000308, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmulesb", "Vector Multiply Even Signed Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmulesh, 0x10000348, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmulesh", "Vector Multiply Even Signed Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmuleub, 0x10000208, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmuleub", "Vector Multiply Even Unsigned Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmuleuh, 0x10000248, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmuleuh", "Vector Multiply Even Unsigned Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmulosb, 0x10000108, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmulosb", "Vector Multiply Odd Signed Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmulosh, 0x10000148, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmulosh", "Vector Multiply Odd Signed Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmuloub, 0x10000008, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmuloub", "Vector Multiply Odd Unsigned Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmulouh, 0x10000048, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vmulouh", "Vector Multiply Odd Unsigned Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vmulfp128, VX128(5, 144), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vmulfp128", "Vector128 Multiply Floating-Point", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vnmsubfp, 0x1000002F, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vnmsubfp", "Vector Negative Multiply-Subtract Floating Point", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vnmsubfp128, VX128(5, 336), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vnmsubfp128", "Vector128 Negative Multiply-Subtract Floating Point", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vnor, 0x10000504, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vnor", "Vector Logical NOR", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vnor128, VX128(5, 656), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vnor128", "Vector128 Logical NOR", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vor, 0x10000484, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vor", "Vector Logical OR", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vor128, VX128(5, 720), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vor128", "Vector128 Logical OR", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vperm, 0x1000002B, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vperm", "Vector Permute", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vperm128, VX128_2(5, 0), VX128_2)(InstrData& i, InstrDisasm& d) { - d.Init("vperm128", "Vector128 Permute", - InstrDisasm::kVMX); - const uint32_t vd = i.VX128_2.VD128l | (i.VX128_2.VD128h << 5); - const uint32_t va = i.VX128_2.VA128l | (i.VX128_2.VA128h << 5) | - (i.VX128_2.VA128H << 6); - const uint32_t vb = i.VX128_2.VB128l | (i.VX128_2.VB128h << 5); - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, va, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, i.VX128_2.VC, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vpermwi128, VX128_P(6, 528), VX128_P)(InstrData& i, InstrDisasm& d) { - d.Init("vpermwi128", "Vector128 Permutate Word Immediate", - InstrDisasm::kVMX); - const uint32_t vd = i.VX128_P.VD128l | (i.VX128_P.VD128h << 5); - const uint32_t vb = i.VX128_P.VB128l | (i.VX128_P.VB128h << 5); - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); - d.AddUImmOperand(i.VX128_P.PERMl | (i.VX128_P.PERMh << 5), 1); - return d.Finish(); -} - -XEDISASMR(vpkpx, 0x1000030E, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vpkpx", "Vector Pack Pixel", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkshss, 0x1000018E, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vpkshss", "Vector Pack Signed Half Word Signed Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkshss128, VX128(5, 512), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vpkshss128", "Vector128 Pack Signed Half Word Signed Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkswss, 0x100001CE, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vpkswss", "Vector Pack Signed Word Signed Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkswss128, VX128(5, 640), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vpkswss128", "Vector128 Pack Signed Word Signed Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkswus, 0x1000014E, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vpkswus", "Vector Pack Signed Word Unsigned Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkswus128, VX128(5, 704), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vpkswus128", "Vector128 Pack Signed Word Unsigned Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkuhum, 0x1000000E, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vpkuhum", "Vector Pack Unsigned Half Word Unsigned Modulo", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkuhum128, VX128(5, 768), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vpkuhum128", "Vector128 Pack Unsigned Half Word Unsigned Modulo", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkuhus, 0x1000008E, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vpkuhus", "Vector Pack Unsigned Half Word Unsigned Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkuhus128, VX128(5, 832), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vpkuhus128", "Vector128 Pack Unsigned Half Word Unsigned Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkshus, 0x1000010E, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vpkshus", "Vector Pack Signed Half Word Unsigned Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkshus128, VX128(5, 576), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vpkshus128", "Vector128 Pack Signed Half Word Unsigned Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkuwum, 0x1000004E, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vpkuwum", "Vector Pack Unsigned Word Unsigned Modulo", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkuwum128, VX128(5, 896), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vpkuwum128", "Vector128 Pack Unsigned Word Unsigned Modulo", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkuwus, 0x100000CE, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vpkuwus", "Vector Pack Unsigned Word Unsigned Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkuwus128, VX128(5, 960), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vpkuwus128", "Vector128 Pack Unsigned Word Unsigned Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vpkd3d128, VX128_4(6, 1552), VX128_4)(InstrData& i, InstrDisasm& d) { - d.Init("vpkd3d128", "Vector128 Pack D3Dtype, Rotate Left Immediate and Mask Insert", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrefp, 0x1000010A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vrefp", "Vector Reciprocal Estimate Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrefp128, VX128_3(6, 1584), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vrefp128", "Vector128 Reciprocal Estimate Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrfim, 0x100002CA, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vrfim", "Vector Round to Floating-Point Integer toward -Infinity", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrfim128, VX128_3(6, 816), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vrfim128", "Vector128 Round to Floating-Point Integer toward -Infinity", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrfin, 0x1000020A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vrfin", "Vector Round to Floating-Point Integer Nearest", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrfin128, VX128_3(6, 880), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vrfin128", "Vector128 Round to Floating-Point Integer Nearest", - InstrDisasm::kVMX); - const uint32_t vd = i.VX128_3.VD128l | (i.VX128_3.VD128h << 5); - const uint32_t vb = i.VX128_3.VB128l | (i.VX128_3.VB128h << 5); - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vrfip, 0x1000028A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vrfip", "Vector Round to Floating-Point Integer toward +Infinity", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrfip128, VX128_3(6, 944), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vrfip128", "Vector128 Round to Floating-Point Integer toward +Infinity", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrfiz, 0x1000024A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vrfiz", "Vector Round to Floating-Point Integer toward Zero", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrfiz128, VX128_3(6, 1008), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vrfiz128", "Vector128 Round to Floating-Point Integer toward Zero", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrlb, 0x10000004, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vrlb", "Vector Rotate Left Integer Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrlh, 0x10000044, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vrlh", "Vector Rotate Left Integer Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrlw, 0x10000084, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vrlw", "Vector Rotate Left Integer Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrlw128, VX128(6, 80), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vrlw128", "Vector128 Rotate Left Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrlimi128, VX128_4(6, 1808), VX128_4)(InstrData& i, InstrDisasm& d) { - d.Init("vrlimi128", "Vector128 Rotate Left Immediate and Mask Insert", - InstrDisasm::kVMX); - const uint32_t vd = i.VX128_4.VD128l | (i.VX128_4.VD128h << 5); - const uint32_t vb = i.VX128_4.VB128l | (i.VX128_4.VB128h << 5); - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); - d.AddUImmOperand(i.VX128_4.IMM, 1); - d.AddUImmOperand(i.VX128_4.z, 1); - return d.Finish(); -} - -XEDISASMR(vrsqrtefp, 0x1000014A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vrsqrtefp", "Vector Reciprocal Square Root Estimate Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vrsqrtefp128, VX128_3(6, 1648), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vrsqrtefp128", "Vector128 Reciprocal Square Root Estimate Floating Point", - InstrDisasm::kVMX); - const uint32_t vd = i.VX128_3.VD128l | (i.VX128_3.VD128h << 5); - const uint32_t vb = i.VX128_3.VB128l | (i.VX128_3.VB128h << 5); - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vsel, 0x1000002A, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vsel", "Vector Conditional Select", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vsel128, VX128(5, 848), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vsel128", "Vector128 Conditional Select", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsl, 0x100001C4, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsl", "Vector Shift Left", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vslb, 0x10000104, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vslb", "Vector Shift Left Integer Byte", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vsldoi, 0x1000002C, VXA )(InstrData& i, InstrDisasm& d) { - d.Init("vsldoi", "Vector Shift Left Double by Octet Immediate", - InstrDisasm::kVMX); - return GeneralVXA(i, d); -} - -XEDISASMR(vsldoi128, VX128_5(4, 16), VX128_5)(InstrData& i, InstrDisasm& d) { - d.Init("vsldoi128", "Vector128 Shift Left Double by Octet Immediate", - InstrDisasm::kVMX); - const uint32_t vd = i.VX128_5.VD128l | (i.VX128_5.VD128h << 5); - const uint32_t va = i.VX128_5.VA128l | (i.VX128_5.VA128h << 5); - const uint32_t vb = i.VX128_5.VB128l | (i.VX128_5.VB128h << 5); - const uint32_t sh = i.VX128_5.SH; - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, va, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); - d.AddUImmOperand(sh, 1); - return d.Finish(); -} - -XEDISASMR(vslh, 0x10000144, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vslh", "Vector Shift Left Integer Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vslo, 0x1000040C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vslo", "Vector Shift Left by Octet", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vslo128, VX128(5, 912), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vslo128", "Vector128 Shift Left Octet", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vslw, 0x10000184, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vslw", "Vector Shift Left Integer Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vslw128, VX128(6, 208), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vslw128", "Vector128 Shift Left Integer Word", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vspltb, 0x1000020C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vspltb", "Vector Splat Byte", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); - d.AddUImmOperand(i.VX.VA & 0xF, 1); - return d.Finish(); -} - -XEDISASMR(vsplth, 0x1000024C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsplth", "Vector Splat Half Word", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); - d.AddUImmOperand(i.VX.VA & 0x7, 1); - return d.Finish(); -} - -XEDISASMR(vspltisb, 0x1000030C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vspltisb", "Vector Splat Immediate Signed Byte", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - // 5bit -> 8bit sign extend - uint64_t v = (i.VX.VA & 0x10) ? (i.VX.VA | 0xFFFFFFFFFFFFFFF0) : i.VX.VA; - d.AddSImmOperand(v, 1); - return d.Finish(); -} - -XEDISASMR(vspltish, 0x1000034C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vspltish", "Vector Splat Immediate Signed Half Word", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - // 5bit -> 16bit sign extend - uint64_t v = (i.VX.VA & 0x10) ? (i.VX.VA | 0xFFFFFFFFFFFFFFF0) : i.VX.VA; - d.AddSImmOperand(v, 1); - return d.Finish(); -} - -XEDISASMR(vspltisw, 0x1000038C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vspltisw", "Vector Splat Immediate Signed Word", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - // 5bit -> 32bit sign extend - uint64_t v = (i.VX.VA & 0x10) ? (i.VX.VA | 0xFFFFFFFFFFFFFFF0) : i.VX.VA; - d.AddSImmOperand(v, 1); - return d.Finish(); -} - -XEDISASMR(vspltisw128, VX128_3(6, 1904), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vspltisw128", "Vector128 Splat Immediate Signed Word", - InstrDisasm::kVMX); - return GeneralVX128_3(i, d); -} - -XEDISASMR(vspltw, 0x1000028C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vspltw", "Vector Splat Word", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); - d.AddUImmOperand(i.VX.VA, 1); - return d.Finish(); -} - -XEDISASMR(vspltw128, VX128_3(6, 1840), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vspltw128", " Vector128 Splat Word", - InstrDisasm::kVMX); - return GeneralVX128_3(i, d); -} - -XEDISASMR(vsr, 0x100002C4, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsr", "Vector Shift Right", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsrab, 0x10000304, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsrab", "Vector Shift Right Algebraic Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsrah, 0x10000344, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsrah", "Vector Shift Right Algebraic Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsraw, 0x10000384, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsraw", "Vector Shift Right Algebraic Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsraw128, VX128(6, 336), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vsraw128", "Vector128 Shift Right Arithmetic Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsrb, 0x10000204, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsrb", "Vector Shift Right Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsrh, 0x10000244, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsrh", "Vector Shift Right Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsro, 0x1000044C, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsro", "Vector Shift Right Octet", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsro128, VX128(5, 976), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vsro128", "Vector128 Shift Right Octet", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsrw, 0x10000284, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsrw", "Vector Shift Right Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsrw128, VX128(6, 464), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vsrw128", "Vector128 Shift Right Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsubcuw, 0x10000580, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsubcuw", "Vector Subtract Carryout Unsigned Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsubfp, 0x1000004A, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsubfp", "Vector Subtract Floating Point", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsubfp128, VX128(5, 80), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vsubfp128", "Vector128 Subtract Floating Point", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - -XEDISASMR(vsubsbs, 0x10000700, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsubsbs", "Vector Subtract Signed Byte Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsubshs, 0x10000740, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsubshs", "Vector Subtract Signed Half Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsubsws, 0x10000780, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsubsws", "Vector Subtract Signed Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsububm, 0x10000400, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsububm", "Vector Subtract Unsigned Byte Modulo", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsububs, 0x10000600, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsububs", "Vector Subtract Unsigned Byte Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsubuhm, 0x10000440, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsubuhm", "Vector Subtract Unsigned Half Word Modulo", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsubuhs, 0x10000640, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsubuhs", "Vector Subtract Unsigned Half Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsubuwm, 0x10000480, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsubuwm", "Vector Subtract Unsigned Word Modulo", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsubuws, 0x10000680, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsubuws", "Vector Subtract Unsigned Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsumsws, 0x10000788, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsumsws", "Vector Sum Across Signed Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsum2sws, 0x10000688, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsum2sws", "Vector Sum Across Partial (1/2) Signed Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsum4sbs, 0x10000708, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsum4sbs", "Vector Sum Across Partial (1/4) Signed Byte Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsum4shs, 0x10000648, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsum4shs", "Vector Sum Across Partial (1/4) Signed Half Word Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vsum4ubs, 0x10000608, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vsum4ubs", "Vector Sum Across Partial (1/4) Unsigned Byte Saturate", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vupkhpx, 0x1000034E, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vupkhpx", "Vector Unpack High Pixel", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vupkhsb, 0x1000020E, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vupkhsb", "Vector Unpack High Signed Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vupkhsb128, VX128(6, 896), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vupkhsb128", "Vector128 Unpack High Signed Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vupkhsh, 0x1000024E, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vupkhsh", "Vector Unpack High Signed Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vupklpx, 0x100003CE, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vupklpx", "Vector Unpack Low Pixel", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vupklsb, 0x1000028E, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vupklsb", "Vector Unpack Low Signed Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vupklsb128, VX128(6, 960), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vupklsb128", "Vector128 Unpack Low Signed Byte", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vupklsh, 0x100002CE, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vupklsh", "Vector Unpack Low Signed Half Word", - InstrDisasm::kVMX); - return 1; -} - -XEDISASMR(vupkd3d128, VX128_3(6, 2032), VX128_3)(InstrData& i, InstrDisasm& d) { - d.Init("vupkd3d128", "Vector128 Unpack D3Dtype", - InstrDisasm::kVMX); - const uint32_t vd = i.VX128_3.VD128l | (i.VX128_3.VD128h << 5); - const uint32_t vb = i.VX128_3.VB128l | (i.VX128_3.VB128h << 5); - d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); - d.AddUImmOperand(i.VX128_3.IMM, 1); - return d.Finish(); -} - -XEDISASMR(vxor, 0x100004C4, VX )(InstrData& i, InstrDisasm& d) { - d.Init("vxor", "Vector Logical XOR", - InstrDisasm::kVMX); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); - return d.Finish(); -} - -XEDISASMR(vxor128, VX128(5, 784), VX128 )(InstrData& i, InstrDisasm& d) { - d.Init("vxor128", "Vector128 Logical XOR", - InstrDisasm::kVMX); - return GeneralVX128(i, d); -} - - -void RegisterDisasmCategoryAltivec() { - XEREGISTERINSTR(dst, 0x7C0002AC); - XEREGISTERINSTR(dstst, 0x7C0002EC); - XEREGISTERINSTR(dss, 0x7C00066C); - XEREGISTERINSTR(lvebx, 0x7C00000E); - XEREGISTERINSTR(lvehx, 0x7C00004E); - XEREGISTERINSTR(lvewx, 0x7C00008E); - XEREGISTERINSTR(lvewx128, VX128_1(4, 131)); - XEREGISTERINSTR(lvsl, 0x7C00000C); - XEREGISTERINSTR(lvsl128, VX128_1(4, 3)); - XEREGISTERINSTR(lvsr, 0x7C00004C); - XEREGISTERINSTR(lvsr128, VX128_1(4, 67)); - XEREGISTERINSTR(lvx, 0x7C0000CE); - XEREGISTERINSTR(lvx128, VX128_1(4, 195)); - XEREGISTERINSTR(lvxl, 0x7C0002CE); - XEREGISTERINSTR(lvxl128, VX128_1(4, 707)); - XEREGISTERINSTR(stvebx, 0x7C00010E); - XEREGISTERINSTR(stvehx, 0x7C00014E); - XEREGISTERINSTR(stvewx, 0x7C00018E); - XEREGISTERINSTR(stvewx128, VX128_1(4, 387)); - XEREGISTERINSTR(stvx, 0x7C0001CE); - XEREGISTERINSTR(stvx128, VX128_1(4, 451)); - XEREGISTERINSTR(stvxl, 0x7C0003CE); - XEREGISTERINSTR(stvxl128, VX128_1(4, 963)); - XEREGISTERINSTR(lvlx, 0x7C00040E); - XEREGISTERINSTR(lvlx128, VX128_1(4, 1027)); - XEREGISTERINSTR(lvlxl, 0x7C00060E); - XEREGISTERINSTR(lvlxl128, VX128_1(4, 1539)); - XEREGISTERINSTR(lvrx, 0x7C00044E); - XEREGISTERINSTR(lvrx128, VX128_1(4, 1091)); - XEREGISTERINSTR(lvrxl, 0x7C00064E); - XEREGISTERINSTR(lvrxl128, VX128_1(4, 1603)); - XEREGISTERINSTR(stvlx, 0x7C00050E); - XEREGISTERINSTR(stvlx128, VX128_1(4, 1283)); - XEREGISTERINSTR(stvlxl, 0x7C00070E); - XEREGISTERINSTR(stvlxl128, VX128_1(4, 1795)); - XEREGISTERINSTR(stvrx, 0x7C00054E); - XEREGISTERINSTR(stvrx128, VX128_1(4, 1347)); - XEREGISTERINSTR(stvrxl, 0x7C00074E); - XEREGISTERINSTR(stvrxl128, VX128_1(4, 1859)); - - XEREGISTERINSTR(mfvscr, 0x10000604); - XEREGISTERINSTR(mtvscr, 0x10000644); - XEREGISTERINSTR(vaddcuw, 0x10000180); - XEREGISTERINSTR(vaddfp, 0x1000000A); - XEREGISTERINSTR(vaddfp128, VX128(5, 16)); - XEREGISTERINSTR(vaddsbs, 0x10000300); - XEREGISTERINSTR(vaddshs, 0x10000340); - XEREGISTERINSTR(vaddsws, 0x10000380); - XEREGISTERINSTR(vaddubm, 0x10000000); - XEREGISTERINSTR(vaddubs, 0x10000200); - XEREGISTERINSTR(vadduhm, 0x10000040); - XEREGISTERINSTR(vadduhs, 0x10000240); - XEREGISTERINSTR(vadduwm, 0x10000080); - XEREGISTERINSTR(vadduws, 0x10000280); - XEREGISTERINSTR(vand, 0x10000404); - XEREGISTERINSTR(vand128, VX128(5, 528)); - XEREGISTERINSTR(vandc, 0x10000444); - XEREGISTERINSTR(vandc128, VX128(5, 592)); - XEREGISTERINSTR(vavgsb, 0x10000502); - XEREGISTERINSTR(vavgsh, 0x10000542); - XEREGISTERINSTR(vavgsw, 0x10000582); - XEREGISTERINSTR(vavgub, 0x10000402); - XEREGISTERINSTR(vavguh, 0x10000442); - XEREGISTERINSTR(vavguw, 0x10000482); - XEREGISTERINSTR(vcfsx, 0x1000034A); - XEREGISTERINSTR(vcsxwfp128, VX128_3(6, 688)); - XEREGISTERINSTR(vcfpsxws128, VX128_3(6, 560)); - XEREGISTERINSTR(vcfux, 0x1000030A); - XEREGISTERINSTR(vcuxwfp128, VX128_3(6, 752)); - XEREGISTERINSTR(vcfpuxws128, VX128_3(6, 624)); - XEREGISTERINSTR(vcmpbfp, 0x100003C6); - XEREGISTERINSTR(vcmpbfp128, VX128(6, 384)); - XEREGISTERINSTR(vcmpeqfp, 0x100000C6); - XEREGISTERINSTR(vcmpeqfp128, VX128(6, 0)); - XEREGISTERINSTR(vcmpequb, 0x10000006); - XEREGISTERINSTR(vcmpequh, 0x10000046); - XEREGISTERINSTR(vcmpequw, 0x10000086); - XEREGISTERINSTR(vcmpequw128, VX128(6, 512)); - XEREGISTERINSTR(vcmpgefp, 0x100001C6); - XEREGISTERINSTR(vcmpgefp128, VX128(6, 128)); - XEREGISTERINSTR(vcmpgtfp, 0x100002C6); - XEREGISTERINSTR(vcmpgtfp128, VX128(6, 256)); - XEREGISTERINSTR(vcmpgtsb, 0x10000306); - XEREGISTERINSTR(vcmpgtsh, 0x10000346); - XEREGISTERINSTR(vcmpgtsw, 0x10000386); - XEREGISTERINSTR(vcmpgtub, 0x10000206); - XEREGISTERINSTR(vcmpgtuh, 0x10000246); - XEREGISTERINSTR(vcmpgtuw, 0x10000286); - XEREGISTERINSTR(vctsxs, 0x100003CA); - XEREGISTERINSTR(vctuxs, 0x1000038A); - XEREGISTERINSTR(vexptefp, 0x1000018A); - XEREGISTERINSTR(vexptefp128, VX128_3(6, 1712)); - XEREGISTERINSTR(vlogefp, 0x100001CA); - XEREGISTERINSTR(vlogefp128, VX128_3(6, 1776)); - XEREGISTERINSTR(vmaddfp, 0x1000002E); - XEREGISTERINSTR(vmaddfp128, VX128(5, 208)); - XEREGISTERINSTR(vmaddcfp128, VX128(5, 272)); - XEREGISTERINSTR(vmaxfp, 0x1000040A); - XEREGISTERINSTR(vmaxfp128, VX128(6, 640)); - XEREGISTERINSTR(vmaxsb, 0x10000102); - XEREGISTERINSTR(vmaxsh, 0x10000142); - XEREGISTERINSTR(vmaxsw, 0x10000182); - XEREGISTERINSTR(vmaxub, 0x10000002); - XEREGISTERINSTR(vmaxuh, 0x10000042); - XEREGISTERINSTR(vmaxuw, 0x10000082); - XEREGISTERINSTR(vmhaddshs, 0x10000020); - XEREGISTERINSTR(vmhraddshs, 0x10000021); - XEREGISTERINSTR(vminfp, 0x1000044A); - XEREGISTERINSTR(vminfp128, VX128(6, 704)); - XEREGISTERINSTR(vminsb, 0x10000302); - XEREGISTERINSTR(vminsh, 0x10000342); - XEREGISTERINSTR(vminsw, 0x10000382); - XEREGISTERINSTR(vminub, 0x10000202); - XEREGISTERINSTR(vminuh, 0x10000242); - XEREGISTERINSTR(vminuw, 0x10000282); - XEREGISTERINSTR(vmladduhm, 0x10000022); - XEREGISTERINSTR(vmrghb, 0x1000000C); - XEREGISTERINSTR(vmrghh, 0x1000004C); - XEREGISTERINSTR(vmrghw, 0x1000008C); - XEREGISTERINSTR(vmrghw128, VX128(6, 768)); - XEREGISTERINSTR(vmrglb, 0x1000010C); - XEREGISTERINSTR(vmrglh, 0x1000014C); - XEREGISTERINSTR(vmrglw, 0x1000018C); - XEREGISTERINSTR(vmrglw128, VX128(6, 832)); - XEREGISTERINSTR(vmsummbm, 0x10000025); - XEREGISTERINSTR(vmsumshm, 0x10000028); - XEREGISTERINSTR(vmsumshs, 0x10000029); - XEREGISTERINSTR(vmsumubm, 0x10000024); - XEREGISTERINSTR(vmsumuhm, 0x10000026); - XEREGISTERINSTR(vmsumuhs, 0x10000027); - XEREGISTERINSTR(vmsum3fp128, VX128(5, 400)); - XEREGISTERINSTR(vmsum4fp128, VX128(5, 464)); - XEREGISTERINSTR(vmulesb, 0x10000308); - XEREGISTERINSTR(vmulesh, 0x10000348); - XEREGISTERINSTR(vmuleub, 0x10000208); - XEREGISTERINSTR(vmuleuh, 0x10000248); - XEREGISTERINSTR(vmulosb, 0x10000108); - XEREGISTERINSTR(vmulosh, 0x10000148); - XEREGISTERINSTR(vmuloub, 0x10000008); - XEREGISTERINSTR(vmulouh, 0x10000048); - XEREGISTERINSTR(vmulfp128, VX128(5, 144)); - XEREGISTERINSTR(vnmsubfp, 0x1000002F); - XEREGISTERINSTR(vnmsubfp128, VX128(5, 336)); - XEREGISTERINSTR(vnor, 0x10000504); - XEREGISTERINSTR(vnor128, VX128(5, 656)); - XEREGISTERINSTR(vor, 0x10000484); - XEREGISTERINSTR(vor128, VX128(5, 720)); - XEREGISTERINSTR(vperm, 0x1000002B); - XEREGISTERINSTR(vperm128, VX128_2(5, 0)); - XEREGISTERINSTR(vpermwi128, VX128_P(6, 528)); - XEREGISTERINSTR(vpkpx, 0x1000030E); - XEREGISTERINSTR(vpkshss, 0x1000018E); - XEREGISTERINSTR(vpkshss128, VX128(5, 512)); - XEREGISTERINSTR(vpkshus, 0x1000010E); - XEREGISTERINSTR(vpkshus128, VX128(5, 576)); - XEREGISTERINSTR(vpkswss, 0x100001CE); - XEREGISTERINSTR(vpkswss128, VX128(5, 640)); - XEREGISTERINSTR(vpkswus, 0x1000014E); - XEREGISTERINSTR(vpkswus128, VX128(5, 704)); - XEREGISTERINSTR(vpkuhum, 0x1000000E); - XEREGISTERINSTR(vpkuhum128, VX128(5, 768)); - XEREGISTERINSTR(vpkuhus, 0x1000008E); - XEREGISTERINSTR(vpkuhus128, VX128(5, 832)); - XEREGISTERINSTR(vpkuwum, 0x1000004E); - XEREGISTERINSTR(vpkuwum128, VX128(5, 896)); - XEREGISTERINSTR(vpkuwus, 0x100000CE); - XEREGISTERINSTR(vpkuwus128, VX128(5, 960)); - XEREGISTERINSTR(vpkd3d128, VX128_4(6, 1552)); - XEREGISTERINSTR(vrefp, 0x1000010A); - XEREGISTERINSTR(vrefp128, VX128_3(6, 1584)); - XEREGISTERINSTR(vrfim, 0x100002CA); - XEREGISTERINSTR(vrfim128, VX128_3(6, 816)); - XEREGISTERINSTR(vrfin, 0x1000020A); - XEREGISTERINSTR(vrfin128, VX128_3(6, 880)); - XEREGISTERINSTR(vrfip, 0x1000028A); - XEREGISTERINSTR(vrfip128, VX128_3(6, 944)); - XEREGISTERINSTR(vrfiz, 0x1000024A); - XEREGISTERINSTR(vrfiz128, VX128_3(6, 1008)); - XEREGISTERINSTR(vrlb, 0x10000004); - XEREGISTERINSTR(vrlh, 0x10000044); - XEREGISTERINSTR(vrlw, 0x10000084); - XEREGISTERINSTR(vrlw128, VX128(6, 80)); - XEREGISTERINSTR(vrlimi128, VX128_4(6, 1808)); - XEREGISTERINSTR(vrsqrtefp, 0x1000014A); - XEREGISTERINSTR(vrsqrtefp128, VX128_3(6, 1648)); - XEREGISTERINSTR(vsel, 0x1000002A); - XEREGISTERINSTR(vsel128, VX128(5, 848)); - XEREGISTERINSTR(vsl, 0x100001C4); - XEREGISTERINSTR(vslb, 0x10000104); - XEREGISTERINSTR(vsldoi, 0x1000002C); - XEREGISTERINSTR(vsldoi128, VX128_5(4, 16)); - XEREGISTERINSTR(vslh, 0x10000144); - XEREGISTERINSTR(vslo, 0x1000040C); - XEREGISTERINSTR(vslo128, VX128(5, 912)); - XEREGISTERINSTR(vslw, 0x10000184); - XEREGISTERINSTR(vslw128, VX128(6, 208)); - XEREGISTERINSTR(vspltb, 0x1000020C); - XEREGISTERINSTR(vsplth, 0x1000024C); - XEREGISTERINSTR(vspltisb, 0x1000030C); - XEREGISTERINSTR(vspltish, 0x1000034C); - XEREGISTERINSTR(vspltisw, 0x1000038C); - XEREGISTERINSTR(vspltisw128, VX128_3(6, 1904)); - XEREGISTERINSTR(vspltw, 0x1000028C); - XEREGISTERINSTR(vspltw128, VX128_3(6, 1840)); - XEREGISTERINSTR(vsr, 0x100002C4); - XEREGISTERINSTR(vsrab, 0x10000304); - XEREGISTERINSTR(vsrah, 0x10000344); - XEREGISTERINSTR(vsraw, 0x10000384); - XEREGISTERINSTR(vsraw128, VX128(6, 336)); - XEREGISTERINSTR(vsrb, 0x10000204); - XEREGISTERINSTR(vsrh, 0x10000244); - XEREGISTERINSTR(vsro, 0x1000044C); - XEREGISTERINSTR(vsro128, VX128(5, 976)); - XEREGISTERINSTR(vsrw, 0x10000284); - XEREGISTERINSTR(vsrw128, VX128(6, 464)); - XEREGISTERINSTR(vsubcuw, 0x10000580); - XEREGISTERINSTR(vsubfp, 0x1000004A); - XEREGISTERINSTR(vsubfp128, VX128(5, 80)); - XEREGISTERINSTR(vsubsbs, 0x10000700); - XEREGISTERINSTR(vsubshs, 0x10000740); - XEREGISTERINSTR(vsubsws, 0x10000780); - XEREGISTERINSTR(vsububm, 0x10000400); - XEREGISTERINSTR(vsububs, 0x10000600); - XEREGISTERINSTR(vsubuhm, 0x10000440); - XEREGISTERINSTR(vsubuhs, 0x10000640); - XEREGISTERINSTR(vsubuwm, 0x10000480); - XEREGISTERINSTR(vsubuws, 0x10000680); - XEREGISTERINSTR(vsumsws, 0x10000788); - XEREGISTERINSTR(vsum2sws, 0x10000688); - XEREGISTERINSTR(vsum4sbs, 0x10000708); - XEREGISTERINSTR(vsum4shs, 0x10000648); - XEREGISTERINSTR(vsum4ubs, 0x10000608); - XEREGISTERINSTR(vupkhpx, 0x1000034E); - XEREGISTERINSTR(vupkhsb, 0x1000020E); - XEREGISTERINSTR(vupkhsb128, VX128(6, 896)); - XEREGISTERINSTR(vupkhsh, 0x1000024E); - XEREGISTERINSTR(vupklpx, 0x100003CE); - XEREGISTERINSTR(vupklsb, 0x1000028E); - XEREGISTERINSTR(vupklsb128, VX128(6, 960)); - XEREGISTERINSTR(vupklsh, 0x100002CE); - XEREGISTERINSTR(vupkd3d128, VX128_3(6, 2032)); - XEREGISTERINSTR(vxor, 0x100004C4); - XEREGISTERINSTR(vxor128, VX128(5, 784)); -} - - -} // namespace ppc -} // namespace cpu -} // namespace xe +/* + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + + +using namespace alloy::frontend::ppc; + + +namespace alloy { +namespace frontend { +namespace ppc { + + +// Most of this file comes from: +// http://biallas.net/doc/vmx128/vmx128.txt +// https://github.com/kakaroto/ps3ida/blob/master/plugins/PPCAltivec/src/main.cpp + + +#define OP(x) ((((uint32_t)(x)) & 0x3f) << 26) +#define VX128(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x3d0)) +#define VX128_1(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x7f3)) +#define VX128_2(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x210)) +#define VX128_3(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x7f0)) +#define VX128_4(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x730)) +#define VX128_5(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x10)) +#define VX128_P(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x630)) + + +namespace { + +int GeneralVXA(InstrData& i, InstrDisasm& d) { + d.AddRegOperand(InstrRegister::kVMX, i.VXA.VD, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, i.VXA.VA, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, i.VXA.VB, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, i.VXA.VC, InstrRegister::kRead); + return d.Finish(); +} + +int GeneralVX128(InstrData& i, InstrDisasm& d) { + const uint32_t vd = i.VX128.VD128l | (i.VX128.VD128h << 5); + const uint32_t va = i.VX128.VA128l | (i.VX128.VA128h << 5) | + (i.VX128.VA128H << 6); + const uint32_t vb = i.VX128.VB128l | (i.VX128.VB128h << 5); + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, va, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); + return d.Finish(); +} + +int GeneralX(InstrData& i, InstrDisasm& d, bool store) { + d.AddRegOperand(InstrRegister::kVMX, i.X.RT, + store ? InstrRegister::kRead : InstrRegister::kWrite); + if (i.X.RA) { + d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead); + } else { + d.AddUImmOperand(0, 1); + } + d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead); + return d.Finish(); +} + +int GeneralVX128_1(InstrData& i, InstrDisasm& d, bool store) { + const uint32_t vd = i.VX128_1.VD128l | (i.VX128_1.VD128h << 5); + d.AddRegOperand(InstrRegister::kVMX, vd, + store ? InstrRegister::kRead : InstrRegister::kWrite); + if (i.VX128_1.RA) { + d.AddRegOperand(InstrRegister::kGPR, i.VX128_1.RA, InstrRegister::kRead); + } else { + d.AddUImmOperand(0, 1); + } + d.AddRegOperand(InstrRegister::kGPR, i.VX128_1.RB, InstrRegister::kRead); + return d.Finish(); +} + +int GeneralVX128_3(InstrData& i, InstrDisasm& d) { + const uint32_t vd = i.VX128_3.VD128l | (i.VX128_3.VD128h << 5); + const uint32_t vb = i.VX128_3.VB128l | (i.VX128_3.VB128h << 5); + const uint32_t uimm = i.VX128_3.IMM; + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); + d.AddUImmOperand(uimm, 1); + return d.Finish(); +} + +} + + +XEDISASMR(dst, 0x7C0002AC, XDSS)(InstrData& i, InstrDisasm& d) { + d.Init("dst", "Data Stream Touch", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(dstst, 0x7C0002EC, XDSS)(InstrData& i, InstrDisasm& d) { + d.Init("dstst", "Data Stream Touch for Store", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(dss, 0x7C00066C, XDSS)(InstrData& i, InstrDisasm& d) { + d.Init("dss", "Data Stream Stop", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(lvebx, 0x7C00000E, X )(InstrData& i, InstrDisasm& d) { + d.Init("lvebx", "Load Vector Element Byte Indexed", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(lvehx, 0x7C00004E, X )(InstrData& i, InstrDisasm& d) { + d.Init("lvehx", "Load Vector Element Half Word Indexed", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(lvewx, 0x7C00008E, X )(InstrData& i, InstrDisasm& d) { + d.Init("lvewx", "Load Vector Element Word Indexed", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(lvewx128, VX128_1(4, 131), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("lvewx128", "Load Vector128 Element Word Indexed", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(lvsl, 0x7C00000C, X )(InstrData& i, InstrDisasm& d) { + d.Init("lvsl", "Load Vector for Shift Left", + InstrDisasm::kVMX); + return GeneralX(i, d, false); +} + +XEDISASMR(lvsl128, VX128_1(4, 3), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("lvsl128", "Load Vector128 for Shift Left", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, false); +} + +XEDISASMR(lvsr, 0x7C00004C, X )(InstrData& i, InstrDisasm& d) { + d.Init("lvsr", "Load Vector for Shift Right", + InstrDisasm::kVMX); + return GeneralX(i, d, false); +} + +XEDISASMR(lvsr128, VX128_1(4, 67), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("lvsr128", "Load Vector128 for Shift Right", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, false); +} + +XEDISASMR(lvx, 0x7C0000CE, X )(InstrData& i, InstrDisasm& d) { + d.Init("lvx", "Load Vector Indexed", + InstrDisasm::kVMX); + return GeneralX(i, d, false); +} + +XEDISASMR(lvx128, VX128_1(4, 195), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("lvx128", "Load Vector128 Indexed", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, false); +} + +XEDISASMR(lvxl, 0x7C0002CE, X )(InstrData& i, InstrDisasm& d) { + d.Init("lvxl", "Load Vector Indexed LRU", + InstrDisasm::kVMX); + return GeneralX(i, d, false); +} + +XEDISASMR(lvxl128, VX128_1(4, 707), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("lvxl128", "Load Vector128 Left Indexed", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, false); +} + +XEDISASMR(stvebx, 0x7C00010E, X )(InstrData& i, InstrDisasm& d) { + d.Init("stvebx", "Store Vector Element Byte Indexed", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(stvehx, 0x7C00014E, X )(InstrData& i, InstrDisasm& d) { + d.Init("stvehx", "Store Vector Element Half Word Indexed", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(stvewx, 0x7C00018E, X )(InstrData& i, InstrDisasm& d) { + d.Init("stvewx", "Store Vector Element Word Indexed", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(stvewx128, VX128_1(4, 387), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("stvewx128", "Store Vector128 Element Word Indexed", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, true); +} + +XEDISASMR(stvx, 0x7C0001CE, X )(InstrData& i, InstrDisasm& d) { + d.Init("stvx", "Store Vector Indexed", + InstrDisasm::kVMX); + return GeneralX(i, d, true); +} + +XEDISASMR(stvx128, VX128_1(4, 451), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("stvx128", "Store Vector128 Indexed", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, true); +} + +XEDISASMR(stvxl, 0x7C0003CE, X )(InstrData& i, InstrDisasm& d) { + d.Init("stvxl", "Store Vector Indexed LRU", + InstrDisasm::kVMX); + return GeneralX(i, d, true); +} + +XEDISASMR(stvxl128, VX128_1(4, 963), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("stvxl128", "Store Vector128 Indexed LRU", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, true); +} + +XEDISASMR(lvlx, 0x7C00040E, X )(InstrData& i, InstrDisasm& d) { + d.Init("lvlx", "Load Vector Indexed", + InstrDisasm::kVMX); + return GeneralX(i, d, false); +} + +XEDISASMR(lvlx128, VX128_1(4, 1027), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("lvlx128", "Load Vector128 Left Indexed LRU", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, false); +} + +XEDISASMR(lvlxl, 0x7C00060E, X )(InstrData& i, InstrDisasm& d) { + d.Init("lvlxl", "Load Vector Indexed LRU", + InstrDisasm::kVMX); + return GeneralX(i, d, false); +} + +XEDISASMR(lvlxl128, VX128_1(4, 1539), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("lvlxl128", "Load Vector128 Indexed LRU", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, false); +} + +XEDISASMR(lvrx, 0x7C00044E, X )(InstrData& i, InstrDisasm& d) { + d.Init("lvrx", "Load Vector Right Indexed", + InstrDisasm::kVMX); + return GeneralX(i, d, false); +} + +XEDISASMR(lvrx128, VX128_1(4, 1091), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("lvrx128", "Load Vector128 Right Indexed", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, false); +} + +XEDISASMR(lvrxl, 0x7C00064E, X )(InstrData& i, InstrDisasm& d) { + d.Init("lvrxl", "Load Vector Right Indexed LRU", + InstrDisasm::kVMX); + return GeneralX(i, d, false); +} + +XEDISASMR(lvrxl128, VX128_1(4, 1603), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("lvrxl128", "Load Vector128 Right Indexed LRU", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, false); +} + +XEDISASMR(stvlx, 0x7C00050E, X )(InstrData& i, InstrDisasm& d) { + d.Init("stvlx", "Store Vector Left Indexed", + InstrDisasm::kVMX); + return GeneralX(i, d, true); +} + +XEDISASMR(stvlx128, VX128_1(4, 1283), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("stvlx128", "Store Vector128 Left Indexed", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, true); +} + +XEDISASMR(stvlxl, 0x7C00070E, X )(InstrData& i, InstrDisasm& d) { + d.Init("stvlxl", "Store Vector Left Indexed LRU", + InstrDisasm::kVMX); + return GeneralX(i, d, true); +} + +XEDISASMR(stvlxl128, VX128_1(4, 1795), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("stvlxl128", "Store Vector128 Left Indexed LRU", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, true); +} + +XEDISASMR(stvrx, 0x7C00054E, X )(InstrData& i, InstrDisasm& d) { + d.Init("stvrx", "Store Vector Right Indexed", + InstrDisasm::kVMX); + return GeneralX(i, d, true); +} + +XEDISASMR(stvrx128, VX128_1(4, 1347), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("stvrx128", "Store Vector128 Right Indexed", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, true); +} + +XEDISASMR(stvrxl, 0x7C00074E, X )(InstrData& i, InstrDisasm& d) { + d.Init("stvrxl", "Store Vector Right Indexed LRU", + InstrDisasm::kVMX); + return GeneralX(i, d, true); +} + +XEDISASMR(stvrxl128, VX128_1(4, 1859), VX128_1)(InstrData& i, InstrDisasm& d) { + d.Init("stvrxl128", "Store Vector128 Right Indexed LRU", + InstrDisasm::kVMX); + return GeneralVX128_1(i, d, true); +} + +XEDISASMR(mfvscr, 0x10000604, VX )(InstrData& i, InstrDisasm& d) { + d.Init("mfvscr", "Move from Vector Status and Control Register", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(mtvscr, 0x10000644, VX )(InstrData& i, InstrDisasm& d) { + d.Init("mtvscr", "Move to Vector Status and Control Register", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vaddcuw, 0x10000180, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vaddcuw", "Vector Add Carryout Unsigned Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vaddfp, 0x1000000A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vaddfp", "Vector Add Floating Point", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vaddfp128, VX128(5, 16), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vaddfp128", "Vector128 Add Floating Point", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vaddsbs, 0x10000300, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vaddsbs", "Vector Add Signed Byte Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vaddshs, 0x10000340, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vaddshs", "Vector Add Signed Half Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vaddsws, 0x10000380, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vaddsws", "Vector Add Signed Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vaddubm, 0x10000000, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vaddubm", "Vector Add Unsigned Byte Modulo", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vaddubs, 0x10000200, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vaddubs", "Vector Add Unsigned Byte Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vadduhm, 0x10000040, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vadduhm", "Vector Add Unsigned Half Word Modulo", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vadduhs, 0x10000240, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vadduhs", "Vector Add Unsigned Half Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vadduwm, 0x10000080, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vadduwm", "Vector Add Unsigned Word Modulo", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vadduws, 0x10000280, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vadduws", "Vector Add Unsigned Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vand, 0x10000404, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vand", "Vector Logical AND", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vand128, VX128(5, 528), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vand128", "Vector128 Logical AND", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vandc, 0x10000444, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vandc", "Vector Logical AND with Complement", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vandc128, VX128(5, 592), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vandc128", "Vector128 Logical AND with Complement", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vavgsb, 0x10000502, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vavgsb", "Vector Average Signed Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vavgsh, 0x10000542, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vavgsh", "Vector Average Signed Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vavgsw, 0x10000582, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vavgsw", "Vector Average Signed Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vavgub, 0x10000402, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vavgub", "Vector Average Unsigned Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vavguh, 0x10000442, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vavguh", "Vector Average Unsigned Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vavguw, 0x10000482, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vavguw", "Vector Average Unsigned Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vcfsx, 0x1000034A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vcfsx", "Vector Convert from Signed Fixed-Point Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vcsxwfp128, VX128_3(6, 688), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vcsxwfp128", "Vector128 Convert From Signed Fixed-Point Word to Floating-Point", + InstrDisasm::kVMX); + return GeneralVX128_3(i, d); +} + +XEDISASMR(vcfpsxws128, VX128_3(6, 560), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vcfpsxws128", "Vector128 Convert From Floating-Point to Signed Fixed-Point Word Saturate", + InstrDisasm::kVMX); + return GeneralVX128_3(i, d); +} + +XEDISASMR(vcfux, 0x1000030A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vcfux", "Vector Convert from Unsigned Fixed-Point Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vcuxwfp128, VX128_3(6, 752), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vcuxwfp128", "Vector128 Convert From Unsigned Fixed-Point Word to Floating-Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vcfpuxws128, VX128_3(6, 624), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vcfpuxws128", "Vector128 Convert From Floating-Point to Unsigned Fixed-Point Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vcmpbfp, 0x100003C6, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpbfp", "Vector Compare Bounds Floating Point", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpbfp128, VX128(6, 384), VX128_R)(InstrData& i, InstrDisasm& d) { + d.Init("vcmpbfp128", "Vector128 Compare Bounds Floating Point", + InstrDisasm::kVMX | (i.VX128_R.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpeqfp, 0x100000C6, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpeqfp", "Vector Compare Equal-to Floating Point", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpeqfp128, VX128(6, 0), VX128_R)(InstrData& i, InstrDisasm& d) { + d.Init("vcmpeqfp128", "Vector128 Compare Equal-to Floating Point", + InstrDisasm::kVMX | (i.VX128_R.Rc ? InstrDisasm::kRc : 0)); + return GeneralVX128(i, d); +} + +XEDISASMR(vcmpequb, 0x10000006, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpequb", "Vector Compare Equal-to Unsigned Byte", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpequh, 0x10000046, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpequh", "Vector Compare Equal-to Unsigned Half Word", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpequw, 0x10000086, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpequw", "Vector Compare Equal-to Unsigned Word", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpequw128, VX128(6, 512), VX128_R)(InstrData& i, InstrDisasm& d) { + d.Init("vcmpequw128", "Vector128 Compare Equal-to Unsigned Word", + InstrDisasm::kVMX | (i.VX128_R.Rc ? InstrDisasm::kRc : 0)); + return GeneralVX128(i, d); +} + +XEDISASMR(vcmpgefp, 0x100001C6, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpgefp", "Vector Compare Greater-Than-or-Equal-to Floating Point", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpgefp128, VX128(6, 128), VX128_R)(InstrData& i, InstrDisasm& d) { + d.Init("vcmpgefp128", "Vector128 Compare Greater-Than-or-Equal-to Floating Point", + InstrDisasm::kVMX | (i.VX128_R.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpgtfp, 0x100002C6, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpgtfp", "Vector Compare Greater-Than Floating Point", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpgtfp128, VX128(6, 256), VX128_R)(InstrData& i, InstrDisasm& d) { + d.Init("vcmpgtfp128", "Vector128 Compare Greater-Than Floating-Point", + InstrDisasm::kVMX | (i.VX128_R.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpgtsb, 0x10000306, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpgtsb", "Vector Compare Greater-Than Signed Byte", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpgtsh, 0x10000346, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpgtsh", "Vector Compare Greater-Than Signed Half Word", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpgtsw, 0x10000386, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpgtsw", "Vector Compare Greater-Than Signed Word", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpgtub, 0x10000206, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpgtub", "Vector Compare Greater-Than Unsigned Byte", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpgtuh, 0x10000246, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpgtuh", "Vector Compare Greater-Than Unsigned Half Word", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vcmpgtuw, 0x10000286, VXR )(InstrData& i, InstrDisasm& d) { + d.Init("vcmpgtuw", "Vector Compare Greater-Than Unsigned Word", + InstrDisasm::kVMX | (i.VXR.Rc ? InstrDisasm::kRc : 0)); + return 1; +} + +XEDISASMR(vctsxs, 0x100003CA, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vctsxs", "Vector Convert to Signed Fixed-Point Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vctuxs, 0x1000038A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vctuxs", "Vector Convert to Unsigned Fixed-Point Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vexptefp, 0x1000018A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vexptefp", "Vector 2 Raised to the Exponent Estimate Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vexptefp128, VX128_3(6, 1712), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vexptefp128", "Vector128 2 Raised to the Exponent Estimate Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vlogefp, 0x100001CA, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vlogefp", "Vector Log2 Estimate Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vlogefp128, VX128_3(6, 1776), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vlogefp128", "Vector128 Log2 Estimate Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmaddfp, 0x1000002E, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vmaddfp", "Vector Multiply-Add Floating Point", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vmaddfp128, VX128(5, 208), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vmaddfp128", "Vector128 Multiply Add Floating Point", + InstrDisasm::kVMX); + const uint32_t vd = i.VX128.VD128l | (i.VX128.VD128h << 5); + const uint32_t va = i.VX128.VA128l | (i.VX128.VA128h << 5) | + (i.VX128.VA128H << 6); + const uint32_t vb = i.VX128.VB128l | (i.VX128.VB128h << 5); + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, va, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vmaddcfp128, VX128(5, 272), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vmaddcfp128", "Vector128 Multiply Add Floating Point", + InstrDisasm::kVMX); + const uint32_t vd = i.VX128.VD128l | (i.VX128.VD128h << 5); + const uint32_t va = i.VX128.VA128l | (i.VX128.VA128h << 5) | + (i.VX128.VA128H << 6); + const uint32_t vb = i.VX128.VB128l | (i.VX128.VB128h << 5); + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, va, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vmaxfp, 0x1000040A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmaxfp", "Vector Maximum Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmaxfp128, VX128(6, 640), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vmaxfp128", "Vector128 Maximum Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmaxsb, 0x10000102, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmaxsb", "Vector Maximum Signed Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmaxsh, 0x10000142, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmaxsh", "Vector Maximum Signed Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmaxsw, 0x10000182, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmaxsw", "Vector Maximum Signed Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmaxub, 0x10000002, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmaxub", "Vector Maximum Unsigned Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmaxuh, 0x10000042, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmaxuh", "Vector Maximum Unsigned Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmaxuw, 0x10000082, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmaxuw", "Vector Maximum Unsigned Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmhaddshs, 0x10000020, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vmhaddshs", "Vector Multiply-High and Add Signed Signed Half Word Saturate", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vmhraddshs, 0x10000021, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vmhraddshs", "Vector Multiply-High Round and Add Signed Signed Half Word Saturate", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vminfp, 0x1000044A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vminfp", "Vector Minimum Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vminfp128, VX128(6, 704), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vminfp128", "Vector128 Minimum Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vminsb, 0x10000302, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vminsb", "Vector Minimum Signed Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vminsh, 0x10000342, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vminsh", "Vector Minimum Signed Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vminsw, 0x10000382, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vminsw", "Vector Minimum Signed Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vminub, 0x10000202, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vminub", "Vector Minimum Unsigned Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vminuh, 0x10000242, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vminuh", "Vector Minimum Unsigned Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vminuw, 0x10000282, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vminuw", "Vector Minimum Unsigned Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmladduhm, 0x10000022, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vmladduhm", "Vector Multiply-Low and Add Unsigned Half Word Modulo", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vmrghb, 0x1000000C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmrghb", "Vector Merge High Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmrghh, 0x1000004C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmrghh", "Vector Merge High Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmrghw, 0x1000008C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmrghw", "Vector Merge High Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmrghw128, VX128(6, 768), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vmrghw128", "Vector128 Merge High Word", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vmrglb, 0x1000010C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmrglb", "Vector Merge Low Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmrglh, 0x1000014C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmrglh", "Vector Merge Low Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmrglw, 0x1000018C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmrglw", "Vector Merge Low Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmrglw128, VX128(6, 832), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vmrglw128", "Vector128 Merge Low Word", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vmsummbm, 0x10000025, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vmsummbm", "Vector Multiply-Sum Mixed-Sign Byte Modulo", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vmsumshm, 0x10000028, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vmsumshm", "Vector Multiply-Sum Signed Half Word Modulo", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vmsumshs, 0x10000029, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vmsumshs", "Vector Multiply-Sum Signed Half Word Saturate", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vmsumubm, 0x10000024, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vmsumubm", "Vector Multiply-Sum Unsigned Byte Modulo", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vmsumuhm, 0x10000026, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vmsumuhm", "Vector Multiply-Sum Unsigned Half Word Modulo", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vmsumuhs, 0x10000027, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vmsumuhs", "Vector Multiply-Sum Unsigned Half Word Saturate", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vmsum3fp128, VX128(5, 400), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vmsum3fp128", "Vector128 Multiply Sum 3-way Floating Point", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vmsum4fp128, VX128(5, 464), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vmsum4fp128", "Vector128 Multiply Sum 4-way Floating-Point", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vmulesb, 0x10000308, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmulesb", "Vector Multiply Even Signed Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmulesh, 0x10000348, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmulesh", "Vector Multiply Even Signed Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmuleub, 0x10000208, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmuleub", "Vector Multiply Even Unsigned Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmuleuh, 0x10000248, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmuleuh", "Vector Multiply Even Unsigned Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmulosb, 0x10000108, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmulosb", "Vector Multiply Odd Signed Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmulosh, 0x10000148, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmulosh", "Vector Multiply Odd Signed Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmuloub, 0x10000008, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmuloub", "Vector Multiply Odd Unsigned Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmulouh, 0x10000048, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vmulouh", "Vector Multiply Odd Unsigned Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vmulfp128, VX128(5, 144), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vmulfp128", "Vector128 Multiply Floating-Point", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vnmsubfp, 0x1000002F, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vnmsubfp", "Vector Negative Multiply-Subtract Floating Point", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vnmsubfp128, VX128(5, 336), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vnmsubfp128", "Vector128 Negative Multiply-Subtract Floating Point", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vnor, 0x10000504, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vnor", "Vector Logical NOR", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vnor128, VX128(5, 656), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vnor128", "Vector128 Logical NOR", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vor, 0x10000484, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vor", "Vector Logical OR", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vor128, VX128(5, 720), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vor128", "Vector128 Logical OR", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vperm, 0x1000002B, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vperm", "Vector Permute", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vperm128, VX128_2(5, 0), VX128_2)(InstrData& i, InstrDisasm& d) { + d.Init("vperm128", "Vector128 Permute", + InstrDisasm::kVMX); + const uint32_t vd = i.VX128_2.VD128l | (i.VX128_2.VD128h << 5); + const uint32_t va = i.VX128_2.VA128l | (i.VX128_2.VA128h << 5) | + (i.VX128_2.VA128H << 6); + const uint32_t vb = i.VX128_2.VB128l | (i.VX128_2.VB128h << 5); + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, va, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, i.VX128_2.VC, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vpermwi128, VX128_P(6, 528), VX128_P)(InstrData& i, InstrDisasm& d) { + d.Init("vpermwi128", "Vector128 Permutate Word Immediate", + InstrDisasm::kVMX); + const uint32_t vd = i.VX128_P.VD128l | (i.VX128_P.VD128h << 5); + const uint32_t vb = i.VX128_P.VB128l | (i.VX128_P.VB128h << 5); + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); + d.AddUImmOperand(i.VX128_P.PERMl | (i.VX128_P.PERMh << 5), 1); + return d.Finish(); +} + +XEDISASMR(vpkpx, 0x1000030E, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vpkpx", "Vector Pack Pixel", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkshss, 0x1000018E, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vpkshss", "Vector Pack Signed Half Word Signed Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkshss128, VX128(5, 512), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vpkshss128", "Vector128 Pack Signed Half Word Signed Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkswss, 0x100001CE, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vpkswss", "Vector Pack Signed Word Signed Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkswss128, VX128(5, 640), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vpkswss128", "Vector128 Pack Signed Word Signed Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkswus, 0x1000014E, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vpkswus", "Vector Pack Signed Word Unsigned Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkswus128, VX128(5, 704), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vpkswus128", "Vector128 Pack Signed Word Unsigned Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkuhum, 0x1000000E, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vpkuhum", "Vector Pack Unsigned Half Word Unsigned Modulo", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkuhum128, VX128(5, 768), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vpkuhum128", "Vector128 Pack Unsigned Half Word Unsigned Modulo", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkuhus, 0x1000008E, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vpkuhus", "Vector Pack Unsigned Half Word Unsigned Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkuhus128, VX128(5, 832), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vpkuhus128", "Vector128 Pack Unsigned Half Word Unsigned Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkshus, 0x1000010E, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vpkshus", "Vector Pack Signed Half Word Unsigned Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkshus128, VX128(5, 576), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vpkshus128", "Vector128 Pack Signed Half Word Unsigned Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkuwum, 0x1000004E, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vpkuwum", "Vector Pack Unsigned Word Unsigned Modulo", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkuwum128, VX128(5, 896), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vpkuwum128", "Vector128 Pack Unsigned Word Unsigned Modulo", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkuwus, 0x100000CE, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vpkuwus", "Vector Pack Unsigned Word Unsigned Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkuwus128, VX128(5, 960), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vpkuwus128", "Vector128 Pack Unsigned Word Unsigned Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vpkd3d128, VX128_4(6, 1552), VX128_4)(InstrData& i, InstrDisasm& d) { + d.Init("vpkd3d128", "Vector128 Pack D3Dtype, Rotate Left Immediate and Mask Insert", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrefp, 0x1000010A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vrefp", "Vector Reciprocal Estimate Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrefp128, VX128_3(6, 1584), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vrefp128", "Vector128 Reciprocal Estimate Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrfim, 0x100002CA, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vrfim", "Vector Round to Floating-Point Integer toward -Infinity", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrfim128, VX128_3(6, 816), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vrfim128", "Vector128 Round to Floating-Point Integer toward -Infinity", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrfin, 0x1000020A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vrfin", "Vector Round to Floating-Point Integer Nearest", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrfin128, VX128_3(6, 880), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vrfin128", "Vector128 Round to Floating-Point Integer Nearest", + InstrDisasm::kVMX); + const uint32_t vd = i.VX128_3.VD128l | (i.VX128_3.VD128h << 5); + const uint32_t vb = i.VX128_3.VB128l | (i.VX128_3.VB128h << 5); + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vrfip, 0x1000028A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vrfip", "Vector Round to Floating-Point Integer toward +Infinity", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrfip128, VX128_3(6, 944), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vrfip128", "Vector128 Round to Floating-Point Integer toward +Infinity", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrfiz, 0x1000024A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vrfiz", "Vector Round to Floating-Point Integer toward Zero", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrfiz128, VX128_3(6, 1008), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vrfiz128", "Vector128 Round to Floating-Point Integer toward Zero", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrlb, 0x10000004, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vrlb", "Vector Rotate Left Integer Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrlh, 0x10000044, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vrlh", "Vector Rotate Left Integer Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrlw, 0x10000084, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vrlw", "Vector Rotate Left Integer Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrlw128, VX128(6, 80), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vrlw128", "Vector128 Rotate Left Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrlimi128, VX128_4(6, 1808), VX128_4)(InstrData& i, InstrDisasm& d) { + d.Init("vrlimi128", "Vector128 Rotate Left Immediate and Mask Insert", + InstrDisasm::kVMX); + const uint32_t vd = i.VX128_4.VD128l | (i.VX128_4.VD128h << 5); + const uint32_t vb = i.VX128_4.VB128l | (i.VX128_4.VB128h << 5); + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); + d.AddUImmOperand(i.VX128_4.IMM, 1); + d.AddUImmOperand(i.VX128_4.z, 1); + return d.Finish(); +} + +XEDISASMR(vrsqrtefp, 0x1000014A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vrsqrtefp", "Vector Reciprocal Square Root Estimate Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vrsqrtefp128, VX128_3(6, 1648), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vrsqrtefp128", "Vector128 Reciprocal Square Root Estimate Floating Point", + InstrDisasm::kVMX); + const uint32_t vd = i.VX128_3.VD128l | (i.VX128_3.VD128h << 5); + const uint32_t vb = i.VX128_3.VB128l | (i.VX128_3.VB128h << 5); + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vsel, 0x1000002A, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vsel", "Vector Conditional Select", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vsel128, VX128(5, 848), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vsel128", "Vector128 Conditional Select", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsl, 0x100001C4, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsl", "Vector Shift Left", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vslb, 0x10000104, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vslb", "Vector Shift Left Integer Byte", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vsldoi, 0x1000002C, VXA )(InstrData& i, InstrDisasm& d) { + d.Init("vsldoi", "Vector Shift Left Double by Octet Immediate", + InstrDisasm::kVMX); + return GeneralVXA(i, d); +} + +XEDISASMR(vsldoi128, VX128_5(4, 16), VX128_5)(InstrData& i, InstrDisasm& d) { + d.Init("vsldoi128", "Vector128 Shift Left Double by Octet Immediate", + InstrDisasm::kVMX); + const uint32_t vd = i.VX128_5.VD128l | (i.VX128_5.VD128h << 5); + const uint32_t va = i.VX128_5.VA128l | (i.VX128_5.VA128h << 5); + const uint32_t vb = i.VX128_5.VB128l | (i.VX128_5.VB128h << 5); + const uint32_t sh = i.VX128_5.SH; + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, va, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); + d.AddUImmOperand(sh, 1); + return d.Finish(); +} + +XEDISASMR(vslh, 0x10000144, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vslh", "Vector Shift Left Integer Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vslo, 0x1000040C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vslo", "Vector Shift Left by Octet", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vslo128, VX128(5, 912), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vslo128", "Vector128 Shift Left Octet", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vslw, 0x10000184, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vslw", "Vector Shift Left Integer Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vslw128, VX128(6, 208), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vslw128", "Vector128 Shift Left Integer Word", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vspltb, 0x1000020C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vspltb", "Vector Splat Byte", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); + d.AddUImmOperand(i.VX.VA & 0xF, 1); + return d.Finish(); +} + +XEDISASMR(vsplth, 0x1000024C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsplth", "Vector Splat Half Word", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); + d.AddUImmOperand(i.VX.VA & 0x7, 1); + return d.Finish(); +} + +XEDISASMR(vspltisb, 0x1000030C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vspltisb", "Vector Splat Immediate Signed Byte", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + // 5bit -> 8bit sign extend + uint64_t v = (i.VX.VA & 0x10) ? (i.VX.VA | 0xFFFFFFFFFFFFFFF0) : i.VX.VA; + d.AddSImmOperand(v, 1); + return d.Finish(); +} + +XEDISASMR(vspltish, 0x1000034C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vspltish", "Vector Splat Immediate Signed Half Word", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + // 5bit -> 16bit sign extend + uint64_t v = (i.VX.VA & 0x10) ? (i.VX.VA | 0xFFFFFFFFFFFFFFF0) : i.VX.VA; + d.AddSImmOperand(v, 1); + return d.Finish(); +} + +XEDISASMR(vspltisw, 0x1000038C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vspltisw", "Vector Splat Immediate Signed Word", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + // 5bit -> 32bit sign extend + uint64_t v = (i.VX.VA & 0x10) ? (i.VX.VA | 0xFFFFFFFFFFFFFFF0) : i.VX.VA; + d.AddSImmOperand(v, 1); + return d.Finish(); +} + +XEDISASMR(vspltisw128, VX128_3(6, 1904), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vspltisw128", "Vector128 Splat Immediate Signed Word", + InstrDisasm::kVMX); + return GeneralVX128_3(i, d); +} + +XEDISASMR(vspltw, 0x1000028C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vspltw", "Vector Splat Word", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); + d.AddUImmOperand(i.VX.VA, 1); + return d.Finish(); +} + +XEDISASMR(vspltw128, VX128_3(6, 1840), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vspltw128", " Vector128 Splat Word", + InstrDisasm::kVMX); + return GeneralVX128_3(i, d); +} + +XEDISASMR(vsr, 0x100002C4, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsr", "Vector Shift Right", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsrab, 0x10000304, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsrab", "Vector Shift Right Algebraic Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsrah, 0x10000344, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsrah", "Vector Shift Right Algebraic Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsraw, 0x10000384, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsraw", "Vector Shift Right Algebraic Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsraw128, VX128(6, 336), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vsraw128", "Vector128 Shift Right Arithmetic Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsrb, 0x10000204, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsrb", "Vector Shift Right Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsrh, 0x10000244, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsrh", "Vector Shift Right Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsro, 0x1000044C, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsro", "Vector Shift Right Octet", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsro128, VX128(5, 976), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vsro128", "Vector128 Shift Right Octet", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsrw, 0x10000284, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsrw", "Vector Shift Right Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsrw128, VX128(6, 464), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vsrw128", "Vector128 Shift Right Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsubcuw, 0x10000580, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsubcuw", "Vector Subtract Carryout Unsigned Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsubfp, 0x1000004A, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsubfp", "Vector Subtract Floating Point", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsubfp128, VX128(5, 80), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vsubfp128", "Vector128 Subtract Floating Point", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + +XEDISASMR(vsubsbs, 0x10000700, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsubsbs", "Vector Subtract Signed Byte Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsubshs, 0x10000740, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsubshs", "Vector Subtract Signed Half Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsubsws, 0x10000780, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsubsws", "Vector Subtract Signed Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsububm, 0x10000400, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsububm", "Vector Subtract Unsigned Byte Modulo", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsububs, 0x10000600, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsububs", "Vector Subtract Unsigned Byte Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsubuhm, 0x10000440, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsubuhm", "Vector Subtract Unsigned Half Word Modulo", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsubuhs, 0x10000640, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsubuhs", "Vector Subtract Unsigned Half Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsubuwm, 0x10000480, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsubuwm", "Vector Subtract Unsigned Word Modulo", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsubuws, 0x10000680, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsubuws", "Vector Subtract Unsigned Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsumsws, 0x10000788, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsumsws", "Vector Sum Across Signed Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsum2sws, 0x10000688, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsum2sws", "Vector Sum Across Partial (1/2) Signed Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsum4sbs, 0x10000708, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsum4sbs", "Vector Sum Across Partial (1/4) Signed Byte Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsum4shs, 0x10000648, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsum4shs", "Vector Sum Across Partial (1/4) Signed Half Word Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vsum4ubs, 0x10000608, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vsum4ubs", "Vector Sum Across Partial (1/4) Unsigned Byte Saturate", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vupkhpx, 0x1000034E, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vupkhpx", "Vector Unpack High Pixel", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vupkhsb, 0x1000020E, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vupkhsb", "Vector Unpack High Signed Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vupkhsb128, VX128(6, 896), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vupkhsb128", "Vector128 Unpack High Signed Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vupkhsh, 0x1000024E, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vupkhsh", "Vector Unpack High Signed Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vupklpx, 0x100003CE, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vupklpx", "Vector Unpack Low Pixel", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vupklsb, 0x1000028E, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vupklsb", "Vector Unpack Low Signed Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vupklsb128, VX128(6, 960), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vupklsb128", "Vector128 Unpack Low Signed Byte", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vupklsh, 0x100002CE, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vupklsh", "Vector Unpack Low Signed Half Word", + InstrDisasm::kVMX); + return 1; +} + +XEDISASMR(vupkd3d128, VX128_3(6, 2032), VX128_3)(InstrData& i, InstrDisasm& d) { + d.Init("vupkd3d128", "Vector128 Unpack D3Dtype", + InstrDisasm::kVMX); + const uint32_t vd = i.VX128_3.VD128l | (i.VX128_3.VD128h << 5); + const uint32_t vb = i.VX128_3.VB128l | (i.VX128_3.VB128h << 5); + d.AddRegOperand(InstrRegister::kVMX, vd, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, vb, InstrRegister::kRead); + d.AddUImmOperand(i.VX128_3.IMM, 1); + return d.Finish(); +} + +XEDISASMR(vxor, 0x100004C4, VX )(InstrData& i, InstrDisasm& d) { + d.Init("vxor", "Vector Logical XOR", + InstrDisasm::kVMX); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead); + return d.Finish(); +} + +XEDISASMR(vxor128, VX128(5, 784), VX128 )(InstrData& i, InstrDisasm& d) { + d.Init("vxor128", "Vector128 Logical XOR", + InstrDisasm::kVMX); + return GeneralVX128(i, d); +} + + +void RegisterDisasmCategoryAltivec() { + XEREGISTERINSTR(dst, 0x7C0002AC); + XEREGISTERINSTR(dstst, 0x7C0002EC); + XEREGISTERINSTR(dss, 0x7C00066C); + XEREGISTERINSTR(lvebx, 0x7C00000E); + XEREGISTERINSTR(lvehx, 0x7C00004E); + XEREGISTERINSTR(lvewx, 0x7C00008E); + XEREGISTERINSTR(lvewx128, VX128_1(4, 131)); + XEREGISTERINSTR(lvsl, 0x7C00000C); + XEREGISTERINSTR(lvsl128, VX128_1(4, 3)); + XEREGISTERINSTR(lvsr, 0x7C00004C); + XEREGISTERINSTR(lvsr128, VX128_1(4, 67)); + XEREGISTERINSTR(lvx, 0x7C0000CE); + XEREGISTERINSTR(lvx128, VX128_1(4, 195)); + XEREGISTERINSTR(lvxl, 0x7C0002CE); + XEREGISTERINSTR(lvxl128, VX128_1(4, 707)); + XEREGISTERINSTR(stvebx, 0x7C00010E); + XEREGISTERINSTR(stvehx, 0x7C00014E); + XEREGISTERINSTR(stvewx, 0x7C00018E); + XEREGISTERINSTR(stvewx128, VX128_1(4, 387)); + XEREGISTERINSTR(stvx, 0x7C0001CE); + XEREGISTERINSTR(stvx128, VX128_1(4, 451)); + XEREGISTERINSTR(stvxl, 0x7C0003CE); + XEREGISTERINSTR(stvxl128, VX128_1(4, 963)); + XEREGISTERINSTR(lvlx, 0x7C00040E); + XEREGISTERINSTR(lvlx128, VX128_1(4, 1027)); + XEREGISTERINSTR(lvlxl, 0x7C00060E); + XEREGISTERINSTR(lvlxl128, VX128_1(4, 1539)); + XEREGISTERINSTR(lvrx, 0x7C00044E); + XEREGISTERINSTR(lvrx128, VX128_1(4, 1091)); + XEREGISTERINSTR(lvrxl, 0x7C00064E); + XEREGISTERINSTR(lvrxl128, VX128_1(4, 1603)); + XEREGISTERINSTR(stvlx, 0x7C00050E); + XEREGISTERINSTR(stvlx128, VX128_1(4, 1283)); + XEREGISTERINSTR(stvlxl, 0x7C00070E); + XEREGISTERINSTR(stvlxl128, VX128_1(4, 1795)); + XEREGISTERINSTR(stvrx, 0x7C00054E); + XEREGISTERINSTR(stvrx128, VX128_1(4, 1347)); + XEREGISTERINSTR(stvrxl, 0x7C00074E); + XEREGISTERINSTR(stvrxl128, VX128_1(4, 1859)); + + XEREGISTERINSTR(mfvscr, 0x10000604); + XEREGISTERINSTR(mtvscr, 0x10000644); + XEREGISTERINSTR(vaddcuw, 0x10000180); + XEREGISTERINSTR(vaddfp, 0x1000000A); + XEREGISTERINSTR(vaddfp128, VX128(5, 16)); + XEREGISTERINSTR(vaddsbs, 0x10000300); + XEREGISTERINSTR(vaddshs, 0x10000340); + XEREGISTERINSTR(vaddsws, 0x10000380); + XEREGISTERINSTR(vaddubm, 0x10000000); + XEREGISTERINSTR(vaddubs, 0x10000200); + XEREGISTERINSTR(vadduhm, 0x10000040); + XEREGISTERINSTR(vadduhs, 0x10000240); + XEREGISTERINSTR(vadduwm, 0x10000080); + XEREGISTERINSTR(vadduws, 0x10000280); + XEREGISTERINSTR(vand, 0x10000404); + XEREGISTERINSTR(vand128, VX128(5, 528)); + XEREGISTERINSTR(vandc, 0x10000444); + XEREGISTERINSTR(vandc128, VX128(5, 592)); + XEREGISTERINSTR(vavgsb, 0x10000502); + XEREGISTERINSTR(vavgsh, 0x10000542); + XEREGISTERINSTR(vavgsw, 0x10000582); + XEREGISTERINSTR(vavgub, 0x10000402); + XEREGISTERINSTR(vavguh, 0x10000442); + XEREGISTERINSTR(vavguw, 0x10000482); + XEREGISTERINSTR(vcfsx, 0x1000034A); + XEREGISTERINSTR(vcsxwfp128, VX128_3(6, 688)); + XEREGISTERINSTR(vcfpsxws128, VX128_3(6, 560)); + XEREGISTERINSTR(vcfux, 0x1000030A); + XEREGISTERINSTR(vcuxwfp128, VX128_3(6, 752)); + XEREGISTERINSTR(vcfpuxws128, VX128_3(6, 624)); + XEREGISTERINSTR(vcmpbfp, 0x100003C6); + XEREGISTERINSTR(vcmpbfp128, VX128(6, 384)); + XEREGISTERINSTR(vcmpeqfp, 0x100000C6); + XEREGISTERINSTR(vcmpeqfp128, VX128(6, 0)); + XEREGISTERINSTR(vcmpequb, 0x10000006); + XEREGISTERINSTR(vcmpequh, 0x10000046); + XEREGISTERINSTR(vcmpequw, 0x10000086); + XEREGISTERINSTR(vcmpequw128, VX128(6, 512)); + XEREGISTERINSTR(vcmpgefp, 0x100001C6); + XEREGISTERINSTR(vcmpgefp128, VX128(6, 128)); + XEREGISTERINSTR(vcmpgtfp, 0x100002C6); + XEREGISTERINSTR(vcmpgtfp128, VX128(6, 256)); + XEREGISTERINSTR(vcmpgtsb, 0x10000306); + XEREGISTERINSTR(vcmpgtsh, 0x10000346); + XEREGISTERINSTR(vcmpgtsw, 0x10000386); + XEREGISTERINSTR(vcmpgtub, 0x10000206); + XEREGISTERINSTR(vcmpgtuh, 0x10000246); + XEREGISTERINSTR(vcmpgtuw, 0x10000286); + XEREGISTERINSTR(vctsxs, 0x100003CA); + XEREGISTERINSTR(vctuxs, 0x1000038A); + XEREGISTERINSTR(vexptefp, 0x1000018A); + XEREGISTERINSTR(vexptefp128, VX128_3(6, 1712)); + XEREGISTERINSTR(vlogefp, 0x100001CA); + XEREGISTERINSTR(vlogefp128, VX128_3(6, 1776)); + XEREGISTERINSTR(vmaddfp, 0x1000002E); + XEREGISTERINSTR(vmaddfp128, VX128(5, 208)); + XEREGISTERINSTR(vmaddcfp128, VX128(5, 272)); + XEREGISTERINSTR(vmaxfp, 0x1000040A); + XEREGISTERINSTR(vmaxfp128, VX128(6, 640)); + XEREGISTERINSTR(vmaxsb, 0x10000102); + XEREGISTERINSTR(vmaxsh, 0x10000142); + XEREGISTERINSTR(vmaxsw, 0x10000182); + XEREGISTERINSTR(vmaxub, 0x10000002); + XEREGISTERINSTR(vmaxuh, 0x10000042); + XEREGISTERINSTR(vmaxuw, 0x10000082); + XEREGISTERINSTR(vmhaddshs, 0x10000020); + XEREGISTERINSTR(vmhraddshs, 0x10000021); + XEREGISTERINSTR(vminfp, 0x1000044A); + XEREGISTERINSTR(vminfp128, VX128(6, 704)); + XEREGISTERINSTR(vminsb, 0x10000302); + XEREGISTERINSTR(vminsh, 0x10000342); + XEREGISTERINSTR(vminsw, 0x10000382); + XEREGISTERINSTR(vminub, 0x10000202); + XEREGISTERINSTR(vminuh, 0x10000242); + XEREGISTERINSTR(vminuw, 0x10000282); + XEREGISTERINSTR(vmladduhm, 0x10000022); + XEREGISTERINSTR(vmrghb, 0x1000000C); + XEREGISTERINSTR(vmrghh, 0x1000004C); + XEREGISTERINSTR(vmrghw, 0x1000008C); + XEREGISTERINSTR(vmrghw128, VX128(6, 768)); + XEREGISTERINSTR(vmrglb, 0x1000010C); + XEREGISTERINSTR(vmrglh, 0x1000014C); + XEREGISTERINSTR(vmrglw, 0x1000018C); + XEREGISTERINSTR(vmrglw128, VX128(6, 832)); + XEREGISTERINSTR(vmsummbm, 0x10000025); + XEREGISTERINSTR(vmsumshm, 0x10000028); + XEREGISTERINSTR(vmsumshs, 0x10000029); + XEREGISTERINSTR(vmsumubm, 0x10000024); + XEREGISTERINSTR(vmsumuhm, 0x10000026); + XEREGISTERINSTR(vmsumuhs, 0x10000027); + XEREGISTERINSTR(vmsum3fp128, VX128(5, 400)); + XEREGISTERINSTR(vmsum4fp128, VX128(5, 464)); + XEREGISTERINSTR(vmulesb, 0x10000308); + XEREGISTERINSTR(vmulesh, 0x10000348); + XEREGISTERINSTR(vmuleub, 0x10000208); + XEREGISTERINSTR(vmuleuh, 0x10000248); + XEREGISTERINSTR(vmulosb, 0x10000108); + XEREGISTERINSTR(vmulosh, 0x10000148); + XEREGISTERINSTR(vmuloub, 0x10000008); + XEREGISTERINSTR(vmulouh, 0x10000048); + XEREGISTERINSTR(vmulfp128, VX128(5, 144)); + XEREGISTERINSTR(vnmsubfp, 0x1000002F); + XEREGISTERINSTR(vnmsubfp128, VX128(5, 336)); + XEREGISTERINSTR(vnor, 0x10000504); + XEREGISTERINSTR(vnor128, VX128(5, 656)); + XEREGISTERINSTR(vor, 0x10000484); + XEREGISTERINSTR(vor128, VX128(5, 720)); + XEREGISTERINSTR(vperm, 0x1000002B); + XEREGISTERINSTR(vperm128, VX128_2(5, 0)); + XEREGISTERINSTR(vpermwi128, VX128_P(6, 528)); + XEREGISTERINSTR(vpkpx, 0x1000030E); + XEREGISTERINSTR(vpkshss, 0x1000018E); + XEREGISTERINSTR(vpkshss128, VX128(5, 512)); + XEREGISTERINSTR(vpkshus, 0x1000010E); + XEREGISTERINSTR(vpkshus128, VX128(5, 576)); + XEREGISTERINSTR(vpkswss, 0x100001CE); + XEREGISTERINSTR(vpkswss128, VX128(5, 640)); + XEREGISTERINSTR(vpkswus, 0x1000014E); + XEREGISTERINSTR(vpkswus128, VX128(5, 704)); + XEREGISTERINSTR(vpkuhum, 0x1000000E); + XEREGISTERINSTR(vpkuhum128, VX128(5, 768)); + XEREGISTERINSTR(vpkuhus, 0x1000008E); + XEREGISTERINSTR(vpkuhus128, VX128(5, 832)); + XEREGISTERINSTR(vpkuwum, 0x1000004E); + XEREGISTERINSTR(vpkuwum128, VX128(5, 896)); + XEREGISTERINSTR(vpkuwus, 0x100000CE); + XEREGISTERINSTR(vpkuwus128, VX128(5, 960)); + XEREGISTERINSTR(vpkd3d128, VX128_4(6, 1552)); + XEREGISTERINSTR(vrefp, 0x1000010A); + XEREGISTERINSTR(vrefp128, VX128_3(6, 1584)); + XEREGISTERINSTR(vrfim, 0x100002CA); + XEREGISTERINSTR(vrfim128, VX128_3(6, 816)); + XEREGISTERINSTR(vrfin, 0x1000020A); + XEREGISTERINSTR(vrfin128, VX128_3(6, 880)); + XEREGISTERINSTR(vrfip, 0x1000028A); + XEREGISTERINSTR(vrfip128, VX128_3(6, 944)); + XEREGISTERINSTR(vrfiz, 0x1000024A); + XEREGISTERINSTR(vrfiz128, VX128_3(6, 1008)); + XEREGISTERINSTR(vrlb, 0x10000004); + XEREGISTERINSTR(vrlh, 0x10000044); + XEREGISTERINSTR(vrlw, 0x10000084); + XEREGISTERINSTR(vrlw128, VX128(6, 80)); + XEREGISTERINSTR(vrlimi128, VX128_4(6, 1808)); + XEREGISTERINSTR(vrsqrtefp, 0x1000014A); + XEREGISTERINSTR(vrsqrtefp128, VX128_3(6, 1648)); + XEREGISTERINSTR(vsel, 0x1000002A); + XEREGISTERINSTR(vsel128, VX128(5, 848)); + XEREGISTERINSTR(vsl, 0x100001C4); + XEREGISTERINSTR(vslb, 0x10000104); + XEREGISTERINSTR(vsldoi, 0x1000002C); + XEREGISTERINSTR(vsldoi128, VX128_5(4, 16)); + XEREGISTERINSTR(vslh, 0x10000144); + XEREGISTERINSTR(vslo, 0x1000040C); + XEREGISTERINSTR(vslo128, VX128(5, 912)); + XEREGISTERINSTR(vslw, 0x10000184); + XEREGISTERINSTR(vslw128, VX128(6, 208)); + XEREGISTERINSTR(vspltb, 0x1000020C); + XEREGISTERINSTR(vsplth, 0x1000024C); + XEREGISTERINSTR(vspltisb, 0x1000030C); + XEREGISTERINSTR(vspltish, 0x1000034C); + XEREGISTERINSTR(vspltisw, 0x1000038C); + XEREGISTERINSTR(vspltisw128, VX128_3(6, 1904)); + XEREGISTERINSTR(vspltw, 0x1000028C); + XEREGISTERINSTR(vspltw128, VX128_3(6, 1840)); + XEREGISTERINSTR(vsr, 0x100002C4); + XEREGISTERINSTR(vsrab, 0x10000304); + XEREGISTERINSTR(vsrah, 0x10000344); + XEREGISTERINSTR(vsraw, 0x10000384); + XEREGISTERINSTR(vsraw128, VX128(6, 336)); + XEREGISTERINSTR(vsrb, 0x10000204); + XEREGISTERINSTR(vsrh, 0x10000244); + XEREGISTERINSTR(vsro, 0x1000044C); + XEREGISTERINSTR(vsro128, VX128(5, 976)); + XEREGISTERINSTR(vsrw, 0x10000284); + XEREGISTERINSTR(vsrw128, VX128(6, 464)); + XEREGISTERINSTR(vsubcuw, 0x10000580); + XEREGISTERINSTR(vsubfp, 0x1000004A); + XEREGISTERINSTR(vsubfp128, VX128(5, 80)); + XEREGISTERINSTR(vsubsbs, 0x10000700); + XEREGISTERINSTR(vsubshs, 0x10000740); + XEREGISTERINSTR(vsubsws, 0x10000780); + XEREGISTERINSTR(vsububm, 0x10000400); + XEREGISTERINSTR(vsububs, 0x10000600); + XEREGISTERINSTR(vsubuhm, 0x10000440); + XEREGISTERINSTR(vsubuhs, 0x10000640); + XEREGISTERINSTR(vsubuwm, 0x10000480); + XEREGISTERINSTR(vsubuws, 0x10000680); + XEREGISTERINSTR(vsumsws, 0x10000788); + XEREGISTERINSTR(vsum2sws, 0x10000688); + XEREGISTERINSTR(vsum4sbs, 0x10000708); + XEREGISTERINSTR(vsum4shs, 0x10000648); + XEREGISTERINSTR(vsum4ubs, 0x10000608); + XEREGISTERINSTR(vupkhpx, 0x1000034E); + XEREGISTERINSTR(vupkhsb, 0x1000020E); + XEREGISTERINSTR(vupkhsb128, VX128(6, 896)); + XEREGISTERINSTR(vupkhsh, 0x1000024E); + XEREGISTERINSTR(vupklpx, 0x100003CE); + XEREGISTERINSTR(vupklsb, 0x1000028E); + XEREGISTERINSTR(vupklsb128, VX128(6, 960)); + XEREGISTERINSTR(vupklsh, 0x100002CE); + XEREGISTERINSTR(vupkd3d128, VX128_3(6, 2032)); + XEREGISTERINSTR(vxor, 0x100004C4); + XEREGISTERINSTR(vxor128, VX128(5, 784)); +} + + +} // namespace ppc +} // namespace frontend +} // namespace alloy diff --git a/src/xenia/cpu/ppc/disasm_alu.cc b/src/alloy/frontend/ppc/ppc_disasm_alu.cc similarity index 99% rename from src/xenia/cpu/ppc/disasm_alu.cc rename to src/alloy/frontend/ppc/ppc_disasm_alu.cc index 87e53b35e..e5fd8a5fe 100644 --- a/src/xenia/cpu/ppc/disasm_alu.cc +++ b/src/alloy/frontend/ppc/ppc_disasm_alu.cc @@ -7,14 +7,14 @@ ****************************************************************************** */ -#include +#include -using namespace xe::cpu::ppc; +using namespace alloy::frontend::ppc; -namespace xe { -namespace cpu { +namespace alloy { +namespace frontend { namespace ppc { @@ -724,5 +724,5 @@ void RegisterDisasmCategoryALU() { } // namespace ppc -} // namespace cpu -} // namespace xe +} // namespace frontend +} // namespace alloy diff --git a/src/xenia/cpu/ppc/disasm_control.cc b/src/alloy/frontend/ppc/ppc_disasm_control.cc similarity index 94% rename from src/xenia/cpu/ppc/disasm_control.cc rename to src/alloy/frontend/ppc/ppc_disasm_control.cc index 29802259f..5c50ca947 100644 --- a/src/xenia/cpu/ppc/disasm_control.cc +++ b/src/alloy/frontend/ppc/ppc_disasm_control.cc @@ -7,14 +7,14 @@ ****************************************************************************** */ -#include +#include -using namespace xe::cpu::ppc; +using namespace alloy::frontend::ppc; -namespace xe { -namespace cpu { +namespace alloy { +namespace frontend { namespace ppc { @@ -22,9 +22,9 @@ XEDISASMR(bx, 0x48000000, I )(InstrData& i, InstrDisasm& d) { d.Init("b", "Branch", i.I.LK ? InstrDisasm::kLR : 0); uint32_t nia; if (i.I.AA) { - nia = XEEXTS26(i.I.LI << 2); + nia = (uint32_t)XEEXTS26(i.I.LI << 2); } else { - nia = i.address + XEEXTS26(i.I.LI << 2); + nia = (uint32_t)(i.address + XEEXTS26(i.I.LI << 2)); } d.AddUImmOperand(nia, 4); return d.Finish(); @@ -41,6 +41,13 @@ XEDISASMR(bcx, 0x40000000, B )(InstrData& i, InstrDisasm& d) { } d.AddUImmOperand(i.B.BO, 1); d.AddUImmOperand(i.B.BI, 1); + uint32_t nia; + if (i.B.AA) { + nia = (uint32_t)XEEXTS16(i.B.BD << 2); + } else { + nia = (uint32_t)(i.address + XEEXTS16(i.B.BD << 2)); + } + d.AddUImmOperand(nia, 4); return d.Finish(); } @@ -272,5 +279,5 @@ void RegisterDisasmCategoryControl() { } // namespace ppc -} // namespace cpu -} // namespace xe +} // namespace frontend +} // namespace alloy diff --git a/src/xenia/cpu/ppc/disasm_fpu.cc b/src/alloy/frontend/ppc/ppc_disasm_fpu.cc similarity index 98% rename from src/xenia/cpu/ppc/disasm_fpu.cc rename to src/alloy/frontend/ppc/ppc_disasm_fpu.cc index 6b63d8290..7b17c3dd2 100644 --- a/src/xenia/cpu/ppc/disasm_fpu.cc +++ b/src/alloy/frontend/ppc/ppc_disasm_fpu.cc @@ -7,14 +7,14 @@ ****************************************************************************** */ -#include +#include -using namespace xe::cpu::ppc; +using namespace alloy::frontend::ppc; -namespace xe { -namespace cpu { +namespace alloy { +namespace frontend { namespace ppc { @@ -409,5 +409,5 @@ void RegisterDisasmCategoryFPU() { } // namespace ppc -} // namespace cpu -} // namespace xe +} // namespace frontend +} // namespace alloy diff --git a/src/xenia/cpu/ppc/disasm_memory.cc b/src/alloy/frontend/ppc/ppc_disasm_memory.cc similarity index 99% rename from src/xenia/cpu/ppc/disasm_memory.cc rename to src/alloy/frontend/ppc/ppc_disasm_memory.cc index c0bbe5acf..aebb72964 100644 --- a/src/xenia/cpu/ppc/disasm_memory.cc +++ b/src/alloy/frontend/ppc/ppc_disasm_memory.cc @@ -7,14 +7,14 @@ ****************************************************************************** */ -#include +#include -using namespace xe::cpu::ppc; +using namespace alloy::frontend::ppc; -namespace xe { -namespace cpu { +namespace alloy { +namespace frontend { namespace ppc { @@ -926,5 +926,5 @@ void RegisterDisasmCategoryMemory() { } // namespace ppc -} // namespace cpu -} // namespace xe +} // namespace frontend +} // namespace alloy diff --git a/src/xenia/cpu/x64/x64_emit.h b/src/alloy/frontend/ppc/ppc_emit-private.h similarity index 53% rename from src/xenia/cpu/x64/x64_emit.h rename to src/alloy/frontend/ppc/ppc_emit-private.h index 60ef435a0..e805bca76 100644 --- a/src/xenia/cpu/x64/x64_emit.h +++ b/src/alloy/frontend/ppc/ppc_emit-private.h @@ -7,24 +7,16 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_X64_X64_EMIT_H_ -#define XENIA_CPU_X64_X64_EMIT_H_ +#ifndef ALLOY_FRONTEND_PPC_PPC_EMIT_PRIVATE_H_ +#define ALLOY_FRONTEND_PPC_PPC_EMIT_PRIVATE_H_ -#include -#include -#include +#include +#include -namespace xe { -namespace cpu { -namespace x64 { - - -void X64RegisterEmitCategoryAltivec(); -void X64RegisterEmitCategoryALU(); -void X64RegisterEmitCategoryControl(); -void X64RegisterEmitCategoryFPU(); -void X64RegisterEmitCategoryMemory(); +namespace alloy { +namespace frontend { +namespace ppc { #define XEEMITTER(name, opcode, format) int InstrEmit_##name @@ -32,13 +24,13 @@ void X64RegisterEmitCategoryMemory(); #define XEREGISTERINSTR(name, opcode) \ RegisterInstrEmit(opcode, (InstrEmitFn)InstrEmit_##name); -#define XEINSTRNOTIMPLEMENTED() -//#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS +//#define XEINSTRNOTIMPLEMENTED() +#define XEINSTRNOTIMPLEMENTED XEASSERTALWAYS -} // namespace x64 -} // namespace cpu -} // namespace xe +} // namespace ppc +} // namespace frontend +} // namespace alloy -#endif // XENIA_CPU_X64_X64_EMIT_H_ +#endif // ALLOY_FRONTEND_PPC_PPC_EMIT_PRIVATE_H_ diff --git a/src/alloy/frontend/ppc/ppc_emit.h b/src/alloy/frontend/ppc/ppc_emit.h new file mode 100644 index 000000000..9afea2f19 --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_emit.h @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_FRONTEND_PPC_PPC_EMIT_H_ +#define ALLOY_FRONTEND_PPC_PPC_EMIT_H_ + +#include + + +namespace alloy { +namespace frontend { +namespace ppc { + + +void RegisterEmitCategoryAltivec(); +void RegisterEmitCategoryALU(); +void RegisterEmitCategoryControl(); +void RegisterEmitCategoryFPU(); +void RegisterEmitCategoryMemory(); + + +} // namespace ppc +} // namespace frontend +} // namespace alloy + + +#endif // ALLOY_FRONTEND_PPC_PPC_EMIT_H_ diff --git a/src/alloy/frontend/ppc/ppc_emit_altivec.cc b/src/alloy/frontend/ppc/ppc_emit_altivec.cc new file mode 100644 index 000000000..0a470eba4 --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_emit_altivec.cc @@ -0,0 +1,2170 @@ +/* + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include + + +using namespace alloy::frontend::ppc; +using namespace alloy::hir; +using namespace alloy::runtime; + + +namespace alloy { +namespace frontend { +namespace ppc { + + +#define SHUFPS_SWAP_DWORDS 0x1B + + +// Most of this file comes from: +// http://biallas.net/doc/vmx128/vmx128.txt +// https://github.com/kakaroto/ps3ida/blob/master/plugins/PPCAltivec/src/main.cpp + + +#define OP(x) ((((uint32_t)(x)) & 0x3f) << 26) +#define VX128(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x3d0)) +#define VX128_1(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x7f3)) +#define VX128_2(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x210)) +#define VX128_3(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x7f0)) +#define VX128_4(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x730)) +#define VX128_5(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x10)) +#define VX128_P(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x630)) + +#define VX128_VD128 (i.VX128.VD128l | (i.VX128.VD128h << 5)) +#define VX128_VA128 (i.VX128.VA128l | (i.VX128.VA128h << 5) | (i.VX128.VA128H << 6)) +#define VX128_VB128 (i.VX128.VB128l | (i.VX128.VB128h << 5)) +#define VX128_1_VD128 (i.VX128_1.VD128l | (i.VX128_1.VD128h << 5)) +#define VX128_2_VD128 (i.VX128_2.VD128l | (i.VX128_2.VD128h << 5)) +#define VX128_2_VA128 (i.VX128_2.VA128l | (i.VX128_2.VA128h << 5) | (i.VX128_2.VA128H << 6)) +#define VX128_2_VB128 (i.VX128_2.VB128l | (i.VX128_2.VD128h << 5)) +#define VX128_2_VC (i.VX128_2.VC) +#define VX128_3_VD128 (i.VX128_3.VD128l | (i.VX128_3.VD128h << 5)) +#define VX128_3_VB128 (i.VX128_3.VB128l | (i.VX128_3.VB128h << 5)) +#define VX128_3_IMM (i.VX128_3.IMM) +#define VX128_5_VD128 (i.VX128_5.VD128l | (i.VX128_5.VD128h << 5)) +#define VX128_5_VA128 (i.VX128_5.VA128l | (i.VX128_5.VA128h << 5)) +#define VX128_5_VB128 (i.VX128_5.VB128l | (i.VX128_5.VB128h << 5)) +#define VX128_5_SH (i.VX128_5.SH) +#define VX128_R_VD128 (i.VX128_R.VD128l | (i.VX128_R.VD128h << 5)) +#define VX128_R_VA128 (i.VX128_R.VA128l | (i.VX128_R.VA128h << 5) | (i.VX128_R.VA128H << 6)) +#define VX128_R_VB128 (i.VX128_R.VB128l | (i.VX128_R.VB128h << 5)) + + +// namespace { + +// // Shuffle masks to shift the values over and insert zeros from the low bits. +// static __m128i __shift_table_left[16] = { +// _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), // unused +// _mm_set_epi8(14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15), +// _mm_set_epi8(13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15), +// _mm_set_epi8(12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15), +// _mm_set_epi8(11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15), +// _mm_set_epi8(10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15), +// _mm_set_epi8( 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15), +// _mm_set_epi8( 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15), +// _mm_set_epi8( 7, 6, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15), +// _mm_set_epi8( 6, 5, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15), +// _mm_set_epi8( 5, 4, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15), +// _mm_set_epi8( 4, 3, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15), +// _mm_set_epi8( 3, 2, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15), +// _mm_set_epi8( 2, 1, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15), +// _mm_set_epi8( 1, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15), +// _mm_set_epi8( 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15), +// }; +// static __m128i __shift_table_right[16] = { +// _mm_set_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), // unused +// _mm_set_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15), +// _mm_set_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 14), +// _mm_set_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 14, 13), +// _mm_set_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 14, 13, 12), +// _mm_set_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 14, 13, 12, 11), +// _mm_set_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 14, 13, 12, 11, 10), +// _mm_set_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 14, 13, 12, 11, 10, 9), +// _mm_set_epi8( 0, 0, 0, 0, 0, 0, 0, 0, 15, 14, 13, 12, 11, 10, 9, 8), +// _mm_set_epi8( 0, 0, 0, 0, 0, 0, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7), +// _mm_set_epi8( 0, 0, 0, 0, 0, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6), +// _mm_set_epi8( 0, 0, 0, 0, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5), +// _mm_set_epi8( 0, 0, 0, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4), +// _mm_set_epi8( 0, 0, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3), +// _mm_set_epi8( 0, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2), +// _mm_set_epi8( 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1), +// }; + +// } + + +XEEMITTER(dst, 0x7C0002AC, XDSS)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(dstst, 0x7C0002EC, XDSS)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(dss, 0x7C00066C, XDSS)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(lvebx, 0x7C00000E, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(lvehx, 0x7C00004E, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +int InstrEmit_lvewx_(PPCFunctionBuilder& f, InstrData& i, uint32_t vd, uint32_t ra, uint32_t rb) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(lvewx, 0x7C00008E, X )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_lvewx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} +XEEMITTER(lvewx128, VX128_1(4, 131), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_lvewx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// static __m128i __lvsl_table[16] = { +// _mm_set_epi8( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), +// _mm_set_epi8( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), +// _mm_set_epi8( 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17), +// _mm_set_epi8( 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18), +// _mm_set_epi8( 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19), +// _mm_set_epi8( 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20), +// _mm_set_epi8( 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21), +// _mm_set_epi8( 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22), +// _mm_set_epi8( 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23), +// _mm_set_epi8( 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24), +// _mm_set_epi8(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25), +// _mm_set_epi8(11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26), +// _mm_set_epi8(12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27), +// _mm_set_epi8(13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28), +// _mm_set_epi8(14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29), +// _mm_set_epi8(15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30), +// }; +// int InstrEmit_lvsl_(PPCFunctionBuilder& f, InstrData& i, uint32_t vd, uint32_t ra, uint32_t rb) { +// GpVar ea(c.newGpVar()); +// c.mov(ea, e.gpr_value(rb)); +// if (ra) { +// c.add(ea, e.gpr_value(ra)); +// } +// c.and_(ea, imm(0xF)); +// c.shl(ea, imm(4)); // table offset = (16b * sh) +// GpVar gt(c.newGpVar()); +// c.mov(gt, imm((sysint_t)__lvsl_table)); +// XmmVar v(c.newXmmVar()); +// c.movaps(v, xmmword_ptr(gt, ea)); +// c.shufps(v, v, imm(SHUFPS_SWAP_DWORDS)); +// f.StoreVR(vd, v); +// e.TraceVR(vd); +// return 0; +// } +// XEEMITTER(lvsl, 0x7C00000C, X )(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvsl_(f, i, i.X.RT, i.X.RA, i.X.RB); +// } +// XEEMITTER(lvsl128, VX128_1(4, 3), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvsl_(f, i, i.X.RT, i.X.RA, i.X.RB); +// } + +// static __m128i __lvsr_table[16] = { +// _mm_set_epi8(16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31), +// _mm_set_epi8(15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30), +// _mm_set_epi8(14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29), +// _mm_set_epi8(13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28), +// _mm_set_epi8(12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27), +// _mm_set_epi8(11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26), +// _mm_set_epi8(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25), +// _mm_set_epi8( 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24), +// _mm_set_epi8( 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23), +// _mm_set_epi8( 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22), +// _mm_set_epi8( 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21), +// _mm_set_epi8( 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20), +// _mm_set_epi8( 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19), +// _mm_set_epi8( 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18), +// _mm_set_epi8( 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17), +// _mm_set_epi8( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), +// }; +// int InstrEmit_lvsr_(PPCFunctionBuilder& f, InstrData& i, uint32_t vd, uint32_t ra, uint32_t rb) { +// GpVar ea(c.newGpVar()); +// c.mov(ea, e.gpr_value(rb)); +// if (ra) { +// c.add(ea, e.gpr_value(ra)); +// } +// c.and_(ea, imm(0xF)); +// c.shl(ea, imm(4)); // table offset = (16b * sh) +// GpVar gt(c.newGpVar()); +// c.mov(gt, imm((sysint_t)__lvsr_table)); +// XmmVar v(c.newXmmVar()); +// c.movaps(v, xmmword_ptr(gt, ea)); +// c.shufps(v, v, imm(SHUFPS_SWAP_DWORDS)); +// f.StoreVR(vd, v); +// e.TraceVR(vd); +// return 0; +// } +// XEEMITTER(lvsr, 0x7C00004C, X )(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvsr_(f, i, i.X.RT, i.X.RA, i.X.RB); +// } +// XEEMITTER(lvsr128, VX128_1(4, 67), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvsr_(f, i, i.X.RT, i.X.RA, i.X.RB); +// } + +int InstrEmit_lvx_(PPCFunctionBuilder& f, InstrData& i, uint32_t vd, uint32_t ra, uint32_t rb) { + Value* ea = ra ? f.Add(f.LoadGPR(ra), f.LoadGPR(rb)) : f.LoadGPR(rb); + f.StoreVR(vd, f.ByteSwap(f.Load(ea, VEC128_TYPE))); + return 0; +} +XEEMITTER(lvx, 0x7C0000CE, X )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_lvx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} +XEEMITTER(lvx128, VX128_1(4, 195), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_lvx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} +XEEMITTER(lvxl, 0x7C0002CE, X )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_lvx(f, i); +} +XEEMITTER(lvxl128, VX128_1(4, 707), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_lvx128(f, i); +} + +XEEMITTER(stvebx, 0x7C00010E, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(stvehx, 0x7C00014E, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +int InstrEmit_stvewx_(PPCFunctionBuilder& f, InstrData& i, uint32_t vd, uint32_t ra, uint32_t rb) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(stvewx, 0x7C00018E, X )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_stvewx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} +XEEMITTER(stvewx128, VX128_1(4, 387), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_stvewx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +int InstrEmit_stvx_(PPCFunctionBuilder& f, InstrData& i, uint32_t vd, uint32_t ra, uint32_t rb) { + Value* ea = ra ? f.Add(f.LoadGPR(ra), f.LoadGPR(rb)) : f.LoadGPR(rb); + f.Store(ea, f.ByteSwap(f.LoadVR(vd))); + return 0; +} +XEEMITTER(stvx, 0x7C0001CE, X )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_stvx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} +XEEMITTER(stvx128, VX128_1(4, 451), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_stvx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} +XEEMITTER(stvxl, 0x7C0003CE, X )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_stvx(f, i); +} +XEEMITTER(stvxl128, VX128_1(4, 963), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_stvx128(f, i); +} + +// // The lvlx/lvrx/etc instructions are in Cell docs only: +// // https://www-01.ibm.com/chips/techlib/techlib.nsf/techdocs/C40E4C6133B31EE8872570B500791108/$file/vector_simd_pem_v_2.07c_26Oct2006_cell.pdf +// int InstrEmit_lvlx_(PPCFunctionBuilder& f, InstrData& i, uint32_t vd, uint32_t ra, uint32_t rb) { +// GpVar ea(c.newGpVar()); +// c.mov(ea, e.gpr_value(rb)); +// if (ra) { +// c.add(ea, e.gpr_value(ra)); +// } +// GpVar sh(c.newGpVar()); +// c.mov(sh, ea); +// c.and_(sh, imm(0xF)); +// XmmVar v = e.ReadMemoryXmm(i.address, ea, 4); +// // If fully aligned skip complex work. +// Label done(c.newLabel()); +// c.test(sh, sh); +// c.jz(done); +// { +// // Shift left by the number of bytes offset and fill with zeros. +// // We reuse the lvsl table here, as it does that for us. +// GpVar gt(c.newGpVar()); +// c.xor_(gt, gt); +// c.pinsrb(v, gt.r8(), imm(15)); +// c.shl(sh, imm(4)); // table offset = (16b * sh) +// c.mov(gt, imm((sysint_t)__shift_table_left)); +// c.pshufb(v, xmmword_ptr(gt, sh)); +// } +// c.bind(done); +// c.shufps(v, v, imm(SHUFPS_SWAP_DWORDS)); +// f.StoreVR(vd, v); +// e.TraceVR(vd); +// return 0; +// } +// XEEMITTER(lvlx, 0x7C00040E, X )(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvlx_(f, i, i.X.RT, i.X.RA, i.X.RB); +// } +// XEEMITTER(lvlx128, VX128_1(4, 1027), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvlx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +// } +// XEEMITTER(lvlxl, 0x7C00060E, X )(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvlx(f, i); +// } +// XEEMITTER(lvlxl128, VX128_1(4, 1539), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvlx128(f, i); +// } + +// int InstrEmit_lvrx_(PPCFunctionBuilder& f, InstrData& i, uint32_t vd, uint32_t ra, uint32_t rb) { +// GpVar ea(c.newGpVar()); +// c.mov(ea, e.gpr_value(rb)); +// if (ra) { +// c.add(ea, e.gpr_value(ra)); +// } +// GpVar sh(c.newGpVar()); +// c.mov(sh, ea); +// c.and_(sh, imm(0xF)); +// // If fully aligned skip complex work. +// XmmVar v(c.newXmmVar()); +// c.pxor(v, v); +// Label done(c.newLabel()); +// c.test(sh, sh); +// c.jz(done); +// { +// // Shift left by the number of bytes offset and fill with zeros. +// // We reuse the lvsl table here, as it does that for us. +// c.movaps(v, e.ReadMemoryXmm(i.address, ea, 4)); +// GpVar gt(c.newGpVar()); +// c.xor_(gt, gt); +// c.pinsrb(v, gt.r8(), imm(0)); +// c.shl(sh, imm(4)); // table offset = (16b * sh) +// c.mov(gt, imm((sysint_t)__shift_table_right)); +// c.pshufb(v, xmmword_ptr(gt, sh)); +// c.shufps(v, v, imm(SHUFPS_SWAP_DWORDS)); +// } +// c.bind(done); +// f.StoreVR(vd, v); +// e.TraceVR(vd); +// return 0; +// } +// XEEMITTER(lvrx, 0x7C00044E, X )(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvrx_(f, i, i.X.RT, i.X.RA, i.X.RB); +// } +// XEEMITTER(lvrx128, VX128_1(4, 1091), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvrx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +// } +// XEEMITTER(lvrxl, 0x7C00064E, X )(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvrx(f, i); +// } +// XEEMITTER(lvrxl128, VX128_1(4, 1603), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_lvrx128(f, i); +// } + +// // TODO(benvanik): implement for real - this is in the memcpy path. +// static void __emulated_stvlx(uint64_t addr, __m128i vd) { +// // addr here is the fully translated address. +// const uint8_t eb = addr & 0xF; +// const size_t size = 16 - eb; +// uint8_t* p = (uint8_t*)addr; +// for (size_t i = 0; i < size; i++) { +// p[i] = vd.m128i_u8[15 - i]; +// } +// } +// int InstrEmit_stvlx_(PPCFunctionBuilder& f, InstrData& i, uint32_t vd, uint32_t ra, uint32_t rb) { +// GpVar ea(c.newGpVar()); +// c.mov(ea, e.gpr_value(rb)); +// if (ra) { +// c.add(ea, e.gpr_value(ra)); +// } +// ea = e.TouchMemoryAddress(i.address, ea); +// XmmVar tvd(c.newXmmVar()); +// c.movaps(tvd, f.LoadVR(vd)); +// c.shufps(tvd, tvd, imm(SHUFPS_SWAP_DWORDS)); +// c.save(tvd); +// GpVar pvd(c.newGpVar()); +// c.lea(pvd, tvd.m128()); +// X86CompilerFuncCall* call = c.call(__emulated_stvlx); +// uint32_t args[] = {kX86VarTypeGpq, kX86VarTypeGpq}; +// call->setPrototype(kX86FuncConvDefault, kX86VarTypeGpq, args, XECOUNT(args)); +// call->setArgument(0, ea); +// call->setArgument(1, pvd); +// e.TraceVR(vd); +// return 0; +// } +// XEEMITTER(stvlx, 0x7C00050E, X )(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_stvlx_(f, i, i.X.RT, i.X.RA, i.X.RB); +// } +// XEEMITTER(stvlx128, VX128_1(4, 1283), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_stvlx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +// } +// XEEMITTER(stvlxl, 0x7C00070E, X )(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_stvlx(f, i); +// } +// XEEMITTER(stvlxl128, VX128_1(4, 1795), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_stvlx128(f, i); +// } + +// // TODO(benvanik): implement for real - this is in the memcpy path. +// static void __emulated_stvrx(uint64_t addr, __m128i vd) { +// // addr here is the fully translated address. +// const uint8_t eb = addr & 0xF; +// const size_t size = eb; +// addr &= ~0xF; +// uint8_t* p = (uint8_t*)addr; +// // Note that if the input is already 16b aligned no bytes are stored. +// for (size_t i = 0; i < size; i++) { +// p[size - 1 - i] = vd.m128i_u8[i]; +// } +// } +// int InstrEmit_stvrx_(PPCFunctionBuilder& f, InstrData& i, uint32_t vd, uint32_t ra, uint32_t rb) { +// GpVar ea(c.newGpVar()); +// c.mov(ea, e.gpr_value(rb)); +// if (ra) { +// c.add(ea, e.gpr_value(ra)); +// } +// ea = e.TouchMemoryAddress(i.address, ea); +// XmmVar tvd(c.newXmmVar()); +// c.movaps(tvd, f.LoadVR(vd)); +// c.shufps(tvd, tvd, imm(SHUFPS_SWAP_DWORDS)); +// c.save(tvd); +// GpVar pvd(c.newGpVar()); +// c.lea(pvd, tvd.m128()); +// X86CompilerFuncCall* call = c.call(__emulated_stvrx); +// uint32_t args[] = {kX86VarTypeGpq, kX86VarTypeGpq}; +// call->setPrototype(kX86FuncConvDefault, kX86VarTypeGpq, args, XECOUNT(args)); +// call->setArgument(0, ea); +// call->setArgument(1, pvd); +// e.TraceVR(vd); +// return 0; +// } +// XEEMITTER(stvrx, 0x7C00054E, X )(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_stvrx_(f, i, i.X.RT, i.X.RA, i.X.RB); +// } +// XEEMITTER(stvrx128, VX128_1(4, 1347), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_stvrx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +// } +// XEEMITTER(stvrxl, 0x7C00074E, X )(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_stvrx(f, i); +// } +// XEEMITTER(stvrxl128, VX128_1(4, 1859), VX128_1)(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_stvrx128(f, i); +// } + +XEEMITTER(mfvscr, 0x10000604, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mtvscr, 0x10000644, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vaddcuw, 0x10000180, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +int InstrEmit_vaddfp_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) + (VB) (4 x fp) + Value* v = f.Add(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vaddfp, 0x1000000A, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vaddfp_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} +XEEMITTER(vaddfp128, VX128(5, 16), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vaddfp_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +XEEMITTER(vaddsbs, 0x10000300, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vaddshs, 0x10000340, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vaddsws, 0x10000380, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vaddubm, 0x10000000, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vaddubs, 0x10000200, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vadduhm, 0x10000040, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vadduhs, 0x10000240, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vadduwm, 0x10000080, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vadduws, 0x10000280, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +int InstrEmit_vand_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) & (VB) + Value* v = f.And(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vand, 0x10000404, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vand_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} +XEEMITTER(vand128, VX128(5, 528), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vand_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +int InstrEmit_vandc_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) & ¬(VB) + Value* v = f.And(f.LoadVR(va), f.Not(f.LoadVR(vb))); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vandc, 0x10000444, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vandc_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} +XEEMITTER(vandc128, VX128(5, 592), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vandc_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +XEEMITTER(vavgsb, 0x10000502, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vavgsh, 0x10000542, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vavgsw, 0x10000582, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vavgub, 0x10000402, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vavguh, 0x10000442, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vavguw, 0x10000482, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vcfsx, 0x1000034A, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vcsxwfp128, VX128_3(6, 688), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + // (VD) <- float(VB) / 2^uimm + uint32_t uimm = VX128_3_IMM; + uimm = uimm ? (2 << (uimm - 1)) : 1; + Value* v = f.Div( + f.VectorConvertI2F(f.LoadVR(VX128_3_VB128)), + f.Splat(f.LoadConstant((float)uimm), VEC128_TYPE)); + f.StoreVR(VX128_3_VD128, v); + return 0; +} + +XEEMITTER(vcfpsxws128, VX128_3(6, 560), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vcfux, 0x1000030A, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vcuxwfp128, VX128_3(6, 752), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vcfpuxws128, VX128_3(6, 624), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +int InstrEmit_vcmpbfp_(PPCFunctionBuilder& f, InstrData& i, uint32_t vd, uint32_t va, uint32_t vb, uint32_t rc) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vcmpbfp, 0x100003C6, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpbfp_(f, i, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpbfp128, VX128(6, 384), VX128_R)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpbfp_(f, i, VX128_R_VD128, VX128_R_VA128, VX128_R_VB128, i.VX128_R.Rc); +} + +enum vcmpxxfp_op { + vcmpxxfp_eq, + vcmpxxfp_gt, + vcmpxxfp_ge, +}; +int InstrEmit_vcmpxxfp_(PPCFunctionBuilder& f, InstrData& i, vcmpxxfp_op cmpop, uint32_t vd, uint32_t va, uint32_t vb, uint32_t rc) { + // (VD.xyzw) = (VA.xyzw) OP (VB.xyzw) ? 0xFFFFFFFF : 0x00000000 + // if (Rc) CR6 = all_equal | 0 | none_equal | 0 + // If an element in either VA or VB is NaN the result will be 0x00000000 + Value* v; + switch (cmpop) { + case vcmpxxfp_eq: + v = f.VectorCompareEQ(f.LoadVR(va), f.LoadVR(vb), FLOAT32_TYPE); + break; + case vcmpxxfp_gt: + v = f.VectorCompareSGT(f.LoadVR(va), f.LoadVR(vb), FLOAT32_TYPE); + break; + case vcmpxxfp_ge: + v = f.VectorCompareSGE(f.LoadVR(va), f.LoadVR(vb), FLOAT32_TYPE); + break; + default: + XEASSERTALWAYS(); + break; + } + if (rc) { + f.UpdateCR6(v); + } + f.StoreVR(vd, v); + return 0; +} + +XEEMITTER(vcmpeqfp, 0x100000C6, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_eq, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpeqfp128, VX128(6, 0), VX128_R)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_eq, VX128_R_VD128, VX128_R_VA128, VX128_R_VB128, i.VX128_R.Rc); +} +XEEMITTER(vcmpgefp, 0x100001C6, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_ge, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpgefp128, VX128(6, 128), VX128_R)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_ge, VX128_R_VD128, VX128_R_VA128, VX128_R_VB128, i.VX128_R.Rc); +} +XEEMITTER(vcmpgtfp, 0x100002C6, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_gt, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpgtfp128, VX128(6, 256), VX128_R)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_gt, VX128_R_VD128, VX128_R_VA128, VX128_R_VB128, i.VX128_R.Rc); +} + +enum vcmpxxi_op { + vcmpxxi_eq, + vcmpxxi_gt_signed, + vcmpxxi_gt_unsigned, +}; +int InstrEmit_vcmpxxi_(PPCFunctionBuilder& f, InstrData& i, vcmpxxi_op cmpop, uint32_t width, uint32_t vd, uint32_t va, uint32_t vb, uint32_t rc) { + // (VD.xyzw) = (VA.xyzw) OP (VB.xyzw) ? 0xFFFFFFFF : 0x00000000 + // if (Rc) CR6 = all_equal | 0 | none_equal | 0 + // If an element in either VA or VB is NaN the result will be 0x00000000 + Value* v; + switch (cmpop) { + case vcmpxxi_eq: + switch (width) { + case 1: + v = f.VectorCompareEQ(f.LoadVR(va), f.LoadVR(vb), INT8_TYPE); + break; + case 2: + v = f.VectorCompareEQ(f.LoadVR(va), f.LoadVR(vb), INT16_TYPE); + break; + case 4: + v = f.VectorCompareEQ(f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + break; + default: XEASSERTALWAYS(); return 1; + } + break; + case vcmpxxi_gt_signed: + switch (width) { + case 1: + v = f.VectorCompareSGT(f.LoadVR(va), f.LoadVR(vb), INT8_TYPE); + break; + case 2: + v = f.VectorCompareSGT(f.LoadVR(va), f.LoadVR(vb), INT16_TYPE); + break; + case 4: + v = f.VectorCompareSGT(f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + break; + default: XEASSERTALWAYS(); return 1; + } + break; + case vcmpxxi_gt_unsigned: + switch (width) { + case 1: + v = f.VectorCompareUGT(f.LoadVR(va), f.LoadVR(vb), INT8_TYPE); + break; + case 2: + v = f.VectorCompareUGT(f.LoadVR(va), f.LoadVR(vb), INT16_TYPE); + break; + case 4: + v = f.VectorCompareUGT(f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + break; + default: XEASSERTALWAYS(); return 1; + } + break; + default: XEASSERTALWAYS(); return 1; + } + if (rc) { + f.UpdateCR6(v); + } + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vcmpequb, 0x10000006, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_eq, 1, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpequh, 0x10000046, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_eq, 2, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpequw, 0x10000086, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_eq, 4, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpequw128, VX128(6, 512), VX128_R)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_eq, 4, VX128_R_VD128, VX128_R_VA128, VX128_R_VB128, i.VX128_R.Rc); +} +XEEMITTER(vcmpgtsb, 0x10000306, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_signed, 1, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpgtsh, 0x10000346, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_signed, 2, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpgtsw, 0x10000386, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_signed, 4, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpgtub, 0x10000206, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_unsigned, 1, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpgtuh, 0x10000246, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_unsigned, 2, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} +XEEMITTER(vcmpgtuw, 0x10000286, VXR )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_unsigned, 4, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} + +XEEMITTER(vctsxs, 0x100003CA, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vctuxs, 0x1000038A, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vexptefp, 0x1000018A, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vexptefp128, VX128_3(6, 1712), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vlogefp, 0x100001CA, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vlogefp128, VX128_3(6, 1776), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +int InstrEmit_vmaddfp_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb, uint32_t vc) { + // (VD) <- ((VA) * (VC)) + (VB) + Value* v = f.MulAdd( + f.LoadVR(va), f.LoadVR(vc), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vmaddfp, 0x1000002E, VXA )(PPCFunctionBuilder& f, InstrData& i) { + // (VD) <- ((VA) * (VC)) + (VB) + return InstrEmit_vmaddfp_(f, i.VXA.VD, i.VXA.VA, i.VXA.VB, i.VXA.VC); +} +XEEMITTER(vmaddfp128, VX128(5, 208), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + // (VD) <- ((VA) * (VB)) + (VD) + // NOTE: this resuses VD and swaps the arg order! + return InstrEmit_vmaddfp_(f, VX128_VD128, VX128_VA128, VX128_VD128, VX128_VB128); +} + +XEEMITTER(vmaddcfp128, VX128(5, 272), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + // (VD) <- ((VA) * (VD)) + (VB) + Value* v = f.MulAdd( + f.LoadVR(VX128_VA128), f.LoadVR(VX128_VD128), f.LoadVR(VX128_VB128)); + f.StoreVR(VX128_VD128, v); + return 0; +} + +int InstrEmit_vmaxfp_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- max((VA), (VB)) + Value* v = f.Max(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vmaxfp, 0x1000040A, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vmaxfp_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} +XEEMITTER(vmaxfp128, VX128(6, 640), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vmaxfp_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +XEEMITTER(vmaxsb, 0x10000102, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmaxsh, 0x10000142, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmaxsw, 0x10000182, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmaxub, 0x10000002, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmaxuh, 0x10000042, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmaxuw, 0x10000082, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmhaddshs, 0x10000020, VXA )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmhraddshs, 0x10000021, VXA )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +int InstrEmit_vminfp_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- min((VA), (VB)) + Value* v = f.Min(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vminfp, 0x1000044A, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vminfp_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} +XEEMITTER(vminfp128, VX128(6, 704), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vminfp_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +XEEMITTER(vminsb, 0x10000302, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vminsh, 0x10000342, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vminsw, 0x10000382, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vminub, 0x10000202, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vminuh, 0x10000242, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vminuw, 0x10000282, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmladduhm, 0x10000022, VXA )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmrghb, 0x1000000C, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmrghh, 0x1000004C, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +int InstrEmit_vmrghw_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD.x) = (VA.x) + // (VD.y) = (VB.x) + // (VD.z) = (VA.y) + // (VD.w) = (VB.y) + Value* v = f.Permute( + f.LoadConstant(0x05010400), + f.LoadVR(va), + f.LoadVR(vb), + INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vmrghw, 0x1000008C, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vmrghw_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} +XEEMITTER(vmrghw128, VX128(6, 768), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vmrghw_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +XEEMITTER(vmrglb, 0x1000010C, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmrglh, 0x1000014C, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +int InstrEmit_vmrglw_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD.x) = (VA.z) + // (VD.y) = (VB.z) + // (VD.z) = (VA.w) + // (VD.w) = (VB.w) + Value* v = f.Permute( + f.LoadConstant(0x07030602), + f.LoadVR(va), + f.LoadVR(vb), + INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vmrglw, 0x1000018C, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vmrglw_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} +XEEMITTER(vmrglw128, VX128(6, 832), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vmrglw_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +XEEMITTER(vmsummbm, 0x10000025, VXA )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmsumshm, 0x10000028, VXA )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmsumshs, 0x10000029, VXA )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmsumubm, 0x10000024, VXA )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmsumuhm, 0x10000026, VXA )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmsumuhs, 0x10000027, VXA )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmsum3fp128, VX128(5, 400), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + // Dot product XYZ. + // (VD.xyzw) = (VA.x * VB.x) + (VA.y * VB.y) + (VA.z * VB.z) + Value* v = f.DotProduct3(f.LoadVR(VX128_VA128), f.LoadVR(VX128_VB128)); + v = f.Splat(v, VEC128_TYPE); + f.StoreVR(VX128_VD128, v); + return 0; +} + +XEEMITTER(vmsum4fp128, VX128(5, 464), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + // Dot product XYZW. + // (VD.xyzw) = (VA.x * VB.x) + (VA.y * VB.y) + (VA.z * VB.z) + (VA.w * VB.w) + Value* v = f.DotProduct4(f.LoadVR(VX128_VA128), f.LoadVR(VX128_VB128)); + v = f.Splat(v, VEC128_TYPE); + f.StoreVR(VX128_VD128, v); + return 0; +} + +XEEMITTER(vmulesb, 0x10000308, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmulesh, 0x10000348, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmuleub, 0x10000208, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmuleuh, 0x10000248, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmulosb, 0x10000108, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmulosh, 0x10000148, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmuloub, 0x10000008, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmulouh, 0x10000048, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vmulfp128, VX128(5, 144), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + // (VD) <- (VA) * (VB) (4 x fp) + Value* v = f.Mul(f.LoadVR(VX128_VA128), f.LoadVR(VX128_VB128)); + f.StoreVR(VX128_VD128, v); + return 0; +} + +int InstrEmit_vnmsubfp_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb, uint32_t vc) { + // (VD) <- -(((VA) * (VC)) - (VB)) + // NOTE: only one rounding should take place, but that's hard... + // This really needs VFNMSUB132PS/VFNMSUB213PS/VFNMSUB231PS but that's AVX. + Value* v = f.Neg(f.MulSub(f.LoadVR(va), f.LoadVR(vc), f.LoadVR(vb))); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vnmsubfp, 0x1000002F, VXA )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vnmsubfp_(f, i.VXA.VD, i.VXA.VA, i.VXA.VB, i.VXA.VC); +} +XEEMITTER(vnmsubfp128, VX128(5, 336), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vnmsubfp_(f, VX128_VD128, VX128_VA128, VX128_VB128, VX128_VD128); +} + +int InstrEmit_vnor_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- ¬((VA) | (VB)) + Value* v = f.Not(f.Or(f.LoadVR(va), f.LoadVR(vb))); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vnor, 0x10000504, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vnor_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} +XEEMITTER(vnor128, VX128(5, 656), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vnor_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +int InstrEmit_vor_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) | (VB) + if (va == vb) { + // Copy VA==VB into VD. + f.StoreVR(vd, f.LoadVR(va)); + } else { + Value* v = f.Or(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + } + return 0; +} +XEEMITTER(vor, 0x10000484, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vor_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} +XEEMITTER(vor128, VX128(5, 720), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vor_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +int InstrEmit_vperm_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb, uint32_t vc) { + Value* v = f.Permute(f.LoadVR(vc), f.LoadVR(va), f.LoadVR(vb), INT8_TYPE); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vperm, 0x1000002B, VXA )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vperm_(f, i.VXA.VD, i.VXA.VA, i.VXA.VB, i.VXA.VC); +} +XEEMITTER(vperm128, VX128_2(5, 0), VX128_2)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vperm_(f, VX128_2_VD128, VX128_2_VA128, VX128_2_VB128, VX128_2_VC); +} + +XEEMITTER(vpermwi128, VX128_P(6, 528), VX128_P)(PPCFunctionBuilder& f, InstrData& i) { + // (VD.x) = (VB.uimm[6-7]) + // (VD.y) = (VB.uimm[4-5]) + // (VD.z) = (VB.uimm[2-3]) + // (VD.w) = (VB.uimm[0-1]) + const uint32_t vd = i.VX128_P.VD128l | (i.VX128_P.VD128h << 5); + const uint32_t vb = i.VX128_P.VB128l | (i.VX128_P.VB128h << 5); + uint32_t uimm = i.VX128_P.PERMl | (i.VX128_P.PERMh << 5); + Value* v = f.Swizzle(f.LoadVR(vb), INT32_TYPE, uimm); + f.StoreVR(vd, v); + return 0; +} + +XEEMITTER(vpkpx, 0x1000030E, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vpkshss, 0x1000018E, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vpkshss128, VX128(5, 512), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vpkswss, 0x100001CE, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vpkswss128, VX128(5, 640), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vpkswus, 0x1000014E, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vpkswus128, VX128(5, 704), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vpkuhum, 0x1000000E, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vpkuhum128, VX128(5, 768), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vpkuhus, 0x1000008E, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vpkuhus128, VX128(5, 832), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vpkshus, 0x1000010E, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vpkshus128, VX128(5, 576), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vpkuwum, 0x1000004E, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vpkuwum128, VX128(5, 896), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vpkuwus, 0x100000CE, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vpkuwus128, VX128(5, 960), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vpkd3d128, VX128_4(6, 1552), VX128_4)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vrefp, 0x1000010A, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vrefp128, VX128_3(6, 1584), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vrfim, 0x100002CA, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vrfim128, VX128_3(6, 816), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +int InstrEmit_vrfin_(PPCFunctionBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- RoundToNearest(VB) + Value* v = f.Round(f.LoadVR(vd), ROUND_TO_NEAREST); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vrfin, 0x1000020A, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vrfin_(f, i.VX.VD, i.VX.VB); +} +XEEMITTER(vrfin128, VX128_3(6, 880), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vrfin_(f, VX128_3_VD128, VX128_3_VB128); +} + +XEEMITTER(vrfip, 0x1000028A, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vrfip128, VX128_3(6, 944), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vrfiz, 0x1000024A, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vrfiz128, VX128_3(6, 1008), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vrlb, 0x10000004, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vrlh, 0x10000044, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vrlw, 0x10000084, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vrlw128, VX128(6, 80), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vrlimi128, VX128_4(6, 1808), VX128_4)(PPCFunctionBuilder& f, InstrData& i) { + const uint32_t vd = i.VX128_4.VD128l | (i.VX128_4.VD128h << 5); + const uint32_t vb = i.VX128_4.VB128l | (i.VX128_4.VB128h << 5); + uint32_t blend_mask = i.VX128_4.IMM; + uint32_t rotate = i.VX128_4.z; + // This is just a fancy permute. + // X Y Z W, rotated left by 2 = Z W X Y + // Then mask select the results into the dest. + // Sometimes rotation is zero, so fast path. + Value* v; + if (rotate) { + // TODO(benvanik): constants need conversion. + uint32_t swizzle_mask; + switch (rotate) { + case 1: + // X Y Z W -> Y Z W X + swizzle_mask = SWIZZLE_XYZW_TO_YZWX; + break; + case 2: + // X Y Z W -> Z W X Y + swizzle_mask = SWIZZLE_XYZW_TO_ZWXY; + break; + case 3: + // X Y Z W -> W X Y Z + swizzle_mask = SWIZZLE_XYZW_TO_WXYZ; + break; + default: XEASSERTALWAYS(); return 1; + } + v = f.Swizzle(f.LoadVR(vb), FLOAT32_TYPE, swizzle_mask); + } else { + v = f.LoadVR(vb); + } + v = f.Permute( + f.LoadConstant(blend_mask), v, f.LoadVR(vd), FLOAT32_TYPE); + f.StoreVR(vd, v); + return 0; +} + +int InstrEmit_vrsqrtefp_(PPCFunctionBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- 1 / sqrt(VB) + // There are a lot of rules in the Altivec_PEM docs for handlings that + // result in nan/infinity/etc. They are ignored here. I hope games would + // never rely on them. + Value* v = f.RSqrt(f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vrsqrtefp, 0x1000014A, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vrsqrtefp_(f, i.VX.VD, i.VX.VB); +} +XEEMITTER(vrsqrtefp128, VX128_3(6, 1648), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vrsqrtefp_(f, VX128_3_VD128, VX128_3_VB128); +} + +int InstrEmit_vsel_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb, uint32_t vc) { + Value* a = f.LoadVR(va); + Value* v = f.Xor(f.And(f.Xor(a, f.LoadVR(vb)), f.LoadVR(vc)), a); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vsel, 0x1000002A, VXA )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vsel_(f, i.VXA.VD, i.VXA.VA, i.VXA.VB, i.VXA.VC); +} +XEEMITTER(vsel128, VX128(5, 848), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vsel_(f, VX128_VD128, VX128_VA128, VX128_VB128, VX128_VD128); +} + +XEEMITTER(vsl, 0x100001C4, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vslb, 0x10000104, VX )(PPCFunctionBuilder& f, InstrData& i) { + Value* v = f.VectorShl(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} + +XEEMITTER(vslh, 0x10000144, VX )(PPCFunctionBuilder& f, InstrData& i) { + Value* v = f.VectorShl(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} + +int InstrEmit_vslw_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VA = |xxxxx|yyyyy|zzzzz|wwwww| + // VB = |...sh|...sh|...sh|...sh| + // VD = |x<> (16 - SH)) +// GpVar gt(c.newGpVar()); +// c.xor_(gt, gt); +// c.pinsrb(v, gt.r8(), imm(0)); +// c.pinsrb(v_r, gt.r8(), imm(15)); +// c.mov(gt, imm((sysint_t)&__shift_table_out[sh])); +// XmmVar shuf(c.newXmmVar()); +// c.movaps(shuf, xmmword_ptr(gt)); +// c.pshufb(v, shuf); +// c.mov(gt, imm((sysint_t)&__shift_table_in[sh])); +// c.movaps(shuf, xmmword_ptr(gt)); +// c.pshufb(v_r, shuf); +// c.por(v, v_r); +// f.StoreVR(vd, v); +// e.TraceVR(vd, va, vb); +// return 0; +// } +// XEEMITTER(vsldoi, 0x1000002C, VXA )(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_vsldoi_(f, i.VXA.VD, i.VXA.VA, i.VXA.VB, i.VXA.VC & 0xF); +// } +// XEEMITTER(vsldoi128, VX128_5(4, 16), VX128_5)(PPCFunctionBuilder& f, InstrData& i) { +// return InstrEmit_vsldoi_(f, VX128_5_VD128, VX128_5_VA128, VX128_5_VB128, VX128_5_SH); +// } + +XEEMITTER(vslo, 0x1000040C, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vslo128, VX128(5, 912), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vspltb, 0x1000020C, VX )(PPCFunctionBuilder& f, InstrData& i) { + // b <- UIMM*8 + // do i = 0 to 127 by 8 + // (VD)[i:i+7] <- (VB)[b:b+7] + Value* b = f.Extract(f.LoadVR(i.VX.VB), (i.VX.VA & 0xF), INT8_TYPE); + Value* v = f.Splat(b, VEC128_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} + +XEEMITTER(vsplth, 0x1000024C, VX )(PPCFunctionBuilder& f, InstrData& i) { + // (VD.xyzw) <- (VB.uimm) + Value* h = f.Extract(f.LoadVR(i.VX.VB), (i.VX.VA & 0x7), INT16_TYPE); + Value* v = f.Splat(h, VEC128_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} + +int InstrEmit_vspltw_(PPCFunctionBuilder& f, uint32_t vd, uint32_t vb, uint32_t uimm) { + // (VD.xyzw) <- (VB.uimm) + Value* w = f.Extract(f.LoadVR(vb), (uimm & 0x3), INT32_TYPE); + Value* v = f.Splat(w, VEC128_TYPE); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vspltw, 0x1000028C, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vspltw_(f, i.VX.VD, i.VX.VB, i.VX.VA); +} +XEEMITTER(vspltw128, VX128_3(6, 1840), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vspltw_(f, VX128_3_VD128, VX128_3_VB128, VX128_3_IMM); +} + +XEEMITTER(vspltisb, 0x1000030C, VX )(PPCFunctionBuilder& f, InstrData& i) { + // (VD.xyzw) <- sign_extend(uimm) + Value* v; + if (i.VX.VA) { + // Sign extend from 5bits -> 8 and load. + int8_t simm = (i.VX.VA & 0x10) ? (i.VX.VA | 0xF0) : i.VX.VA; + v = f.Splat(f.LoadConstant(simm), VEC128_TYPE); + } else { + // Zero out the register. + v = f.LoadZero(VEC128_TYPE); + } + f.StoreVR(i.VX.VD, v); + return 0; +} + +XEEMITTER(vspltish, 0x1000034C, VX )(PPCFunctionBuilder& f, InstrData& i) { + // (VD.xyzw) <- sign_extend(uimm) + Value* v; + if (i.VX.VA) { + // Sign extend from 5bits -> 16 and load. + int16_t simm = (i.VX.VA & 0x10) ? (i.VX.VA | 0xFFF0) : i.VX.VA; + v = f.Splat(f.LoadConstant(simm), VEC128_TYPE); + } else { + // Zero out the register. + v = f.LoadZero(VEC128_TYPE); + } + f.StoreVR(i.VX.VD, v); + return 0; +} + +int InstrEmit_vspltisw_(PPCFunctionBuilder& f, uint32_t vd, uint32_t uimm) { + // (VD.xyzw) <- sign_extend(uimm) + Value* v; + if (uimm) { + // Sign extend from 5bits -> 32 and load. + int32_t simm = (uimm & 0x10) ? (uimm | 0xFFFFFFF0) : uimm; + v = f.Splat(f.LoadConstant(simm), VEC128_TYPE); + } else { + // Zero out the register. + v = f.LoadZero(VEC128_TYPE); + } + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vspltisw, 0x1000038C, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vspltisw_(f, i.VX.VD, i.VX.VA); +} +XEEMITTER(vspltisw128, VX128_3(6, 1904), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vspltisw_(f, VX128_3_VD128, VX128_3_IMM); +} + +XEEMITTER(vsr, 0x100002C4, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsrab, 0x10000304, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsrah, 0x10000344, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsraw, 0x10000384, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vsraw128, VX128(6, 336), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsrb, 0x10000204, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsrh, 0x10000244, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsro, 0x1000044C, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vsro128, VX128(5, 976), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsrw, 0x10000284, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vsrw128, VX128(6, 464), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsubcuw, 0x10000580, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +int InstrEmit_vsubfp_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) - (VB) (4 x fp) + Value* v = f.Sub(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vsubfp, 0x1000004A, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vsubfp_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} +XEEMITTER(vsubfp128, VX128(5, 80), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vsubfp_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +XEEMITTER(vsubsbs, 0x10000700, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsubshs, 0x10000740, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsubsws, 0x10000780, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsububm, 0x10000400, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsububs, 0x10000600, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsubuhm, 0x10000440, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsubuhs, 0x10000640, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsubuwm, 0x10000480, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsubuws, 0x10000680, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsumsws, 0x10000788, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsum2sws, 0x10000688, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsum4sbs, 0x10000708, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsum4shs, 0x10000648, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vsum4ubs, 0x10000608, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vupkhpx, 0x1000034E, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vupkhsb, 0x1000020E, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vupkhsb128, VX128(6, 896), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vupkhsh, 0x1000024E, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vupklpx, 0x100003CE, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vupklsb, 0x1000028E, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} +XEEMITTER(vupklsb128, VX128(6, 960), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(vupklsh, 0x100002CE, VX )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +// __m128 half_to_float5_SSE2(__m128i h) { +// #define SSE_CONST4(name, val) static const __declspec(align(16)) uint name[4] = { (val), (val), (val), (val) } +// #define SSE_CONST(name) *(const __m128i *)&name +// #define SSE_CONSTF(name) *(const __m128 *)&name +// SSE_CONST4(mask_nosign, 0x7fff); +// SSE_CONST4(magic, (254 - 15) << 23); +// SSE_CONST4(was_infnan, 0x7bff); +// SSE_CONST4(exp_infnan, 255 << 23); +// __m128i mnosign = SSE_CONST(mask_nosign); +// __m128i expmant = _mm_and_si128(mnosign, h); +// __m128i justsign = _mm_xor_si128(h, expmant); +// __m128i expmant2 = expmant; // copy (just here for counting purposes) +// __m128i shifted = _mm_slli_epi32(expmant, 13); +// __m128 scaled = _mm_mul_ps(_mm_castsi128_ps(shifted), *(const __m128 *)&magic); +// __m128i b_wasinfnan = _mm_cmpgt_epi32(expmant2, SSE_CONST(was_infnan)); +// __m128i sign = _mm_slli_epi32(justsign, 16); +// __m128 infnanexp = _mm_and_ps(_mm_castsi128_ps(b_wasinfnan), SSE_CONSTF(exp_infnan)); +// __m128 sign_inf = _mm_or_ps(_mm_castsi128_ps(sign), infnanexp); +// __m128 final = _mm_or_ps(scaled, sign_inf); +// // ~11 SSE2 ops. +// return final; +// #undef SSE_CONST4 +// #undef CONST +// #undef CONSTF +// } + +XEEMITTER(vupkd3d128, VX128_3(6, 2032), VX128_3)(PPCFunctionBuilder& f, InstrData& i) { + // Can't find many docs on this. Best reference is + // http://worldcraft.googlecode.com/svn/trunk/src/qylib/math/xmmatrix.inl, + // which shows how it's used in some cases. Since it's all intrinsics, + // finding it in code is pretty easy. + const uint32_t vd = i.VX128_3.VD128l | (i.VX128_3.VD128h << 5); + const uint32_t vb = i.VX128_3.VB128l | (i.VX128_3.VB128h << 5); + const uint32_t type = i.VX128_3.IMM >> 2; + Value* v; + switch (type) { + case 0: // VPACK_D3DCOLOR + { + XEASSERTALWAYS(); + return 1; + // http://hlssmod.net/he_code/public/pixelwriter.h + // ARGB (WXYZ) -> RGBA (XYZW) + // zzzzZZZZzzzzARGB + //c.movaps(vt, f.LoadVR(vb)); + //// zzzzZZZZzzzzARGB + //// 000R000G000B000A + //c.mov(gt, imm( + // ((1ull << 7) << 56) | + // ((1ull << 7) << 48) | + // ((1ull << 7) << 40) | + // ((0ull) << 32) | // B + // ((1ull << 7) << 24) | + // ((1ull << 7) << 16) | + // ((1ull << 7) << 8) | + // ((3ull) << 0)) // A + // ); // lo + //c.movq(v, gt); + //c.mov(gt, imm( + // ((1ull << 7) << 56) | + // ((1ull << 7) << 48) | + // ((1ull << 7) << 40) | + // ((2ull) << 32) | // R + // ((1ull << 7) << 24) | + // ((1ull << 7) << 16) | + // ((1ull << 7) << 8) | + // ((1ull) << 0)) // G + // ); // hi + //c.pinsrq(v, gt, imm(1)); + //c.pshufb(vt, v); + //// {256*R.0, 256*G.0, 256*B.0, 256*A.0} + //c.cvtdq2ps(v, vt); + //// {R.0, G.0, B.0 A.0} + //// 1/256 = 0.00390625 = 0x3B800000 + //c.mov(gt, imm(0x3B800000)); + //c.movd(vt, gt.r32()); + //c.shufps(vt, vt, imm(0)); + //c.mulps(v, vt); + } + break; + case 1: // VPACK_NORMSHORT2 + { + // (VD.x) = 3.0 + (VB.x)*2^-22 + // (VD.y) = 3.0 + (VB.y)*2^-22 + // (VD.z) = 0.0 + // (VD.w) = 3.0 + // v = VB.x|VB.y|0|0 + v = f.Permute( + f.LoadConstant(PERMUTE_XY_ZW), + f.LoadVR(vb), + f.LoadZero(VEC128_TYPE), + INT32_TYPE); + // *= 2^-22 + {3.0, 3.0, 0, 1.0} + vec128_t v3301 = { 3.0, 3.0, 0, 1.0 }; + v = f.MulAdd( + v, + f.Splat(f.LoadConstant(0x34800000), VEC128_TYPE), + f.LoadConstant(v3301)); + } + break; + case 3: // VPACK_... 2 FLOAT16s + { + // (VD.x) = fixed_16_to_32(VB.x (low)) + // (VD.y) = fixed_16_to_32(VB.x (high)) + // (VD.z) = 0.0 + // (VD.w) = 1.0 + v = f.LoadZero(VEC128_TYPE); + f.DebugBreak(); + // 1 bit sign, 5 bit exponent, 10 bit mantissa + // D3D10 half float format + // TODO(benvanik): fixed_16_to_32 in SSE? + // TODO(benvanik): http://blogs.msdn.com/b/chuckw/archive/2012/09/11/directxmath-f16c-and-fma.aspx + // Use _mm_cvtph_ps -- requires very modern processors (SSE5+) + // Unpacking half floats: http://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/ + // Packing half floats: https://gist.github.com/rygorous/2156668 + // Load source, move from tight pack of X16Y16.... to X16...Y16... + // Also zero out the high end. + //c.int3(); + //c.movaps(vt, f.LoadVR(vb)); + //c.save(vt); + //c.lea(gt, vt.m128()); + //X86CompilerFuncCall* call = c.call(half_to_float5_SSE2); + //uint32_t args[] = {kX86VarTypeGpq}; + //call->setPrototype(kX86FuncConvDefault, kX86VarTypeXmm, args, XECOUNT(args)); + //call->setArgument(0, gt); + //call->setReturn(v); + //// Select XY00. + //c.xorps(vt, vt); + //c.shufps(v, vt, imm(0x04)); + //// {0.0, 0.0, 0.0, 1.0} + //c.mov(gt, imm(0x3F800000)); + //c.pinsrd(v, gt.r32(), imm(3)); + } + break; + default: + XEASSERTALWAYS(); + return 1; + } + f.StoreVR(vd, v); + return 0; +} + +int InstrEmit_vxor_(PPCFunctionBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) ^ (VB) + Value* v; + if (va == vb) { + // Fast clear. + v = f.LoadZero(VEC128_TYPE); + } else { + v = f.Xor(f.LoadVR(va), f.LoadVR(vb)); + } + f.StoreVR(vd, v); + return 0; +} +XEEMITTER(vxor, 0x100004C4, VX )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vxor_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} +XEEMITTER(vxor128, VX128(5, 784), VX128 )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_vxor_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + + +void RegisterEmitCategoryAltivec() { + XEREGISTERINSTR(dst, 0x7C0002AC); + XEREGISTERINSTR(dstst, 0x7C0002EC); + XEREGISTERINSTR(dss, 0x7C00066C); + XEREGISTERINSTR(lvebx, 0x7C00000E); + XEREGISTERINSTR(lvehx, 0x7C00004E); + XEREGISTERINSTR(lvewx, 0x7C00008E); + XEREGISTERINSTR(lvewx128, VX128_1(4, 131)); + // XEREGISTERINSTR(lvsl, 0x7C00000C); + // XEREGISTERINSTR(lvsl128, VX128_1(4, 3)); + // XEREGISTERINSTR(lvsr, 0x7C00004C); + // XEREGISTERINSTR(lvsr128, VX128_1(4, 67)); + XEREGISTERINSTR(lvx, 0x7C0000CE); + XEREGISTERINSTR(lvx128, VX128_1(4, 195)); + XEREGISTERINSTR(lvxl, 0x7C0002CE); + XEREGISTERINSTR(lvxl128, VX128_1(4, 707)); + XEREGISTERINSTR(stvebx, 0x7C00010E); + XEREGISTERINSTR(stvehx, 0x7C00014E); + XEREGISTERINSTR(stvewx, 0x7C00018E); + XEREGISTERINSTR(stvewx128, VX128_1(4, 387)); + XEREGISTERINSTR(stvx, 0x7C0001CE); + XEREGISTERINSTR(stvx128, VX128_1(4, 451)); + XEREGISTERINSTR(stvxl, 0x7C0003CE); + XEREGISTERINSTR(stvxl128, VX128_1(4, 963)); + // XEREGISTERINSTR(lvlx, 0x7C00040E); + // XEREGISTERINSTR(lvlx128, VX128_1(4, 1027)); + // XEREGISTERINSTR(lvlxl, 0x7C00060E); + // XEREGISTERINSTR(lvlxl128, VX128_1(4, 1539)); + // XEREGISTERINSTR(lvrx, 0x7C00044E); + // XEREGISTERINSTR(lvrx128, VX128_1(4, 1091)); + // XEREGISTERINSTR(lvrxl, 0x7C00064E); + // XEREGISTERINSTR(lvrxl128, VX128_1(4, 1603)); + // XEREGISTERINSTR(stvlx, 0x7C00050E); + // XEREGISTERINSTR(stvlx128, VX128_1(4, 1283)); + // XEREGISTERINSTR(stvlxl, 0x7C00070E); + // XEREGISTERINSTR(stvlxl128, VX128_1(4, 1795)); + // XEREGISTERINSTR(stvrx, 0x7C00054E); + // XEREGISTERINSTR(stvrx128, VX128_1(4, 1347)); + // XEREGISTERINSTR(stvrxl, 0x7C00074E); + // XEREGISTERINSTR(stvrxl128, VX128_1(4, 1859)); + + XEREGISTERINSTR(mfvscr, 0x10000604); + XEREGISTERINSTR(mtvscr, 0x10000644); + XEREGISTERINSTR(vaddcuw, 0x10000180); + XEREGISTERINSTR(vaddfp, 0x1000000A); + XEREGISTERINSTR(vaddfp128, VX128(5, 16)); + XEREGISTERINSTR(vaddsbs, 0x10000300); + XEREGISTERINSTR(vaddshs, 0x10000340); + XEREGISTERINSTR(vaddsws, 0x10000380); + XEREGISTERINSTR(vaddubm, 0x10000000); + XEREGISTERINSTR(vaddubs, 0x10000200); + XEREGISTERINSTR(vadduhm, 0x10000040); + XEREGISTERINSTR(vadduhs, 0x10000240); + XEREGISTERINSTR(vadduwm, 0x10000080); + XEREGISTERINSTR(vadduws, 0x10000280); + XEREGISTERINSTR(vand, 0x10000404); + XEREGISTERINSTR(vand128, VX128(5, 528)); + XEREGISTERINSTR(vandc, 0x10000444); + XEREGISTERINSTR(vandc128, VX128(5, 592)); + XEREGISTERINSTR(vavgsb, 0x10000502); + XEREGISTERINSTR(vavgsh, 0x10000542); + XEREGISTERINSTR(vavgsw, 0x10000582); + XEREGISTERINSTR(vavgub, 0x10000402); + XEREGISTERINSTR(vavguh, 0x10000442); + XEREGISTERINSTR(vavguw, 0x10000482); + XEREGISTERINSTR(vcfsx, 0x1000034A); + XEREGISTERINSTR(vcsxwfp128, VX128_3(6, 688)); + XEREGISTERINSTR(vcfpsxws128, VX128_3(6, 560)); + XEREGISTERINSTR(vcfux, 0x1000030A); + XEREGISTERINSTR(vcuxwfp128, VX128_3(6, 752)); + XEREGISTERINSTR(vcfpuxws128, VX128_3(6, 624)); + XEREGISTERINSTR(vcmpbfp, 0x100003C6); + XEREGISTERINSTR(vcmpbfp128, VX128(6, 384)); + XEREGISTERINSTR(vcmpeqfp, 0x100000C6); + XEREGISTERINSTR(vcmpeqfp128, VX128(6, 0)); + XEREGISTERINSTR(vcmpgefp, 0x100001C6); + XEREGISTERINSTR(vcmpgefp128, VX128(6, 128)); + XEREGISTERINSTR(vcmpgtfp, 0x100002C6); + XEREGISTERINSTR(vcmpgtfp128, VX128(6, 256)); + XEREGISTERINSTR(vcmpgtsb, 0x10000306); + XEREGISTERINSTR(vcmpgtsh, 0x10000346); + XEREGISTERINSTR(vcmpgtsw, 0x10000386); + XEREGISTERINSTR(vcmpequb, 0x10000006); + XEREGISTERINSTR(vcmpgtub, 0x10000206); + XEREGISTERINSTR(vcmpequh, 0x10000046); + XEREGISTERINSTR(vcmpgtuh, 0x10000246); + XEREGISTERINSTR(vcmpequw, 0x10000086); + XEREGISTERINSTR(vcmpequw128, VX128(6, 512)); + XEREGISTERINSTR(vcmpgtuw, 0x10000286); + XEREGISTERINSTR(vctsxs, 0x100003CA); + XEREGISTERINSTR(vctuxs, 0x1000038A); + XEREGISTERINSTR(vexptefp, 0x1000018A); + XEREGISTERINSTR(vexptefp128, VX128_3(6, 1712)); + XEREGISTERINSTR(vlogefp, 0x100001CA); + XEREGISTERINSTR(vlogefp128, VX128_3(6, 1776)); + XEREGISTERINSTR(vmaddfp, 0x1000002E); + XEREGISTERINSTR(vmaddfp128, VX128(5, 208)); + XEREGISTERINSTR(vmaddcfp128, VX128(5, 272)); + XEREGISTERINSTR(vmaxfp, 0x1000040A); + XEREGISTERINSTR(vmaxfp128, VX128(6, 640)); + XEREGISTERINSTR(vmaxsb, 0x10000102); + XEREGISTERINSTR(vmaxsh, 0x10000142); + XEREGISTERINSTR(vmaxsw, 0x10000182); + XEREGISTERINSTR(vmaxub, 0x10000002); + XEREGISTERINSTR(vmaxuh, 0x10000042); + XEREGISTERINSTR(vmaxuw, 0x10000082); + XEREGISTERINSTR(vmhaddshs, 0x10000020); + XEREGISTERINSTR(vmhraddshs, 0x10000021); + XEREGISTERINSTR(vminfp, 0x1000044A); + XEREGISTERINSTR(vminfp128, VX128(6, 704)); + XEREGISTERINSTR(vminsb, 0x10000302); + XEREGISTERINSTR(vminsh, 0x10000342); + XEREGISTERINSTR(vminsw, 0x10000382); + XEREGISTERINSTR(vminub, 0x10000202); + XEREGISTERINSTR(vminuh, 0x10000242); + XEREGISTERINSTR(vminuw, 0x10000282); + XEREGISTERINSTR(vmladduhm, 0x10000022); + XEREGISTERINSTR(vmrghb, 0x1000000C); + XEREGISTERINSTR(vmrghh, 0x1000004C); + XEREGISTERINSTR(vmrghw, 0x1000008C); + XEREGISTERINSTR(vmrghw128, VX128(6, 768)); + XEREGISTERINSTR(vmrglb, 0x1000010C); + XEREGISTERINSTR(vmrglh, 0x1000014C); + XEREGISTERINSTR(vmrglw, 0x1000018C); + XEREGISTERINSTR(vmrglw128, VX128(6, 832)); + XEREGISTERINSTR(vmsummbm, 0x10000025); + XEREGISTERINSTR(vmsumshm, 0x10000028); + XEREGISTERINSTR(vmsumshs, 0x10000029); + XEREGISTERINSTR(vmsumubm, 0x10000024); + XEREGISTERINSTR(vmsumuhm, 0x10000026); + XEREGISTERINSTR(vmsumuhs, 0x10000027); + XEREGISTERINSTR(vmsum3fp128, VX128(5, 400)); + XEREGISTERINSTR(vmsum4fp128, VX128(5, 464)); + XEREGISTERINSTR(vmulesb, 0x10000308); + XEREGISTERINSTR(vmulesh, 0x10000348); + XEREGISTERINSTR(vmuleub, 0x10000208); + XEREGISTERINSTR(vmuleuh, 0x10000248); + XEREGISTERINSTR(vmulosb, 0x10000108); + XEREGISTERINSTR(vmulosh, 0x10000148); + XEREGISTERINSTR(vmuloub, 0x10000008); + XEREGISTERINSTR(vmulouh, 0x10000048); + XEREGISTERINSTR(vmulfp128, VX128(5, 144)); + XEREGISTERINSTR(vnmsubfp, 0x1000002F); + XEREGISTERINSTR(vnmsubfp128, VX128(5, 336)); + XEREGISTERINSTR(vnor, 0x10000504); + XEREGISTERINSTR(vnor128, VX128(5, 656)); + XEREGISTERINSTR(vor, 0x10000484); + XEREGISTERINSTR(vor128, VX128(5, 720)); + XEREGISTERINSTR(vperm, 0x1000002B); + XEREGISTERINSTR(vperm128, VX128_2(5, 0)); + XEREGISTERINSTR(vpermwi128, VX128_P(6, 528)); + XEREGISTERINSTR(vpkpx, 0x1000030E); + XEREGISTERINSTR(vpkshss, 0x1000018E); + XEREGISTERINSTR(vpkshss128, VX128(5, 512)); + XEREGISTERINSTR(vpkshus, 0x1000010E); + XEREGISTERINSTR(vpkshus128, VX128(5, 576)); + XEREGISTERINSTR(vpkswss, 0x100001CE); + XEREGISTERINSTR(vpkswss128, VX128(5, 640)); + XEREGISTERINSTR(vpkswus, 0x1000014E); + XEREGISTERINSTR(vpkswus128, VX128(5, 704)); + XEREGISTERINSTR(vpkuhum, 0x1000000E); + XEREGISTERINSTR(vpkuhum128, VX128(5, 768)); + XEREGISTERINSTR(vpkuhus, 0x1000008E); + XEREGISTERINSTR(vpkuhus128, VX128(5, 832)); + XEREGISTERINSTR(vpkuwum, 0x1000004E); + XEREGISTERINSTR(vpkuwum128, VX128(5, 896)); + XEREGISTERINSTR(vpkuwus, 0x100000CE); + XEREGISTERINSTR(vpkuwus128, VX128(5, 960)); + XEREGISTERINSTR(vpkd3d128, VX128_4(6, 1552)); + XEREGISTERINSTR(vrefp, 0x1000010A); + XEREGISTERINSTR(vrefp128, VX128_3(6, 1584)); + XEREGISTERINSTR(vrfim, 0x100002CA); + XEREGISTERINSTR(vrfim128, VX128_3(6, 816)); + XEREGISTERINSTR(vrfin, 0x1000020A); + XEREGISTERINSTR(vrfin128, VX128_3(6, 880)); + XEREGISTERINSTR(vrfip, 0x1000028A); + XEREGISTERINSTR(vrfip128, VX128_3(6, 944)); + XEREGISTERINSTR(vrfiz, 0x1000024A); + XEREGISTERINSTR(vrfiz128, VX128_3(6, 1008)); + XEREGISTERINSTR(vrlb, 0x10000004); + XEREGISTERINSTR(vrlh, 0x10000044); + XEREGISTERINSTR(vrlw, 0x10000084); + XEREGISTERINSTR(vrlw128, VX128(6, 80)); + XEREGISTERINSTR(vrlimi128, VX128_4(6, 1808)); + XEREGISTERINSTR(vrsqrtefp, 0x1000014A); + XEREGISTERINSTR(vrsqrtefp128, VX128_3(6, 1648)); + XEREGISTERINSTR(vsel, 0x1000002A); + XEREGISTERINSTR(vsel128, VX128(5, 848)); + XEREGISTERINSTR(vsl, 0x100001C4); + XEREGISTERINSTR(vslb, 0x10000104); + XEREGISTERINSTR(vslh, 0x10000144); + XEREGISTERINSTR(vslo, 0x1000040C); + XEREGISTERINSTR(vslo128, VX128(5, 912)); + XEREGISTERINSTR(vslw, 0x10000184); + XEREGISTERINSTR(vslw128, VX128(6, 208)); + // XEREGISTERINSTR(vsldoi, 0x1000002C); + // XEREGISTERINSTR(vsldoi128, VX128_5(4, 16)); + XEREGISTERINSTR(vspltb, 0x1000020C); + XEREGISTERINSTR(vsplth, 0x1000024C); + XEREGISTERINSTR(vspltw, 0x1000028C); + XEREGISTERINSTR(vspltw128, VX128_3(6, 1840)); + XEREGISTERINSTR(vspltisb, 0x1000030C); + XEREGISTERINSTR(vspltish, 0x1000034C); + XEREGISTERINSTR(vspltisw, 0x1000038C); + XEREGISTERINSTR(vspltisw128, VX128_3(6, 1904)); + XEREGISTERINSTR(vsr, 0x100002C4); + XEREGISTERINSTR(vsrab, 0x10000304); + XEREGISTERINSTR(vsrah, 0x10000344); + XEREGISTERINSTR(vsraw, 0x10000384); + XEREGISTERINSTR(vsraw128, VX128(6, 336)); + XEREGISTERINSTR(vsrb, 0x10000204); + XEREGISTERINSTR(vsrh, 0x10000244); + XEREGISTERINSTR(vsro, 0x1000044C); + XEREGISTERINSTR(vsro128, VX128(5, 976)); + XEREGISTERINSTR(vsrw, 0x10000284); + XEREGISTERINSTR(vsrw128, VX128(6, 464)); + XEREGISTERINSTR(vsubcuw, 0x10000580); + XEREGISTERINSTR(vsubfp, 0x1000004A); + XEREGISTERINSTR(vsubfp128, VX128(5, 80)); + XEREGISTERINSTR(vsubsbs, 0x10000700); + XEREGISTERINSTR(vsubshs, 0x10000740); + XEREGISTERINSTR(vsubsws, 0x10000780); + XEREGISTERINSTR(vsububm, 0x10000400); + XEREGISTERINSTR(vsububs, 0x10000600); + XEREGISTERINSTR(vsubuhm, 0x10000440); + XEREGISTERINSTR(vsubuhs, 0x10000640); + XEREGISTERINSTR(vsubuwm, 0x10000480); + XEREGISTERINSTR(vsubuws, 0x10000680); + XEREGISTERINSTR(vsumsws, 0x10000788); + XEREGISTERINSTR(vsum2sws, 0x10000688); + XEREGISTERINSTR(vsum4sbs, 0x10000708); + XEREGISTERINSTR(vsum4shs, 0x10000648); + XEREGISTERINSTR(vsum4ubs, 0x10000608); + XEREGISTERINSTR(vupkhpx, 0x1000034E); + XEREGISTERINSTR(vupkhsb, 0x1000020E); + XEREGISTERINSTR(vupkhsb128, VX128(6, 896)); + XEREGISTERINSTR(vupkhsh, 0x1000024E); + XEREGISTERINSTR(vupklpx, 0x100003CE); + XEREGISTERINSTR(vupklsb, 0x1000028E); + XEREGISTERINSTR(vupklsb128, VX128(6, 960)); + XEREGISTERINSTR(vupklsh, 0x100002CE); + XEREGISTERINSTR(vupkd3d128, VX128_3(6, 2032)); + XEREGISTERINSTR(vxor, 0x100004C4); + XEREGISTERINSTR(vxor128, VX128(5, 784)); +} + + +} // namespace ppc +} // namespace frontend +} // namespace alloy diff --git a/src/alloy/frontend/ppc/ppc_emit_alu.cc b/src/alloy/frontend/ppc/ppc_emit_alu.cc new file mode 100644 index 000000000..c207c7d64 --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_emit_alu.cc @@ -0,0 +1,1394 @@ +/* + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include + + +using namespace alloy::frontend::ppc; +using namespace alloy::hir; +using namespace alloy::runtime; + + +namespace alloy { +namespace frontend { +namespace ppc { + + +// Integer arithmetic (A-3) + +XEEMITTER(addx, 0x7C000214, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RD <- (RA) + (RB) + Value* v = f.Add( + f.LoadGPR(i.XO.RA), + f.LoadGPR(i.XO.RB)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEASSERTALWAYS(); + //e.update_xer_with_overflow(EFLAGS OF?); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(addcx, 0x7C000014, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RD <- (RA) + (RB) + // CA <- carry bit + Value* v = f.Add( + f.LoadGPR(i.XO.RA), + f.LoadGPR(i.XO.RB), + ARITHMETIC_SET_CARRY); + f.StoreCA(f.DidCarry(v)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEASSERTALWAYS(); + //e.update_xer_with_overflow(EFLAGS OF?); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(addex, 0x7C000114, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RD <- (RA) + (RB) + XER[CA] + Value* v = f.AddWithCarry( + f.LoadGPR(i.XO.RA), + f.LoadGPR(i.XO.RB), + f.LoadCA(), + ARITHMETIC_SET_CARRY); + f.StoreCA(f.DidCarry(v)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEASSERTALWAYS(); + //e.update_xer_with_overflow(EFLAGS OF?); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(addi, 0x38000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // RT <- EXTS(SI) + // else + // RT <- (RA) + EXTS(SI) + Value* si = f.LoadConstant(XEEXTS16(i.D.DS)); + Value* v = si; + if (i.D.RA) { + v = f.Add(f.LoadGPR(i.D.RA), si); + } + f.StoreGPR(i.D.RT, v); + return 0; +} + +XEEMITTER(addic, 0x30000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- (RA) + EXTS(SI) + Value* v = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS)), + ARITHMETIC_SET_CARRY); + f.StoreCA(f.DidCarry(v)); + f.StoreGPR(i.D.RT, v); + return 0; +} + +XEEMITTER(addicx, 0x34000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- (RA) + EXTS(SI) + Value* v = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS)), + ARITHMETIC_SET_CARRY); + f.StoreCA(f.DidCarry(v)); + f.StoreGPR(i.D.RT, v); + f.UpdateCR(0, v); + return 0; +} + +XEEMITTER(addis, 0x3C000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // RT <- EXTS(SI) || i16.0 + // else + // RT <- (RA) + EXTS(SI) || i16.0 + Value* si = f.LoadConstant(XEEXTS16(i.D.DS) << 16); + Value* v = si; + if (i.D.RA) { + v = f.Add(f.LoadGPR(i.D.RA), si); + } + f.StoreGPR(i.D.RT, v); + return 0; +} + +XEEMITTER(addmex, 0x7C0001D4, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- (RA) + CA - 1 + Value* v = f.AddWithCarry( + f.LoadGPR(i.XO.RA), + f.LoadConstant((int64_t)-1), + f.LoadCA(), + ARITHMETIC_SET_CARRY); + if (i.XO.OE) { + // With XER[SO] update too. + //e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + XEASSERTALWAYS(); + } else { + // Just CA update. + f.StoreCA(f.DidCarry(v)); + } + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(addzex, 0x7C000194, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- (RA) + CA + Value* v = f.AddWithCarry( + f.LoadGPR(i.XO.RA), + f.LoadZero(INT64_TYPE), + f.LoadCA(), + ARITHMETIC_SET_CARRY); + if (i.XO.OE) { + // With XER[SO] update too. + //e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + XEASSERTALWAYS(); + } else { + // Just CA update. + f.StoreCA(f.DidCarry(v)); + } + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(divdx, 0x7C0003D2, XO )(PPCFunctionBuilder& f, InstrData& i) { + // dividend <- (RA) + // divisor <- (RB) + // if divisor = 0 then + // if OE = 1 then + // XER[OV] <- 1 + // return + // RT <- dividend ÷ divisor + Value* divisor = f.LoadGPR(i.XO.RB); + // TODO(benvanik): check if zero + // if OE=1, set XER[OV] = 1 + // else skip the divide + Value* v = f.Div(f.LoadGPR(i.XO.RA), divisor); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + // If we are OE=1 we need to clear the overflow bit. + //e.update_xer_with_overflow(e.get_uint64(0)); + XEASSERTALWAYS(); + return 1; + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(divdux, 0x7C000392, XO )(PPCFunctionBuilder& f, InstrData& i) { + // dividend <- (RA) + // divisor <- (RB) + // if divisor = 0 then + // if OE = 1 then + // XER[OV] <- 1 + // return + // RT <- dividend ÷ divisor + Value* divisor = f.LoadGPR(i.XO.RB); + // TODO(benvanik): check if zero + // if OE=1, set XER[OV] = 1 + // else skip the divide + Value* v = f.Div(f.LoadGPR(i.XO.RA), divisor); +f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + // If we are OE=1 we need to clear the overflow bit. + //e.update_xer_with_overflow(e.get_uint64(0)); + XEASSERTALWAYS(); + return 1; + } + if (i.XO.Rc) { + f.UpdateCR(0, v, false); + } + return 0; +} + +XEEMITTER(divwx, 0x7C0003D6, XO )(PPCFunctionBuilder& f, InstrData& i) { + // dividend[0:31] <- (RA)[32:63] + // divisor[0:31] <- (RB)[32:63] + // if divisor = 0 then + // if OE = 1 then + // XER[OV] <- 1 + // return + // RT[32:63] <- dividend ÷ divisor + // RT[0:31] <- undefined + Value* divisor = f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE); + // TODO(benvanik): check if zero + // if OE=1, set XER[OV] = 1 + // else skip the divide + Value* v = f.Div(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), divisor); + v = f.ZeroExtend(v, INT64_TYPE); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + // If we are OE=1 we need to clear the overflow bit. + //e.update_xer_with_overflow(e.get_uint64(0)); + XEASSERTALWAYS(); + return 1; + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(divwux, 0x7C000396, XO )(PPCFunctionBuilder& f, InstrData& i) { + // dividend[0:31] <- (RA)[32:63] + // divisor[0:31] <- (RB)[32:63] + // if divisor = 0 then + // if OE = 1 then + // XER[OV] <- 1 + // return + // RT[32:63] <- dividend ÷ divisor + // RT[0:31] <- undefined + Value* divisor = f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE); + // TODO(benvanik): check if zero + // if OE=1, set XER[OV] = 1 + // else skip the divide + Value* v = f.Div(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), divisor); + v = f.ZeroExtend(v, INT64_TYPE); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + // If we are OE=1 we need to clear the overflow bit. + //e.update_xer_with_overflow(e.get_uint64(0)); + XEASSERTALWAYS(); + return 1; + } + if (i.XO.Rc) { + f.UpdateCR(0, v, false); + } + return 0; +} + +XEEMITTER(mulhdx, 0x7C000092, XO )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mulhdux, 0x7C000012, XO )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mulhwx, 0x7C000096, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT[32:64] <- ((RA)[32:63] × (RB)[32:63])[0:31] + if (i.XO.OE) { + // With XER update. + XEINSTRNOTIMPLEMENTED(); + return 1; + } + Value* v = f.Mul( + f.ZeroExtend(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), INT64_TYPE), + f.ZeroExtend(f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE), INT64_TYPE)); + v = f.Shr(v, 32); + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(mulhwux, 0x7C000016, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT[32:64] <- ((RA)[32:63] × (RB)[32:63])[0:31] + if (i.XO.OE) { + // With XER update. + XEINSTRNOTIMPLEMENTED(); + return 1; + } + Value* v = f.Mul( + f.ZeroExtend(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), INT64_TYPE), + f.ZeroExtend(f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE), INT64_TYPE)); + v = f.Shr(v, 32); + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v, false); + } + return 0; +} + +XEEMITTER(mulldx, 0x7C0001D2, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- ((RA) × (RB))[64:127] + if (i.XO.OE) { + // With XER update. + XEINSTRNOTIMPLEMENTED(); + return 1; + } + Value* v = f.Mul(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(mulli, 0x1C000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // prod[0:127] <- (RA) × EXTS(SI) + // RT <- prod[64:127] + Value* v = f.Mul(f.LoadGPR(i.D.RA), f.LoadConstant(XEEXTS16(i.D.DS))); + f.StoreGPR(i.D.RT, v); + return 0; +} + +XEEMITTER(mullwx, 0x7C0001D6, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- (RA)[32:63] × (RB)[32:63] + if (i.XO.OE) { + // With XER update. + XEINSTRNOTIMPLEMENTED(); + return 1; + } + Value* v = f.Mul( + f.ZeroExtend(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), INT64_TYPE), + f.ZeroExtend(f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE), INT64_TYPE)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(negx, 0x7C0000D0, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- ¬(RA) + 1 + if (i.XO.OE) { + // With XER update. + // This is a different codepath as we need to use llvm.ssub.with.overflow. + + // if RA == 0x8000000000000000 then no-op and set OV=1 + // This may just magically do that... + + XEASSERTALWAYS(); + //Function* ssub_with_overflow = Intrinsic::getDeclaration( + // e.gen_module(), Intrinsic::ssub_with_overflow, jit_type_nint); + //jit_value_t v = b.CreateCall2(ssub_with_overflow, + // e.get_int64(0), f.LoadGPR(i.XO.RA)); + //jit_value_t v0 = b.CreateExtractValue(v, 0); + //f.StoreGPR(i.XO.RT, v0); + //e.update_xer_with_overflow(b.CreateExtractValue(v, 1)); + + //if (i.XO.Rc) { + // // With cr0 update. + // f.UpdateCR(0, v0, e.get_int64(0), true); + //} + } else { + // No OE bit setting. + Value* v = f.Neg(f.LoadGPR(i.XO.RA)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + } + return 0; +} + +XEEMITTER(subfx, 0x7C000050, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- ¬(RA) + (RB) + 1 + Value* v = f.Sub(f.LoadGPR(i.XO.RB), f.LoadGPR(i.XO.RA)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEASSERTALWAYS(); + //e.update_xer_with_overflow(EFLAGS??); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(subfcx, 0x7C000010, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- ¬(RA) + (RB) + 1 + Value* v = f.Sub( + f.LoadGPR(i.XO.RB), + f.LoadGPR(i.XO.RA), + ARITHMETIC_SET_CARRY); + f.StoreCA(f.DidCarry(v)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEASSERTALWAYS(); + //e.update_xer_with_overflow(EFLAGS??); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(subficx, 0x20000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- ¬(RA) + EXTS(SI) + 1 + Value* v = f.Sub( + f.LoadConstant(XEEXTS16(i.D.DS)), + f.LoadGPR(i.D.RA), + ARITHMETIC_SET_CARRY); + f.StoreCA(f.DidCarry(v)); + f.StoreGPR(i.D.RT, v); + return 0; +} + +XEEMITTER(subfex, 0x7C000110, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- ¬(RA) + (RB) + CA + Value* v = f.AddWithCarry( + f.Not(f.LoadGPR(i.XO.RA)), + f.LoadGPR(i.XO.RB), + f.LoadCA(), + ARITHMETIC_SET_CARRY); + f.StoreCA(f.DidCarry(v)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEASSERTALWAYS(); + //e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(subfmex, 0x7C0001D0, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- ¬(RA) + CA - 1 + Value* v = f.AddWithCarry( + f.Not(f.LoadGPR(i.XO.RA)), + f.LoadConstant((int64_t)-1), + f.LoadCA()); + if (i.XO.OE) { + XEASSERTALWAYS(); + //e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + } else { + f.StoreCA(f.DidCarry(v)); + } + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(subfzex, 0x7C000190, XO )(PPCFunctionBuilder& f, InstrData& i) { + // RT <- ¬(RA) + CA + Value* v = f.AddWithCarry( + f.Not(f.LoadGPR(i.XO.RA)), + f.LoadZero(INT64_TYPE), + f.LoadCA()); + if (i.XO.OE) { + XEASSERTALWAYS(); + //e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + } else { + f.StoreCA(f.DidCarry(v)); + } + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + + +// Integer compare (A-4) + +XEEMITTER(cmp, 0x7C000000, X )(PPCFunctionBuilder& f, InstrData& i) { + // if L = 0 then + // a <- EXTS((RA)[32:63]) + // b <- EXTS((RB)[32:63]) + // else + // a <- (RA) + // b <- (RB) + // if a < b then + // c <- 0b100 + // else if a > b then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + uint32_t BF = i.X.RT >> 2; + uint32_t L = i.X.RT & 1; + Value* lhs; + Value* rhs; + if (L) { + lhs = f.LoadGPR(i.X.RA); + rhs = f.LoadGPR(i.X.RB); + } else { + lhs = f.Truncate(f.LoadGPR(i.X.RA), INT32_TYPE); + rhs = f.Truncate(f.LoadGPR(i.X.RB), INT32_TYPE); + } + f.UpdateCR(BF, lhs, rhs); + return 0; +} + +XEEMITTER(cmpi, 0x2C000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if L = 0 then + // a <- EXTS((RA)[32:63]) + // else + // a <- (RA) + // if a < EXTS(SI) then + // c <- 0b100 + // else if a > EXTS(SI) then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + uint32_t BF = i.D.RT >> 2; + uint32_t L = i.D.RT & 1; + Value* lhs; + Value* rhs; + if (L) { + lhs = f.LoadGPR(i.D.RA); + rhs = f.LoadConstant(XEEXTS16(i.D.DS)); + } else { + lhs = f.Truncate(f.LoadGPR(i.D.RA), INT32_TYPE); + rhs = f.LoadConstant((int32_t)XEEXTS16(i.D.DS)); + } + f.UpdateCR(BF, lhs, rhs); + return 0; +} + +XEEMITTER(cmpl, 0x7C000040, X )(PPCFunctionBuilder& f, InstrData& i) { + // if L = 0 then + // a <- i32.0 || (RA)[32:63] + // b <- i32.0 || (RB)[32:63] + // else + // a <- (RA) + // b <- (RB) + // if a u b then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + uint32_t BF = i.X.RT >> 2; + uint32_t L = i.X.RT & 1; + Value* lhs; + Value* rhs; + if (L) { + lhs = f.LoadGPR(i.X.RA); + rhs = f.LoadGPR(i.X.RB); + } else { + lhs = f.Truncate(f.LoadGPR(i.X.RA), INT32_TYPE); + rhs = f.Truncate(f.LoadGPR(i.X.RB), INT32_TYPE); + } + f.UpdateCR(BF, lhs, rhs, false); + return 0; +} + +XEEMITTER(cmpli, 0x28000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if L = 0 then + // a <- i32.0 || (RA)[32:63] + // else + // a <- (RA) + // if a u i48.0 || SI then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + uint32_t BF = i.D.RT >> 2; + uint32_t L = i.D.RT & 1; + Value* lhs; + Value* rhs; + if (L) { + lhs = f.LoadGPR(i.D.RA); + rhs = f.LoadConstant((uint64_t)i.D.DS); + } else { + lhs = f.Truncate(f.LoadGPR(i.D.RA), INT32_TYPE); + rhs = f.LoadConstant((uint32_t)i.D.DS); + } + f.UpdateCR(BF, lhs, rhs, false); + return 0; +} + + +// Integer logical (A-5) + +XEEMITTER(andx, 0x7C000038, X )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) & (RB) + Value* ra = f.Add(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + f.StoreGPR(i.X.RA, ra); + return 0; +} + +XEEMITTER(andcx, 0x7C000078, X )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) & ¬(RB) + Value* ra = f.Add(f.LoadGPR(i.X.RT), f.Not(f.LoadGPR(i.X.RB))); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + f.StoreGPR(i.X.RA, ra); + return 0; +} + +XEEMITTER(andix, 0x70000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) & (i48.0 || UI) + Value* ra = f.Add( + f.LoadGPR(i.D.RT), + f.LoadConstant((uint64_t)i.D.DS)); + f.UpdateCR(0, ra); + f.StoreGPR(i.D.RA, ra); + return 0; +} + +XEEMITTER(andisx, 0x74000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) & (i32.0 || UI || i16.0) + Value* ra = f.Add( + f.LoadGPR(i.D.RT), + f.LoadConstant((uint64_t)(i.D.DS << 16))); + f.UpdateCR(0, ra); + f.StoreGPR(i.D.RA, ra); + return 0; +} + +XEEMITTER(cntlzdx, 0x7C000074, X )(PPCFunctionBuilder& f, InstrData& i) { + // n <- 0 + // do while n < 64 + // if (RS)[n] = 1 then leave n + // n <- n + 1 + // RA <- n + Value* v = f.CountLeadingZeros(f.LoadGPR(i.X.RT)); + v = f.ZeroExtend(v, INT64_TYPE); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + f.StoreGPR(i.X.RA, v); + return 0; +} + +XEEMITTER(cntlzwx, 0x7C000034, X )(PPCFunctionBuilder& f, InstrData& i) { + // n <- 32 + // do while n < 64 + // if (RS)[n] = 1 then leave n + // n <- n + 1 + // RA <- n - 32 + Value* v = f.CountLeadingZeros( + f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE)); + v = f.ZeroExtend(v, INT64_TYPE); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + f.StoreGPR(i.X.RA, v); + return 0; +} + +XEEMITTER(eqvx, 0x7C000238, X )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) == (RB) + + // UNTESTED: ensure this is correct. + XEASSERTALWAYS(); + f.DebugBreak(); + + Value* ra = f.Xor(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)); + ra = f.Not(ra); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + f.StoreGPR(i.X.RA, ra); + return 0; +} + +XEEMITTER(extsbx, 0x7C000774, X )(PPCFunctionBuilder& f, InstrData& i) { + // s <- (RS)[56] + // RA[56:63] <- (RS)[56:63] + // RA[0:55] <- i56.s + Value* rt = f.LoadGPR(i.X.RT); + rt = f.SignExtend(f.Truncate(rt, INT8_TYPE), INT64_TYPE); + if (i.X.Rc) { + f.UpdateCR(0, rt); + } + f.StoreGPR(i.X.RA, rt); + return 0; +} + +XEEMITTER(extshx, 0x7C000734, X )(PPCFunctionBuilder& f, InstrData& i) { + // s <- (RS)[48] + // RA[48:63] <- (RS)[48:63] + // RA[0:47] <- 48.s + Value* rt = f.LoadGPR(i.X.RT); + rt = f.SignExtend(f.Truncate(rt, INT16_TYPE), INT64_TYPE); + if (i.X.Rc) { + f.UpdateCR(0, rt); + } + f.StoreGPR(i.X.RA, rt); + return 0; +} + +XEEMITTER(extswx, 0x7C0007B4, X )(PPCFunctionBuilder& f, InstrData& i) { + // s <- (RS)[32] + // RA[32:63] <- (RS)[32:63] + // RA[0:31] <- i32.s + Value* rt = f.LoadGPR(i.X.RT); + rt = f.SignExtend(f.Truncate(rt, INT32_TYPE), INT64_TYPE); + if (i.X.Rc) { + f.UpdateCR(0, rt); + } + f.StoreGPR(i.X.RA, rt); + return 0; +} + +XEEMITTER(nandx, 0x7C0003B8, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(norx, 0x7C0000F8, X )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- ¬((RS) | (RB)) + Value* ra = f.Or( + f.LoadGPR(i.X.RT), + f.LoadGPR(i.X.RB)); + ra = f.Not(ra); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + f.StoreGPR(i.X.RA, ra); + return 0; +} + +XEEMITTER(orx, 0x7C000378, X )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) | (RB) + if (i.X.RT == i.X.RB && i.X.RT == i.X.RA && + !i.X.Rc) { + // Sometimes used as no-op. + f.Nop(); + return 0; + } + Value* ra; + if (i.X.RT == i.X.RB) { + ra = f.LoadGPR(i.X.RT); + } else { + ra = f.Or( + f.LoadGPR(i.X.RT), + f.LoadGPR(i.X.RB)); + } + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + f.StoreGPR(i.X.RA, ra); + return 0; +} + +XEEMITTER(orcx, 0x7C000338, X )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) | ¬(RB) + Value* ra = f.Or( + f.LoadGPR(i.X.RT), + f.Not(f.LoadGPR(i.X.RB))); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + f.StoreGPR(i.X.RA, ra); + return 0; +} + +XEEMITTER(ori, 0x60000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) | (i48.0 || UI) + Value* ra = f.Or( + f.LoadGPR(i.D.RT), + f.LoadConstant((uint64_t)i.D.DS)); + f.StoreGPR(i.D.RA, ra); + return 0; +} + +XEEMITTER(oris, 0x64000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) | (i32.0 || UI || i16.0) + Value* ra = f.Or( + f.LoadGPR(i.D.RT), + f.LoadConstant((uint64_t)(i.D.DS << 16))); + f.StoreGPR(i.D.RA, ra); + return 0; +} + +XEEMITTER(xorx, 0x7C000278, X )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) XOR (RB) + Value* ra = f.Xor( + f.LoadGPR(i.X.RT), + f.LoadGPR(i.X.RB)); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + f.StoreGPR(i.X.RA, ra); + return 0; +} + +XEEMITTER(xori, 0x68000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) XOR (i48.0 || UI) + Value* ra = f.Xor( + f.LoadGPR(i.D.RT), + f.LoadConstant((uint64_t)i.D.DS)); + f.StoreGPR(i.D.RA, ra); + return 0; +} + +XEEMITTER(xoris, 0x6C000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // RA <- (RS) XOR (i32.0 || UI || i16.0) + Value* ra = f.Xor( + f.LoadGPR(i.D.RT), + f.LoadConstant((uint64_t)(i.D.DS << 16))); + f.StoreGPR(i.D.RA, ra); + return 0; +} + + +// Integer rotate (A-6) + +//XEEMITTER(rld, 0x78000000, MDS)(PPCFunctionBuilder& f, InstrData& i) { +// if (i.MD.idx == 0) { +// // XEEMITTER(rldiclx, 0x78000000, MD ) +// // n <- sh[5] || sh[0:4] +// // r <- ROTL64((RS), n) +// // b <- mb[5] || mb[0:4] +// // m <- MASK(b, 63) +// // RA <- r & m +// +// uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; +// uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; +// uint64_t m = XEMASK(mb, 63); +// +// GpVar v(c.newGpVar()); +// c.mov(v, f.LoadGPR(i.MD.RT)); +// if (sh) { +// c.rol(v, imm(sh)); +// } +// if (m != 0xFFFFFFFFFFFFFFFF) { +// GpVar mask(c.newGpVar()); +// c.mov(mask, imm(m)); +// c.and_(v, mask); +// } +// f.StoreGPR(i.MD.RA, v); +// +// if (i.MD.Rc) { +// // With cr0 update. +// f.UpdateCR(0, v); +// } +// +// e.clear_constant_gpr_value(i.MD.RA); +// +// return 0; +// } else if (i.MD.idx == 1) { +// // XEEMITTER(rldicrx, 0x78000004, MD ) +// // n <- sh[5] || sh[0:4] +// // r <- ROTL64((RS), n) +// // e <- me[5] || me[0:4] +// // m <- MASK(0, e) +// // RA <- r & m +// +// uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; +// uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; +// uint64_t m = XEMASK(0, mb); +// +// GpVar v(c.newGpVar()); +// c.mov(v, f.LoadGPR(i.MD.RT)); +// if (sh) { +// c.rol(v, imm(sh)); +// } +// if (m != 0xFFFFFFFFFFFFFFFF) { +// GpVar mask(c.newGpVar()); +// c.mov(mask, imm(m)); +// c.and_(v, mask); +// } +// f.StoreGPR(i.MD.RA, v); +// +// if (i.MD.Rc) { +// // With cr0 update. +// f.UpdateCR(0, v); +// } +// +// e.clear_constant_gpr_value(i.MD.RA); +// +// return 0; +// } else if (i.MD.idx == 2) { +// // XEEMITTER(rldicx, 0x78000008, MD ) +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } else if (i.MDS.idx == 8) { +// // XEEMITTER(rldclx, 0x78000010, MDS) +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } else if (i.MDS.idx == 9) { +// // XEEMITTER(rldcrx, 0x78000012, MDS) +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } else if (i.MD.idx == 3) { +// // XEEMITTER(rldimix, 0x7800000C, MD ) +// // n <- sh[5] || sh[0:4] +// // r <- ROTL64((RS), n) +// // b <- me[5] || me[0:4] +// // m <- MASK(b, ¬n) +// // RA <- (r & m) | ((RA)&¬m) +// +// uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; +// uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; +// uint64_t m = XEMASK(mb, ~sh); +// +// GpVar v(c.newGpVar()); +// c.mov(v, f.LoadGPR(i.MD.RT)); +// if (sh) { +// c.rol(v, imm(sh)); +// } +// if (m != 0xFFFFFFFFFFFFFFFF) { +// GpVar mask(c.newGpVar()); +// c.mov(mask, e.get_uint64(m)); +// c.and_(v, mask); +// GpVar ra(c.newGpVar()); +// c.mov(ra, f.LoadGPR(i.MD.RA)); +// c.not_(mask); +// c.and_(ra, mask); +// c.or_(v, ra); +// } +// f.StoreGPR(i.MD.RA, v); +// +// if (i.MD.Rc) { +// // With cr0 update. +// f.UpdateCR(0, v); +// } +// +// e.clear_constant_gpr_value(i.MD.RA); +// +// return 0; +// } else { +// XEINSTRNOTIMPLEMENTED(); +// return 1; +// } +//} + +XEEMITTER(rlwimix, 0x50000000, M )(PPCFunctionBuilder& f, InstrData& i) { + // n <- SH + // r <- ROTL32((RS)[32:63], n) + // m <- MASK(MB+32, ME+32) + // RA <- r&m | (RA)&¬m + Value* v = f.Truncate(f.LoadGPR(i.M.RT), INT32_TYPE); + if (i.M.SH) { + v = f.RotateLeft(v, f.LoadConstant(i.M.SH)); + } + // Compiler sometimes masks with 0xFFFFFFFF (identity) - avoid the work here + // as our truncation/zero-extend does it for us. + uint32_t m = (uint32_t)XEMASK(i.M.MB + 32, i.M.ME + 32); + if (!(i.M.MB == 0 && i.M.ME == 31)) { + v = f.And(v, f.LoadConstant(m)); + } + v = f.ZeroExtend(v, INT64_TYPE); + Value* ra = f.LoadGPR(i.M.RA); + v = f.Or(v, f.And(f.LoadGPR(i.M.RA), f.LoadConstant(~m))); + if (i.M.Rc) { + f.UpdateCR(0, v); + } + f.StoreGPR(i.M.RA, v); + return 0; +} + +XEEMITTER(rlwinmx, 0x54000000, M )(PPCFunctionBuilder& f, InstrData& i) { + // n <- SH + // r <- ROTL32((RS)[32:63], n) + // m <- MASK(MB+32, ME+32) + // RA <- r & m + Value* v = f.Truncate(f.LoadGPR(i.M.RT), INT32_TYPE); + // The compiler will generate a bunch of these for the special case of SH=0. + // Which seems to just select some bits and set cr0 for use with a branch. + // We can detect this and do less work. + if (i.M.SH) { + v = f.RotateLeft(v, f.LoadConstant(i.M.SH)); + } + // Compiler sometimes masks with 0xFFFFFFFF (identity) - avoid the work here + // as our truncation/zero-extend does it for us. + if (!(i.M.MB == 0 && i.M.ME == 31)) { + v = f.And(v, f.LoadConstant((uint32_t)XEMASK(i.M.MB + 32, i.M.ME + 32))); + } + v = f.ZeroExtend(v, INT64_TYPE); + if (i.M.Rc) { + f.UpdateCR(0, v); + } + f.StoreGPR(i.M.RA, v); + return 0; +} + +XEEMITTER(rlwnmx, 0x5C000000, M )(PPCFunctionBuilder& f, InstrData& i) { + // n <- (RB)[59:63] + // r <- ROTL32((RS)[32:63], n) + // m <- MASK(MB+32, ME+32) + // RA <- r & m + Value* v = f.Truncate(f.LoadGPR(i.M.RT), INT32_TYPE); + Value* sh = f.And(f.LoadGPR(i.M.SH), f.LoadConstant(0x1F)); + v = f.RotateLeft(v, sh); + // Compiler sometimes masks with 0xFFFFFFFF (identity) - avoid the work here + // as our truncation/zero-extend does it for us. + if (!(i.M.MB == 0 && i.M.ME == 31)) { + v = f.And(v, f.LoadConstant((uint32_t)XEMASK(i.M.MB + 32, i.M.ME + 32))); + } + v = f.ZeroExtend(v, INT64_TYPE); + if (i.M.Rc) { + f.UpdateCR(0, v); + } + f.StoreGPR(i.M.RA, v); + return 0; +} + + +// Integer shift (A-7) + +XEEMITTER(sldx, 0x7C000036, X )(PPCFunctionBuilder& f, InstrData& i) { + // n <- (RB)[59:63] + // r <- ROTL64((RS), n) + // if (RB)[58] = 0 then + // m <- MASK(0, 63-n) + // else + // m <- i64.0 + // RA <- r & m + Value* v = f.Shl(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(slwx, 0x7C000030, X )(PPCFunctionBuilder& f, InstrData& i) { + // n <- (RB)[59:63] + // r <- ROTL32((RS)[32:63], n) + // if (RB)[58] = 0 then + // m <- MASK(32, 63-n) + // else + // m <- i64.0 + // RA <- r & m + Value* v = f.Shl(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE), + f.LoadGPR(i.X.RB)); + v = f.ZeroExtend(v, INT64_TYPE); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(srdx, 0x7C000436, X )(PPCFunctionBuilder& f, InstrData& i) { + // n <- (RB)[59:63] + // r <- ROTL64((RS), 64-n) + // if (RB)[58] = 0 then + // m <- MASK(n, 63) + // else + // m <- i64.0 + // RA <- r & m + Value* v = f.Shr(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +XEEMITTER(srwx, 0x7C000430, X )(PPCFunctionBuilder& f, InstrData& i) { + // n <- (RB)[59:63] + // r <- ROTL32((RS)[32:63], 64-n) + // if (RB)[58] = 0 then + // m <- MASK(n+32, 63) + // else + // m <- i64.0 + // RA <- r & m + Value* v = f.Shr(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE), + f.LoadGPR(i.X.RB)); + v = f.ZeroExtend(v, INT64_TYPE); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + +// XEEMITTER(sradx, 0x7C000634, X )(PPCFunctionBuilder& f, InstrData& i) { +// // n <- rB[58-63] +// // r <- ROTL[64](rS, 64 - n) +// // if rB[57] = 0 then m ↠MASK(n, 63) +// // else m ↠(64)0 +// // S ↠rS[0] +// // rA <- (r & m) | (((64)S) & ¬ m) +// // XER[CA] <- S & ((r & ¬ m) ¦ 0) + +// // if n == 0: rA <- rS, XER[CA] = 0 +// // if n >= 64: rA <- 64 sign bits of rS, XER[CA] = sign bit of rS + +// GpVar v(c.newGpVar()); +// c.mov(v, f.LoadGPR(i.X.RT)); +// GpVar sh(c.newGpVar()); +// c.mov(sh, f.LoadGPR(i.X.RB)); +// c.and_(sh, imm(0x7F)); + +// // CA is set if any bits are shifted out of the right and if the result +// // is negative. Start tracking that here. +// GpVar ca(c.newGpVar()); +// c.mov(ca, imm(0xFFFFFFFFFFFFFFFF)); +// GpVar ca_sh(c.newGpVar()); +// c.mov(ca_sh, imm(63)); +// c.sub(ca_sh, sh); +// c.shl(ca, ca_sh); +// c.shr(ca, ca_sh); +// c.and_(ca, v); +// c.cmp(ca, imm(0)); +// c.xor_(ca, ca); +// c.setnz(ca.r8()); + +// // Shift right. +// c.sar(v, sh); + +// // CA is set to 1 if the low-order 32 bits of (RS) contain a negative number +// // and any 1-bits are shifted out of position 63; otherwise CA is set to 0. +// // We already have ca set to indicate the pos 63 bit, now just and in sign. +// GpVar ca_2(c.newGpVar()); +// c.mov(ca_2, v); +// c.shr(ca_2, imm(63)); +// c.and_(ca, ca_2); + +// f.StoreGPR(i.X.RA, v); +// e.update_xer_with_carry(ca); + +// if (i.X.Rc) { +// f.UpdateCR(0, v); +// } +// return 0; +// } + +// XEEMITTER(sradix, 0x7C000674, XS )(PPCFunctionBuilder& f, InstrData& i) { +// // n <- sh[5] || sh[0-4] +// // r <- ROTL[64](rS, 64 - n) +// // m ↠MASK(n, 63) +// // S ↠rS[0] +// // rA <- (r & m) | (((64)S) & ¬ m) +// // XER[CA] <- S & ((r & ¬ m) ¦ 0) + +// // if n == 0: rA <- rS, XER[CA] = 0 +// // if n >= 64: rA <- 64 sign bits of rS, XER[CA] = sign bit of rS + +// GpVar v(c.newGpVar()); +// c.mov(v, f.LoadGPR(i.XS.RA)); +// GpVar sh(c.newGpVar()); +// c.mov(sh, imm((i.XS.SH5 << 5) | i.XS.SH)); + +// // CA is set if any bits are shifted out of the right and if the result +// // is negative. Start tracking that here. +// GpVar ca(c.newGpVar()); +// c.mov(ca, imm(0xFFFFFFFFFFFFFFFF)); +// GpVar ca_sh(c.newGpVar()); +// c.mov(ca_sh, imm(63)); +// c.sub(ca_sh, sh); +// c.shl(ca, ca_sh); +// c.shr(ca, ca_sh); +// c.and_(ca, v); +// c.cmp(ca, imm(0)); +// c.xor_(ca, ca); +// c.setnz(ca.r8()); + +// // Shift right. +// c.sar(v, sh); + +// // CA is set to 1 if the low-order 32 bits of (RS) contain a negative number +// // and any 1-bits are shifted out of position 63; otherwise CA is set to 0. +// // We already have ca set to indicate the pos 63 bit, now just and in sign. +// GpVar ca_2(c.newGpVar()); +// c.mov(ca_2, v); +// c.shr(ca_2, imm(63)); +// c.and_(ca, ca_2); + +// f.StoreGPR(i.XS.RT, v); +// e.update_xer_with_carry(ca); + +// if (i.X.Rc) { +// f.UpdateCR(0, v); +// } +// e.clear_constant_gpr_value(i.X.RA); +// return 0; +// } + +// XEEMITTER(srawx, 0x7C000630, X )(PPCFunctionBuilder& f, InstrData& i) { +// // n <- rB[59-63] +// // r <- ROTL32((RS)[32:63], 64-n) +// // m <- MASK(n+32, 63) +// // s <- (RS)[32] +// // RA <- r&m | (i64.s)&¬m +// // CA <- s & ((r&¬m)[32:63]≠0) + +// // if n == 0: rA <- sign_extend(rS), XER[CA] = 0 +// // if n >= 32: rA <- 64 sign bits of rS, XER[CA] = sign bit of lo_32(rS) + +// GpVar v(c.newGpVar()); +// c.mov(v, f.LoadGPR(i.X.RT)); +// GpVar sh(c.newGpVar()); +// c.mov(sh, f.LoadGPR(i.X.RB)); +// c.and_(sh, imm(0x7F)); + +// GpVar ca(c.newGpVar()); +// Label skip(c.newLabel()); +// Label full(c.newLabel()); +// c.test(sh, sh); +// c.jnz(full); +// { +// // No shift, just a fancy sign extend and CA clearer. +// c.cdqe(v); +// c.mov(ca, imm(0)); +// } +// c.jmp(skip); +// c.bind(full); +// { +// // CA is set if any bits are shifted out of the right and if the result +// // is negative. Start tracking that here. +// c.mov(ca, v); +// c.and_(ca, imm(~XEMASK(32 + i.X.RB, 64))); +// c.cmp(ca, imm(0)); +// c.xor_(ca, ca); +// c.setnz(ca.r8()); + +// // Shift right and sign extend the 32bit part. +// c.sar(v.r32(), imm(i.X.RB)); +// c.cdqe(v); + +// // CA is set to 1 if the low-order 32 bits of (RS) contain a negative number +// // and any 1-bits are shifted out of position 63; otherwise CA is set to 0. +// // We already have ca set to indicate the shift bits, now just and in sign. +// GpVar ca_2(c.newGpVar()); +// c.mov(ca_2, v.r32()); +// c.shr(ca_2, imm(31)); +// c.and_(ca, ca_2); +// } +// c.bind(skip); + +// f.StoreGPR(i.X.RA, v); +// e.update_xer_with_carry(ca); +// if (i.X.Rc) { +// f.UpdateCR(0, v); +// } +// return 0; +// } + +XEEMITTER(srawix, 0x7C000670, X )(PPCFunctionBuilder& f, InstrData& i) { + // n <- SH + // r <- ROTL32((RS)[32:63], 64-n) + // m <- MASK(n+32, 63) + // s <- (RS)[32] + // RA <- r&m | (i64.s)&¬m + // CA <- s & ((r&¬m)[32:63]≠0) + + // if n == 0: rA <- sign_extend(rS), XER[CA] = 0 + // if n >= 32: rA <- 64 sign bits of rS, XER[CA] = sign bit of lo_32(rS) + + Value* v = f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE); + Value* ca; + if (!i.X.RB) { + // No shift, just a fancy sign extend and CA clearer. + v = f.SignExtend(v, INT64_TYPE); + ca = f.LoadZero(INT8_TYPE); + } else { + // CA is set if any bits are shifted out of the right and if the result + // is negative. Start tracking that here. + ca = f.IsTrue( + f.And(v, f.LoadConstant((uint32_t)~XEMASK(32 + i.X.RB, 64)))); + + // Shift right. + v = f.Sha(v, (int8_t)i.X.RB), + + // CA is set to 1 if the low-order 32 bits of (RS) contain a negative number + // and any 1-bits are shifted out of position 63; otherwise CA is set to 0. + // We already have ca set to indicate the shift bits, now just and in sign. + ca = f.And(ca, f.IsTrue(f.Shr(v, 31))); + + // Sign extend out to 64bit. + v = f.SignExtend(v, INT64_TYPE); + } + f.StoreCA(ca); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} + + +void RegisterEmitCategoryALU() { + XEREGISTERINSTR(addx, 0x7C000214); + XEREGISTERINSTR(addcx, 0X7C000014); + XEREGISTERINSTR(addex, 0x7C000114); + XEREGISTERINSTR(addi, 0x38000000); + XEREGISTERINSTR(addic, 0x30000000); + XEREGISTERINSTR(addicx, 0x34000000); + XEREGISTERINSTR(addis, 0x3C000000); + XEREGISTERINSTR(addmex, 0x7C0001D4); + XEREGISTERINSTR(addzex, 0x7C000194); + XEREGISTERINSTR(divdx, 0x7C0003D2); + XEREGISTERINSTR(divdux, 0x7C000392); + XEREGISTERINSTR(divwx, 0x7C0003D6); + XEREGISTERINSTR(divwux, 0x7C000396); + XEREGISTERINSTR(mulhdx, 0x7C000092); + XEREGISTERINSTR(mulhdux, 0x7C000012); + XEREGISTERINSTR(mulhwx, 0x7C000096); + XEREGISTERINSTR(mulhwux, 0x7C000016); + XEREGISTERINSTR(mulldx, 0x7C0001D2); + XEREGISTERINSTR(mulli, 0x1C000000); + XEREGISTERINSTR(mullwx, 0x7C0001D6); + XEREGISTERINSTR(negx, 0x7C0000D0); + XEREGISTERINSTR(subfx, 0x7C000050); + XEREGISTERINSTR(subfcx, 0x7C000010); + XEREGISTERINSTR(subficx, 0x20000000); + XEREGISTERINSTR(subfex, 0x7C000110); + XEREGISTERINSTR(subfmex, 0x7C0001D0); + XEREGISTERINSTR(subfzex, 0x7C000190); + XEREGISTERINSTR(cmp, 0x7C000000); + XEREGISTERINSTR(cmpi, 0x2C000000); + XEREGISTERINSTR(cmpl, 0x7C000040); + XEREGISTERINSTR(cmpli, 0x28000000); + XEREGISTERINSTR(andx, 0x7C000038); + XEREGISTERINSTR(andcx, 0x7C000078); + XEREGISTERINSTR(andix, 0x70000000); + XEREGISTERINSTR(andisx, 0x74000000); + XEREGISTERINSTR(cntlzdx, 0x7C000074); + XEREGISTERINSTR(cntlzwx, 0x7C000034); + XEREGISTERINSTR(eqvx, 0x7C000238); + XEREGISTERINSTR(extsbx, 0x7C000774); + XEREGISTERINSTR(extshx, 0x7C000734); + XEREGISTERINSTR(extswx, 0x7C0007B4); + XEREGISTERINSTR(nandx, 0x7C0003B8); + XEREGISTERINSTR(norx, 0x7C0000F8); + XEREGISTERINSTR(orx, 0x7C000378); + XEREGISTERINSTR(orcx, 0x7C000338); + XEREGISTERINSTR(ori, 0x60000000); + XEREGISTERINSTR(oris, 0x64000000); + XEREGISTERINSTR(xorx, 0x7C000278); + XEREGISTERINSTR(xori, 0x68000000); + XEREGISTERINSTR(xoris, 0x6C000000); + // XEREGISTERINSTR(rld, 0x78000000); + // -- // XEREGISTERINSTR(rldclx, 0x78000010); + // -- // XEREGISTERINSTR(rldcrx, 0x78000012); + // -- // XEREGISTERINSTR(rldicx, 0x78000008); + // -- // XEREGISTERINSTR(rldiclx, 0x78000000); + // -- // XEREGISTERINSTR(rldicrx, 0x78000004); + // -- // XEREGISTERINSTR(rldimix, 0x7800000C); + XEREGISTERINSTR(rlwimix, 0x50000000); + XEREGISTERINSTR(rlwinmx, 0x54000000); + XEREGISTERINSTR(rlwnmx, 0x5C000000); + XEREGISTERINSTR(sldx, 0x7C000036); + XEREGISTERINSTR(slwx, 0x7C000030); + XEREGISTERINSTR(srdx, 0x7C000436); + XEREGISTERINSTR(srwx, 0x7C000430); + // XEREGISTERINSTR(sradx, 0x7C000634); + // XEREGISTERINSTR(sradix, 0x7C000674); + // XEREGISTERINSTR(srawx, 0x7C000630); + XEREGISTERINSTR(srawix, 0x7C000670); +} + + +} // namespace ppc +} // namespace frontend +} // namespace alloy diff --git a/src/alloy/frontend/ppc/ppc_emit_control.cc b/src/alloy/frontend/ppc/ppc_emit_control.cc new file mode 100644 index 000000000..09d8a1ca8 --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_emit_control.cc @@ -0,0 +1,577 @@ +/* + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include + + +using namespace alloy::frontend::ppc; +using namespace alloy::hir; +using namespace alloy::runtime; + + +namespace alloy { +namespace frontend { +namespace ppc { + + +int InstrEmit_branch( + PPCFunctionBuilder& f, const char* src, uint64_t cia, + Value* nia, bool lk, Value* cond = NULL, bool expect_true = true) { + uint32_t call_flags = 0; + + // TODO(benvanik): this may be wrong and overwrite LRs when not desired! + // The docs say always, though... + // Note that we do the update before we branch/call as we need it to + // be correct for returns. + if (lk) { + f.StoreLR(f.LoadConstant(cia + 4)); + } + + if (!lk) { + // If LR is not set this call will never return here. + call_flags |= CALL_TAIL; + } + + // TODO(benvanik): set CALL_TAIL if !lk and the last block in the fn. + // This is almost always a jump to restore gpr. + + // TODO(benvanik): detect call-self. + + if (nia->IsConstant()) { + // Direct branch to address. + // If it's a block inside of ourself, setup a fast jump. + uint64_t nia_value = nia->AsUint64() & 0xFFFFFFFF; + Label* label = f.LookupLabel(nia_value); + if (label) { + // Branch to label. + uint32_t branch_flags = 0; + if (cond) { + if (expect_true) { + f.BranchTrue(cond, label, branch_flags); + } else { + f.BranchFalse(cond, label, branch_flags); + } + } else { + f.Branch(label, branch_flags); + } + } else { + // Call function. + FunctionInfo* symbol_info = f.LookupFunction(nia_value); + if (cond) { + if (!expect_true) { + cond = f.IsFalse(cond); + } + f.CallTrue(cond, symbol_info, call_flags); + } else { + f.Call(symbol_info, call_flags); + } + } + } else { + // Indirect branch to pointer. + if (cond) { + if (!expect_true) { + cond = f.IsFalse(cond); + } + f.CallIndirectTrue(cond, nia, call_flags); + } else { + f.CallIndirect(nia, call_flags); + } + } + + return 0; +} + + +XEEMITTER(bx, 0x48000000, I )(PPCFunctionBuilder& f, InstrData& i) { + // if AA then + // NIA <- EXTS(LI || 0b00) + // else + // NIA <- CIA + EXTS(LI || 0b00) + // if LK then + // LR <- CIA + 4 + + uint32_t nia; + if (i.I.AA) { + nia = (uint32_t)XEEXTS26(i.I.LI << 2); + } else { + nia = (uint32_t)(i.address + XEEXTS26(i.I.LI << 2)); + } + + return InstrEmit_branch( + f, "bx", i.address, f.LoadConstant(nia), i.I.LK); +} + +XEEMITTER(bcx, 0x40000000, B )(PPCFunctionBuilder& f, InstrData& i) { + // if ¬BO[2] then + // CTR <- CTR - 1 + // ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3]) + // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) + // if ctr_ok & cond_ok then + // if AA then + // NIA <- EXTS(BD || 0b00) + // else + // NIA <- CIA + EXTS(BD || 0b00) + // if LK then + // LR <- CIA + 4 + + // NOTE: the condition bits are reversed! + // 01234 (docs) + // 43210 (real) + + Value* ctr_ok = NULL; + if (XESELECTBITS(i.B.BO, 2, 2)) { + // Ignore ctr. + } else { + // Decrement counter. + Value* ctr = f.LoadCTR(); + ctr = f.Sub(ctr, f.LoadConstant((int64_t)1)); + f.StoreCTR(ctr); + // Ctr check. + // TODO(benvanik): could do something similar to cond and avoid the + // is_true/branch_true pairing. + if (XESELECTBITS(i.B.BO, 1, 1)) { + ctr_ok = f.IsFalse(ctr); + } else { + ctr_ok = f.IsTrue(ctr); + } + } + + Value* cond_ok = NULL; + bool not_cond_ok = false; + if (XESELECTBITS(i.B.BO, 4, 4)) { + // Ignore cond. + } else { + Value* cr = f.LoadCRField(i.B.BI >> 2, i.B.BI & 3); + cond_ok = cr; + if (XESELECTBITS(i.B.BO, 3, 3)) { + // Expect true. + not_cond_ok = false; + } else { + // Expect false. + not_cond_ok = true; + } + } + + // We do a bit of optimization here to make the llvm assembly easier to read. + Value* ok = NULL; + bool expect_true = true; + if (ctr_ok && cond_ok) { + if (not_cond_ok) { + cond_ok = f.IsFalse(cond_ok); + } + ok = f.And(ctr_ok, cond_ok); + } else if (ctr_ok) { + ok = ctr_ok; + } else if (cond_ok) { + ok = cond_ok; + expect_true = !not_cond_ok; + } + + uint32_t nia; + if (i.B.AA) { + nia = (uint32_t)XEEXTS16(i.B.BD << 2); + } else { + nia = (uint32_t)(i.address + XEEXTS16(i.B.BD << 2)); + } + return InstrEmit_branch( + f, "bcx", i.address, f.LoadConstant(nia), i.B.LK, ok, expect_true); +} + +XEEMITTER(bcctrx, 0x4C000420, XL )(PPCFunctionBuilder& f, InstrData& i) { + // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) + // if cond_ok then + // NIA <- CTR[0:61] || 0b00 + // if LK then + // LR <- CIA + 4 + + // NOTE: the condition bits are reversed! + // 01234 (docs) + // 43210 (real) + + Value* cond_ok = NULL; + bool not_cond_ok = false; + if (XESELECTBITS(i.XL.BO, 4, 4)) { + // Ignore cond. + } else { + Value* cr = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + cond_ok = cr; + if (XESELECTBITS(i.XL.BO, 3, 3)) { + // Expect true. + not_cond_ok = false; + } else { + // Expect false. + not_cond_ok = true; + } + } + + bool expect_true = !not_cond_ok; + return InstrEmit_branch( + f, "bcctrx", i.address, f.LoadCTR(), i.XL.LK, cond_ok, expect_true); +} + +XEEMITTER(bclrx, 0x4C000020, XL )(PPCFunctionBuilder& f, InstrData& i) { + // if ¬BO[2] then + // CTR <- CTR - 1 + // ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3] + // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) + // if ctr_ok & cond_ok then + // NIA <- LR[0:61] || 0b00 + // if LK then + // LR <- CIA + 4 + + // NOTE: the condition bits are reversed! + // 01234 (docs) + // 43210 (real) + + Value* ctr_ok = NULL; + if (XESELECTBITS(i.XL.BO, 2, 2)) { + // Ignore ctr. + } else { + // Decrement counter. + Value* ctr = f.LoadCTR(); + ctr = f.Sub(ctr, f.LoadConstant((int64_t)1)); + f.StoreCTR(ctr); + // Ctr check. + // TODO(benvanik): could do something similar to cond and avoid the + // is_true/branch_true pairing. + if (XESELECTBITS(i.XL.BO, 1, 1)) { + ctr_ok = f.IsFalse(ctr); + } else { + ctr_ok = f.IsTrue(ctr); + } + } + + Value* cond_ok = NULL; + bool not_cond_ok = false; + if (XESELECTBITS(i.XL.BO, 4, 4)) { + // Ignore cond. + } else { + Value* cr = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + cond_ok = cr; + if (XESELECTBITS(i.XL.BO, 3, 3)) { + // Expect true. + not_cond_ok = false; + } else { + // Expect false. + not_cond_ok = true; + } + } + + // We do a bit of optimization here to make the llvm assembly easier to read. + Value* ok = NULL; + bool expect_true = true; + if (ctr_ok && cond_ok) { + if (not_cond_ok) { + cond_ok = f.IsFalse(cond_ok); + } + ok = f.And(ctr_ok, cond_ok); + } else if (ctr_ok) { + ok = ctr_ok; + } else if (cond_ok) { + ok = cond_ok; + expect_true = !not_cond_ok; + } + + // TODO(benvanik): run a DFA pass to see if we can detect whether this is + // a normal function return that is pulling the LR from the stack that + // it set in the prolog. If so, we can omit the dynamic check! + + //// Dynamic test when branching to LR, which is usually used for the return. + //// We only do this if LK=0 as returns wouldn't set LR. + //// Ideally it's a return and we can just do a simple ret and be done. + //// If it's not, we fall through to the full indirection logic. + //if (!lk && reg == kXEPPCRegLR) { + // // The return block will spill registers for us. + // // TODO(benvanik): 'lr_mismatch' debug info. + // // Note: we need to test on *only* the 32-bit target, as the target ptr may + // // have garbage in the upper 32 bits. + // c.cmp(target.r32(), c.getGpArg(1).r32()); + // // TODO(benvanik): evaluate hint here. + // c.je(e.GetReturnLabel(), kCondHintLikely); + //} + if (!i.XL.LK && !ok) { + // Return (most likely). + // TODO(benvanik): test? ReturnCheck()? + f.Return(); + return 0; + } + + return InstrEmit_branch( + f, "bclrx", i.address, f.LoadLR(), i.XL.LK, ok, expect_true); +} + + +// Condition register logical (A-23) + +XEEMITTER(crand, 0x4C000202, XL )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(crandc, 0x4C000102, XL )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(creqv, 0x4C000242, XL )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(crnand, 0x4C0001C2, XL )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(crnor, 0x4C000042, XL )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(cror, 0x4C000382, XL )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(crorc, 0x4C000342, XL )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(crxor, 0x4C000182, XL )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mcrf, 0x4C000000, XL )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// System linkage (A-24) + +XEEMITTER(sc, 0x44000002, SC )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Trap (A-25) + +int InstrEmit_trap(PPCFunctionBuilder& f, InstrData& i, + Value* va, Value* vb, uint32_t TO) { + // if (a < b) & TO[0] then TRAP + // if (a > b) & TO[1] then TRAP + // if (a = b) & TO[2] then TRAP + // if (a u b) & TO[4] then TRAP + // Bits swapped: + // 01234 + // 43210 + if (!TO) { + return 0; + } + if (TO & (1 << 4)) { + // a < b + f.TrapTrue(f.CompareSLT(va, vb)); + } + if (TO & (1 << 3)) { + // a > b + f.TrapTrue(f.CompareSGT(va, vb)); + } + if (TO & (1 << 2)) { + // a = b + f.TrapTrue(f.CompareEQ(va, vb)); + } + if (TO & (1 << 1)) { + // a u b + f.TrapTrue(f.CompareUGT(va, vb)); + } + return 0; +} + +XEEMITTER(td, 0x7C000088, X )(PPCFunctionBuilder& f, InstrData& i) { + // a <- (RA) + // b <- (RB) + // if (a < b) & TO[0] then TRAP + // if (a > b) & TO[1] then TRAP + // if (a = b) & TO[2] then TRAP + // if (a u b) & TO[4] then TRAP + Value* ra = f.LoadGPR(i.X.RA); + Value* rb = f.LoadGPR(i.X.RB); + return InstrEmit_trap(f, i, ra, rb, i.X.RT); +} + +XEEMITTER(tdi, 0x08000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // a <- (RA) + // if (a < EXTS(SI)) & TO[0] then TRAP + // if (a > EXTS(SI)) & TO[1] then TRAP + // if (a = EXTS(SI)) & TO[2] then TRAP + // if (a u EXTS(SI)) & TO[4] then TRAP + Value* ra = f.LoadGPR(i.D.RA); + Value* rb = f.LoadConstant(XEEXTS16(i.D.DS)); + return InstrEmit_trap(f, i, ra, rb, i.D.RT); +} + +XEEMITTER(tw, 0x7C000008, X )(PPCFunctionBuilder& f, InstrData& i) { + // a <- EXTS((RA)[32:63]) + // b <- EXTS((RB)[32:63]) + // if (a < b) & TO[0] then TRAP + // if (a > b) & TO[1] then TRAP + // if (a = b) & TO[2] then TRAP + // if (a u b) & TO[4] then TRAP + Value* ra = f.SignExtend(f.Truncate( + f.LoadGPR(i.X.RA), INT32_TYPE), INT64_TYPE); + Value* rb = f.SignExtend(f.Truncate( + f.LoadGPR(i.X.RB), INT32_TYPE), INT64_TYPE); + return InstrEmit_trap(f, i, ra, rb, i.X.RT); +} + +XEEMITTER(twi, 0x0C000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // a <- EXTS((RA)[32:63]) + // if (a < EXTS(SI)) & TO[0] then TRAP + // if (a > EXTS(SI)) & TO[1] then TRAP + // if (a = EXTS(SI)) & TO[2] then TRAP + // if (a u EXTS(SI)) & TO[4] then TRAP + Value* ra = f.SignExtend(f.Truncate( + f.LoadGPR(i.D.RA), INT32_TYPE), INT64_TYPE); + Value* rb = f.LoadConstant(XEEXTS16(i.D.DS)); + return InstrEmit_trap(f, i, ra, rb, i.D.RT); +} + + +// Processor control (A-26) + +XEEMITTER(mfcr, 0x7C000026, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mfspr, 0x7C0002A6, XFX)(PPCFunctionBuilder& f, InstrData& i) { + // n <- spr[5:9] || spr[0:4] + // if length(SPR(n)) = 64 then + // RT <- SPR(n) + // else + // RT <- i32.0 || SPR(n) + Value* v; + const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F); + switch (n) { + case 1: + // XER + v = f.LoadXER(); + break; + case 8: + // LR + v = f.LoadLR(); + break; + case 9: + // CTR + v = f.LoadCTR(); + break; + // 268 + 269 = TB + TBU + default: + XEINSTRNOTIMPLEMENTED(); + return 1; + } + f.StoreGPR(i.XFX.RT, v); + return 0; +} + +XEEMITTER(mftb, 0x7C0002E6, XFX)(PPCFunctionBuilder& f, InstrData& i) { + Value* time; + LARGE_INTEGER counter; + if (QueryPerformanceCounter(&counter)) { + time = f.LoadConstant(counter.QuadPart); + } else { + time = f.LoadZero(INT64_TYPE); + } + f.StoreGPR(i.XFX.RT, time); + + return 0; +} + +XEEMITTER(mtcrf, 0x7C000120, XFX)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mtspr, 0x7C0003A6, XFX)(PPCFunctionBuilder& f, InstrData& i) { + // n <- spr[5:9] || spr[0:4] + // if length(SPR(n)) = 64 then + // SPR(n) <- (RS) + // else + // SPR(n) <- (RS)[32:63] + + Value* rt = f.LoadGPR(i.XFX.RT); + + const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F); + switch (n) { + case 1: + // XER + f.StoreXER(rt); + break; + case 8: + // LR + f.StoreLR(rt); + break; + case 9: + // CTR + f.StoreCTR(rt); + break; + default: + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + return 0; +} + + +void RegisterEmitCategoryControl() { + XEREGISTERINSTR(bx, 0x48000000); + XEREGISTERINSTR(bcx, 0x40000000); + XEREGISTERINSTR(bcctrx, 0x4C000420); + XEREGISTERINSTR(bclrx, 0x4C000020); + XEREGISTERINSTR(crand, 0x4C000202); + XEREGISTERINSTR(crandc, 0x4C000102); + XEREGISTERINSTR(creqv, 0x4C000242); + XEREGISTERINSTR(crnand, 0x4C0001C2); + XEREGISTERINSTR(crnor, 0x4C000042); + XEREGISTERINSTR(cror, 0x4C000382); + XEREGISTERINSTR(crorc, 0x4C000342); + XEREGISTERINSTR(crxor, 0x4C000182); + XEREGISTERINSTR(mcrf, 0x4C000000); + XEREGISTERINSTR(sc, 0x44000002); + XEREGISTERINSTR(td, 0x7C000088); + XEREGISTERINSTR(tdi, 0x08000000); + XEREGISTERINSTR(tw, 0x7C000008); + XEREGISTERINSTR(twi, 0x0C000000); + XEREGISTERINSTR(mfcr, 0x7C000026); + XEREGISTERINSTR(mfspr, 0x7C0002A6); + XEREGISTERINSTR(mftb, 0x7C0002E6); + XEREGISTERINSTR(mtcrf, 0x7C000120); + XEREGISTERINSTR(mtspr, 0x7C0003A6); +} + + +} // namespace ppc +} // namespace frontend +} // namespace alloy diff --git a/src/alloy/frontend/ppc/ppc_emit_fpu.cc b/src/alloy/frontend/ppc/ppc_emit_fpu.cc new file mode 100644 index 000000000..4a09cd4b5 --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_emit_fpu.cc @@ -0,0 +1,543 @@ +/* + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include + + +using namespace alloy::frontend::ppc; +using namespace alloy::hir; +using namespace alloy::runtime; + + +namespace alloy { +namespace frontend { +namespace ppc { + + +// Good source of information: +// http://mamedev.org/source/src/emu/cpu/powerpc/ppc_ops.c +// The correctness of that code is not reflected here yet -_- + + +// Enable rounding numbers to single precision as required. +// This adds a bunch of work per operation and I'm not sure it's required. +#define ROUND_TO_SINGLE + + +// Floating-point arithmetic (A-8) + +XEEMITTER(faddx, 0xFC00002A, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- (frA) + (frB) + Value* v = f.Add(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(faddsx, 0xEC00002A, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- (frA) + (frB) + Value* v = f.Add(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); + v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fdivx, 0xFC000024, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- frA / frB + Value* v = f.Div(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fdivsx, 0xEC000024, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- frA / frB + Value* v = f.Div(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); + v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fmulx, 0xFC000032, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- (frA) x (frC) + Value* v = f.Mul(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC)); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fmulsx, 0xEC000032, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- (frA) x (frC) + Value* v = f.Mul(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC)); + v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fresx, 0xEC000030, A )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(frsqrtex, 0xFC000034, A )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fsubx, 0xFC000028, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- (frA) - (frB) + Value* v = f.Sub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fsubsx, 0xEC000028, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- (frA) - (frB) + Value* v = f.Sub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); + v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fselx, 0xFC00002E, A )(PPCFunctionBuilder& f, InstrData& i) { + // if (frA) >= 0.0 + // then frD <- (frC) + // else frD <- (frB) + Value* ge = f.CompareSGE(f.LoadFPR(i.A.FRA), f.LoadConstant(0.0)); + Value* v = f.Select(ge, f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB)); + f.StoreFPR(i.A.FRT, v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fsqrtx, 0xFC00002C, A )(PPCFunctionBuilder& f, InstrData& i) { + // Double precision: + // frD <- sqrt(frB) + Value* v = f.Sqrt(f.LoadFPR(i.A.FRA)); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fsqrtsx, 0xEC00002C, A )(PPCFunctionBuilder& f, InstrData& i) { + // Single precision: + // frD <- sqrt(frB) + Value* v = f.Sqrt(f.LoadFPR(i.A.FRA)); + v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + + +// Floating-point multiply-add (A-9) + +XEEMITTER(fmaddx, 0xFC00003A, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- (frA x frC) + frB + Value* v = f.MulAdd( + f.LoadFPR(i.A.FRA), + f.LoadFPR(i.A.FRC), + f.LoadFPR(i.A.FRB)); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fmaddsx, 0xEC00003A, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- (frA x frC) + frB + Value* v = f.MulAdd( + f.LoadFPR(i.A.FRA), + f.LoadFPR(i.A.FRC), + f.LoadFPR(i.A.FRB)); + v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fmsubx, 0xFC000038, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- (frA x frC) - frB + Value* v = f.MulSub( + f.LoadFPR(i.A.FRA), + f.LoadFPR(i.A.FRC), + f.LoadFPR(i.A.FRB)); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fmsubsx, 0xEC000038, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- (frA x frC) - frB + Value* v = f.MulSub( + f.LoadFPR(i.A.FRA), + f.LoadFPR(i.A.FRC), + f.LoadFPR(i.A.FRB)); + v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fnmaddx, 0xFC00003E, A )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fnmaddsx, 0xEC00003E, A )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fnmsubx, 0xFC00003C, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- -([frA x frC] - frB) + Value* v = f.Neg(f.MulSub( + f.LoadFPR(i.A.FRA), + f.LoadFPR(i.A.FRC), + f.LoadFPR(i.A.FRB))); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fnmsubsx, 0xEC00003C, A )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- -([frA x frC] - frB) + Value* v = f.Neg(f.MulSub( + f.LoadFPR(i.A.FRA), + f.LoadFPR(i.A.FRC), + f.LoadFPR(i.A.FRB))); + v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + + +// Floating-point rounding and conversion (A-10) + +XEEMITTER(fcfidx, 0xFC00069C, X )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- signed_int64_to_double( frB ) + Value* v = f.Convert( + f.Cast(f.LoadFPR(i.A.FRB), INT64_TYPE), + FLOAT64_TYPE); + f.StoreFPR(i.A.FRT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fctidx, 0xFC00065C, X )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- double_to_signed_int64( frB ) + // TODO(benvanik): pull from FPSCR[RN] + RoundMode round_mode = ROUND_TO_ZERO; + Value* v = f.Convert(f.LoadFPR(i.X.RB), INT64_TYPE, round_mode); + v = f.Cast(v, FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + // f.UpdateFPRF(v); + if (i.X.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fctidzx, 0xFC00065E, X )(PPCFunctionBuilder& f, InstrData& i) { + // TODO(benvanik): assuming round to zero is always set, is that ok? + return InstrEmit_fctidx(f, i); +} + +XEEMITTER(fctiwx, 0xFC00001C, X )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- double_to_signed_int32( frB ) + // TODO(benvanik): pull from FPSCR[RN] + RoundMode round_mode = ROUND_TO_ZERO; + Value* v = f.Convert(f.LoadFPR(i.X.RB), INT32_TYPE, round_mode); + v = f.Cast(f.ZeroExtend(v, INT64_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + // f.UpdateFPRF(v); + if (i.A.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fctiwzx, 0xFC00001E, X )(PPCFunctionBuilder& f, InstrData& i) { + // TODO(benvanik): assuming round to zero is always set, is that ok? + return InstrEmit_fctiwx(f, i); +} + +XEEMITTER(frspx, 0xFC000018, X )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- Round_single(frB) + // TODO(benvanik): pull from FPSCR[RN] + RoundMode round_mode = ROUND_TO_ZERO; + Value* v = f.Convert(f.LoadFPR(i.X.RB), FLOAT32_TYPE, round_mode); + v = f.Convert(v, FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + // f.UpdateFPRF(v); + if (i.X.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + + +// Floating-point compare (A-11) + +int InstrEmit_fcmpx_(PPCFunctionBuilder& f, InstrData& i, bool ordered) { + // if (FRA) is a NaN or (FRB) is a NaN then + // c <- 0b0001 + // else if (FRA) < (FRB) then + // c <- 0b1000 + // else if (FRA) > (FRB) then + // c <- 0b0100 + // else { + // c <- 0b0010 + // } + // FPCC <- c + // CR[4*BF:4*BF+3] <- c + // if (FRA) is an SNaN or (FRB) is an SNaN then + // VXSNAN <- 1 + + // TODO(benvanik): update FPCC for mffsx/etc + // TODO(benvanik): update VXSNAN + const uint32_t crf = i.X.RT >> 2; + // f.UpdateFPRF(v); + f.UpdateCR(crf, f.LoadFPR(i.X.RA), f.LoadFPR(i.X.RB), true); + return 0; +} +XEEMITTER(fcmpo, 0xFC000040, X )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_fcmpx_(f, i, true); +} +XEEMITTER(fcmpu, 0xFC000000, X )(PPCFunctionBuilder& f, InstrData& i) { + return InstrEmit_fcmpx_(f, i, false); +} + + +// Floating-point status and control register (A + +XEEMITTER(mcrfs, 0xFC000080, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mffsx, 0xFC00048E, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mtfsb0x, 0xFC00008C, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mtfsb1x, 0xFC00004C, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mtfsfx, 0xFC00058E, XFL)(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(mtfsfix, 0xFC00010C, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Floating-point move (A-21) + +XEEMITTER(fabsx, 0xFC000210, X )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- abs(frB) + Value* v = f.Abs(f.LoadFPR(i.X.RB)); + f.StoreFPR(i.X.RT, v); + if (i.X.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fmrx, 0xFC000090, X )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- (frB) + Value* v = f.LoadFPR(i.X.RB); + f.StoreFPR(i.X.RT, v); + if (i.X.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + +XEEMITTER(fnabsx, 0xFC000110, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(fnegx, 0xFC000050, X )(PPCFunctionBuilder& f, InstrData& i) { + // frD <- ¬ frB[0] || frB[1-63] + Value* v = f.Neg(f.LoadFPR(i.X.RB)); + f.StoreFPR(i.X.RT, v); + if (i.X.Rc) { + //e.update_cr_with_cond(1, v); + XEINSTRNOTIMPLEMENTED(); + return 1; + } + return 0; +} + + +void RegisterEmitCategoryFPU() { + XEREGISTERINSTR(faddx, 0xFC00002A); + XEREGISTERINSTR(faddsx, 0xEC00002A); + XEREGISTERINSTR(fdivx, 0xFC000024); + XEREGISTERINSTR(fdivsx, 0xEC000024); + XEREGISTERINSTR(fmulx, 0xFC000032); + XEREGISTERINSTR(fmulsx, 0xEC000032); + XEREGISTERINSTR(fresx, 0xEC000030); + XEREGISTERINSTR(frsqrtex, 0xFC000034); + XEREGISTERINSTR(fsubx, 0xFC000028); + XEREGISTERINSTR(fsubsx, 0xEC000028); + XEREGISTERINSTR(fselx, 0xFC00002E); + XEREGISTERINSTR(fsqrtx, 0xFC00002C); + XEREGISTERINSTR(fsqrtsx, 0xEC00002C); + XEREGISTERINSTR(fmaddx, 0xFC00003A); + XEREGISTERINSTR(fmaddsx, 0xEC00003A); + XEREGISTERINSTR(fmsubx, 0xFC000038); + XEREGISTERINSTR(fmsubsx, 0xEC000038); + XEREGISTERINSTR(fnmaddx, 0xFC00003E); + XEREGISTERINSTR(fnmaddsx, 0xEC00003E); + XEREGISTERINSTR(fnmsubx, 0xFC00003C); + XEREGISTERINSTR(fnmsubsx, 0xEC00003C); + XEREGISTERINSTR(fcfidx, 0xFC00069C); + XEREGISTERINSTR(fctidx, 0xFC00065C); + XEREGISTERINSTR(fctidzx, 0xFC00065E); + XEREGISTERINSTR(fctiwx, 0xFC00001C); + XEREGISTERINSTR(fctiwzx, 0xFC00001E); + XEREGISTERINSTR(frspx, 0xFC000018); + XEREGISTERINSTR(fcmpo, 0xFC000040); + XEREGISTERINSTR(fcmpu, 0xFC000000); + XEREGISTERINSTR(mcrfs, 0xFC000080); + XEREGISTERINSTR(mffsx, 0xFC00048E); + XEREGISTERINSTR(mtfsb0x, 0xFC00008C); + XEREGISTERINSTR(mtfsb1x, 0xFC00004C); + XEREGISTERINSTR(mtfsfx, 0xFC00058E); + XEREGISTERINSTR(mtfsfix, 0xFC00010C); + XEREGISTERINSTR(fabsx, 0xFC000210); + XEREGISTERINSTR(fmrx, 0xFC000090); + XEREGISTERINSTR(fnabsx, 0xFC000110); + XEREGISTERINSTR(fnegx, 0xFC000050); +} + + +} // namespace ppc +} // namespace frontend +} // namespace alloy diff --git a/src/alloy/frontend/ppc/ppc_emit_memory.cc b/src/alloy/frontend/ppc/ppc_emit_memory.cc new file mode 100644 index 000000000..cae80c772 --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_emit_memory.cc @@ -0,0 +1,1349 @@ +/* + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include + + +using namespace alloy::frontend::ppc; +using namespace alloy::hir; +using namespace alloy::runtime; + + +namespace alloy { +namespace frontend { +namespace ppc { + + +// Integer load (A-13) + +XEEMITTER(lbz, 0x88000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // RT <- i56.0 || MEM(EA, 1) + Value* ea; + if (i.D.RA) { + ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + } else { + ea = f.LoadConstant(XEEXTS16(i.D.DS)); + } + Value* rt = f.ZeroExtend(f.Load(ea, INT8_TYPE), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + return 0; +} + +XEEMITTER(lbzu, 0x8C000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(D) + // RT <- i56.0 || MEM(EA, 1) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + Value* rt = f.ZeroExtend(f.Load(ea, INT8_TYPE), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + f.StoreGPR(i.D.RA, ea); + return 0; +} + +XEEMITTER(lbzux, 0x7C0000EE, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // RT <- i56.0 || MEM(EA, 1) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + Value* rt = f.ZeroExtend(f.Load(ea, INT8_TYPE), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(lbzx, 0x7C0000AE, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i56.0 || MEM(EA, 1) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.ZeroExtend(f.Load(ea, INT8_TYPE), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} + +XEEMITTER(lha, 0xA8000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // RT <- EXTS(MEM(EA, 2)) + Value* ea; + if (i.D.RA) { + ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + } else { + ea = f.LoadConstant(XEEXTS16(i.D.DS)); + } + Value* rt = f.SignExtend(f.ByteSwap(f.Load(ea, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + return 0; +} + +XEEMITTER(lhau, 0xAC000000, D )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(lhaux, 0x7C0002EE, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(lhax, 0x7C0002AE, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- EXTS(MEM(EA, 2)) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.SignExtend(f.ByteSwap(f.Load(ea, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} + +XEEMITTER(lhz, 0xA0000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // RT <- i48.0 || MEM(EA, 2) + Value* ea; + if (i.D.RA) { + ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + } else { + ea = f.LoadConstant(XEEXTS16(i.D.DS)); + } + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + return 0; +} + +XEEMITTER(lhzu, 0xA4000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(D) + // RT <- i48.0 || MEM(EA, 2) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + f.StoreGPR(i.D.RA, ea); + return 0; +} + +XEEMITTER(lhzux, 0x7C00026E, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // RT <- i48.0 || MEM(EA, 2) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(lhzx, 0x7C00022E, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i48.0 || MEM(EA, 2) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} + +XEEMITTER(lwa, 0xE8000002, DS )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D || 00) + // RT <- EXTS(MEM(EA, 4)) + Value* ea; + if (i.DS.RA) { + ea = f.Add( + f.LoadGPR(i.DS.RA), + f.LoadConstant(XEEXTS16(i.DS.DS << 2))); + } else { + ea = f.LoadConstant(XEEXTS16(i.DS.DS << 2)); + } + Value* rt = f.SignExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.DS.RT, rt); + return 0; +} + +XEEMITTER(lwaux, 0x7C0002EA, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // RT <- EXTS(MEM(EA, 4)) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + Value* rt = f.SignExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(lwax, 0x7C0002AA, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- EXTS(MEM(EA, 4)) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.SignExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} + +XEEMITTER(lwz, 0x80000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // RT <- i32.0 || MEM(EA, 4) + Value* ea; + if (i.D.RA) { + ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + } else { + ea = f.LoadConstant(XEEXTS16(i.D.DS)); + } + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + return 0; +} + +XEEMITTER(lwzu, 0x84000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(D) + // RT <- i32.0 || MEM(EA, 4) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + f.StoreGPR(i.D.RA, ea); + return 0; +} + +XEEMITTER(lwzux, 0x7C00006E, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // RT <- i32.0 || MEM(EA, 4) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(lwzx, 0x7C00002E, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i32.0 || MEM(EA, 4) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} + + +XEEMITTER(ld, 0xE8000000, DS )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(DS || 0b00) + // RT <- MEM(EA, 8) + Value* ea; + if (i.DS.RA) { + ea = f.Add( + f.LoadGPR(i.DS.RA), + f.LoadConstant(XEEXTS16(i.DS.DS << 2))); + } else { + ea = f.LoadConstant(XEEXTS16(i.DS.DS << 2)); + } + Value* rt = f.ByteSwap(f.Load(ea, INT64_TYPE)); + f.StoreGPR(i.DS.RT, rt); + return 0; +} + +XEEMITTER(ldu, 0xE8000001, DS )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(DS || 0b00) + // RT <- MEM(EA, 8) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.DS.RA), + f.LoadConstant(XEEXTS16(i.DS.DS << 2))); + Value* rt = f.ByteSwap(f.Load(ea, INT64_TYPE)); + f.StoreGPR(i.DS.RT, rt); + f.StoreGPR(i.DS.RA, ea); + return 0; +} + +XEEMITTER(ldux, 0x7C00006A, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // RT <- MEM(EA, 8) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + Value* rt = f.ByteSwap(f.Load(ea, INT64_TYPE)); + f.StoreGPR(i.X.RT, rt); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(ldx, 0x7C00002A, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- MEM(EA, 8) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.ByteSwap(f.Load(ea, INT64_TYPE)); + f.StoreGPR(i.X.RT, rt); + return 0; +} + + +// Integer store (A-14) + +XEEMITTER(stb, 0x98000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // MEM(EA, 1) <- (RS)[56:63] + Value* ea; + if (i.D.RA) { + ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + } else { + ea = f.LoadConstant(XEEXTS16(i.D.DS)); + } + f.Store(ea, f.Truncate(f.LoadGPR(i.D.RT), INT8_TYPE)); + return 0; +} + +XEEMITTER(stbu, 0x9C000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(D) + // MEM(EA, 1) <- (RS)[56:63] + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + f.Store(ea, f.Truncate(f.LoadGPR(i.D.RT), INT8_TYPE)); + f.StoreGPR(i.D.RA, ea); + return 0; +} + +XEEMITTER(stbux, 0x7C0001EE, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 1) <- (RS)[56:63] + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + f.Store(ea, f.Truncate(f.LoadGPR(i.X.RT), INT8_TYPE)); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(stbx, 0x7C0001AE, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 1) <- (RS)[56:63] + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + f.Store(ea, f.Truncate(f.LoadGPR(i.X.RT), INT8_TYPE)); + return 0; +} + +XEEMITTER(sth, 0xB0000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // MEM(EA, 2) <- (RS)[48:63] + Value* ea; + if (i.D.RA) { + ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + } else { + ea = f.LoadConstant(XEEXTS16(i.D.DS)); + } + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.D.RT), INT16_TYPE))); + return 0; +} + +XEEMITTER(sthu, 0xB4000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(D) + // MEM(EA, 2) <- (RS)[48:63] + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.D.RT), INT16_TYPE))); + f.StoreGPR(i.D.RA, ea); + return 0; +} + +XEEMITTER(sthux, 0x7C00036E, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 2) <- (RS)[48:63] + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT16_TYPE))); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(sthx, 0x7C00032E, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 2) <- (RS)[48:63] + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT16_TYPE))); + return 0; +} + +XEEMITTER(stw, 0x90000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // MEM(EA, 4) <- (RS)[32:63] + Value* ea; + if (i.D.RA) { + ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + } else { + ea = f.LoadConstant(XEEXTS16(i.D.DS)); + } + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.D.RT), INT32_TYPE))); + return 0; +} + +XEEMITTER(stwu, 0x94000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(D) + // MEM(EA, 4) <- (RS)[32:63] + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.D.RT), INT32_TYPE))); + f.StoreGPR(i.D.RA, ea); + return 0; +} + +XEEMITTER(stwux, 0x7C00016E, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 4) <- (RS)[32:63] + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE))); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(stwx, 0x7C00012E, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 4) <- (RS)[32:63] + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE))); + return 0; +} + +XEEMITTER(std, 0xF8000000, DS )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(DS || 0b00) + // MEM(EA, 8) <- (RS) + Value* ea; + if (i.DS.RA) { + ea = f.Add( + f.LoadGPR(i.DS.RA), + f.LoadConstant(XEEXTS16(i.DS.DS << 2))); + } else { + ea = f.LoadConstant(XEEXTS16(i.DS.DS << 2)); + } + f.Store(ea, f.ByteSwap(f.LoadGPR(i.DS.RT))); + return 0; +} + +XEEMITTER(stdu, 0xF8000001, DS )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(DS || 0b00) + // MEM(EA, 8) <- (RS) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.DS.RA), + f.LoadConstant(XEEXTS16(i.DS.DS << 2))); + f.Store(ea, f.ByteSwap(f.LoadGPR(i.DS.RT))); + f.StoreGPR(i.DS.RA, ea); + return 0; +} + +XEEMITTER(stdux, 0x7C00016A, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 8) <- (RS) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + f.Store(ea, f.ByteSwap(f.LoadGPR(i.X.RT))); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(stdx, 0x7C00012A, X)(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 8) <- (RS) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + f.Store(ea, f.ByteSwap(f.LoadGPR(i.X.RT))); + return 0; +} + + +// Integer load and store with byte reverse (A-1 + +XEEMITTER(lhbrx, 0x7C00062C, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i48.0 || bswap(MEM(EA, 2)) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.ZeroExtend(f.Load(ea, INT16_TYPE), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} + +XEEMITTER(lwbrx, 0x7C00042C, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i32.0 || bswap(MEM(EA, 4)) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.ZeroExtend(f.Load(ea, INT32_TYPE), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} + +XEEMITTER(ldbrx, 0x7C000428, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- bswap(MEM(EA, 8)) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.Load(ea, INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} + +XEEMITTER(sthbrx, 0x7C00072C, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 2) <- bswap((RS)[48:63]) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + f.Store(ea, f.Truncate(f.LoadGPR(i.X.RT), INT16_TYPE)); + return 0; +} + +XEEMITTER(stwbrx, 0x7C00052C, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 4) <- bswap((RS)[32:63]) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + f.Store(ea, f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE)); + return 0; +} + +XEEMITTER(stdbrx, 0x7C000528, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 8) <- bswap(RS) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + f.Store(ea, f.LoadGPR(i.X.RT)); + return 0; +} + + +// Integer load and store multiple (A-16) + +XEEMITTER(lmw, 0xB8000000, D )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(stmw, 0xBC000000, D )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Integer load and store string (A-17) + +XEEMITTER(lswi, 0x7C0004AA, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(lswx, 0x7C00042A, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(stswi, 0x7C0005AA, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + +XEEMITTER(stswx, 0x7C00052A, X )(PPCFunctionBuilder& f, InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} + + +// Memory synchronization (A-18) + +XEEMITTER(eieio, 0x7C0006AC, X )(PPCFunctionBuilder& f, InstrData& i) { + // XEINSTRNOTIMPLEMENTED(); + f.Nop(); + return 0; +} + +XEEMITTER(sync, 0x7C0004AC, X )(PPCFunctionBuilder& f, InstrData& i) { + // XEINSTRNOTIMPLEMENTED(); + f.Nop(); + return 0; +} + +XEEMITTER(isync, 0x4C00012C, XL )(PPCFunctionBuilder& f, InstrData& i) { + // XEINSTRNOTIMPLEMENTED(); + f.Nop(); + return 0; +} + +XEEMITTER(ldarx, 0x7C0000A8, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RESERVE <- 1 + // RESERVE_LENGTH <- 8 + // RESERVE_ADDR <- real_addr(EA) + // RT <- MEM(EA, 8) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.ByteSwap(f.LoadAcquire(ea, INT64_TYPE)); + f.StoreGPR(i.X.RT, rt); + return 0; +} + +XEEMITTER(lwarx, 0x7C000028, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RESERVE <- 1 + // RESERVE_LENGTH <- 4 + // RESERVE_ADDR <- real_addr(EA) + // RT <- i32.0 || MEM(EA, 4) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.ZeroExtend(f.ByteSwap(f.LoadAcquire(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} + +XEEMITTER(stdcx, 0x7C0001AD, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RESERVE stuff... + // MEM(EA, 8) <- (RS) + // n <- 1 if store performed + // CR0[LT GT EQ SO] = 0b00 || n || XER[SO] + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.ByteSwap(f.LoadGPR(i.X.RT)); + Value* stored = f.StoreRelease(ea, rt); + f.StoreContext(offsetof(PPCContext, cr0.cr0_eq), stored); + return 0; +} + +XEEMITTER(stwcx, 0x7C00012D, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RESERVE stuff... + // MEM(EA, 4) <- (RS)[32:63] + // n <- 1 if store performed + // CR0[LT GT EQ SO] = 0b00 || n || XER[SO] + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE)); + Value* stored = f.StoreRelease(ea, rt); + f.StoreContext(offsetof(PPCContext, cr0.cr0_eq), stored); + return 0; +} + + +// Floating-point load (A-19) + +XEEMITTER(lfd, 0xC8000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // FRT <- MEM(EA, 8) + Value* ea; + if (i.D.RA) { + ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + } else { + ea = f.LoadConstant(XEEXTS16(i.D.DS)); + } + Value* rt = f.Cast(f.ByteSwap(f.Load(ea, INT64_TYPE)), FLOAT64_TYPE); + f.StoreFPR(i.D.RT, rt); + return 0; +} + +XEEMITTER(lfdu, 0xCC000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(D) + // FRT <- MEM(EA, 8) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + Value* rt = f.Cast(f.ByteSwap(f.Load(ea, INT64_TYPE)), FLOAT64_TYPE); + f.StoreFPR(i.D.RT, rt); + f.StoreGPR(i.D.RA, ea); + return 0; +} + +XEEMITTER(lfdux, 0x7C0004EE, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // FRT <- MEM(EA, 8) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + Value* rt = f.Cast(f.ByteSwap(f.Load(ea, INT64_TYPE)), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, rt); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(lfdx, 0x7C0004AE, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // FRT <- MEM(EA, 8) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.Cast(f.ByteSwap(f.Load(ea, INT64_TYPE)), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, rt); + return 0; +} + +XEEMITTER(lfs, 0xC0000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // FRT <- DOUBLE(MEM(EA, 4)) + Value* ea; + if (i.D.RA) { + ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + } else { + ea = f.LoadConstant(XEEXTS16(i.D.DS)); + } + Value* rt = f.Convert( + f.Cast(f.ByteSwap(f.Load(ea, INT32_TYPE)), FLOAT32_TYPE), + FLOAT64_TYPE); + f.StoreFPR(i.D.RT, rt); + return 0; +} + +XEEMITTER(lfsu, 0xC4000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(D) + // FRT <- DOUBLE(MEM(EA, 4)) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + Value* rt = f.Convert( + f.Cast(f.ByteSwap(f.Load(ea, INT32_TYPE)), FLOAT32_TYPE), + FLOAT64_TYPE); + f.StoreFPR(i.D.RT, rt); + f.StoreGPR(i.D.RA, ea); + return 0; +} + +XEEMITTER(lfsux, 0x7C00046E, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // FRT <- DOUBLE(MEM(EA, 4)) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + Value* rt = f.Convert( + f.Cast(f.ByteSwap(f.Load(ea, INT32_TYPE)), FLOAT32_TYPE), + FLOAT64_TYPE); + f.StoreFPR(i.X.RT, rt); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(lfsx, 0x7C00042E, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // FRT <- DOUBLE(MEM(EA, 4)) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + Value* rt = f.Convert( + f.Cast(f.ByteSwap(f.Load(ea, INT32_TYPE)), FLOAT32_TYPE), + FLOAT64_TYPE); + f.StoreFPR(i.X.RT, rt); + return 0; +} + + +// Floating-point store (A-20) + +XEEMITTER(stfd, 0xD8000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // MEM(EA, 8) <- (FRS) + Value* ea; + if (i.D.RA) { + ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + } else { + ea = f.LoadConstant(XEEXTS16(i.D.DS)); + } + f.Store(ea, f.ByteSwap(f.Cast(f.LoadFPR(i.D.RT), INT64_TYPE))); + return 0; +} + +XEEMITTER(stfdu, 0xDC000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(D) + // MEM(EA, 8) <- (FRS) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + f.Store(ea, f.ByteSwap(f.Cast(f.LoadFPR(i.D.RT), INT64_TYPE))); + f.StoreGPR(i.D.RA, ea); + return 0; +} + +XEEMITTER(stfdux, 0x7C0005EE, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 8) <- (FRS) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + f.Store(ea, f.ByteSwap(f.Cast(f.LoadFPR(i.X.RT), INT64_TYPE))); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(stfdx, 0x7C0005AE, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 8) <- (FRS) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + f.Store(ea, f.ByteSwap(f.Cast(f.LoadFPR(i.X.RT), INT64_TYPE))); + return 0; +} + +XEEMITTER(stfiwx, 0x7C0007AE, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 4) <- (FRS)[32:63] + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + f.Store(ea, f.ByteSwap(f.Cast(f.LoadFPR(i.X.RT), INT32_TYPE))); + return 0; +} + +XEEMITTER(stfs, 0xD0000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // MEM(EA, 4) <- SINGLE(FRS) + Value* ea; + if (i.D.RA) { + ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + } else { + ea = f.LoadConstant(XEEXTS16(i.D.DS)); + } + f.Store(ea, f.ByteSwap(f.Cast( + f.Convert(f.LoadFPR(i.D.RT), FLOAT32_TYPE), INT32_TYPE))); + return 0; +} + +XEEMITTER(stfsu, 0xD4000000, D )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + EXTS(D) + // MEM(EA, 4) <- SINGLE(FRS) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.D.RA), + f.LoadConstant(XEEXTS16(i.D.DS))); + f.Store(ea, f.ByteSwap(f.Cast( + f.Convert(f.LoadFPR(i.D.RT), FLOAT32_TYPE), INT32_TYPE))); + f.StoreGPR(i.D.RA, ea); + return 0; +} + +XEEMITTER(stfsux, 0x7C00056E, X )(PPCFunctionBuilder& f, InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 4) <- SINGLE(FRS) + // RA <- EA + Value* ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + f.Store(ea, f.ByteSwap(f.Cast( + f.Convert(f.LoadFPR(i.X.RT), FLOAT32_TYPE), INT32_TYPE))); + f.StoreGPR(i.X.RA, ea); + return 0; +} + +XEEMITTER(stfsx, 0x7C00052E, X )(PPCFunctionBuilder& f, InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 4) <- SINGLE(FRS) + Value* ea; + if (i.X.RA) { + ea = f.Add( + f.LoadGPR(i.X.RA), + f.LoadGPR(i.X.RB)); + } else { + ea = f.LoadGPR(i.X.RB); + } + f.Store(ea, f.ByteSwap(f.Cast( + f.Convert(f.LoadFPR(i.X.RT), FLOAT32_TYPE), INT32_TYPE))); + return 0; +} + + +// Cache management (A-27) + +XEEMITTER(dcbf, 0x7C0000AC, X )(PPCFunctionBuilder& f, InstrData& i) { + // No-op for now. + // TODO(benvanik): use prefetch + // XEINSTRNOTIMPLEMENTED(); + f.Nop(); + return 0; +} + +XEEMITTER(dcbst, 0x7C00006C, X )(PPCFunctionBuilder& f, InstrData& i) { + // No-op for now. + // TODO(benvanik): use prefetch + // XEINSTRNOTIMPLEMENTED(); + f.Nop(); + return 0; +} + +XEEMITTER(dcbt, 0x7C00022C, X )(PPCFunctionBuilder& f, InstrData& i) { + // No-op for now. + // TODO(benvanik): use prefetch + // XEINSTRNOTIMPLEMENTED(); + f.Nop(); + return 0; +} + +XEEMITTER(dcbtst, 0x7C0001EC, X )(PPCFunctionBuilder& f, InstrData& i) { + // No-op for now. + // TODO(benvanik): use prefetch + // XEINSTRNOTIMPLEMENTED(); + f.Nop(); + return 0; +} + +XEEMITTER(dcbz, 0x7C0007EC, X )(PPCFunctionBuilder& f, InstrData& i) { + // No-op for now. + // TODO(benvanik): use prefetch + // or dcbz128 0x7C2007EC + // XEINSTRNOTIMPLEMENTED(); + f.Nop(); + return 0; +} + +XEEMITTER(icbi, 0x7C0007AC, X )(PPCFunctionBuilder& f, InstrData& i) { + // XEINSTRNOTIMPLEMENTED(); + f.Nop(); + return 0; +} + + +void RegisterEmitCategoryMemory() { + XEREGISTERINSTR(lbz, 0x88000000); + XEREGISTERINSTR(lbzu, 0x8C000000); + XEREGISTERINSTR(lbzux, 0x7C0000EE); + XEREGISTERINSTR(lbzx, 0x7C0000AE); + XEREGISTERINSTR(lha, 0xA8000000); + XEREGISTERINSTR(lhau, 0xAC000000); + XEREGISTERINSTR(lhaux, 0x7C0002EE); + XEREGISTERINSTR(lhax, 0x7C0002AE); + XEREGISTERINSTR(lhz, 0xA0000000); + XEREGISTERINSTR(lhzu, 0xA4000000); + XEREGISTERINSTR(lhzux, 0x7C00026E); + XEREGISTERINSTR(lhzx, 0x7C00022E); + XEREGISTERINSTR(lwa, 0xE8000002); + XEREGISTERINSTR(lwaux, 0x7C0002EA); + XEREGISTERINSTR(lwax, 0x7C0002AA); + XEREGISTERINSTR(lwz, 0x80000000); + XEREGISTERINSTR(lwzu, 0x84000000); + XEREGISTERINSTR(lwzux, 0x7C00006E); + XEREGISTERINSTR(lwzx, 0x7C00002E); + XEREGISTERINSTR(ld, 0xE8000000); + XEREGISTERINSTR(ldu, 0xE8000001); + XEREGISTERINSTR(ldux, 0x7C00006A); + XEREGISTERINSTR(ldx, 0x7C00002A); + XEREGISTERINSTR(stb, 0x98000000); + XEREGISTERINSTR(stbu, 0x9C000000); + XEREGISTERINSTR(stbux, 0x7C0001EE); + XEREGISTERINSTR(stbx, 0x7C0001AE); + XEREGISTERINSTR(sth, 0xB0000000); + XEREGISTERINSTR(sthu, 0xB4000000); + XEREGISTERINSTR(sthux, 0x7C00036E); + XEREGISTERINSTR(sthx, 0x7C00032E); + XEREGISTERINSTR(stw, 0x90000000); + XEREGISTERINSTR(stwu, 0x94000000); + XEREGISTERINSTR(stwux, 0x7C00016E); + XEREGISTERINSTR(stwx, 0x7C00012E); + XEREGISTERINSTR(std, 0xF8000000); + XEREGISTERINSTR(stdu, 0xF8000001); + XEREGISTERINSTR(stdux, 0x7C00016A); + XEREGISTERINSTR(stdx, 0x7C00012A); + XEREGISTERINSTR(lhbrx, 0x7C00062C); + XEREGISTERINSTR(lwbrx, 0x7C00042C); + XEREGISTERINSTR(ldbrx, 0x7C000428); + XEREGISTERINSTR(sthbrx, 0x7C00072C); + XEREGISTERINSTR(stwbrx, 0x7C00052C); + XEREGISTERINSTR(stdbrx, 0x7C000528); + XEREGISTERINSTR(lmw, 0xB8000000); + XEREGISTERINSTR(stmw, 0xBC000000); + XEREGISTERINSTR(lswi, 0x7C0004AA); + XEREGISTERINSTR(lswx, 0x7C00042A); + XEREGISTERINSTR(stswi, 0x7C0005AA); + XEREGISTERINSTR(stswx, 0x7C00052A); + XEREGISTERINSTR(eieio, 0x7C0006AC); + XEREGISTERINSTR(sync, 0x7C0004AC); + XEREGISTERINSTR(isync, 0x4C00012C); + XEREGISTERINSTR(ldarx, 0x7C0000A8); + XEREGISTERINSTR(lwarx, 0x7C000028); + XEREGISTERINSTR(stdcx, 0x7C0001AD); + XEREGISTERINSTR(stwcx, 0x7C00012D); + XEREGISTERINSTR(lfd, 0xC8000000); + XEREGISTERINSTR(lfdu, 0xCC000000); + XEREGISTERINSTR(lfdux, 0x7C0004EE); + XEREGISTERINSTR(lfdx, 0x7C0004AE); + XEREGISTERINSTR(lfs, 0xC0000000); + XEREGISTERINSTR(lfsu, 0xC4000000); + XEREGISTERINSTR(lfsux, 0x7C00046E); + XEREGISTERINSTR(lfsx, 0x7C00042E); + XEREGISTERINSTR(stfd, 0xD8000000); + XEREGISTERINSTR(stfdu, 0xDC000000); + XEREGISTERINSTR(stfdux, 0x7C0005EE); + XEREGISTERINSTR(stfdx, 0x7C0005AE); + XEREGISTERINSTR(stfiwx, 0x7C0007AE); + XEREGISTERINSTR(stfs, 0xD0000000); + XEREGISTERINSTR(stfsu, 0xD4000000); + XEREGISTERINSTR(stfsux, 0x7C00056E); + XEREGISTERINSTR(stfsx, 0x7C00052E); + XEREGISTERINSTR(dcbf, 0x7C0000AC); + XEREGISTERINSTR(dcbst, 0x7C00006C); + XEREGISTERINSTR(dcbt, 0x7C00022C); + XEREGISTERINSTR(dcbtst, 0x7C0001EC); + XEREGISTERINSTR(dcbz, 0x7C0007EC); + XEREGISTERINSTR(icbi, 0x7C0007AC); +} + + +} // namespace ppc +} // namespace frontend +} // namespace alloy diff --git a/src/alloy/frontend/ppc/ppc_frontend.cc b/src/alloy/frontend/ppc/ppc_frontend.cc new file mode 100644 index 000000000..2e587865f --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_frontend.cc @@ -0,0 +1,96 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include +#include + +using namespace alloy; +using namespace alloy::frontend; +using namespace alloy::frontend::ppc; +using namespace alloy::runtime; + + +namespace { + void InitializeIfNeeded(); + void CleanupOnShutdown(); + + void InitializeIfNeeded() { + static bool has_initialized = false; + if (has_initialized) { + return; + } + has_initialized = true; + + RegisterDisasmCategoryAltivec(); + RegisterDisasmCategoryALU(); + RegisterDisasmCategoryControl(); + RegisterDisasmCategoryFPU(); + RegisterDisasmCategoryMemory(); + + RegisterEmitCategoryAltivec(); + RegisterEmitCategoryALU(); + RegisterEmitCategoryControl(); + RegisterEmitCategoryFPU(); + RegisterEmitCategoryMemory(); + + atexit(CleanupOnShutdown); + } + + void CleanupOnShutdown() { + } +} + + +PPCFrontend::PPCFrontend(Runtime* runtime) : + Frontend(runtime) { + InitializeIfNeeded(); +} + +PPCFrontend::~PPCFrontend() { + // Force cleanup now before we deinit. + translator_pool_.Reset(); + + alloy::tracing::WriteEvent(EventType::Deinit({ + })); +} + +int PPCFrontend::Initialize() { + int result = Frontend::Initialize(); + if (result) { + return result; + } + + alloy::tracing::WriteEvent(EventType::Init({ + })); + + return result; +} + +int PPCFrontend::DeclareFunction( + FunctionInfo* symbol_info) { + // Could scan or something here. + // Could also check to see if it's a well-known function type and classify + // for later. + // Could also kick off a precompiler, since we know it's likely the function + // will be demanded soon. + return 0; +} + +int PPCFrontend::DefineFunction( + FunctionInfo* symbol_info, + Function** out_function) { + PPCTranslator* translator = translator_pool_.Allocate(this); + int result = translator->Translate(symbol_info, out_function); + translator_pool_.Release(translator); + return result; +} diff --git a/src/alloy/frontend/ppc/ppc_frontend.h b/src/alloy/frontend/ppc/ppc_frontend.h new file mode 100644 index 000000000..ca0f60903 --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_frontend.h @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_FRONTEND_PPC_PPC_FRONTEND_H_ +#define ALLOY_FRONTEND_PPC_PPC_FRONTEND_H_ + +#include +#include + +#include + + +namespace alloy { +namespace frontend { +namespace ppc { + +class PPCTranslator; + +class PPCFrontend : public Frontend { +public: + PPCFrontend(runtime::Runtime* runtime); + virtual ~PPCFrontend(); + + virtual int Initialize(); + + virtual int DeclareFunction( + runtime::FunctionInfo* symbol_info); + virtual int DefineFunction( + runtime::FunctionInfo* symbol_info, + runtime::Function** out_function); + +private: + TypePool translator_pool_; +}; + + +} // namespace ppc +} // namespace frontend +} // namespace alloy + + +#endif // ALLOY_FRONTEND_PPC_PPC_FRONTEND_H_ diff --git a/src/alloy/frontend/ppc/ppc_function_builder.cc b/src/alloy/frontend/ppc/ppc_function_builder.cc new file mode 100644 index 000000000..f92c3a806 --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_function_builder.cc @@ -0,0 +1,306 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include +#include +#include +#include + +using namespace alloy; +using namespace alloy::frontend; +using namespace alloy::frontend::ppc; +using namespace alloy::hir; +using namespace alloy::runtime; + + +PPCFunctionBuilder::PPCFunctionBuilder(PPCFrontend* frontend) : + frontend_(frontend), + FunctionBuilder() { +} + +PPCFunctionBuilder::~PPCFunctionBuilder() { +} + +void PPCFunctionBuilder::Reset() { + start_address_ = 0; + instr_offset_list_ = NULL; + label_list_ = NULL; + FunctionBuilder::Reset(); +} + +const bool FLAGS_annotate_disassembly = true; + +int PPCFunctionBuilder::Emit(FunctionInfo* symbol_info) { + Memory* memory = frontend_->memory(); + const uint8_t* p = memory->membase(); + + symbol_info_ = symbol_info; + start_address_ = symbol_info->address(); + instr_count_ = + (symbol_info->end_address() - symbol_info->address()) / 4 + 1; + + // TODO(benvanik): get/make up symbol name. + Comment("%s fn %.8X-%.8X %s", + symbol_info->module()->name(), + symbol_info->address(), symbol_info->end_address(), + "(symbol name)"); + + // Allocate offset list. + // This is used to quickly map labels to instructions. + // The list is built as the instructions are traversed, with the values + // being the previous HIR Instr before the given instruction. An + // instruction may have a label assigned to it if it hasn't been hit + // yet. + size_t list_size = instr_count_ * sizeof(void*); + instr_offset_list_ = (Instr**)arena_->Alloc(list_size); + label_list_ = (Label**)arena_->Alloc(list_size); + xe_zero_struct(instr_offset_list_, list_size); + xe_zero_struct(label_list_, list_size); + + // Always mark entry with label. + label_list_[0] = NewLabel(); + + uint64_t start_address = symbol_info->address(); + uint64_t end_address = symbol_info->end_address(); + InstrData i; + for (uint64_t address = start_address, offset = 0; address <= end_address; + address += 4, offset++) { + i.address = address; + i.code = XEGETUINT32BE(p + address); + // TODO(benvanik): find a way to avoid using the opcode tables. + i.type = GetInstrType(i.code); + + // Stash instruction offset. + instr_offset_list_[offset] = last_instr(); + + // Mark label, if we were assigned one earlier on in the walk. + // We may still get a label, but it'll be inserted by LookupLabel + // as needed. + Label* label = label_list_[offset]; + if (label) { + MarkLabel(label); + } + + if (FLAGS_annotate_disassembly) { + if (label) { + AnnotateLabel(address, label); + } + if (!i.type) { + Comment("%.8X: %.8X ???", address, i.code); + } else if (i.type->disassemble) { + ppc::InstrDisasm d; + i.type->disassemble(i, d); + std::string disasm; + d.Dump(disasm); + Comment("%.8X: %.8X %s", address, i.code, disasm.c_str()); + } else { + Comment("%.8X: %.8X %s ???", address, i.code, i.type->name); + } + } + + if (!i.type) { + XELOGCPU("Invalid instruction %.8X %.8X", i.address, i.code); + Comment("INVALID!"); + //TraceInvalidInstruction(i); + continue; + } + + typedef int (*InstrEmitter)(PPCFunctionBuilder& f, InstrData& i); + InstrEmitter emit = (InstrEmitter)i.type->emit; + + /*if (i.address == FLAGS_break_on_instruction) { + Comment("--break-on-instruction target"); + DebugBreak(); + }*/ + + if (!i.type->emit || emit(*this, i)) { + XELOGCPU("Unimplemented instr %.8X %.8X %s", + i.address, i.code, i.type->name); + Comment("UNIMPLEMENTED!"); + DebugBreak(); + //TraceInvalidInstruction(i); + + // This printf is handy for sort/uniquify to find instructions. + printf("unimplinstr %s\n", i.type->name); + } + } + + return 0; +} + +void PPCFunctionBuilder::AnnotateLabel(uint64_t address, Label* label) { + char name_buffer[13]; + xesnprintfa(name_buffer, XECOUNT(name_buffer), "loc_%.8X", address); + label->name = (char*)arena_->Alloc(sizeof(name_buffer)); + xe_copy_struct(label->name, name_buffer, sizeof(name_buffer)); +} + +FunctionInfo* PPCFunctionBuilder::LookupFunction(uint64_t address) { + Runtime* runtime = frontend_->runtime(); + FunctionInfo* symbol_info; + if (runtime->LookupFunctionInfo(address, &symbol_info)) { + return NULL; + } + return symbol_info; +} + +Label* PPCFunctionBuilder::LookupLabel(uint64_t address) { + if (address < start_address_) { + return NULL; + } + size_t offset = (address - start_address_) / 4; + if (offset >= instr_count_) { + return NULL; + } + Label* label = label_list_[offset]; + if (label) { + return label; + } + // No label. If we haven't yet hit the instruction in the walk + // then create a label. Otherwise, we must go back and insert + // the label. + label = NewLabel(); + label_list_[offset] = label; + Instr* prev_instr = instr_offset_list_[offset]; + if (prev_instr) { + // Insert label, breaking up existing instructions. + InsertLabel(label, prev_instr); + + // Annotate the label, as we won't do it later. + if (FLAGS_annotate_disassembly) { + AnnotateLabel(address, label); + } + } + return label; +} + +//Value* PPCFunctionBuilder::LoadXER() { +//} +// +//void PPCFunctionBuilder::StoreXER(Value* value) { +//} + +Value* PPCFunctionBuilder::LoadLR() { + return LoadContext(offsetof(PPCContext, lr), INT64_TYPE); +} + +void PPCFunctionBuilder::StoreLR(Value* value) { + XEASSERT(value->type == INT64_TYPE); + StoreContext(offsetof(PPCContext, lr), value); +} + +Value* PPCFunctionBuilder::LoadCTR() { + return LoadContext(offsetof(PPCContext, ctr), INT64_TYPE); +} + +void PPCFunctionBuilder::StoreCTR(Value* value) { + XEASSERT(value->type == INT64_TYPE); + StoreContext(offsetof(PPCContext, ctr), value); +} + +Value* PPCFunctionBuilder::LoadCR(uint32_t n) { + XEASSERTALWAYS(); + return 0; +} + +Value* PPCFunctionBuilder::LoadCRField(uint32_t n, uint32_t bit) { + return LoadContext(offsetof(PPCContext, cr0) + (4 * n) + bit, INT8_TYPE); +} + +void PPCFunctionBuilder::StoreCR(uint32_t n, Value* value) { + // TODO(benvanik): split bits out and store in values. + XEASSERTALWAYS(); +} + +void PPCFunctionBuilder::UpdateCR( + uint32_t n, Value* lhs, bool is_signed) { + UpdateCR(n, lhs, LoadZero(lhs->type), is_signed); +} + +void PPCFunctionBuilder::UpdateCR( + uint32_t n, Value* lhs, Value* rhs, bool is_signed) { + Value* lt; + Value* gt; + if (is_signed) { + lt = CompareSLT(lhs, rhs); + gt = CompareSGT(lhs, rhs); + } else { + lt = CompareULT(lhs, rhs); + gt = CompareUGT(lhs, rhs); + } + Value* eq = CompareEQ(lhs, rhs); + StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 0, lt); + StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 1, gt); + StoreContext(offsetof(PPCContext, cr0) + (4 * n) + 2, eq); + + // Value* so = AllocValue(UINT8_TYPE); + // StoreContext(offsetof(PPCContext, cr) + (4 * n) + 3, so); +} + +void PPCFunctionBuilder::UpdateCR6(Value* src_value) { + // Testing for all 1's and all 0's. + // if (Rc) CR6 = all_equal | 0 | none_equal | 0 + // TODO(benvanik): efficient instruction? + StoreContext(offsetof(PPCContext, cr6.cr6_all_equal), IsFalse(Not(src_value))); + StoreContext(offsetof(PPCContext, cr6.cr6_none_equal), IsFalse(src_value)); +} + +Value* PPCFunctionBuilder::LoadXER() { + XEASSERTALWAYS(); + return NULL; +} + +void PPCFunctionBuilder::StoreXER(Value* value) { + XEASSERTALWAYS(); +} + +Value* PPCFunctionBuilder::LoadCA() { + return LoadContext(offsetof(PPCContext, xer_ca), INT8_TYPE); +} + +void PPCFunctionBuilder::StoreCA(Value* value) { + StoreContext(offsetof(PPCContext, xer_ca), value); +} + +Value* PPCFunctionBuilder::LoadGPR(uint32_t reg) { + return LoadContext( + offsetof(PPCContext, r) + reg * 8, INT64_TYPE); +} + +void PPCFunctionBuilder::StoreGPR(uint32_t reg, Value* value) { + XEASSERT(value->type == INT64_TYPE); + StoreContext( + offsetof(PPCContext, r) + reg * 8, value); +} + +Value* PPCFunctionBuilder::LoadFPR(uint32_t reg) { + return LoadContext( + offsetof(PPCContext, f) + reg * 8, FLOAT64_TYPE); +} + +void PPCFunctionBuilder::StoreFPR(uint32_t reg, Value* value) { + XEASSERT(value->type == FLOAT64_TYPE); + StoreContext( + offsetof(PPCContext, f) + reg * 8, value); +} + +Value* PPCFunctionBuilder::LoadVR(uint32_t reg) { + return LoadContext( + offsetof(PPCContext, v) + reg * 16, VEC128_TYPE); +} + +void PPCFunctionBuilder::StoreVR(uint32_t reg, Value* value) { + XEASSERT(value->type == VEC128_TYPE); + StoreContext( + offsetof(PPCContext, v) + reg * 16, value); +} diff --git a/src/alloy/frontend/ppc/ppc_function_builder.h b/src/alloy/frontend/ppc/ppc_function_builder.h new file mode 100644 index 000000000..026fdc079 --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_function_builder.h @@ -0,0 +1,86 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_FRONTEND_PPC_PPC_FUNCTION_BUILDER_H_ +#define ALLOY_FRONTEND_PPC_PPC_FUNCTION_BUILDER_H_ + +#include +#include +#include +#include + + +namespace alloy { +namespace frontend { +namespace ppc { + +class PPCFrontend; + + +class PPCFunctionBuilder : public hir::FunctionBuilder { + using Instr = alloy::hir::Instr; + using Label = alloy::hir::Label; + using Value = alloy::hir::Value; +public: + PPCFunctionBuilder(PPCFrontend* frontend); + virtual ~PPCFunctionBuilder(); + + virtual void Reset(); + + int Emit(runtime::FunctionInfo* symbol_info); + + runtime::FunctionInfo* LookupFunction(uint64_t address); + Label* LookupLabel(uint64_t address); + + Value* LoadLR(); + void StoreLR(Value* value); + Value* LoadCTR(); + void StoreCTR(Value* value); + Value* LoadCR(uint32_t n); + Value* LoadCRField(uint32_t n, uint32_t bit); + void StoreCR(uint32_t n, Value* value); + void UpdateCR(uint32_t n, Value* lhs, bool is_signed = true); + void UpdateCR(uint32_t n, Value* lhs, Value* rhs, bool is_signed = true); + void UpdateCR6(Value* src_value); + Value* LoadXER(); + void StoreXER(Value* value); + //void UpdateXERWithOverflow(); + //void UpdateXERWithOverflowAndCarry(); + //void StoreOV(Value* value); + Value* LoadCA(); + void StoreCA(Value* value); + + Value* LoadGPR(uint32_t reg); + void StoreGPR(uint32_t reg, Value* value); + Value* LoadFPR(uint32_t reg); + void StoreFPR(uint32_t reg, Value* value); + Value* LoadVR(uint32_t reg); + void StoreVR(uint32_t reg, Value* value); + +private: + void AnnotateLabel(uint64_t address, Label* label); + +private: + PPCFrontend* frontend_; + + // Reset each Emit: + runtime::FunctionInfo* symbol_info_; + uint64_t start_address_; + uint64_t instr_count_; + Instr** instr_offset_list_; + Label** label_list_; +}; + + +} // namespace ppc +} // namespace frontend +} // namespace alloy + + +#endif // ALLOY_FRONTEND_PPC_PPC_FUNCTION_BUILDER_H_ diff --git a/src/xenia/cpu/ppc/instr.cc b/src/alloy/frontend/ppc/ppc_instr.cc similarity index 90% rename from src/xenia/cpu/ppc/instr.cc rename to src/alloy/frontend/ppc/ppc_instr.cc index b53c4bfe9..1e8a5cbff 100644 --- a/src/xenia/cpu/ppc/instr.cc +++ b/src/alloy/frontend/ppc/ppc_instr.cc @@ -7,14 +7,16 @@ ****************************************************************************** */ -#include +#include #include -#include +#include -using namespace xe::cpu::ppc; +using namespace alloy; +using namespace alloy::frontend; +using namespace alloy::frontend::ppc; void InstrOperand::Dump(std::string& out_str) { @@ -419,46 +421,45 @@ void InstrDisasm::Dump(std::string& out_str, size_t pad) { } -InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) { +InstrType* alloy::frontend::ppc::GetInstrType(uint32_t code) { // Fast lookup via tables. InstrType* slot = NULL; switch (code >> 26) { case 4: // Opcode = 4, index = bits 10-0 (10) - slot = xe::cpu::ppc::tables::instr_table_4[XESELECTBITS(code, 0, 10)]; + slot = alloy::frontend::ppc::tables::instr_table_4[XESELECTBITS(code, 0, 10)]; break; case 19: // Opcode = 19, index = bits 10-1 (10) - slot = xe::cpu::ppc::tables::instr_table_19[XESELECTBITS(code, 1, 10)]; + slot = alloy::frontend::ppc::tables::instr_table_19[XESELECTBITS(code, 1, 10)]; break; case 30: // Opcode = 30, index = bits 4-1 (4) // Special cased to an uber instruction. - slot = xe::cpu::ppc::tables::instr_table_30[XESELECTBITS(code, 0, 0)]; - // slot = &xe::cpu::ppc::tables::instr_table_30[XESELECTBITS(code, 1, 4)]; + slot = alloy::frontend::ppc::tables::instr_table_30[XESELECTBITS(code, 0, 0)]; break; case 31: // Opcode = 31, index = bits 10-1 (10) - slot = xe::cpu::ppc::tables::instr_table_31[XESELECTBITS(code, 1, 10)]; + slot = alloy::frontend::ppc::tables::instr_table_31[XESELECTBITS(code, 1, 10)]; break; case 58: // Opcode = 58, index = bits 1-0 (2) - slot = xe::cpu::ppc::tables::instr_table_58[XESELECTBITS(code, 0, 1)]; + slot = alloy::frontend::ppc::tables::instr_table_58[XESELECTBITS(code, 0, 1)]; break; case 59: // Opcode = 59, index = bits 5-1 (5) - slot = xe::cpu::ppc::tables::instr_table_59[XESELECTBITS(code, 1, 5)]; + slot = alloy::frontend::ppc::tables::instr_table_59[XESELECTBITS(code, 1, 5)]; break; case 62: // Opcode = 62, index = bits 1-0 (2) - slot = xe::cpu::ppc::tables::instr_table_62[XESELECTBITS(code, 0, 1)]; + slot = alloy::frontend::ppc::tables::instr_table_62[XESELECTBITS(code, 0, 1)]; break; case 63: // Opcode = 63, index = bits 10-1 (10) - slot = xe::cpu::ppc::tables::instr_table_63[XESELECTBITS(code, 1, 10)]; + slot = alloy::frontend::ppc::tables::instr_table_63[XESELECTBITS(code, 1, 10)]; break; default: - slot = xe::cpu::ppc::tables::instr_table[XESELECTBITS(code, 26, 31)]; + slot = alloy::frontend::ppc::tables::instr_table[XESELECTBITS(code, 26, 31)]; break; } if (slot && slot->opcode) { @@ -467,9 +468,10 @@ InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) { // Slow lookup via linear scan. // This is primarily due to laziness. It could be made fast like the others. - for (size_t n = 0; n < XECOUNT(xe::cpu::ppc::tables::instr_table_scan); + for (size_t n = 0; + n < XECOUNT(alloy::frontend::ppc::tables::instr_table_scan); n++) { - slot = &(xe::cpu::ppc::tables::instr_table_scan[n]); + slot = &(alloy::frontend::ppc::tables::instr_table_scan[n]); if (slot->opcode == (code & slot->opcode_mask)) { return slot; } @@ -478,7 +480,7 @@ InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) { return NULL; } -int xe::cpu::ppc::RegisterInstrDisassemble( +int alloy::frontend::ppc::RegisterInstrDisassemble( uint32_t code, InstrDisassembleFn disassemble) { InstrType* instr_type = GetInstrType(code); XEASSERTNOTNULL(instr_type); @@ -490,7 +492,7 @@ int xe::cpu::ppc::RegisterInstrDisassemble( return 0; } -int xe::cpu::ppc::RegisterInstrEmit(uint32_t code, InstrEmitFn emit) { +int alloy::frontend::ppc::RegisterInstrEmit(uint32_t code, InstrEmitFn emit) { InstrType* instr_type = GetInstrType(code); XEASSERTNOTNULL(instr_type); if (!instr_type) { diff --git a/src/xenia/cpu/ppc/instr.h b/src/alloy/frontend/ppc/ppc_instr.h similarity index 96% rename from src/xenia/cpu/ppc/instr.h rename to src/alloy/frontend/ppc/ppc_instr.h index 4c3083796..f4e22f1de 100644 --- a/src/xenia/cpu/ppc/instr.h +++ b/src/alloy/frontend/ppc/ppc_instr.h @@ -7,17 +7,17 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_PPC_INSTR_H_ -#define XENIA_CPU_PPC_INSTR_H_ +#ifndef ALLOY_FRONTEND_PPC_PPC_INSTR_H_ +#define ALLOY_FRONTEND_PPC_PPC_INSTR_H_ -#include +#include #include #include -namespace xe { -namespace cpu { +namespace alloy { +namespace frontend { namespace ppc { @@ -81,14 +81,14 @@ typedef enum { class InstrType; -static inline int32_t XEEXTS16(uint32_t v) { - return (int32_t)((int16_t)v); +static inline int64_t XEEXTS16(uint32_t v) { + return (int64_t)((int16_t)v); } -static inline int32_t XEEXTS26(uint32_t v) { - return v & 0x02000000 ? (int32_t)v | 0xFC000000 : (int32_t)(v); +static inline int64_t XEEXTS26(uint32_t v) { + return (int64_t)(v & 0x02000000 ? (int32_t)v | 0xFC000000 : (int32_t)(v)); } -static inline uint32_t XEEXTZ16(uint32_t v) { - return (uint32_t)((uint16_t)v); +static inline uint64_t XEEXTZ16(uint32_t v) { + return (uint64_t)((uint16_t)v); } static inline uint64_t XEMASK(uint32_t mstart, uint32_t mstop) { // if mstart ≤ mstop then @@ -108,7 +108,7 @@ static inline uint64_t XEMASK(uint32_t mstart, uint32_t mstop) { typedef struct { InstrType* type; - uint32_t address; + uint64_t address; union { uint32_t code; @@ -523,9 +523,9 @@ int RegisterInstrEmit(uint32_t code, InstrEmitFn emit); } // namespace ppc -} // namespace cpu -} // namespace xe +} // namespace frontend +} // namespace alloy -#endif // XENIA_CPU_PPC_INSTR_H_ +#endif // ALLOY_FRONTEND_PPC_PPC_INSTR_H_ diff --git a/src/xenia/cpu/ppc/instr_tables.h b/src/alloy/frontend/ppc/ppc_instr_tables.h similarity index 99% rename from src/xenia/cpu/ppc/instr_tables.h rename to src/alloy/frontend/ppc/ppc_instr_tables.h index 0d43a0166..6c9998133 100644 --- a/src/xenia/cpu/ppc/instr_tables.h +++ b/src/alloy/frontend/ppc/ppc_instr_tables.h @@ -7,14 +7,14 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_PPC_INSTR_TABLE_H_ -#define XENIA_CPU_PPC_INSTR_TABLE_H_ +#ifndef ALLOY_FRONTEND_PPC_PPC_INSTR_TABLES_H_ +#define ALLOY_FRONTEND_PPC_PPC_INSTR_TABLES_H_ -#include +#include -namespace xe { -namespace cpu { +namespace alloy { +namespace frontend { namespace ppc { namespace tables { @@ -636,8 +636,8 @@ static InstrType instr_table_scan[] = { } // namespace tables } // namespace ppc -} // namespace cpu -} // namespace xe +} // namespace frontend +} // namespace alloy -#endif // XENIA_CPU_PPC_INSTR_TABLE_H_ +#endif // ALLOY_FRONTEND_PPC_PPC_INSTR_TABLES_H_ diff --git a/src/alloy/frontend/ppc/ppc_scanner.cc b/src/alloy/frontend/ppc/ppc_scanner.cc new file mode 100644 index 000000000..0d2af4c3a --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_scanner.cc @@ -0,0 +1,278 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include + +using namespace alloy; +using namespace alloy::frontend; +using namespace alloy::frontend::ppc; +using namespace alloy::runtime; + + +PPCScanner::PPCScanner(PPCFrontend* frontend) : + frontend_(frontend) { +} + +PPCScanner::~PPCScanner() { +} + +bool PPCScanner::IsRestGprLr(uint64_t address) { + // TODO(benvanik): detect type. + /*FunctionSymbol* fn = GetFunction(addr); + return fn && (fn->flags & FunctionSymbol::kFlagRestGprLr);*/ + return false; +} + +int PPCScanner::FindExtents(FunctionInfo* symbol_info) { + // This is a simple basic block analyizer. It walks the start address to the + // end address looking for branches. Each span of instructions between + // branches is considered a basic block. When the last blr (that has no + // branches to after it) is found the function is considered ended. If this + // is before the expected end address then the function address range is + // split up and the second half is treated as another function. + + Memory* memory = frontend_->memory(); + const uint8_t* p = memory->membase(); + + XELOGSDB("Analyzing function %.8X...", symbol_info->address()); + + uint64_t start_address = symbol_info->address(); + uint64_t end_address = symbol_info->end_address(); + uint64_t address = start_address; + uint64_t furthest_target = start_address; + size_t blocks_found = 0; + bool in_block = false; + bool starts_with_mfspr_lr = false; + InstrData i; + while (true) { + i.address = address; + i.code = XEGETUINT32BE(p + address); + + // If we fetched 0 assume that we somehow hit one of the awesome + // 'no really we meant to end after that bl' functions. + if (!i.code) { + XELOGSDB("function end %.8X (0x00000000 read)", address); + // Don't include the 0's. + address -= 4; + break; + } + + // TODO(benvanik): find a way to avoid using the opcode tables. + // This lookup is *expensive* and should be avoided when scanning. + i.type = GetInstrType(i.code); + + // Check if the function starts with a mfspr lr, as that's a good indication + // of whether or not this is a normal function with a prolog/epilog. + // Some valid leaf functions won't have this, but most will. + if (address == start_address && + i.type && + i.type->opcode == 0x7C0002A6 && + (((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F)) == 8) { + starts_with_mfspr_lr = true; + } + + if (!in_block) { + in_block = true; + blocks_found++; + } + + bool ends_fn = false; + bool ends_block = false; + if (!i.type) { + // Invalid instruction. + // We can just ignore it because there's (very little)/no chance it'll + // affect flow control. + XELOGSDB("Invalid instruction at %.8X: %.8X", address, i.code); + } else if (i.code == 0x4E800020) { + // blr -- unconditional branch to LR. + // This is generally a return. + if (furthest_target > address) { + // Remaining targets within function, not end. + XELOGSDB("ignoring blr %.8X (branch to %.8X)", + address, furthest_target); + } else { + // Function end point. + XELOGSDB("function end %.8X", address); + ends_fn = true; + } + ends_block = true; + } else if (i.code == 0x4E800420) { + // bctr -- unconditional branch to CTR. + // This is generally a jump to a function pointer (non-return). + if (furthest_target > address) { + // Remaining targets within function, not end. + XELOGSDB("ignoring bctr %.8X (branch to %.8X)", address, + furthest_target); + } else { + // Function end point. + XELOGSDB("function end %.8X", address); + ends_fn = true; + } + ends_block = true; + } else if (i.type->opcode == 0x48000000) { + // b/ba/bl/bla + uint32_t target = + (uint32_t)XEEXTS26(i.I.LI << 2) + (i.I.AA ? 0 : (int32_t)address); + + if (i.I.LK) { + XELOGSDB("bl %.8X -> %.8X", address, target); + // Queue call target if needed. + // GetOrInsertFunction(target); + } else { + XELOGSDB("b %.8X -> %.8X", address, target); + + // If the target is back into the function and there's no further target + // we are at the end of a function. + // (Indirect branches may still go beyond, but no way of knowing). + if (target >= start_address && + target < address && furthest_target <= address) { + XELOGSDB("function end %.8X (back b)", addr); + ends_fn = true; + } + + // If the target is not a branch and it goes to before the current + // address it's definitely a tail call. + if (!ends_fn && + target < start_address && furthest_target <= address) { + XELOGSDB("function end %.8X (back b before addr)", addr); + ends_fn = true; + } + + // If the target is a __restgprlr_* method it's the end of a function. + // Note that sometimes functions stick this in a basic block *inside* + // of the function somewhere, so ensure we don't have any branches over + // it. + if (!ends_fn && + furthest_target <= address && + IsRestGprLr(target)) { + XELOGSDB("function end %.8X (__restgprlr_*)", addr); + ends_fn = true; + } + + // Heuristic: if there's an unconditional branch in the first block of + // the function it's likely a thunk. + // Ex: + // li r3, 0 + // b KeBugCheck + // This check may hit on functions that jump over data code, so only + // trigger this check in leaf functions (no mfspr lr/prolog). + if (!ends_fn && + !starts_with_mfspr_lr && + blocks_found == 1) { + XELOGSDB("HEURISTIC: ending at simple leaf thunk %.8X", address); + ends_fn = true; + } + + // Heuristic: if this is an unconditional branch at the end of the + // function (nothing jumps over us) and we are jumping forward there's + // a good chance it's a tail call. + // This may not be true if the code is jumping over data/etc. + // TODO(benvanik): figure out how to do this reliably. This check as is + // is too aggressive and turns a lot of valid branches into tail calls. + // It seems like a lot of functions end up with some prologue bit then + // jump deep inside only to jump back towards the top soon after. May + // need something more complex than just a simple 1-pass system to + // detect these, unless more signals can be found. + /* + if (!ends_fn && + target > addr && + furthest_target < addr) { + XELOGSDB("HEURISTIC: ending at tail call branch %.8X", addr); + ends_fn = true; + } + */ + + if (!ends_fn) { + furthest_target = MAX(furthest_target, target); + + // TODO(benvanik): perhaps queue up for a speculative check? I think + // we are running over tail-call functions here that branch to + // somewhere else. + //GetOrInsertFunction(target); + } + } + ends_block = true; + } else if (i.type->opcode == 0x40000000) { + // bc/bca/bcl/bcla + uint32_t target = + (uint32_t)XEEXTS16(i.B.BD << 2) + (i.B.AA ? 0 : (int32_t)address); + if (i.B.LK) { + XELOGSDB("bcl %.8X -> %.8X", address, target); + + // Queue call target if needed. + // TODO(benvanik): see if this is correct - not sure anyone makes + // function calls with bcl. + //GetOrInsertFunction(target); + } else { + XELOGSDB("bc %.8X -> %.8X", address, target); + + // TODO(benvanik): GetOrInsertFunction? it's likely a BB + + furthest_target = MAX(furthest_target, target); + } + ends_block = true; + } else if (i.type->opcode == 0x4C000020) { + // bclr/bclrl + if (i.XL.LK) { + XELOGSDB("bclrl %.8X", addr); + } else { + XELOGSDB("bclr %.8X", addr); + } + ends_block = true; + } else if (i.type->opcode == 0x4C000420) { + // bcctr/bcctrl + if (i.XL.LK) { + XELOGSDB("bcctrl %.8X", addr); + } else { + XELOGSDB("bcctr %.8X", addr); + } + ends_block = true; + } + + if (ends_block) { + in_block = false; + } + if (ends_fn) { + break; + } + + address += 4; + if (end_address && address > end_address) { + // Hmm.... + XELOGSDB("Ran over function bounds! %.8X-%.8X", + start_address, end_address); + break; + } + } + + if (end_address && address + 4 < end_address) { + // Ran under the expected value - since we probably got the initial bounds + // from someplace valid (like method hints) this may indicate an error. + // It's also possible that we guessed in hole-filling and there's another + // function below this one. + XELOGSDB("Function ran under: %.8X-%.8X ended at %.8X", + start_address, end_address, address + 4); + } + symbol_info->set_end_address(address); + + // If there's spare bits at the end, split the function. + // TODO(benvanik): splitting? + + // TODO(benvanik): find and record stack information + // - look for __savegprlr_* and __restgprlr_* + // - if present, flag function as needing a stack + // - record prolog/epilog lengths/stack size/etc + + XELOGSDB("Finished analyzing %.8X", start_address); + return 0; +} diff --git a/src/alloy/frontend/ppc/ppc_scanner.h b/src/alloy/frontend/ppc/ppc_scanner.h new file mode 100644 index 000000000..d90373f57 --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_scanner.h @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_FRONTEND_PPC_PPC_SCANNER_H_ +#define ALLOY_FRONTEND_PPC_PPC_SCANNER_H_ + +#include +#include + + +namespace alloy { +namespace frontend { +namespace ppc { + +class PPCFrontend; + + +class PPCScanner { +public: + PPCScanner(PPCFrontend* frontend); + ~PPCScanner(); + + int FindExtents(runtime::FunctionInfo* symbol_info); + +private: + bool IsRestGprLr(uint64_t address); + +private: + PPCFrontend* frontend_; +}; + + +} // namespace ppc +} // namespace frontend +} // namespace alloy + + +#endif // ALLOY_FRONTEND_PPC_PPC_SCANNER_H_ diff --git a/src/alloy/frontend/ppc/ppc_translator.cc b/src/alloy/frontend/ppc/ppc_translator.cc new file mode 100644 index 000000000..a847863ad --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_translator.cc @@ -0,0 +1,101 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include +#include +#include +#include + +using namespace alloy; +using namespace alloy::backend; +using namespace alloy::compiler; +using namespace alloy::frontend; +using namespace alloy::frontend::ppc; +using namespace alloy::hir; +using namespace alloy::runtime; + + +PPCTranslator::PPCTranslator(PPCFrontend* frontend) : + frontend_(frontend) { + scanner_ = new PPCScanner(frontend); + builder_ = new PPCFunctionBuilder(frontend); + + compiler_ = new Compiler(); + + // TODO(benvanik): passes in a sensible order/etc. + compiler_->AddPass(new passes::Mem2RegPass()); + + Backend* backend = frontend->runtime()->backend(); + assembler_ = backend->CreateAssembler(); +} + +PPCTranslator::~PPCTranslator() { + delete assembler_; + delete compiler_; + delete builder_; + delete scanner_; +} + +int PPCTranslator::Translate( + FunctionInfo* symbol_info, + Function** out_function) { + char* pre_ir = NULL; + char* post_ir = NULL; + + // Scan the function to find its extents. We only need to do this if we + // haven't already been provided with them from some other source. + if (!symbol_info->has_end_address()) { + // TODO(benvanik): find a way to remove the need for the scan. A fixup + // scheme acting on branches could go back and modify calls to branches + // if they are within the extents. + int result = scanner_->FindExtents(symbol_info); + if (result) { + return result; + } + } + + // Emit function. + int result = builder_->Emit(symbol_info); + XEEXPECTZERO(result); + + if (true) { + builder_->Dump(&string_buffer_); + pre_ir = string_buffer_.ToString(); + string_buffer_.Reset(); + } + + // Compile/optimize/etc. + result = compiler_->Compile(builder_); + XEEXPECTZERO(result); + + if (true) { + builder_->Dump(&string_buffer_); + post_ir = string_buffer_.ToString(); + string_buffer_.Reset(); + } + + // Assemble to backend machine code. + result = assembler_->Assemble(symbol_info, builder_, out_function); + XEEXPECTZERO(result); + + result = 0; + +XECLEANUP: + if (pre_ir) xe_free(pre_ir); + if (post_ir) xe_free(post_ir); + builder_->Reset(); + compiler_->Reset(); + assembler_->Reset(); + string_buffer_.Reset(); + return result; +}; diff --git a/src/alloy/frontend/ppc/ppc_translator.h b/src/alloy/frontend/ppc/ppc_translator.h new file mode 100644 index 000000000..548b3fdeb --- /dev/null +++ b/src/alloy/frontend/ppc/ppc_translator.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_FRONTEND_PPC_PPC_TRANSLATOR_H_ +#define ALLOY_FRONTEND_PPC_PPC_TRANSLATOR_H_ + +#include +#include +#include +#include + + +namespace alloy { +namespace frontend { +namespace ppc { + +class PPCFrontend; +class PPCFunctionBuilder; +class PPCScanner; + + +class PPCTranslator { +public: + PPCTranslator(PPCFrontend* frontend); + ~PPCTranslator(); + + int Translate(runtime::FunctionInfo* symbol_info, + runtime::Function** out_function); + +private: + PPCFrontend* frontend_; + PPCScanner* scanner_; + PPCFunctionBuilder* builder_; + compiler::Compiler* compiler_; + backend::Assembler* assembler_; + + StringBuffer string_buffer_; +}; + + +} // namespace ppc +} // namespace frontend +} // namespace alloy + + +#endif // ALLOY_FRONTEND_PPC_PPC_TRANSLATOR_H_ diff --git a/src/alloy/frontend/ppc/sources.gypi b/src/alloy/frontend/ppc/sources.gypi new file mode 100644 index 000000000..ff97163b6 --- /dev/null +++ b/src/alloy/frontend/ppc/sources.gypi @@ -0,0 +1,32 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'ppc_context.cc', + 'ppc_context.h', + 'ppc_disasm-private.h', + 'ppc_disasm.h', + 'ppc_disasm_altivec.cc', + 'ppc_disasm_alu.cc', + 'ppc_disasm_control.cc', + 'ppc_disasm_fpu.cc', + 'ppc_disasm_memory.cc', + 'ppc_emit-private.h', + 'ppc_emit.h', + 'ppc_emit_altivec.cc', + 'ppc_emit_alu.cc', + 'ppc_emit_control.cc', + 'ppc_emit_fpu.cc', + 'ppc_emit_memory.cc', + 'ppc_frontend.cc', + 'ppc_frontend.h', + 'ppc_function_builder.cc', + 'ppc_function_builder.h', + 'ppc_instr.cc', + 'ppc_instr.h', + 'ppc_instr_tables.h', + 'ppc_scanner.cc', + 'ppc_scanner.h', + 'ppc_translator.cc', + 'ppc_translator.h', + ], +} diff --git a/src/alloy/frontend/sources.gypi b/src/alloy/frontend/sources.gypi new file mode 100644 index 000000000..bfd855ad1 --- /dev/null +++ b/src/alloy/frontend/sources.gypi @@ -0,0 +1,12 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'frontend.cc', + 'frontend.h', + 'tracing.h', + ], + + 'includes': [ + 'ppc/sources.gypi', + ], +} diff --git a/src/alloy/frontend/tracing.h b/src/alloy/frontend/tracing.h new file mode 100644 index 000000000..61aadb949 --- /dev/null +++ b/src/alloy/frontend/tracing.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef ALLOY_FRONTEND_TRACING_H_ +#define ALLOY_FRONTEND_TRACING_H_ + +#include +#include + + +namespace alloy { +namespace frontend { + +const uint32_t ALLOY_FRONTEND = alloy::tracing::EventType::ALLOY_FRONTEND; + + +class EventType { +public: + enum { + ALLOY_FRONTEND_INIT = ALLOY_FRONTEND | (1), + ALLOY_FRONTEND_DEINIT = ALLOY_FRONTEND | (2), + }; + + typedef struct { + static const uint32_t event_type = ALLOY_FRONTEND_INIT; + } Init; + typedef struct { + static const uint32_t event_type = ALLOY_FRONTEND_DEINIT; + } Deinit; +}; + + +} // namespace frontend +} // namespace alloy + + +#endif // ALLOY_FRONTEND_TRACING_H_ diff --git a/src/alloy/hir/block.cc b/src/alloy/hir/block.cc new file mode 100644 index 000000000..635ab14c9 --- /dev/null +++ b/src/alloy/hir/block.cc @@ -0,0 +1,13 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +using namespace alloy; +using namespace alloy::hir; diff --git a/src/xenia/cpu/x64/x64_backend.h b/src/alloy/hir/block.h similarity index 53% rename from src/xenia/cpu/x64/x64_backend.h rename to src/alloy/hir/block.h index 8ac539d14..3ff100f03 100644 --- a/src/xenia/cpu/x64/x64_backend.h +++ b/src/alloy/hir/block.h @@ -7,33 +7,34 @@ ****************************************************************************** */ -#ifndef XENIA_CPU_X64_X64_BACKEND_H_ -#define XENIA_CPU_X64_X64_BACKEND_H_ +#ifndef ALLOY_HIR_BLOCK_H_ +#define ALLOY_HIR_BLOCK_H_ -#include - -#include +#include -namespace xe { -namespace cpu { -namespace x64 { +namespace alloy { +namespace hir { + +class Instr; +class Label; -class X64Backend : public Backend { +class Block { public: - X64Backend(); - virtual ~X64Backend(); + Block* next; + Block* prev; - virtual JIT* CreateJIT(xe_memory_ref memory, sdb::SymbolTable* sym_table); + Label* label_head; + Label* label_tail; -protected: + Instr* instr_head; + Instr* instr_tail; }; -} // namespace x64 -} // namespace cpu -} // namespace xe +} // namespace hir +} // namespace alloy -#endif // XENIA_CPU_X64_X64_BACKEND_H_ +#endif // ALLOY_HIR_BLOCK_H_ diff --git a/src/alloy/hir/function_builder.cc b/src/alloy/hir/function_builder.cc new file mode 100644 index 000000000..da442b485 --- /dev/null +++ b/src/alloy/hir/function_builder.cc @@ -0,0 +1,2110 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include + +using namespace alloy; +using namespace alloy::hir; +using namespace alloy::runtime; + + +#define ASSERT_ADDRESS_TYPE(value) +#define ASSERT_INTEGER_TYPE(value) +#define ASSERT_FLOAT_TYPE(value) +#define ASSERT_NON_VECTOR_TYPE(value) +#define ASSERT_VECTOR_TYPE(value) +#define ASSERT_TYPES_EQUAL(value1, value2) + + +FunctionBuilder::FunctionBuilder() { + arena_ = new Arena(); + Reset(); +} + +FunctionBuilder::~FunctionBuilder() { + Reset(); + delete arena_; +} + +void FunctionBuilder::Reset() { + attributes_ = 0; + next_label_id_ = 0; + next_value_ordinal_ = 0; + block_head_ = block_tail_ = NULL; + current_block_ = NULL; +} + +void FunctionBuilder::DumpValue(StringBuffer* str, Value* value) { + if (value->IsConstant()) { + switch (value->type) { + case INT8_TYPE: str->Append("%X", value->constant.i8); break; + case INT16_TYPE: str->Append("%X", value->constant.i16); break; + case INT32_TYPE: str->Append("%X", value->constant.i32); break; + case INT64_TYPE: str->Append("%X", value->constant.i64); break; + case FLOAT32_TYPE: str->Append("%F", value->constant.f32); break; + case FLOAT64_TYPE: str->Append("%F", value->constant.f64); break; + case VEC128_TYPE: str->Append("(%F,%F,%F,%F)", + value->constant.v128.x, + value->constant.v128.y, + value->constant.v128.z, + value->constant.v128.w); break; + default: XEASSERTALWAYS(); break; + } + } else { + static const char* type_names[] = { + "i8", "i16", "i32", "i64", "f32", "f64", "v128", + }; + str->Append("v%d.%s", value->ordinal, type_names[value->type]); + } +} + +void FunctionBuilder::DumpOp( + StringBuffer* str, OpcodeSignatureType sig_type, Instr::Op* op) { + switch (sig_type) { + case OPCODE_SIG_TYPE_X: + break; + case OPCODE_SIG_TYPE_L: + if (op->label->name) { + str->Append(op->label->name); + } else { + str->Append("label%d", op->label->id); + } + break; + case OPCODE_SIG_TYPE_O: + str->Append("+%d", op->offset); + break; + case OPCODE_SIG_TYPE_S: + str->Append(""); + break; + case OPCODE_SIG_TYPE_V: + DumpValue(str, op->value); + break; + } +} + +void FunctionBuilder::Dump(StringBuffer* str) { + if (attributes_) { + str->Append("; attributes = %.8X\n", attributes_); + } + + uint32_t block_ordinal = 0; + Block* block = block_head_; + while (block) { + if (block == block_head_) { + str->Append(":\n"); + } else { + str->Append(":\n", block_ordinal); + } + block_ordinal++; + + Label* label = block->label_head; + while (label) { + if (label->name) { + str->Append("%s:\n", label->name); + } else { + str->Append("label%d:\n", label->id); + } + label = label->next; + } + + Instr* i = block->instr_head; + while (i) { + if (i->opcode->num == OPCODE_COMMENT) { + str->Append(" ; %s\n", (char*)i->src1.offset); + i = i->next; + continue; + } + + const OpcodeInfo* info = i->opcode; + OpcodeSignatureType dest_type = GET_OPCODE_SIG_TYPE_DEST(info->signature); + OpcodeSignatureType src1_type = GET_OPCODE_SIG_TYPE_SRC1(info->signature); + OpcodeSignatureType src2_type = GET_OPCODE_SIG_TYPE_SRC2(info->signature); + OpcodeSignatureType src3_type = GET_OPCODE_SIG_TYPE_SRC3(info->signature); + str->Append(" "); + if (dest_type) { + DumpValue(str, i->dest); + str->Append(" = "); + } + if (i->flags) { + str->Append("%s.%d", info->name, i->flags); + } else { + str->Append("%s", info->name); + } + if (src1_type) { + str->Append(" "); + DumpOp(str, src1_type, &i->src1); + } + if (src2_type) { + str->Append(", "); + DumpOp(str, src2_type, &i->src2); + } + if (src3_type) { + str->Append(", "); + DumpOp(str, src3_type, &i->src3); + } + str->Append("\n"); + i = i->next; + } + + block = block->next; + } +} + +Block* FunctionBuilder::current_block() const { + return current_block_; +} + +Instr* FunctionBuilder::last_instr() const { + if (current_block_ && current_block_->instr_tail) { + return current_block_->instr_tail; + } else if (block_tail_) { + return block_tail_->instr_tail; + } + return NULL; +} + +Label* FunctionBuilder::NewLabel() { + Label* label = arena_->Alloc