xenia-canary/src/alloy/backend/ivm/ivm_intcode.cc

4242 lines
157 KiB
C++

/**
******************************************************************************
* 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 <alloy/backend/ivm/ivm_intcode.h>
#include <algorithm>
#include <poly/poly.h>
#include <alloy/hir/label.h>
#include <alloy/runtime/runtime.h>
#include <alloy/runtime/symbol_info.h>
#include <alloy/runtime/thread_state.h>
// TODO(benvanik): make a compile time flag?
//#define DYNAMIC_REGISTER_ACCESS_CHECK(address) false
#define DYNAMIC_REGISTER_ACCESS_CHECK(address) \
((address & 0xFF000000) == 0x7F000000)
namespace alloy {
namespace backend {
namespace ivm {
// TODO(benvanik): remove when enums redefined.
using namespace alloy::hir;
using alloy::hir::Instr;
using alloy::hir::Label;
using alloy::hir::OpcodeInfo;
using alloy::hir::OpcodeSignatureType;
using alloy::hir::TypeName;
using alloy::hir::Value;
using alloy::runtime::Function;
using alloy::runtime::FunctionInfo;
#define IPRINT(...) (void())
#define IFLUSH() (void())
#define DPRINT(...) (void())
#define DFLUSH() (void())
//#define IPRINT if (ics.thread_state->thread_id() == 1) printf
//#define IFLUSH() fflush(stdout)
//#define DPRINT if (ics.thread_state->thread_id() == 1) printf
//#define DFLUSH() fflush(stdout)
#if XE_CPU_BIGENDIAN
#define VECB16(v, n) (v.b16[n])
#define VECS8(v, n) (v.s8[n])
#define VECI4(v, n) (v.i4[n])
#define VECF4(v, n) (v.f4[n])
#else
static const uint8_t __vector_b16_table[16] = {
3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12,
};
static const uint8_t __vector_s8_table[8] = {
1, 0, 3, 2, 5, 4, 7, 6,
};
#define VECB16(v, n) (v.b16[__vector_b16_table[(n)]])
#define VECS8(v, n) (v.s8[__vector_s8_table[(n)]])
#define VECI4(v, n) (v.i4[(n)])
#define VECF4(v, n) (v.f4[(n)])
#endif
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<IntCode>();
ic->intcode_fn = IntCode_INT_LOAD_CONSTANT;
ic->flags = 0;
ic->debug_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<IntCode>();
ic->intcode_fn = IntCode_INT_LOAD_CONSTANT;
ic->flags = 0;
ic->debug_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 = *reinterpret_cast<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<LabelRef>();
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) {
if (value->flags & VALUE_IS_ALLOCATED) {
return *reinterpret_cast<uint32_t*>(value->tag);
} else {
value->flags |= VALUE_IS_ALLOCATED;
auto reg = ctx.register_count++;
value->tag = reinterpret_cast<void*>(reg);
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) {
assert_true(fn != IntCode_INVALID);
assert_true(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<IntCode>();
ic->intcode_fn = fn;
ic->flags = i->flags;
ic->debug_flags = 0;
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) {
assert_always();
return IA_NEXT;
}
uint32_t IntCode_INVALID_TYPE(IntCodeState& ics, const IntCode* i) {
assert_always();
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));
(void)(value);
IPRINT("XE[t] :%d: %s\n", ics.thread_state->thread_id(), value);
IFLUSH();
return IA_NEXT;
}
int Translate_COMMENT(TranslationContext& ctx, Instr* i) {
ctx.intcode_count++;
IntCode* ic = ctx.intcode_arena->Alloc<IntCode>();
ic->intcode_fn = IntCode_COMMENT;
ic->flags = i->flags;
ic->debug_flags = 0;
// HACK HACK HACK
char* src = strdup(reinterpret_cast<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_SOURCE_OFFSET(IntCodeState& ics, const IntCode* i) {
return IA_NEXT;
}
int Translate_SOURCE_OFFSET(TranslationContext& ctx, Instr* i) {
int result = DispatchToC(ctx, i, IntCode_SOURCE_OFFSET);
if (result) {
return result;
}
auto entry = ctx.source_map_arena->Alloc<SourceMapEntry>();
entry->intcode_index = ctx.intcode_count - 1;
entry->source_offset = i->src1.offset;
ctx.source_map_count++;
return 0;
}
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) {
// TODO(benvanik): post software interrupt to debugger.
switch (i->flags) {
case 20:
// 0x0FE00014 is a 'debug print' where r3 = buffer r4 = length
break;
case 22:
// Always trap?
break;
}
__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 = symbol_info->function();
if (!fn) {
ics.thread_state->runtime()->ResolveFunction(symbol_info->address(), &fn);
}
assert_not_null(fn);
// TODO(benvanik): proper tail call support, somehow.
uint64_t return_address =
(i->flags & CALL_TAIL) ? ics.return_address : ics.call_return_address;
fn->Call(ics.thread_state, return_address);
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) {
uint64_t target = ics.rf[reg].u32;
// Check if return address - if so, return.
if (i->flags & CALL_POSSIBLE_RETURN) {
if (target == ics.return_address) {
return IA_RETURN;
}
}
// Real call.
Function* fn = NULL;
ics.thread_state->runtime()->ResolveFunction(target, &fn);
assert_not_null(fn);
// TODO(benvanik): proper tail call support, somehow.
uint64_t return_address =
(i->flags & CALL_TAIL) ? ics.return_address : ics.call_return_address;
fn->Call(ics.thread_state, return_address);
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_CALL_EXTERN(IntCodeState& ics, const IntCode* i) {
return IntCode_CALL_XX(ics, i, i->src1_reg);
}
int Translate_CALL_EXTERN(TranslationContext& ctx, Instr* i) {
return DispatchToC(ctx, i, IntCode_CALL_EXTERN);
}
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_RETURN_TRUE_I8(IntCodeState& ics, const IntCode* i) {
if (ics.rf[i->src1_reg].u8) {
return IA_RETURN;
}
return IA_NEXT;
}
uint32_t IntCode_RETURN_TRUE_I16(IntCodeState& ics, const IntCode* i) {
if (ics.rf[i->src1_reg].u16) {
return IA_RETURN;
}
return IA_NEXT;
}
uint32_t IntCode_RETURN_TRUE_I32(IntCodeState& ics, const IntCode* i) {
if (ics.rf[i->src1_reg].u32) {
return IA_RETURN;
}
return IA_NEXT;
}
uint32_t IntCode_RETURN_TRUE_I64(IntCodeState& ics, const IntCode* i) {
if (ics.rf[i->src1_reg].u64) {
return IA_RETURN;
}
return IA_NEXT;
}
uint32_t IntCode_RETURN_TRUE_F32(IntCodeState& ics, const IntCode* i) {
if (ics.rf[i->src1_reg].f32) {
return IA_RETURN;
}
return IA_NEXT;
}
uint32_t IntCode_RETURN_TRUE_F64(IntCodeState& ics, const IntCode* i) {
if (ics.rf[i->src1_reg].f64) {
return IA_RETURN;
}
return IA_NEXT;
}
int Translate_RETURN_TRUE(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_RETURN_TRUE_I8, IntCode_RETURN_TRUE_I16, IntCode_RETURN_TRUE_I32,
IntCode_RETURN_TRUE_I64, IntCode_RETURN_TRUE_F32, IntCode_RETURN_TRUE_F64,
IntCode_INVALID_TYPE,
};
return DispatchToC(ctx, i, fns[i->src1.value->type]);
}
uint32_t IntCode_SET_RETURN_ADDRESS(IntCodeState& ics, const IntCode* i) {
ics.call_return_address = ics.rf[i->src1_reg].u32;
return IA_NEXT;
}
int Translate_SET_RETURN_ADDRESS(TranslationContext& ctx, Instr* i) {
return DispatchToC(ctx, i, IntCode_SET_RETURN_ADDRESS);
}
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_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_I32(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].i32 = (int32_t)ics.rf[i->src1_reg].f64;
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_CONVERT_F64_TO_I32,
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_ROUND_F32(IntCodeState& ics, const IntCode* i) {
float src1 = ics.rf[i->src1_reg].f32;
float dest = src1;
switch (i->flags) {
case ROUND_TO_ZERO:
dest = truncf(src1);
break;
case ROUND_TO_NEAREST:
dest = roundf(src1);
break;
case ROUND_TO_MINUS_INFINITY:
dest = floorf(src1);
break;
case ROUND_TO_POSITIVE_INFINITY:
dest = ceilf(src1);
break;
}
ics.rf[i->dest_reg].f32 = dest;
return IA_NEXT;
}
uint32_t IntCode_ROUND_F64(IntCodeState& ics, const IntCode* i) {
double src1 = ics.rf[i->src1_reg].f64;
double dest = src1;
switch (i->flags) {
case ROUND_TO_ZERO:
dest = trunc(src1);
break;
case ROUND_TO_NEAREST:
dest = round(src1);
break;
case ROUND_TO_MINUS_INFINITY:
dest = floor(src1);
break;
case ROUND_TO_POSITIVE_INFINITY:
dest = ceil(src1);
break;
}
ics.rf[i->dest_reg].f64 = dest;
return IA_NEXT;
}
uint32_t IntCode_ROUND_V128_ZERO(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 n = 0; n < 4; n++) {
dest.f4[n] = truncf(src1.f4[n]);
}
return IA_NEXT;
}
uint32_t IntCode_ROUND_V128_NEAREST(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 n = 0; n < 4; n++) {
dest.f4[n] = roundf(src1.f4[n]);
}
return IA_NEXT;
}
uint32_t IntCode_ROUND_V128_MINUS_INFINITY(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 n = 0; n < 4; n++) {
dest.f4[n] = floorf(src1.f4[n]);
}
return IA_NEXT;
}
uint32_t IntCode_ROUND_V128_POSITIVE_INFINTIY(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 n = 0; n < 4; n++) {
dest.f4[n] = ceilf(src1.f4[n]);
}
return IA_NEXT;
}
int Translate_ROUND(TranslationContext& ctx, Instr* i) {
if (i->dest->type == VEC128_TYPE) {
static IntCodeFn fns[] = {
IntCode_ROUND_V128_ZERO, IntCode_ROUND_V128_NEAREST,
IntCode_ROUND_V128_MINUS_INFINITY, IntCode_ROUND_V128_POSITIVE_INFINTIY,
};
return DispatchToC(ctx, i, fns[i->flags]);
} else {
static IntCodeFn fns[] = {
IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE, IntCode_ROUND_F32, IntCode_ROUND_F64,
IntCode_INVALID_TYPE,
};
return DispatchToC(ctx, i, fns[i->dest->type]);
}
}
uint32_t IntCode_VECTOR_CONVERT_I2F_S(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
VECF4(dest, 0) = (float)(int32_t)VECI4(src1, 0);
VECF4(dest, 1) = (float)(int32_t)VECI4(src1, 1);
VECF4(dest, 2) = (float)(int32_t)VECI4(src1, 2);
VECF4(dest, 3) = (float)(int32_t)VECI4(src1, 3);
return IA_NEXT;
}
uint32_t IntCode_VECTOR_CONVERT_I2F_U(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
VECF4(dest, 0) = (float)(uint32_t)VECI4(src1, 0);
VECF4(dest, 1) = (float)(uint32_t)VECI4(src1, 1);
VECF4(dest, 2) = (float)(uint32_t)VECI4(src1, 2);
VECF4(dest, 3) = (float)(uint32_t)VECI4(src1, 3);
return IA_NEXT;
}
int Translate_VECTOR_CONVERT_I2F(TranslationContext& ctx, Instr* i) {
if (i->flags & ARITHMETIC_UNSIGNED) {
return DispatchToC(ctx, i, IntCode_VECTOR_CONVERT_I2F_U);
} else {
return DispatchToC(ctx, i, IntCode_VECTOR_CONVERT_I2F_S);
}
}
uint32_t IntCode_VECTOR_CONVERT_F2I(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
if (i->flags & ARITHMETIC_UNSIGNED) {
VECI4(dest, 0) = (uint32_t)VECF4(src1, 0);
VECI4(dest, 1) = (uint32_t)VECF4(src1, 1);
VECI4(dest, 2) = (uint32_t)VECF4(src1, 2);
VECI4(dest, 3) = (uint32_t)VECF4(src1, 3);
} else {
VECI4(dest, 0) = (int32_t)VECF4(src1, 0);
VECI4(dest, 1) = (int32_t)VECF4(src1, 1);
VECI4(dest, 2) = (int32_t)VECF4(src1, 2);
VECI4(dest, 3) = (int32_t)VECF4(src1, 3);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_CONVERT_F2I_SAT(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
if (i->flags & ARITHMETIC_UNSIGNED) {
for (int n = 0; n < 4; n++) {
float src = src1.f4[n];
if (src < 0) {
VECI4(dest, n) = 0;
ics.did_saturate = 1;
} else if (src > UINT_MAX) {
VECI4(dest, n) = UINT_MAX;
ics.did_saturate = 1;
} else {
VECI4(dest, n) = (uint32_t)src;
}
}
} else {
for (int n = 0; n < 4; n++) {
float src = src1.f4[n];
if (src < INT_MIN) {
VECI4(dest, n) = INT_MIN;
ics.did_saturate = 1;
} else if (src > INT_MAX) {
VECI4(dest, n) = INT_MAX;
ics.did_saturate = 1;
} else {
VECI4(dest, n) = (int32_t)src;
}
}
}
return IA_NEXT;
}
int Translate_VECTOR_CONVERT_F2I(TranslationContext& ctx, Instr* i) {
if (i->flags & ARITHMETIC_SATURATE) {
return DispatchToC(ctx, i, IntCode_VECTOR_CONVERT_F2I_SAT);
} else {
return DispatchToC(ctx, i, IntCode_VECTOR_CONVERT_F2I);
}
}
static uint8_t __lvsl_table[17][16] = {
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},
{3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18},
{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19},
{5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21},
{7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22},
{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24},
{10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
{11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
{12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27},
{13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28},
{14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29},
{15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30},
{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
};
static uint8_t __lvsr_table[17][16] = {
{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
{15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30},
{14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29},
{13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28},
{12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27},
{11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
{10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},
{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24},
{8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
{7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22},
{6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21},
{5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19},
{3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18},
{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
};
uint32_t IntCode_LOAD_VECTOR_SHL(IntCodeState& ics, const IntCode* i) {
int8_t sh = std::min<int8_t>(16, ics.rf[i->src1_reg].i8);
vec128_t& dest = ics.rf[i->dest_reg].v128;
for (int n = 0; n < 16; n++) {
VECB16(dest, n) = __lvsl_table[sh][n];
}
return IA_NEXT;
}
int Translate_LOAD_VECTOR_SHL(TranslationContext& ctx, Instr* i) {
return DispatchToC(ctx, i, IntCode_LOAD_VECTOR_SHL);
}
uint32_t IntCode_LOAD_VECTOR_SHR(IntCodeState& ics, const IntCode* i) {
int8_t sh = std::min<int8_t>(16, ics.rf[i->src1_reg].i8);
vec128_t& dest = ics.rf[i->dest_reg].v128;
for (int n = 0; n < 16; n++) {
VECB16(dest, n) = __lvsr_table[sh][n];
}
return IA_NEXT;
}
int Translate_LOAD_VECTOR_SHR(TranslationContext& ctx, Instr* i) {
return DispatchToC(ctx, i, IntCode_LOAD_VECTOR_SHR);
}
uint32_t IntCode_LOAD_CLOCK(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].i64 = poly::threading::ticks();
return IA_NEXT;
}
int Translate_LOAD_CLOCK(TranslationContext& ctx, Instr* i) {
return DispatchToC(ctx, i, IntCode_LOAD_CLOCK);
}
uint32_t IntCode_LOAD_LOCAL_I8(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].i8 = *((int8_t*)(ics.locals + ics.rf[i->src1_reg].u32));
return IA_NEXT;
}
uint32_t IntCode_LOAD_LOCAL_I16(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].i16 = *((int16_t*)(ics.locals + ics.rf[i->src1_reg].u32));
return IA_NEXT;
}
uint32_t IntCode_LOAD_LOCAL_I32(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].i32 = *((int32_t*)(ics.locals + ics.rf[i->src1_reg].u32));
return IA_NEXT;
}
uint32_t IntCode_LOAD_LOCAL_I64(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].i64 = *((int64_t*)(ics.locals + ics.rf[i->src1_reg].u32));
return IA_NEXT;
}
uint32_t IntCode_LOAD_LOCAL_F32(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f32 = *((float*)(ics.locals + ics.rf[i->src1_reg].u32));
return IA_NEXT;
}
uint32_t IntCode_LOAD_LOCAL_F64(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f64 = *((double*)(ics.locals + ics.rf[i->src1_reg].u32));
return IA_NEXT;
}
uint32_t IntCode_LOAD_LOCAL_V128(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].v128 =
*((vec128_t*)(ics.locals + ics.rf[i->src1_reg].u32));
return IA_NEXT;
}
int Translate_LOAD_LOCAL(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_LOAD_LOCAL_I8, IntCode_LOAD_LOCAL_I16, IntCode_LOAD_LOCAL_I32,
IntCode_LOAD_LOCAL_I64, IntCode_LOAD_LOCAL_F32, IntCode_LOAD_LOCAL_F64,
IntCode_LOAD_LOCAL_V128,
};
return DispatchToC(ctx, i, fns[i->dest->type]);
}
uint32_t IntCode_STORE_LOCAL_I8(IntCodeState& ics, const IntCode* i) {
*((int8_t*)(ics.locals + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].i8;
return IA_NEXT;
}
uint32_t IntCode_STORE_LOCAL_I16(IntCodeState& ics, const IntCode* i) {
*((int16_t*)(ics.locals + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].i16;
return IA_NEXT;
}
uint32_t IntCode_STORE_LOCAL_I32(IntCodeState& ics, const IntCode* i) {
*((int32_t*)(ics.locals + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].i32;
return IA_NEXT;
}
uint32_t IntCode_STORE_LOCAL_I64(IntCodeState& ics, const IntCode* i) {
*((int64_t*)(ics.locals + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].i64;
return IA_NEXT;
}
uint32_t IntCode_STORE_LOCAL_F32(IntCodeState& ics, const IntCode* i) {
*((float*)(ics.locals + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].f32;
return IA_NEXT;
}
uint32_t IntCode_STORE_LOCAL_F64(IntCodeState& ics, const IntCode* i) {
*((double*)(ics.locals + ics.rf[i->src1_reg].u32)) = ics.rf[i->src2_reg].f64;
return IA_NEXT;
}
uint32_t IntCode_STORE_LOCAL_V128(IntCodeState& ics, const IntCode* i) {
*((vec128_t*)(ics.locals + ics.rf[i->src1_reg].u32)) =
ics.rf[i->src2_reg].v128;
return IA_NEXT;
}
int Translate_STORE_LOCAL(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_STORE_LOCAL_I8, IntCode_STORE_LOCAL_I16,
IntCode_STORE_LOCAL_I32, IntCode_STORE_LOCAL_I64,
IntCode_STORE_LOCAL_F32, IntCode_STORE_LOCAL_F64,
IntCode_STORE_LOCAL_V128,
};
return DispatchToC(ctx, i, fns[i->src2.value->type]);
}
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("%lld (%llX) = 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));
DPRINT("%e (%X) = ctx f32 +%d\n", ics.rf[i->dest_reg].f32,
ics.rf[i->dest_reg].u32, 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));
DPRINT("%lle (%llX) = ctx f64 +%d\n", ics.rf[i->dest_reg].f64,
ics.rf[i->dest_reg].u64, 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));
DPRINT("[%e, %e, %e, %e] [%.8X, %.8X, %.8X, %.8X] = ctx v128 +%d\n",
VECF4(ics.rf[i->dest_reg].v128, 0), VECF4(ics.rf[i->dest_reg].v128, 1),
VECF4(ics.rf[i->dest_reg].v128, 2), VECF4(ics.rf[i->dest_reg].v128, 3),
VECI4(ics.rf[i->dest_reg].v128, 0), VECI4(ics.rf[i->dest_reg].v128, 1),
VECI4(ics.rf[i->dest_reg].v128, 2), VECI4(ics.rf[i->dest_reg].v128, 3),
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 = %lld (%llX)\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;
DPRINT("ctx f32 +%d = %e (%X)\n", ics.rf[i->src1_reg].u64,
ics.rf[i->src2_reg].f32, ics.rf[i->src2_reg].u32);
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;
DPRINT("ctx f64 +%d = %lle (%llX)\n", ics.rf[i->src1_reg].u64,
ics.rf[i->src2_reg].f64, ics.rf[i->src2_reg].u64);
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;
DPRINT("ctx v128 +%d = [%e, %e, %e, %e] [%.8X, %.8X, %.8X, %.8X]\n",
ics.rf[i->src1_reg].u64, VECF4(ics.rf[i->src2_reg].v128, 0),
VECF4(ics.rf[i->src2_reg].v128, 1), VECF4(ics.rf[i->src2_reg].v128, 2),
VECF4(ics.rf[i->src2_reg].v128, 3), VECI4(ics.rf[i->src2_reg].v128, 0),
VECI4(ics.rf[i->src2_reg].v128, 1), VECI4(ics.rf[i->src2_reg].v128, 2),
VECI4(ics.rf[i->src2_reg].v128, 3));
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) {
uint32_t address = ics.rf[i->src1_reg].u32;
if (DYNAMIC_REGISTER_ACCESS_CHECK(address)) {
ics.rf[i->dest_reg].i8 = ics.thread_state->memory()->LoadI8(address);
return IA_NEXT;
}
DPRINT("%d (%X) = load.i8 %.8X\n", *((int8_t*)(ics.membase + address)),
*((uint8_t*)(ics.membase + address)), address);
DFLUSH();
ics.rf[i->dest_reg].i8 = *((int8_t*)(ics.membase + address));
return IA_NEXT;
}
uint32_t IntCode_LOAD_I16(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
if (DYNAMIC_REGISTER_ACCESS_CHECK(address)) {
ics.rf[i->dest_reg].i16 =
poly::byte_swap(ics.thread_state->memory()->LoadI16(address));
return IA_NEXT;
}
DPRINT("%d (%X) = load.i16 %.8X\n", *((int16_t*)(ics.membase + address)),
*((uint16_t*)(ics.membase + address)), address);
DFLUSH();
ics.rf[i->dest_reg].i16 = *((int16_t*)(ics.membase + address));
return IA_NEXT;
}
uint32_t IntCode_LOAD_I32(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
if (DYNAMIC_REGISTER_ACCESS_CHECK(address)) {
ics.rf[i->dest_reg].i32 =
poly::byte_swap(ics.thread_state->memory()->LoadI32(address));
return IA_NEXT;
}
DFLUSH();
DPRINT("%d (%X) = load.i32 %.8X\n", *((int32_t*)(ics.membase + address)),
*((uint32_t*)(ics.membase + address)), address);
DFLUSH();
ics.rf[i->dest_reg].i32 = *((int32_t*)(ics.membase + address));
return IA_NEXT;
}
uint32_t IntCode_LOAD_I64(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
if (DYNAMIC_REGISTER_ACCESS_CHECK(address)) {
ics.rf[i->dest_reg].i64 =
poly::byte_swap(ics.thread_state->memory()->LoadI64(address));
return IA_NEXT;
}
DPRINT("%lld (%llX) = load.i64 %.8X\n", *((int64_t*)(ics.membase + address)),
*((uint64_t*)(ics.membase + address)), address);
DFLUSH();
ics.rf[i->dest_reg].i64 = *((int64_t*)(ics.membase + address));
return IA_NEXT;
}
uint32_t IntCode_LOAD_F32(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
DPRINT("%e (%X) = load.f32 %.8X\n", *((float*)(ics.membase + address)),
*((uint64_t*)(ics.membase + address)), address);
DFLUSH();
ics.rf[i->dest_reg].f32 = *((float*)(ics.membase + address));
return IA_NEXT;
}
uint32_t IntCode_LOAD_F64(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
DPRINT("%lle (%llX) = load.f64 %.8X\n", *((double*)(ics.membase + address)),
*((uint64_t*)(ics.membase + address)), address);
DFLUSH();
ics.rf[i->dest_reg].f64 = *((double*)(ics.membase + address));
return IA_NEXT;
}
uint32_t IntCode_LOAD_V128(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
vec128_t& dest = ics.rf[i->dest_reg].v128;
for (int n = 0; n < 4; n++) {
VECI4(dest, n) = *((uint32_t*)(ics.membase + address + n * 4));
}
DPRINT("[%e, %e, %e, %e] [%.8X, %.8X, %.8X, %.8X] = load.v128 %.8X\n",
VECF4(dest, 0), VECF4(dest, 1), VECF4(dest, 2), VECF4(dest, 3),
VECI4(dest, 0), VECI4(dest, 1), VECI4(dest, 2), VECI4(dest, 3),
address);
DFLUSH();
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]);
}
void MarkPageDirty(IntCodeState& ics, uint32_t address) {
// 16KB pages.
ics.page_table[(address >> 14) & 0x7FFF] = 1;
}
uint32_t IntCode_STORE_I8(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
if (DYNAMIC_REGISTER_ACCESS_CHECK(address)) {
ics.thread_state->memory()->StoreI8(address, ics.rf[i->src2_reg].i8);
return IA_NEXT;
}
DPRINT("store.i8 %.8X = %d (%X)\n", address, ics.rf[i->src2_reg].i8,
ics.rf[i->src2_reg].u8);
DFLUSH();
*((int8_t*)(ics.membase + address)) = ics.rf[i->src2_reg].i8;
MarkPageDirty(ics, address);
return IA_NEXT;
}
uint32_t IntCode_STORE_I16(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
if (DYNAMIC_REGISTER_ACCESS_CHECK(address)) {
ics.thread_state->memory()->StoreI16(
address, poly::byte_swap(ics.rf[i->src2_reg].i16));
return IA_NEXT;
}
DPRINT("store.i16 %.8X = %d (%X)\n", address, ics.rf[i->src2_reg].i16,
ics.rf[i->src2_reg].u16);
DFLUSH();
*((int16_t*)(ics.membase + address)) = ics.rf[i->src2_reg].i16;
MarkPageDirty(ics, address);
return IA_NEXT;
}
uint32_t IntCode_STORE_I32(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
if (DYNAMIC_REGISTER_ACCESS_CHECK(address)) {
ics.thread_state->memory()->StoreI32(
address, poly::byte_swap(ics.rf[i->src2_reg].i32));
return IA_NEXT;
}
DPRINT("store.i32 %.8X = %d (%X)\n", address, ics.rf[i->src2_reg].i32,
ics.rf[i->src2_reg].u32);
DFLUSH();
*((int32_t*)(ics.membase + address)) = ics.rf[i->src2_reg].i32;
MarkPageDirty(ics, address);
return IA_NEXT;
}
uint32_t IntCode_STORE_I64(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
if (DYNAMIC_REGISTER_ACCESS_CHECK(address)) {
ics.thread_state->memory()->StoreI64(
address, poly::byte_swap(ics.rf[i->src2_reg].i64));
return IA_NEXT;
}
DPRINT("store.i64 %.8X = %lld (%llX)\n", address, ics.rf[i->src2_reg].i64,
ics.rf[i->src2_reg].u64);
DFLUSH();
*((int64_t*)(ics.membase + address)) = ics.rf[i->src2_reg].i64;
MarkPageDirty(ics, address);
return IA_NEXT;
}
uint32_t IntCode_STORE_F32(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
DPRINT("store.f32 %.8X = %e (%X)\n", address, ics.rf[i->src2_reg].f32,
ics.rf[i->src2_reg].u32);
DFLUSH();
*((float*)(ics.membase + address)) = ics.rf[i->src2_reg].f32;
MarkPageDirty(ics, address);
return IA_NEXT;
}
uint32_t IntCode_STORE_F64(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
DPRINT("store.f64 %.8X = %lle (%llX)\n", address, ics.rf[i->src2_reg].f64,
ics.rf[i->src2_reg].u64);
DFLUSH();
*((double*)(ics.membase + address)) = ics.rf[i->src2_reg].f64;
MarkPageDirty(ics, address);
return IA_NEXT;
}
uint32_t IntCode_STORE_V128(IntCodeState& ics, const IntCode* i) {
uint32_t address = ics.rf[i->src1_reg].u32;
DPRINT("store.v128 %.8X = [%e, %e, %e, %e] [%.8X, %.8X, %.8X, %.8X]\n",
address, VECF4(ics.rf[i->src2_reg].v128, 0),
VECF4(ics.rf[i->src2_reg].v128, 1), VECF4(ics.rf[i->src2_reg].v128, 2),
VECF4(ics.rf[i->src2_reg].v128, 3), VECI4(ics.rf[i->src2_reg].v128, 0),
VECI4(ics.rf[i->src2_reg].v128, 1), VECI4(ics.rf[i->src2_reg].v128, 2),
VECI4(ics.rf[i->src2_reg].v128, 3));
DFLUSH();
*((vec128_t*)(ics.membase + address)) = ics.rf[i->src2_reg].v128;
MarkPageDirty(ics, address);
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_MAX_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;
ics.rf[i->dest_reg].i8 = std::max(a, b);
return IA_NEXT;
}
uint32_t IntCode_MAX_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;
ics.rf[i->dest_reg].i16 = std::max(a, b);
return IA_NEXT;
}
uint32_t IntCode_MAX_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;
ics.rf[i->dest_reg].i32 = std::max(a, b);
return IA_NEXT;
}
uint32_t IntCode_MAX_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;
ics.rf[i->dest_reg].i64 = std::max(a, b);
return IA_NEXT;
}
uint32_t IntCode_MAX_F32_F32(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f32 =
std::max(ics.rf[i->src1_reg].f32, ics.rf[i->src2_reg].f32);
return IA_NEXT;
}
uint32_t IntCode_MAX_F64_F64(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f64 =
std::max(ics.rf[i->src1_reg].f64, ics.rf[i->src2_reg].f64);
return IA_NEXT;
}
uint32_t IntCode_MAX_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] = std::max(src1.f4[n], src2.f4[n]);
}
return IA_NEXT;
}
int Translate_MAX(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_MAX_I8_I8, IntCode_MAX_I16_I16, IntCode_MAX_I32_I32,
IntCode_MAX_I64_I64, IntCode_MAX_F32_F32, IntCode_MAX_F64_F64,
IntCode_MAX_V128_V128,
};
return DispatchToC(ctx, i, fns[i->dest->type]);
}
uint32_t IntCode_VECTOR_MAX_I8_UNSIGNED(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] = std::max(src1.b16[n], src2.b16[n]);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_MAX_I16_UNSIGNED(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] = std::max(src1.s8[n], src2.s8[n]);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_MAX_I32_UNSIGNED(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] = std::max(src1.i4[n], src2.i4[n]);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_MAX_I8_SIGNED(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] = std::max((int8_t)src1.b16[n], (int8_t)src2.b16[n]);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_MAX_I16_SIGNED(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] = std::max((int16_t)src1.s8[n], (int16_t)src2.s8[n]);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_MAX_I32_SIGNED(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] = std::max((int32_t)src1.i4[n], (int32_t)src2.i4[n]);
}
return IA_NEXT;
}
int Translate_VECTOR_MAX(TranslationContext& ctx, Instr* i) {
static IntCodeFn unsigned_fns[] = {
IntCode_VECTOR_MAX_I8_UNSIGNED, IntCode_VECTOR_MAX_I16_UNSIGNED,
IntCode_VECTOR_MAX_I32_UNSIGNED,
};
static IntCodeFn signed_fns[] = {
IntCode_VECTOR_MAX_I8_SIGNED, IntCode_VECTOR_MAX_I16_SIGNED,
IntCode_VECTOR_MAX_I32_SIGNED,
};
uint32_t part_type = i->flags >> 8;
if (i->flags & ARITHMETIC_UNSIGNED) {
return DispatchToC(ctx, i, unsigned_fns[part_type]);
} else {
return DispatchToC(ctx, i, signed_fns[part_type]);
}
}
uint32_t IntCode_MIN_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;
ics.rf[i->dest_reg].i8 = std::min(a, b);
return IA_NEXT;
}
uint32_t IntCode_MIN_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;
ics.rf[i->dest_reg].i16 = std::min(a, b);
return IA_NEXT;
}
uint32_t IntCode_MIN_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;
ics.rf[i->dest_reg].i32 = std::min(a, b);
return IA_NEXT;
}
uint32_t IntCode_MIN_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;
ics.rf[i->dest_reg].i64 = std::min(a, b);
return IA_NEXT;
}
uint32_t IntCode_MIN_F32_F32(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f32 =
std::min(ics.rf[i->src1_reg].f32, ics.rf[i->src2_reg].f32);
return IA_NEXT;
}
uint32_t IntCode_MIN_F64_F64(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f64 =
std::min(ics.rf[i->src1_reg].f64, ics.rf[i->src2_reg].f64);
return IA_NEXT;
}
uint32_t IntCode_MIN_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] = std::min(src1.f4[n], src2.f4[n]);
}
return IA_NEXT;
}
int Translate_MIN(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_MIN_I8_I8, IntCode_MIN_I16_I16, IntCode_MIN_I32_I32,
IntCode_MIN_I64_I64, IntCode_MIN_F32_F32, IntCode_MIN_F64_F64,
IntCode_MIN_V128_V128,
};
return DispatchToC(ctx, i, fns[i->dest->type]);
}
uint32_t IntCode_VECTOR_MIN_I8_UNSIGNED(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] = std::min(src1.b16[n], src2.b16[n]);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_MIN_I16_UNSIGNED(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] = std::min(src1.s8[n], src2.s8[n]);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_MIN_I32_UNSIGNED(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] = std::min(src1.i4[n], src2.i4[n]);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_MIN_I8_SIGNED(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] = std::min((int8_t)src1.b16[n], (int8_t)src2.b16[n]);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_MIN_I16_SIGNED(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] = std::min((int16_t)src1.s8[n], (int16_t)src2.s8[n]);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_MIN_I32_SIGNED(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] = std::min((int32_t)src1.i4[n], (int32_t)src2.i4[n]);
}
return IA_NEXT;
}
int Translate_VECTOR_MIN(TranslationContext& ctx, Instr* i) {
static IntCodeFn unsigned_fns[] = {
IntCode_VECTOR_MIN_I8_UNSIGNED, IntCode_VECTOR_MIN_I16_UNSIGNED,
IntCode_VECTOR_MIN_I32_UNSIGNED,
};
static IntCodeFn signed_fns[] = {
IntCode_VECTOR_MIN_I8_SIGNED, IntCode_VECTOR_MIN_I16_SIGNED,
IntCode_VECTOR_MIN_I32_SIGNED,
};
uint32_t part_type = i->flags >> 8;
if (i->flags & ARITHMETIC_UNSIGNED) {
return DispatchToC(ctx, i, unsigned_fns[part_type]);
} else {
return DispatchToC(ctx, i, signed_fns[part_type]);
}
}
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->dest->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);
}
uint32_t IntCode_DID_SATURATE(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].i8 = ics.did_saturate;
return IA_NEXT;
}
int Translate_DID_SATURATE(TranslationContext& ctx, Instr* i) {
return DispatchToC(ctx, i, IntCode_DID_SATURATE);
}
#define VECTOR_COMPARER(type, value, dest_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.dest_value[n] = \
((type)src1.value[n] op(type) src2.value[n]) ? 0xFFFFFFFF : 0; \
} \
return IA_NEXT;
uint32_t IntCode_VECTOR_COMPARE_EQ_I8(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(uint8_t, b16, b16, 16, == )};
uint32_t IntCode_VECTOR_COMPARE_EQ_I16(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(uint16_t, s8, s8, 8, == )};
uint32_t IntCode_VECTOR_COMPARE_EQ_I32(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(uint32_t, i4, i4, 4, == )};
uint32_t IntCode_VECTOR_COMPARE_EQ_F32(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(float, f4, i4, 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, b16, 16, > )};
uint32_t IntCode_VECTOR_COMPARE_SGT_I16(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(int16_t, s8, s8, 8, > )};
uint32_t IntCode_VECTOR_COMPARE_SGT_I32(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(int32_t, i4, i4, 4, > )};
uint32_t IntCode_VECTOR_COMPARE_SGT_F32(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(float, f4, i4, 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, b16, 16, >= )};
uint32_t IntCode_VECTOR_COMPARE_SGE_I16(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(int16_t, s8, s8, 8, >= )};
uint32_t IntCode_VECTOR_COMPARE_SGE_I32(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(int32_t, i4, i4, 4, >= )};
uint32_t IntCode_VECTOR_COMPARE_SGE_F32(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(float, f4, i4, 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, b16, 16, > )};
uint32_t IntCode_VECTOR_COMPARE_UGT_I16(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(uint16_t, s8, s8, 8, > )};
uint32_t IntCode_VECTOR_COMPARE_UGT_I32(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(uint32_t, i4, i4, 4, > )};
uint32_t IntCode_VECTOR_COMPARE_UGT_F32(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(float, f4, i4, 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, b16, 16, >= )};
uint32_t IntCode_VECTOR_COMPARE_UGE_I16(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(uint16_t, s8, s8, 8, >= )};
uint32_t IntCode_VECTOR_COMPARE_UGE_I32(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(uint32_t, i4, i4, 4, >= )};
uint32_t IntCode_VECTOR_COMPARE_UGE_F32(IntCodeState& ics, const IntCode* i){
VECTOR_COMPARER(float, f4, i4, 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) (((uint64_t)v2) > ~((uint64_t)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) {
assert_true(!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) {
assert_true(!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) {
assert_true(!i->flags);
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) {
assert_true(!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) {
assert_true(!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]);
}
uint32_t Translate_VECTOR_ADD_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;
const uint32_t arithmetic_flags = i->flags >> 8;
if (arithmetic_flags & ARITHMETIC_SATURATE) {
if (arithmetic_flags & ARITHMETIC_UNSIGNED) {
for (int n = 0; n < 16; n++) {
uint16_t v = VECB16(src1, n) + VECB16(src2, n);
if (v > 0xFF) {
VECB16(dest, n) = 0xFF;
ics.did_saturate = 1;
} else {
VECB16(dest, n) = (uint8_t)v;
}
}
} else {
for (int n = 0; n < 16; n++) {
int16_t v = (int8_t)VECB16(src1, n) + (int8_t)VECB16(src2, n);
if (v > 0x7F) {
VECB16(dest, n) = 0x7F;
ics.did_saturate = 1;
} else if (v < -0x80) {
VECB16(dest, n) = -0x80;
ics.did_saturate = 1;
} else {
VECB16(dest, n) = (uint8_t)v;
}
}
}
} else {
for (int n = 0; n < 16; n++) {
VECB16(dest, n) = VECB16(src1, n) + VECB16(src2, n);
}
}
return IA_NEXT;
}
uint32_t Translate_VECTOR_ADD_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;
const uint32_t arithmetic_flags = i->flags >> 8;
if (arithmetic_flags & ARITHMETIC_SATURATE) {
if (arithmetic_flags & ARITHMETIC_UNSIGNED) {
for (int n = 0; n < 8; n++) {
uint32_t v = VECS8(src1, n) + VECS8(src2, n);
if (v > 0xFFFF) {
VECS8(dest, n) = 0xFFFF;
ics.did_saturate = 1;
} else {
VECS8(dest, n) = (uint16_t)v;
}
}
} else {
for (int n = 0; n < 8; n++) {
int32_t v = (int16_t)VECS8(src1, n) + (int16_t)VECS8(src2, n);
if (v > 0x7FFF) {
VECS8(dest, n) = 0x7FFF;
ics.did_saturate = 1;
} else if (v < -0x8000) {
VECS8(dest, n) = -0x8000;
ics.did_saturate = 1;
} else {
VECS8(dest, n) = (uint16_t)v;
}
}
}
} else {
for (int n = 0; n < 8; n++) {
VECS8(dest, n) = VECS8(src1, n) + VECS8(src2, n);
}
}
return IA_NEXT;
}
uint32_t Translate_VECTOR_ADD_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;
const uint32_t arithmetic_flags = i->flags >> 8;
if (arithmetic_flags & ARITHMETIC_SATURATE) {
if (arithmetic_flags & ARITHMETIC_UNSIGNED) {
for (int n = 0; n < 4; n++) {
uint64_t v = VECI4(src1, n) + VECI4(src2, n);
if (v > 0xFFFFFFFF) {
VECI4(dest, n) = 0xFFFFFFFF;
ics.did_saturate = 1;
} else {
VECI4(dest, n) = (uint32_t)v;
}
}
} else {
for (int n = 0; n < 4; n++) {
int64_t v = (int32_t)VECI4(src1, n) + (int32_t)VECI4(src2, n);
if (v > 0x7FFFFFFF) {
VECI4(dest, n) = 0x7FFFFFFF;
ics.did_saturate = 1;
} else if (v < -0x80000000ll) {
VECI4(dest, n) = 0x80000000;
ics.did_saturate = 1;
} else {
VECI4(dest, n) = (uint32_t)v;
}
}
}
} else {
for (int n = 0; n < 4; n++) {
VECI4(dest, n) = VECI4(src1, n) + VECI4(src2, n);
}
}
return IA_NEXT;
}
uint32_t Translate_VECTOR_ADD_F32(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_VECTOR_ADD(TranslationContext& ctx, Instr* i) {
TypeName part_type = (TypeName)(i->flags & 0xFF);
static IntCodeFn fns[] = {
Translate_VECTOR_ADD_I8, Translate_VECTOR_ADD_I16,
Translate_VECTOR_ADD_I32, IntCode_INVALID_TYPE,
Translate_VECTOR_ADD_F32, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE,
};
return DispatchToC(ctx, i, fns[part_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 = SUB_DID_CARRY(a, b);
}
ics.rf[i->dest_reg].i32 = 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) {
assert_true(!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) {
assert_true(!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]);
}
int Translate_VECTOR_SUB(TranslationContext& ctx, Instr* i) {
// TODO(benvanik): VECTOR_SUB in IVM.
assert_always();
return 1;
}
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;
}
uint32_t IntCode_MUL_I8_I8_U(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].u8 = ics.rf[i->src1_reg].u8 * ics.rf[i->src2_reg].u8;
return IA_NEXT;
}
uint32_t IntCode_MUL_I16_I16_U(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].u16 = ics.rf[i->src1_reg].u16 * ics.rf[i->src2_reg].u16;
return IA_NEXT;
}
uint32_t IntCode_MUL_I32_I32_U(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].u32 = ics.rf[i->src1_reg].u32 * ics.rf[i->src2_reg].u32;
return IA_NEXT;
}
uint32_t IntCode_MUL_I64_I64_U(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].u64 = ics.rf[i->src1_reg].u64 * ics.rf[i->src2_reg].u64;
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,
};
static IntCodeFn fns_unsigned[] = {
IntCode_MUL_I8_I8_U, IntCode_MUL_I16_I16_U, IntCode_MUL_I32_I32_U,
IntCode_MUL_I64_I64_U, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE,
};
if (i->flags & ARITHMETIC_UNSIGNED) {
return DispatchToC(ctx, i, fns_unsigned[i->dest->type]);
} else {
return DispatchToC(ctx, i, fns[i->dest->type]);
}
}
#if XE_COMPILER_MSVC
uint64_t Mul128(uint64_t xi_low, uint64_t xi_high, uint64_t yi_low,
uint64_t yi_high) {
// 128bit multiply, simplified for two input 64bit integers.
// http://mrob.com/pub/math/int128.c.txt
#define HI_WORD 0xFFFFFFFF00000000LL
#define LO_WORD 0x00000000FFFFFFFFLL
uint64_t d = xi_low & LO_WORD;
uint64_t c = (xi_low & HI_WORD) >> 32LL;
uint64_t b = xi_high & LO_WORD;
uint64_t a = (xi_high & HI_WORD) >> 32LL;
uint64_t h = yi_low & LO_WORD;
uint64_t g = (yi_low & HI_WORD) >> 32LL;
uint64_t f = yi_high & LO_WORD;
uint64_t e = (yi_high & HI_WORD) >> 32LL;
uint64_t acc = d * h;
acc >>= 32LL;
uint64_t carry = 0;
uint64_t ac2 = acc + c * h;
if (ac2 < acc) {
carry++;
}
acc = ac2 + d * g;
if (acc < ac2) {
carry++;
}
ac2 = (acc >> 32LL) | (carry << 32LL);
carry = 0;
acc = ac2 + b * h;
if (acc < ac2) {
carry++;
}
ac2 = acc + c * g;
if (ac2 < acc) {
carry++;
}
acc = ac2 + d * f;
if (acc < ac2) {
carry++;
}
uint64_t o2 = acc & LO_WORD;
ac2 = (acc >> 32LL) | (carry << 32LL);
acc = ac2 + a * h;
ac2 = acc + b * g;
acc = ac2 + c * f;
ac2 = acc + d * e;
uint64_t rv2_hi = (ac2 << 32LL) | o2;
return rv2_hi;
}
#endif // !XE_COMPILER_MSVC
uint32_t IntCode_MUL_HI_I8_I8(IntCodeState& ics, const IntCode* i) {
int16_t v = (int16_t)ics.rf[i->src1_reg].i8 * (int16_t)ics.rf[i->src2_reg].i8;
ics.rf[i->dest_reg].i8 = (v >> 8);
return IA_NEXT;
}
uint32_t IntCode_MUL_HI_I16_I16(IntCodeState& ics, const IntCode* i) {
int32_t v =
(int32_t)ics.rf[i->src1_reg].i16 * (int32_t)ics.rf[i->src2_reg].i16;
ics.rf[i->dest_reg].i16 = (v >> 16);
return IA_NEXT;
}
uint32_t IntCode_MUL_HI_I32_I32(IntCodeState& ics, const IntCode* i) {
int64_t v =
(int64_t)ics.rf[i->src1_reg].i32 * (int64_t)ics.rf[i->src2_reg].i32;
ics.rf[i->dest_reg].i32 = (v >> 32);
return IA_NEXT;
}
uint32_t IntCode_MUL_HI_I64_I64(IntCodeState& ics, const IntCode* i) {
#if !XE_COMPILER_MSVC
// GCC can, in theory, do this:
__int128 v =
(__int128)ics.rf[i->src1_reg].i64 * (__int128)ics.rf[i->src2_reg].i64;
ics.rf[i->dest_reg].i64 = (v >> 64);
#else
// 128bit multiply, simplified for two input 64bit integers.
// http://mrob.com/pub/math/int128.c.txt
int64_t xi_low = ics.rf[i->src1_reg].i64;
int64_t xi_high = xi_low < 0 ? -1 : 0;
int64_t yi_low = ics.rf[i->src2_reg].i64;
int64_t yi_high = yi_low < 0 ? -1 : 0;
ics.rf[i->dest_reg].i64 = Mul128(xi_low, xi_high, yi_low, yi_high);
#endif // !MSVC
return IA_NEXT;
}
uint32_t IntCode_MUL_HI_I8_I8_U(IntCodeState& ics, const IntCode* i) {
uint16_t v =
(uint16_t)ics.rf[i->src1_reg].u8 * (uint16_t)ics.rf[i->src2_reg].u8;
ics.rf[i->dest_reg].u8 = (v >> 8);
return IA_NEXT;
}
uint32_t IntCode_MUL_HI_I16_I16_U(IntCodeState& ics, const IntCode* i) {
uint32_t v =
(uint32_t)ics.rf[i->src1_reg].u16 * (uint32_t)ics.rf[i->src2_reg].u16;
ics.rf[i->dest_reg].u16 = (v >> 16);
return IA_NEXT;
}
uint32_t IntCode_MUL_HI_I32_I32_U(IntCodeState& ics, const IntCode* i) {
uint64_t v =
(uint64_t)ics.rf[i->src1_reg].u32 * (uint64_t)ics.rf[i->src2_reg].u32;
ics.rf[i->dest_reg].u32 = (v >> 32);
return IA_NEXT;
}
uint32_t IntCode_MUL_HI_I64_I64_U(IntCodeState& ics, const IntCode* i) {
#if !XE_COMPILER_MSVC
// GCC can, in theory, do this:
__int128 v =
(__int128)ics.rf[i->src1_reg].i64 * (__int128)ics.rf[i->src2_reg].i64;
ics.rf[i->dest_reg].i64 = (v >> 64);
#else
// 128bit multiply, simplified for two input 64bit integers.
// http://mrob.com/pub/math/int128.c.txt
int64_t xi_low = ics.rf[i->src1_reg].i64;
int64_t xi_high = 0;
int64_t yi_low = ics.rf[i->src2_reg].i64;
int64_t yi_high = 0;
ics.rf[i->dest_reg].i64 = Mul128(xi_low, xi_high, yi_low, yi_high);
#endif // !MSVC
return IA_NEXT;
}
int Translate_MUL_HI(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_MUL_HI_I8_I8, IntCode_MUL_HI_I16_I16, IntCode_MUL_HI_I32_I32,
IntCode_MUL_HI_I64_I64, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE,
};
static IntCodeFn fns_unsigned[] = {
IntCode_MUL_HI_I8_I8_U, IntCode_MUL_HI_I16_I16_U,
IntCode_MUL_HI_I32_I32_U, IntCode_MUL_HI_I64_I64_U,
IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE,
};
if (i->flags & ARITHMETIC_UNSIGNED) {
return DispatchToC(ctx, i, fns_unsigned[i->dest->type]);
} else {
return DispatchToC(ctx, i, fns[i->dest->type]);
}
}
uint32_t IntCode_DIV_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_DIV_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_DIV_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_DIV_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_DIV_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_DIV_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_DIV_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;
}
uint32_t IntCode_DIV_I8_I8_U(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].u8 = ics.rf[i->src1_reg].u8 / ics.rf[i->src2_reg].u8;
return IA_NEXT;
}
uint32_t IntCode_DIV_I16_I16_U(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].u16 = ics.rf[i->src1_reg].u16 / ics.rf[i->src2_reg].u16;
return IA_NEXT;
}
uint32_t IntCode_DIV_I32_I32_U(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].u32 = ics.rf[i->src1_reg].u32 / ics.rf[i->src2_reg].u32;
return IA_NEXT;
}
uint32_t IntCode_DIV_I64_I64_U(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].u64 = ics.rf[i->src1_reg].u64 / ics.rf[i->src2_reg].u64;
return IA_NEXT;
}
int Translate_DIV(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_DIV_I8_I8, IntCode_DIV_I16_I16, IntCode_DIV_I32_I32,
IntCode_DIV_I64_I64, IntCode_DIV_F32_F32, IntCode_DIV_F64_F64,
IntCode_DIV_V128_V128,
};
static IntCodeFn fns_unsigned[] = {
IntCode_DIV_I8_I8_U, IntCode_DIV_I16_I16_U, IntCode_DIV_I32_I32_U,
IntCode_DIV_I64_I64_U, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE,
};
if (i->flags & ARITHMETIC_UNSIGNED) {
return DispatchToC(ctx, i, fns_unsigned[i->dest->type]);
} else {
return DispatchToC(ctx, i, fns[i->dest->type]);
}
}
// TODO(benvanik): use intrinsics or something
uint32_t IntCode_MUL_ADD_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_MUL_ADD_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_MUL_ADD_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_MUL_ADD_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_MUL_ADD_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].f32;
return IA_NEXT;
}
uint32_t IntCode_MUL_ADD_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].f64;
return IA_NEXT;
}
uint32_t IntCode_MUL_ADD_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_MUL_ADD(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_MUL_ADD_I8, IntCode_MUL_ADD_I16, IntCode_MUL_ADD_I32,
IntCode_MUL_ADD_I64, IntCode_MUL_ADD_F32, IntCode_MUL_ADD_F64,
IntCode_MUL_ADD_V128,
};
return DispatchToC(ctx, i, fns[i->dest->type]);
}
// TODO(benvanik): use intrinsics or something
uint32_t IntCode_MUL_SUB_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_MUL_SUB_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_MUL_SUB_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_MUL_SUB_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_MUL_SUB_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].f32;
return IA_NEXT;
}
uint32_t IntCode_MUL_SUB_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].f64;
return IA_NEXT;
}
uint32_t IntCode_MUL_SUB_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_MUL_SUB(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_MUL_SUB_I8, IntCode_MUL_SUB_I16, IntCode_MUL_SUB_I32,
IntCode_MUL_SUB_I64, IntCode_MUL_SUB_F32, IntCode_MUL_SUB_F64,
IntCode_MUL_SUB_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->src2_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->src2_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_SQRT_F32(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f32 = sqrt(ics.rf[i->src1_reg].f32);
return IA_NEXT;
}
uint32_t IntCode_SQRT_F64(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f64 = sqrt(ics.rf[i->src1_reg].f64);
return IA_NEXT;
}
uint32_t IntCode_SQRT_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] = sqrt(src1.f4[i]);
}
return IA_NEXT;
}
int Translate_SQRT(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE, IntCode_SQRT_F32, IntCode_SQRT_F64,
IntCode_SQRT_V128,
};
return DispatchToC(ctx, i, fns[i->dest->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_POW2_F32(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f32 = (float)pow(2, ics.rf[i->src1_reg].f32);
return IA_NEXT;
}
uint32_t IntCode_POW2_F64(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f64 = pow(2, ics.rf[i->src1_reg].f64);
return IA_NEXT;
}
uint32_t IntCode_POW2_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] = (float)pow(2, src1.f4[i]);
}
return IA_NEXT;
}
int Translate_POW2(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE, IntCode_POW2_F32, IntCode_POW2_F64,
IntCode_POW2_V128,
};
return DispatchToC(ctx, i, fns[i->dest->type]);
}
uint32_t IntCode_LOG2_F32(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f32 = log2(ics.rf[i->src1_reg].f32);
return IA_NEXT;
}
uint32_t IntCode_LOG2_F64(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].f64 = log2(ics.rf[i->src1_reg].f64);
return IA_NEXT;
}
uint32_t IntCode_LOG2_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] = log2(src1.f4[i]);
}
return IA_NEXT;
}
int Translate_LOG2(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE, IntCode_LOG2_F32, IntCode_LOG2_F64,
IntCode_LOG2_V128,
};
return DispatchToC(ctx, i, fns[i->dest->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++) {
VECI4(dest, n) = VECI4(src1, n) & VECI4(src2, 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++) {
VECI4(dest, n) = VECI4(src1, n) | VECI4(src2, 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++) {
VECI4(dest, n) = VECI4(src1, n) ^ VECI4(src2, 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++) {
VECI4(dest, n) = ~VECI4(src1, 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++) {
VECB16(dest, n) = VECB16(src1, n) << (VECB16(src2, 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++) {
VECS8(dest, n) = VECS8(src1, n) << (VECS8(src2, 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++) {
VECI4(dest, n) = VECI4(src1, n) << (VECI4(src2, 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_VECTOR_SHR_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++) {
VECB16(dest, n) = VECB16(src1, n) >> (VECB16(src2, n) & 0x7);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_SHR_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++) {
VECS8(dest, n) = VECS8(src1, n) >> (VECS8(src2, n) & 0xF);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_SHR_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++) {
VECI4(dest, n) = VECI4(src1, n) >> (VECI4(src2, n) & 0x1F);
}
return IA_NEXT;
}
int Translate_VECTOR_SHR(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_VECTOR_SHR_I8, IntCode_VECTOR_SHR_I16, IntCode_VECTOR_SHR_I32,
IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE,
};
return DispatchToC(ctx, i, fns[i->flags]);
}
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]);
}
uint32_t IntCode_VECTOR_SHA_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++) {
VECB16(dest, n) = int8_t(VECB16(src1, n)) >> (VECB16(src2, n) & 0x7);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_SHA_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++) {
VECS8(dest, n) = int16_t(VECS8(src1, n)) >> (VECS8(src2, n) & 0xF);
}
return IA_NEXT;
}
uint32_t IntCode_VECTOR_SHA_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++) {
VECI4(dest, n) = int32_t(VECI4(src1, n)) >> (VECI4(src2, n) & 0x1F);
}
return IA_NEXT;
}
int Translate_VECTOR_SHA(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_VECTOR_SHA_I8, IntCode_VECTOR_SHA_I16, IntCode_VECTOR_SHA_I32,
IntCode_INVALID_TYPE, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE,
};
return DispatchToC(ctx, i, fns[i->flags]);
}
uint32_t IntCode_ROTATE_LEFT_I8(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].i8 = poly::rotate_left<uint8_t>(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 = poly::rotate_left<uint16_t>(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) {
// TODO(benvanik): use _rtol on vc++
ics.rf[i->dest_reg].i32 = poly::rotate_left<uint32_t>(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) {
// TODO(benvanik): use _rtol64 on vc++
ics.rf[i->dest_reg].i64 = poly::rotate_left<uint64_t>(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]);
}
int Translate_VECTOR_ROTATE_LEFT(TranslationContext& ctx, Instr* i) {
assert_always();
return 1;
}
uint32_t IntCode_BYTE_SWAP_I16(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].i16 = poly::byte_swap(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 = poly::byte_swap(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 = poly::byte_swap(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;
for (int n = 0; n < 4; n++) {
VECI4(dest, n) = poly::byte_swap(VECI4(src1, n));
}
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
assert_always();
ics.rf[i->dest_reg].i8 = poly::lzcnt(ics.rf[i->src1_reg].i8);
return IA_NEXT;
}
uint32_t IntCode_CNTLZ_I16(IntCodeState& ics, const IntCode* i) {
// CHECK
assert_always();
ics.rf[i->dest_reg].i8 = poly::lzcnt(ics.rf[i->src1_reg].i16);
return IA_NEXT;
}
uint32_t IntCode_CNTLZ_I32(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].i8 = poly::lzcnt(ics.rf[i->src1_reg].i32);
return IA_NEXT;
}
uint32_t IntCode_CNTLZ_I64(IntCodeState& ics, const IntCode* i) {
ics.rf[i->dest_reg].i8 = poly::lzcnt(ics.rf[i->src1_reg].i64);
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 = VECB16(src1, ics.rf[i->src2_reg].i8);
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 = VECS8(src1, ics.rf[i->src2_reg].i8);
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 = VECI4(src1, ics.rf[i->src2_reg].i8);
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_INSERT_INT8_V128(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
const size_t offset = ics.rf[i->src2_reg].i64;
const uint8_t part = ics.rf[i->src3_reg].i8;
vec128_t& dest = ics.rf[i->dest_reg].v128;
for (size_t n = 0; n < 16; n++) {
VECB16(dest, n) = (n == offset) ? part : VECB16(src1, n);
}
return IA_NEXT;
}
uint32_t IntCode_INSERT_INT16_V128(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
const size_t offset = ics.rf[i->src2_reg].i64;
const uint16_t part = ics.rf[i->src3_reg].i16;
vec128_t& dest = ics.rf[i->dest_reg].v128;
for (size_t n = 0; n < 8; n++) {
VECS8(dest, n) = (n == offset) ? part : VECS8(src1, n);
}
return IA_NEXT;
}
uint32_t IntCode_INSERT_INT32_V128(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
const size_t offset = ics.rf[i->src2_reg].i64;
const uint32_t part = ics.rf[i->src3_reg].i32;
vec128_t& dest = ics.rf[i->dest_reg].v128;
for (size_t n = 0; n < 4; n++) {
VECI4(dest, n) = (n == offset) ? part : VECI4(src1, n);
}
return IA_NEXT;
}
int Translate_INSERT(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_INSERT_INT8_V128, IntCode_INSERT_INT16_V128,
IntCode_INSERT_INT32_V128, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE,
};
IntCodeFn fn = fns[i->src1.value->type * MAX_TYPENAME + i->src3.value->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++) {
VECB16(dest, 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++) {
VECS8(dest, 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++) {
VECI4(dest, 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 table = 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++) {
size_t b = (table >> ((3 - i) * 8)) & 0x7;
VECI4(dest, i) = b < 4 ? VECI4(src2, b) : VECI4(src3, b - 4);
}
return IA_NEXT;
}
uint32_t IntCode_PERMUTE_V128_BY_V128(IntCodeState& ics, const IntCode* i) {
const vec128_t& table = 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;
dest.low = dest.high = 0;
for (size_t n = 0; n < 16; n++) {
uint8_t index = VECB16(table, n) & 0x1F;
VECB16(dest, n) =
index < 16 ? VECB16(src2, index) : VECB16(src3, index - 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_V128,
};
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;
uint32_t swizzle_mask = ics.rf[i->src2_reg].u32;
vec128_t& dest = ics.rf[i->dest_reg].v128;
VECI4(dest, 0) = VECI4(src1, (swizzle_mask >> 6) & 0x3);
VECI4(dest, 1) = VECI4(src1, (swizzle_mask >> 4) & 0x3);
VECI4(dest, 2) = VECI4(src1, (swizzle_mask >> 2) & 0x3);
VECI4(dest, 3) = VECI4(src1, (swizzle_mask)&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]);
}
uint32_t IntCode_PACK_D3DCOLOR(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
// RGBA (XYZW) -> ARGB (WXYZ)
dest.ix = dest.iy = dest.iz = 0;
float r = roundf(((src1.x < 0) ? 0 : ((1 < src1.x) ? 1 : src1.x)) * 255);
float g = roundf(((src1.y < 0) ? 0 : ((1 < src1.y) ? 1 : src1.y)) * 255);
float b = roundf(((src1.z < 0) ? 0 : ((1 < src1.z) ? 1 : src1.z)) * 255);
float a = roundf(((src1.w < 0) ? 0 : ((1 < src1.w) ? 1 : src1.w)) * 255);
dest.iw = ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) |
((uint32_t)b);
return IA_NEXT;
}
uint32_t IntCode_PACK_FLOAT16_2(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.ix = dest.iy = dest.iz = 0;
dest.iw = (uint32_t(poly::float_to_half(src1.x)) << 16) |
poly::float_to_half(src1.y);
return IA_NEXT;
}
uint32_t IntCode_PACK_FLOAT16_4(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.ix = dest.iy = 0;
dest.iz = (uint32_t(poly::float_to_half(src1.x)) << 16) |
poly::float_to_half(src1.y);
dest.iw = (uint32_t(poly::float_to_half(src1.z)) << 16) |
poly::float_to_half(src1.w);
return IA_NEXT;
}
uint32_t IntCode_PACK_SHORT_2(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
// sx = 3 + (x / 1<<22)
// x = (sx - 3) * 1<<22
float sx = src1.x;
float sy = src1.y;
union {
int16_t dx;
int16_t dy;
};
dx = (int16_t)((sx - 3.0f) * (float)(1 << 22));
dy = (int16_t)((sy - 3.0f) * (float)(1 << 22));
dest.ix = dest.iy = dest.iz = 0;
dest.iw = ((uint32_t)dx << 16) | dy;
return IA_NEXT;
}
int Translate_PACK(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_PACK_D3DCOLOR, IntCode_PACK_FLOAT16_2, IntCode_PACK_FLOAT16_4,
IntCode_PACK_SHORT_2, IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
};
return DispatchToC(ctx, i, fns[i->flags]);
}
uint32_t IntCode_UNPACK_D3DCOLOR(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
// ARGB (WXYZ) -> RGBA (XYZW)
// XMLoadColor
int32_t src = (int32_t)src1.iw;
dest.f4[0] = (float)((src >> 16) & 0xFF) * (1.0f / 255.0f);
dest.f4[1] = (float)((src >> 8) & 0xFF) * (1.0f / 255.0f);
dest.f4[2] = (float)(src & 0xFF) * (1.0f / 255.0f);
dest.f4[3] = (float)((src >> 24) & 0xFF) * (1.0f / 255.0f);
return IA_NEXT;
}
uint32_t IntCode_UNPACK_FLOAT16_2(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 src = src1.iw;
for (int n = 0; n < 2; n++) {
dest.f4[n] = poly::half_to_float(uint16_t(src));
src >>= 16;
}
dest.f4[2] = 0.0f;
dest.f4[3] = 1.0f;
return IA_NEXT;
}
uint32_t IntCode_UNPACK_FLOAT16_4(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
uint64_t src = src1.iz | ((uint64_t)src1.iw << 32);
for (int n = 0; n < 4; n++) {
dest.f4[n] = poly::half_to_float(uint16_t(src));
src >>= 16;
}
return IA_NEXT;
}
uint32_t IntCode_UNPACK_SHORT_2(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
// XMLoadShortN2
union {
int16_t sx;
int16_t sy;
};
sx = (int16_t)(src1.iw >> 16);
sy = (int16_t)src1.iw;
dest.f4[0] = 3.0f + ((float)sx / (float)(1 << 22));
dest.f4[1] = 3.0f + ((float)sy / (float)(1 << 22));
dest.f4[2] = 0.0f;
dest.f4[3] = 1.0f; // 3?
return IA_NEXT;
}
uint32_t IntCode_UNPACK_S8_IN_16_LO(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
VECS8(dest, 0) = (int16_t)(int8_t)VECB16(src1, 8 + 0);
VECS8(dest, 1) = (int16_t)(int8_t)VECB16(src1, 8 + 1);
VECS8(dest, 2) = (int16_t)(int8_t)VECB16(src1, 8 + 2);
VECS8(dest, 3) = (int16_t)(int8_t)VECB16(src1, 8 + 3);
VECS8(dest, 4) = (int16_t)(int8_t)VECB16(src1, 8 + 4);
VECS8(dest, 5) = (int16_t)(int8_t)VECB16(src1, 8 + 5);
VECS8(dest, 6) = (int16_t)(int8_t)VECB16(src1, 8 + 6);
VECS8(dest, 7) = (int16_t)(int8_t)VECB16(src1, 8 + 7);
return IA_NEXT;
}
uint32_t IntCode_UNPACK_S8_IN_16_HI(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
VECS8(dest, 0) = (int16_t)(int8_t)VECB16(src1, 0);
VECS8(dest, 1) = (int16_t)(int8_t)VECB16(src1, 1);
VECS8(dest, 2) = (int16_t)(int8_t)VECB16(src1, 2);
VECS8(dest, 3) = (int16_t)(int8_t)VECB16(src1, 3);
VECS8(dest, 4) = (int16_t)(int8_t)VECB16(src1, 4);
VECS8(dest, 5) = (int16_t)(int8_t)VECB16(src1, 5);
VECS8(dest, 6) = (int16_t)(int8_t)VECB16(src1, 6);
VECS8(dest, 7) = (int16_t)(int8_t)VECB16(src1, 7);
return IA_NEXT;
}
uint32_t IntCode_UNPACK_S16_IN_32_LO(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
VECI4(dest, 0) = (int32_t)(int16_t)VECS8(src1, 4 + 0);
VECI4(dest, 1) = (int32_t)(int16_t)VECS8(src1, 4 + 1);
VECI4(dest, 2) = (int32_t)(int16_t)VECS8(src1, 4 + 2);
VECI4(dest, 3) = (int32_t)(int16_t)VECS8(src1, 4 + 3);
return IA_NEXT;
}
uint32_t IntCode_UNPACK_S16_IN_32_HI(IntCodeState& ics, const IntCode* i) {
const vec128_t& src1 = ics.rf[i->src1_reg].v128;
vec128_t& dest = ics.rf[i->dest_reg].v128;
VECI4(dest, 0) = (int32_t)(int16_t)VECS8(src1, 0);
VECI4(dest, 1) = (int32_t)(int16_t)VECS8(src1, 1);
VECI4(dest, 2) = (int32_t)(int16_t)VECS8(src1, 2);
VECI4(dest, 3) = (int32_t)(int16_t)VECS8(src1, 3);
return IA_NEXT;
}
int Translate_UNPACK(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_UNPACK_D3DCOLOR, IntCode_UNPACK_FLOAT16_2,
IntCode_UNPACK_FLOAT16_4, IntCode_UNPACK_SHORT_2,
IntCode_UNPACK_S8_IN_16_LO, IntCode_UNPACK_S8_IN_16_HI,
IntCode_UNPACK_S16_IN_32_LO, IntCode_UNPACK_S16_IN_32_HI,
};
return DispatchToC(ctx, i, fns[i->flags]);
}
uint32_t IntCode_ATOMIC_EXCHANGE_I32(IntCodeState& ics, const IntCode* i) {
auto address = (uint32_t*)ics.rf[i->src1_reg].u64;
auto new_value = ics.rf[i->src2_reg].u32;
auto old_value = poly::atomic_exchange(new_value, address);
ics.rf[i->dest_reg].u32 = old_value;
return IA_NEXT;
}
uint32_t IntCode_ATOMIC_EXCHANGE_I64(IntCodeState& ics, const IntCode* i) {
auto address = (uint64_t*)ics.rf[i->src1_reg].u64;
auto new_value = ics.rf[i->src2_reg].u64;
auto old_value = poly::atomic_exchange(new_value, address);
ics.rf[i->dest_reg].u64 = old_value;
return IA_NEXT;
}
int Translate_ATOMIC_EXCHANGE(TranslationContext& ctx, Instr* i) {
static IntCodeFn fns[] = {
IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_ATOMIC_EXCHANGE_I32, IntCode_ATOMIC_EXCHANGE_I64,
IntCode_INVALID_TYPE, IntCode_INVALID_TYPE,
IntCode_INVALID_TYPE,
};
return DispatchToC(ctx, i, fns[i->src2.value->type]);
}
typedef int (*TranslateFn)(TranslationContext& ctx, Instr* i);
static const TranslateFn dispatch_table[] = {
Translate_COMMENT, Translate_NOP,
Translate_SOURCE_OFFSET, 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_CALL_EXTERN,
Translate_RETURN, Translate_RETURN_TRUE,
Translate_SET_RETURN_ADDRESS, Translate_BRANCH,
Translate_BRANCH_TRUE, Translate_BRANCH_FALSE,
Translate_ASSIGN, Translate_CAST,
Translate_ZERO_EXTEND, Translate_SIGN_EXTEND,
Translate_TRUNCATE, Translate_CONVERT,
Translate_ROUND, Translate_VECTOR_CONVERT_I2F,
Translate_VECTOR_CONVERT_F2I, Translate_LOAD_VECTOR_SHL,
Translate_LOAD_VECTOR_SHR, Translate_LOAD_CLOCK,
Translate_LOAD_LOCAL, Translate_STORE_LOCAL,
Translate_LOAD_CONTEXT, Translate_STORE_CONTEXT,
Translate_LOAD, Translate_STORE,
Translate_PREFETCH, Translate_MAX,
Translate_VECTOR_MAX, Translate_MIN,
Translate_VECTOR_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_DID_SATURATE, 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_VECTOR_ADD, Translate_SUB,
Translate_VECTOR_SUB, Translate_MUL,
Translate_MUL_HI, Translate_DIV,
Translate_MUL_ADD, Translate_MUL_SUB,
Translate_NEG, Translate_ABS,
Translate_SQRT, Translate_RSQRT,
Translate_POW2, Translate_LOG2,
Translate_DOT_PRODUCT_3, Translate_DOT_PRODUCT_4,
Translate_AND, Translate_OR,
Translate_XOR, Translate_NOT,
Translate_SHL, Translate_VECTOR_SHL,
Translate_SHR, Translate_VECTOR_SHR,
Translate_SHA, Translate_VECTOR_SHA,
Translate_ROTATE_LEFT, Translate_VECTOR_ROTATE_LEFT,
Translate_BYTE_SWAP, Translate_CNTLZ,
Translate_INSERT, Translate_EXTRACT,
Translate_SPLAT, Translate_PERMUTE,
Translate_SWIZZLE, Translate_PACK,
Translate_UNPACK,
TranslateInvalid, // Translate_COMPARE_EXCHANGE,
Translate_ATOMIC_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