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