diff --git a/desmume/src/Makefile.am b/desmume/src/Makefile.am index 03f9e1819..be69586f5 100644 --- a/desmume/src/Makefile.am +++ b/desmume/src/Makefile.am @@ -95,40 +95,74 @@ libdesmume_a_SOURCES = \ if HAVE_JIT libdesmume_a_SOURCES += \ arm_jit.cpp arm_jit.h instruction_attributes.h \ - utils/AsmJit/ApiBegin.h \ - utils/AsmJit/ApiEnd.h \ - utils/AsmJit/AsmJit.h \ - utils/AsmJit/Assembler.h \ - utils/AsmJit/AssemblerX86X64.cpp \ - utils/AsmJit/AssemblerX86X64.h \ - utils/AsmJit/Build.h \ - utils/AsmJit/CodeGenerator.cpp \ - utils/AsmJit/CodeGenerator.h \ - utils/AsmJit/Compiler.cpp \ - utils/AsmJit/Compiler.h \ - utils/AsmJit/CompilerX86X64.cpp \ - utils/AsmJit/CompilerX86X64.h \ - utils/AsmJit/Config.h \ - utils/AsmJit/CpuInfo.cpp \ - utils/AsmJit/CpuInfo.h \ - utils/AsmJit/Defs.cpp \ - utils/AsmJit/Defs.h \ - utils/AsmJit/DefsX86X64.cpp \ - utils/AsmJit/DefsX86X64.h \ - utils/AsmJit/Logger.cpp \ - utils/AsmJit/Logger.h \ - utils/AsmJit/MemoryManager.cpp \ - utils/AsmJit/MemoryManager.h \ - utils/AsmJit/MemoryMarker.cpp \ - utils/AsmJit/MemoryMarker.h \ - utils/AsmJit/Operand.h \ - utils/AsmJit/OperandX86X64.cpp \ - utils/AsmJit/OperandX86X64.h \ - utils/AsmJit/Platform.cpp \ - utils/AsmJit/Platform.h \ - utils/AsmJit/Util.cpp \ - utils/AsmJit/Util.h \ - utils/AsmJit/Util_p.h + utils/AsmJit/asmjit.h \ + utils/AsmJit/config.h \ + utils/AsmJit/core.h \ + utils/AsmJit/x86.h \ + utils/AsmJit/core/apibegin.h \ + utils/AsmJit/core/apiend.h \ + utils/AsmJit/core/assembler.cpp \ + utils/AsmJit/core/assembler.h \ + utils/AsmJit/core/assert.cpp \ + utils/AsmJit/core/assert.h \ + utils/AsmJit/core/buffer.cpp \ + utils/AsmJit/core/buffer.h \ + utils/AsmJit/core/build.h \ + utils/AsmJit/core/compiler.cpp \ + utils/AsmJit/core/compiler.h \ + utils/AsmJit/core/compilercontext.cpp \ + utils/AsmJit/core/compilercontext.h \ + utils/AsmJit/core/compilerfunc.cpp \ + utils/AsmJit/core/compilerfunc.h \ + utils/AsmJit/core/compileritem.cpp \ + utils/AsmJit/core/compileritem.h \ + utils/AsmJit/core/context.cpp \ + utils/AsmJit/core/context.h \ + utils/AsmJit/core/cpuinfo.cpp \ + utils/AsmJit/core/cpuinfo.h \ + utils/AsmJit/core/defs.cpp \ + utils/AsmJit/core/defs.h \ + utils/AsmJit/core/func.cpp \ + utils/AsmJit/core/func.h \ + utils/AsmJit/core/intutil.h \ + utils/AsmJit/core/lock.h \ + utils/AsmJit/core/logger.cpp \ + utils/AsmJit/core/logger.h \ + utils/AsmJit/core/memorymanager.cpp \ + utils/AsmJit/core/memorymanager.h \ + utils/AsmJit/core/memorymarker.cpp \ + utils/AsmJit/core/memorymarker.h \ + utils/AsmJit/core/operand.cpp \ + utils/AsmJit/core/operand.h \ + utils/AsmJit/core/podvector.h \ + utils/AsmJit/core/stringbuilder.cpp \ + utils/AsmJit/core/stringbuilder.h \ + utils/AsmJit/core/stringutil.cpp \ + utils/AsmJit/core/stringutil.h \ + utils/AsmJit/core/virtualmemory.cpp \ + utils/AsmJit/core/virtualmemory.h \ + utils/AsmJit/core/zonememory.cpp \ + utils/AsmJit/core/zonememory.h \ + utils/AsmJit/x86/x86assembler.cpp \ + utils/AsmJit/x86/x86assembler.h \ + utils/AsmJit/x86/x86compiler.cpp \ + utils/AsmJit/x86/x86compiler.h \ + utils/AsmJit/x86/x86compilercontext.cpp \ + utils/AsmJit/x86/x86compilercontext.h \ + utils/AsmJit/x86/x86compilerfunc.cpp \ + utils/AsmJit/x86/x86compilerfunc.h \ + utils/AsmJit/x86/x86compileritem.cpp \ + utils/AsmJit/x86/x86compileritem.h \ + utils/AsmJit/x86/x86cpuinfo.cpp \ + utils/AsmJit/x86/x86cpuinfo.h \ + utils/AsmJit/x86/x86defs.cpp \ + utils/AsmJit/x86/x86defs.h \ + utils/AsmJit/x86/x86func.cpp \ + utils/AsmJit/x86/x86func.h \ + utils/AsmJit/x86/x86operand.cpp \ + utils/AsmJit/x86/x86operand.h \ + utils/AsmJit/x86/x86util.cpp \ + utils/AsmJit/x86/x86util.h endif if HAVE_GL diff --git a/desmume/src/arm_jit.cpp b/desmume/src/arm_jit.cpp index ec62fd094..5ee801746 100644 --- a/desmume/src/arm_jit.cpp +++ b/desmume/src/arm_jit.cpp @@ -35,7 +35,7 @@ #include "Disassembler.h" #include "MMU.h" #include "MMU_timing.h" -#include "utils/AsmJit/AsmJit.h" +#include "utils/AsmJit/asmjit.h" #include "arm_jit.h" #include "bios.h" @@ -217,9 +217,9 @@ struct ASMJIT_API StaticCodeGenerator : public CodeGenerator }; static StaticCodeGenerator codegen; -static Compiler c(&codegen); +static X86Compiler c(&codegen); #else -static Compiler c; +static X86Compiler c; #endif static void emit_branch(int cond, Label to); @@ -232,9 +232,9 @@ static int *PROCNUM_ptr = &PROCNUM; static int bb_opcodesize; static int bb_adr; static bool bb_thumb; -static GPVar bb_cpu; -static GPVar bb_cycles; -static GPVar total_cycles; +static GpVar bb_cpu; +static GpVar bb_cycles; +static GpVar total_cycles; #define cpu (&ARMPROC) #define bb_next_instruction (bb_adr + bb_opcodesize) @@ -261,8 +261,8 @@ static GPVar total_cycles; // sequencer.reschedule = true; #define changeCPSR { \ - ECall* ctxCPSR = c.call((void*)NDS_Reschedule); \ - ctxCPSR->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder0()); \ + X86CompilerFuncCall* ctxCPSR = c.call((void*)NDS_Reschedule); \ + ctxCPSR->setPrototype(ASMJIT_CALL_CONV, FuncBuilder0()); \ } #if (PROFILER_JIT_LEVEL > 0) @@ -284,7 +284,7 @@ struct JIT_PROFILER u64 thumb_count[1024]; } profiler_counter[2]; -static GPVar bb_profiler; +static GpVar bb_profiler; #define profiler_counter_arm(opcode) qword_ptr(bb_profiler, offsetof(JIT_PROFILER, arm_count[INSTRUCTION_INDEX(opcode)])) #define profiler_counter_thumb(opcode) qword_ptr(bb_profiler, offsetof(JIT_PROFILER, thumb_count[opcode>>6])) @@ -296,7 +296,7 @@ struct PROFILER_ENTRY u32 cycles; } profiler_entry[2][1<<26]; -static GPVar bb_profiler_entry; +static GpVar bb_profiler_entry; #endif #endif @@ -305,15 +305,15 @@ static GPVar bb_profiler_entry; //----------------------------------------------------------------------------- #define SET_NZCV(sign) { \ JIT_COMMENT("SET_NZCV"); \ - GPVar x = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar y = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar x = c.newGpVar(kX86VarTypeGpd); \ + GpVar y = c.newGpVar(kX86VarTypeGpd); \ c.sets(x.r8Lo()); \ c.setz(y.r8Lo()); \ - c.lea(x, ptr(y.r64(), x.r64(), TIMES_2)); \ - c.set(sign ? C_NC : C_C, y.r8Lo()); \ - c.lea(x, ptr(y.r64(), x.r64(), TIMES_2)); \ + c.lea(x, ptr(y.r64(), x.r64(), kScale2Times)); \ + if (sign) { c.setnc(y.r8Lo()); } else { c.setc(y.r8Lo()); } \ + c.lea(x, ptr(y.r64(), x.r64(), kScale2Times)); \ c.seto(y.r8Lo()); \ - c.lea(x, ptr(y.r64(), x.r64(), TIMES_2)); \ + c.lea(x, ptr(y.r64(), x.r64(), kScale2Times)); \ c.movzx(y, flags_ptr); \ c.shl(x, 4); \ c.and_(y, 0xF); \ @@ -326,12 +326,12 @@ static GPVar bb_profiler_entry; #define SET_NZC { \ JIT_COMMENT("SET_NZC"); \ - GPVar x = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar y = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar x = c.newGpVar(kX86VarTypeGpd); \ + GpVar y = c.newGpVar(kX86VarTypeGpd); \ c.sets(x.r8Lo()); \ c.setz(y.r8Lo()); \ - c.lea(x, ptr(y.r64(), x.r64(), TIMES_2)); \ - if (cf_change) { c.lea(x, ptr(rcf.r64(), x.r64(), TIMES_2)); c.unuse(rcf); } \ + c.lea(x, ptr(y.r64(), x.r64(), kScale2Times)); \ + if (cf_change) { c.lea(x, ptr(rcf.r64(), x.r64(), kScale2Times)); c.unuse(rcf); } \ c.movzx(y, flags_ptr); \ c.shl(x, 6 - cf_change); \ c.and_(y, cf_change?0x1F:0x3F); \ @@ -356,11 +356,11 @@ static GPVar bb_profiler_entry; #define SET_NZ(clear_cv) { \ JIT_COMMENT("SET_NZ"); \ - GPVar x = c.newGP(VARIABLE_TYPE_GPN); \ - GPVar y = c.newGP(VARIABLE_TYPE_GPN); \ + GpVar x = c.newGpVar(kX86VarTypeGpz); \ + GpVar y = c.newGpVar(kX86VarTypeGpz); \ c.sets(x.r8Lo()); \ c.setz(y.r8Lo()); \ - c.lea(x, ptr(y.r64(), x.r64(), TIMES_2)); \ + c.lea(x, ptr(y.r64(), x.r64(), kScale2Times)); \ c.movzx(y, flags_ptr); \ c.and_(y, clear_cv?0x0F:0x3F); \ c.shl(x, 6); \ @@ -371,7 +371,7 @@ static GPVar bb_profiler_entry; #define SET_Q { \ JIT_COMMENT("SET_Q"); \ - GPVar x = c.newGP(VARIABLE_TYPE_GPN); \ + GpVar x = c.newGpVar(kX86VarTypeGpz); \ c.seto(x.r8Lo()); \ c.shl(x, 3); \ c.or_(flags_ptr, x.r8Lo()); \ @@ -380,19 +380,19 @@ static GPVar bb_profiler_entry; #define S_DST_R15 { \ JIT_COMMENT("S_DST_R15"); \ - GPVar SPSR = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar SPSR = c.newGpVar(kX86VarTypeGpd); \ + GpVar tmp = c.newGpVar(kX86VarTypeGpd); \ c.mov(SPSR, cpu_ptr(SPSR.val)); \ c.mov(tmp, SPSR); \ c.and_(tmp, 0x1F); \ - ECall* ctx = c.call((void*)armcpu_switchMode); \ - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder2()); \ + X86CompilerFuncCall* ctx = c.call((void*)armcpu_switchMode); \ + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); \ ctx->setArgument(0, bb_cpu); \ ctx->setArgument(1, tmp); \ c.mov(cpu_ptr(CPSR.val), SPSR); \ c.and_(SPSR, (1<<5)); \ c.shr(SPSR, 5); \ - c.lea(tmp, ptr_abs((void*)0xFFFFFFFC, SPSR.r64(), TIMES_2)); \ + c.lea(tmp, ptr_abs((void*)0xFFFFFFFC, SPSR.r64(), kScale2Times)); \ c.and_(tmp, reg_ptr(15)); \ c.mov(cpu_ptr(next_instruction), tmp); \ c.unuse(tmp); \ @@ -404,7 +404,7 @@ static GPVar bb_profiler_entry; JIT_COMMENT("LSL_IMM"); \ bool rhs_is_imm = false; \ u32 imm = ((i>>7)&0x1F); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ c.mov(rhs, reg_pos_ptr(0)); \ if(imm) c.shl(rhs, imm); \ u32 rhs_first = cpu->R[REG_POS(i,0)] << imm; @@ -413,15 +413,15 @@ static GPVar bb_profiler_entry; JIT_COMMENT("S_LSL_IMM"); \ bool rhs_is_imm = false; \ u8 cf_change = 0; \ - GPVar rcf; \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar rcf; \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ u32 imm = ((i>>7)&0x1F); \ c.mov(rhs, reg_pos_ptr(0)); \ if (imm) \ { \ cf_change = 1; \ c.shl(rhs, imm); \ - rcf = c.newGP(VARIABLE_TYPE_GPD); \ + rcf = c.newGpVar(kX86VarTypeGpd); \ c.setc(rcf.r8Lo()); \ } @@ -429,7 +429,7 @@ static GPVar bb_profiler_entry; JIT_COMMENT("LSR_IMM"); \ bool rhs_is_imm = false; \ u32 imm = ((i>>7)&0x1F); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ if(imm) \ { \ c.mov(rhs, reg_pos_ptr(0)); \ @@ -443,8 +443,8 @@ static GPVar bb_profiler_entry; JIT_COMMENT("S_LSR_IMM"); \ bool rhs_is_imm = false; \ u8 cf_change = 1; \ - GPVar rcf = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar rcf = c.newGpVar(kX86VarTypeGpd); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ u32 imm = ((i>>7)&0x1F); \ c.mov(rhs, reg_pos_ptr(0)); \ if (!imm) \ @@ -463,7 +463,7 @@ static GPVar bb_profiler_entry; JIT_COMMENT("ASR_IMM"); \ bool rhs_is_imm = false; \ u32 imm = ((i>>7)&0x1F); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ c.mov(rhs, reg_pos_ptr(0)); \ if(!imm) imm = 31; \ c.sar(rhs, imm); \ @@ -473,8 +473,8 @@ static GPVar bb_profiler_entry; JIT_COMMENT("S_ASR_IMM"); \ bool rhs_is_imm = false; \ u8 cf_change = 1; \ - GPVar rcf = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar rcf = c.newGpVar(kX86VarTypeGpd); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ u32 imm = ((i>>7)&0x1F); \ c.mov(rhs, reg_pos_ptr(0)); \ if (!imm) imm = 31; \ @@ -485,7 +485,7 @@ static GPVar bb_profiler_entry; JIT_COMMENT("ROR_IMM"); \ bool rhs_is_imm = false; \ u32 imm = ((i>>7)&0x1F); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ c.mov(rhs, reg_pos_ptr(0)); \ if (!imm) \ { \ @@ -500,8 +500,8 @@ static GPVar bb_profiler_entry; JIT_COMMENT("S_ROR_IMM"); \ bool rhs_is_imm = false; \ u8 cf_change = 1; \ - GPVar rcf = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar rcf = c.newGpVar(kX86VarTypeGpd); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ u32 imm = ((i>>7)&0x1F); \ c.mov(rhs, reg_pos_ptr(0)); \ if (!imm) \ @@ -529,12 +529,12 @@ static GPVar bb_profiler_entry; JIT_COMMENT("S_IMM_VAL"); \ bool rhs_is_imm = true; \ u8 cf_change = 0; \ - GPVar rcf; \ + GpVar rcf; \ u32 rhs = ROR((i&0xFF), (i>>7)&0x1E); \ if ((i>>8)&0xF) \ { \ cf_change = 1; \ - rcf = c.newGP(VARIABLE_TYPE_GPD); \ + rcf = c.newGpVar(kX86VarTypeGpd); \ c.mov(rcf, BIT31(rhs)); \ } \ u32 rhs_first = rhs; @@ -555,9 +555,9 @@ static GPVar bb_profiler_entry; #define LSX_REG(name, x86inst, sign) \ JIT_COMMENT(#name); \ bool rhs_is_imm = false; \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar imm = c.newGP(VARIABLE_TYPE_GPN); \ - GPVar tmp = c.newGP(VARIABLE_TYPE_GPN); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ + GpVar imm = c.newGpVar(kX86VarTypeGpz); \ + GpVar tmp = c.newGpVar(kX86VarTypeGpz); \ if(sign) c.mov(tmp, 31); \ else c.mov(tmp, 0); \ c.movzx(imm, reg_pos_ptrB(8)); \ @@ -572,9 +572,9 @@ static GPVar bb_profiler_entry; JIT_COMMENT(#name); \ bool rhs_is_imm = false; \ u8 cf_change = 1; \ - GPVar rcf = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar imm = c.newGP(VARIABLE_TYPE_GPN); \ + GpVar rcf = c.newGpVar(kX86VarTypeGpd); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ + GpVar imm = c.newGpVar(kX86VarTypeGpz); \ Label __zero = c.newLabel(); \ Label __lt32 = c.newLabel(); \ Label __done = c.newLabel(); \ @@ -621,8 +621,8 @@ static GPVar bb_profiler_entry; #define ROR_REG \ JIT_COMMENT("ROR_REG"); \ bool rhs_is_imm = false; \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar imm = c.newGP(VARIABLE_TYPE_GPN); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ + GpVar imm = c.newGpVar(kX86VarTypeGpz); \ c.mov(rhs, reg_pos_ptr(0)); \ c.mov(imm, reg_pos_ptrB(8)); \ c.ror(rhs, imm.r8Lo()); @@ -631,9 +631,9 @@ static GPVar bb_profiler_entry; JIT_COMMENT("S_ROR_REG"); \ bool rhs_is_imm = false; \ bool cf_change = 1; \ - GPVar rcf = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar imm = c.newGP(VARIABLE_TYPE_GPN); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar rcf = c.newGpVar(kX86VarTypeGpd); \ + GpVar imm = c.newGpVar(kX86VarTypeGpz); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ Label __zero = c.newLabel(); \ Label __zero_1F = c.newLabel(); \ Label __done = c.newLabel(); \ @@ -660,13 +660,13 @@ static GPVar bb_profiler_entry; c.bind(__done); //==================================================================== common funcs -static void emit_MMU_aluMemCycles(int alu_cycles, GPVar mem_cycles, int population) +static void emit_MMU_aluMemCycles(int alu_cycles, GpVar mem_cycles, int population) { if(PROCNUM==ARMCPU_ARM9) { if(population < alu_cycles) { - GPVar x = c.newGP(VARIABLE_TYPE_GPD); + GpVar x = c.newGpVar(kX86VarTypeGpd); c.mov(x, alu_cycles); c.cmp(mem_cycles, alu_cycles); c.cmovl(mem_cycles, x); @@ -681,12 +681,12 @@ static void emit_MMU_aluMemCycles(int alu_cycles, GPVar mem_cycles, int populati //----------------------------------------------------------------------------- #define OP_ARITHMETIC(arg, x86inst, symmetric, flags) \ arg; \ - GPVar lhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar lhs = c.newGpVar(kX86VarTypeGpd); \ if(REG_POS(i,12) == REG_POS(i,16)) \ c.x86inst(reg_pos_ptr(12), rhs); \ else if(symmetric && !rhs_is_imm) \ { \ - c.x86inst(*(GPVar*)&rhs, reg_pos_ptr(16)); \ + c.x86inst(*(GpVar*)&rhs, reg_pos_ptr(16)); \ c.mov(reg_pos_ptr(12), rhs); \ } \ else \ @@ -709,7 +709,7 @@ static void emit_MMU_aluMemCycles(int alu_cycles, GPVar mem_cycles, int populati { \ if(REG_POS(i,12)==15) \ { \ - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar tmp = c.newGpVar(kX86VarTypeGpd); \ c.mov(tmp, reg_ptr(15)); \ c.mov(cpu_ptr(next_instruction), tmp); \ c.add(total_cycles, 2); \ @@ -719,7 +719,7 @@ static void emit_MMU_aluMemCycles(int alu_cycles, GPVar mem_cycles, int populati #define OP_ARITHMETIC_R(arg, x86inst, flags) \ arg; \ - GPVar lhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar lhs = c.newGpVar(kX86VarTypeGpd); \ c.mov(lhs, rhs); \ c.x86inst(lhs, reg_pos_ptr(16)); \ c.mov(reg_pos_ptr(12), lhs); \ @@ -737,7 +737,7 @@ static void emit_MMU_aluMemCycles(int alu_cycles, GPVar mem_cycles, int populati { \ if(REG_POS(i,12)==15) \ { \ - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar tmp = c.newGpVar(kX86VarTypeGpd); \ c.mov(cpu_ptr(next_instruction), lhs); \ c.add(total_cycles, 2); \ } \ @@ -750,12 +750,12 @@ static void emit_MMU_aluMemCycles(int alu_cycles, GPVar mem_cycles, int populati c.x86inst(reg_pos_ptr(12), rhs); \ else if(symmetric && !rhs_is_imm) \ { \ - c.x86inst(*(GPVar*)&rhs, reg_pos_ptr(16)); \ + c.x86inst(*(GpVar*)&rhs, reg_pos_ptr(16)); \ c.mov(reg_pos_ptr(12), rhs); \ } \ else \ { \ - GPVar lhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar lhs = c.newGpVar(kX86VarTypeGpd); \ c.mov(lhs, reg_pos_ptr(16)); \ c.x86inst(lhs, rhs); \ c.mov(reg_pos_ptr(12), lhs); \ @@ -999,10 +999,10 @@ static int OP_TST_IMM_VAL(const u32 i) { OP_TST_(S_IMM_VAL); } #define OP_TEQ_(arg) \ arg; \ if (!rhs_is_imm) \ - c.xor_(*(GPVar*)&rhs, reg_pos_ptr(16)); \ + c.xor_(*(GpVar*)&rhs, reg_pos_ptr(16)); \ else \ { \ - GPVar x = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar x = c.newGpVar(kX86VarTypeGpd); \ c.mov(x, rhs); \ c.xor_(x, reg_pos_ptr(16)); \ } \ @@ -1050,7 +1050,7 @@ static int OP_CMP_IMM_VAL(const u32 i) { OP_CMP(IMM_VAL); } c.cmp(reg_pos_ptr(16), -rhs_imm); \ else \ { \ - GPVar lhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar lhs = c.newGpVar(kX86VarTypeGpd); \ c.mov(lhs, reg_pos_ptr(16)); \ c.add(lhs, rhs); \ } \ @@ -1101,7 +1101,7 @@ static int OP_MOV_IMM_VAL(const u32 i) { OP_MOV(IMM_VAL); } return 1; \ } \ if(!rhs_is_imm) \ - c.cmp(*(GPVar*)&rhs, 0); \ + c.cmp(*(GpVar*)&rhs, 0); \ else \ c.cmp(reg_pos_ptr(12), 0); \ SET_NZC; \ @@ -1152,11 +1152,11 @@ static int OP_QDSUB(const u32 i) { printf("JIT: unimplemented OP_QDSUB\n"); retu //----------------------------------------------------------------------------- // MUL //----------------------------------------------------------------------------- -static void MUL_Mxx_END(GPVar x, bool sign, int cycles) +static void MUL_Mxx_END(GpVar x, bool sign, int cycles) { if(sign) { - GPVar y = c.newGP(VARIABLE_TYPE_GPD); + GpVar y = c.newGpVar(kX86VarTypeGpd); c.mov(y, x); c.sar(x, 31); c.xor_(x, y); @@ -1168,12 +1168,12 @@ static void MUL_Mxx_END(GPVar x, bool sign, int cycles) } #define OP_MUL_(op, width, sign, accum, flags) \ - GPVar lhs = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar hi; \ + GpVar lhs = c.newGpVar(kX86VarTypeGpd); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ + GpVar hi; \ if (width) \ { \ - hi = c.newGP(VARIABLE_TYPE_GPD); \ + hi = c.newGpVar(kX86VarTypeGpd); \ c.xor_(hi, hi); \ } \ c.mov(lhs, reg_pos_ptr(0)); \ @@ -1225,14 +1225,14 @@ static int OP_SMULL_S(const u32 i) { OP_MUL_(c.imul(hi,lhs,rhs), 1, 1, 0, 1); } static int OP_SMLAL_S(const u32 i) { OP_MUL_(c.imul(hi,lhs,rhs), 1, 1, 1, 1); } #define OP_MULxy_(op, x, y, width, accum, flags) \ - GPVar lhs = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar hi; \ + GpVar lhs = c.newGpVar(kX86VarTypeGpd); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ + GpVar hi; \ c.movsx(lhs, reg_pos_ptr##x(0)); \ c.movsx(rhs, reg_pos_ptr##y(8)); \ if (width) \ { \ - hi = c.newGP(VARIABLE_TYPE_GPD); \ + hi = c.newGpVar(kX86VarTypeGpd); \ } \ op; \ if(width && accum) \ @@ -1296,8 +1296,8 @@ static int OP_SMLAL_T_T(const u32 i) { OP_MULxy_(c.imul(hi,lhs,rhs), H, H, 1, 1, //----------------------------------------------------------------------------- #ifdef ASMJIT_X64 #define OP_SMxxW_(x, accum, flags) \ - GPVar lhs = c.newGP(VARIABLE_TYPE_GPN); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPN); \ + GpVar lhs = c.newGpVar(kX86VarTypeGpz); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpz); \ c.movsx(lhs, reg_pos_ptr##x(8)); \ c.movsxd(rhs, reg_pos_ptr(0)); \ c.imul(lhs, rhs); \ @@ -1308,9 +1308,9 @@ static int OP_SMLAL_T_T(const u32 i) { OP_MULxy_(c.imul(hi,lhs,rhs), H, H, 1, 1, return 1; #else #define OP_SMxxW_(x, accum, flags) \ - GPVar lhs = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar hi = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar lhs = c.newGpVar(kX86VarTypeGpd); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ + GpVar hi = c.newGpVar(kX86VarTypeGpd); \ c.movsx(lhs, reg_pos_ptr##x(8)); \ c.mov(rhs, reg_pos_ptr(0)); \ c.imul(hi, lhs, rhs); \ @@ -1333,7 +1333,7 @@ static int OP_SMLAW_T(const u32 i) { OP_SMxxW_(H, 1, 1); } //----------------------------------------------------------------------------- static int OP_MRS_CPSR(const u32 i) { - GPVar x = c.newGP(VARIABLE_TYPE_GPD); + GpVar x = c.newGpVar(kX86VarTypeGpd); c.mov(x, cpu_ptr(CPSR)); c.mov(reg_pos_ptr(12), x); return 1; @@ -1341,7 +1341,7 @@ static int OP_MRS_CPSR(const u32 i) static int OP_MRS_SPSR(const u32 i) { - GPVar x = c.newGP(VARIABLE_TYPE_GPD); + GpVar x = c.newGpVar(kX86VarTypeGpd); c.mov(x, cpu_ptr(SPSR)); c.mov(reg_pos_ptr(12), x); return 1; @@ -1349,13 +1349,13 @@ static int OP_MRS_SPSR(const u32 i) // TODO: SPSR: if(cpu->CPSR.bits.mode == USR || cpu->CPSR.bits.mode == SYS) return 1; #define OP_MSR_(reg, args, sw) \ - GPVar operand = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar operand = c.newGpVar(kX86VarTypeGpd); \ args; \ switch (((i>>16) & 0xF)) \ { \ case 0x1: /* bit 16 */ \ { \ - GPVar mode = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar mode = c.newGpVar(kX86VarTypeGpd); \ Label __skip = c.newLabel(); \ c.mov(mode, cpu_ptr(CPSR)); \ c.and_(mode, 0x1F); \ @@ -1365,8 +1365,8 @@ static int OP_MRS_SPSR(const u32 i) { \ c.mov(mode, rhs); \ c.and_(mode, 0x1F); \ - ECall* ctx = c.call((void*)armcpu_switchMode); \ - ctx->setPrototype(CALL_CONV_DEFAULT, FunctionBuilder2()); \ + X86CompilerFuncCall* ctx = c.call((void*)armcpu_switchMode); \ + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); \ ctx->setArgument(0, bb_cpu); \ ctx->setArgument(1, mode); \ } \ @@ -1379,7 +1379,7 @@ static int OP_MRS_SPSR(const u32 i) return 1; \ case 0x2: /* bit 17 */ \ { \ - GPVar mode = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar mode = c.newGpVar(kX86VarTypeGpd); \ Label __skip = c.newLabel(); \ c.mov(mode, cpu_ptr(CPSR)); \ c.and_(mode, 0x1F); \ @@ -1395,7 +1395,7 @@ static int OP_MRS_SPSR(const u32 i) return 1; \ case 0x4: /* bit 18 */ \ { \ - GPVar mode = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar mode = c.newGpVar(kX86VarTypeGpd); \ Label __skip = c.newLabel(); \ c.mov(mode, cpu_ptr(CPSR)); \ c.and_(mode, 0x1F); \ @@ -1429,8 +1429,8 @@ static int OP_MRS_SPSR(const u32 i) static u32 byte_mask_USR = (BIT19(i)?0xFF000000:0x00000000); \ \ Mem xPSR_mem = cpu_ptr(reg.val); \ - GPVar xPSR = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar mode = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar xPSR = c.newGpVar(kX86VarTypeGpd); \ + GpVar mode = c.newGpVar(kX86VarTypeGpd); \ Label __USR = c.newLabel(); \ Label __done = c.newLabel(); \ c.mov(mode, cpu_ptr(CPSR.val)); \ @@ -1443,8 +1443,8 @@ static int OP_MRS_SPSR(const u32 i) /* armcpu_switchMode */ \ c.mov(mode, rhs); \ c.and_(mode, 0x1F); \ - ECall* ctx = c.call((void*)armcpu_switchMode); \ - ctx->setPrototype(CALL_CONV_DEFAULT, FunctionBuilder2()); \ + X86CompilerFuncCall* ctx = c.call((void*)armcpu_switchMode); \ + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); \ ctx->setArgument(0, bb_cpu); \ ctx->setArgument(1, mode); \ } \ @@ -1556,8 +1556,8 @@ static u32 add(u32 lhs, u32 rhs) { return lhs + rhs; } static u32 sub(u32 lhs, u32 rhs) { return lhs - rhs; } #define OP_LDR_(mem_op, arg, sign_op, writeback) \ - GPVar adr = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar dst = c.newGP(VARIABLE_TYPE_GPN); \ + GpVar adr = c.newGpVar(kX86VarTypeGpd); \ + GpVar dst = c.newGpVar(kX86VarTypeGpz); \ c.mov(adr, reg_pos_ptr(16)); \ c.lea(dst, reg_pos_ptr(12)); \ arg; \ @@ -1572,25 +1572,25 @@ static u32 sub(u32 lhs, u32 rhs) { return lhs - rhs; } } \ else if(writeback > 0) \ { \ - GPVar tmp_reg = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar tmp_reg = c.newGpVar(kX86VarTypeGpd); \ c.mov(tmp_reg, adr); \ c.sign_op(tmp_reg, rhs); \ c.mov(reg_pos_ptr(16), tmp_reg); \ } \ } \ u32 adr_first = sign_op(cpu->R[REG_POS(i,16)], rhs_first); \ - ECall *ctx = c.call((void*)mem_op##_tab[PROCNUM][classify_adr(adr_first,0)]); \ - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder2()); \ + X86CompilerFuncCall *ctx = c.call((void*)mem_op##_tab[PROCNUM][classify_adr(adr_first,0)]); \ + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); \ ctx->setArgument(0, adr); \ ctx->setArgument(1, dst); \ ctx->setReturn(bb_cycles); \ if(REG_POS(i,12)==15) \ { \ - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar tmp = c.newGpVar(kX86VarTypeGpd); \ c.mov(tmp, reg_ptr(15)); \ if (PROCNUM == 0) \ { \ - GPVar thumb = c.newGP(VARIABLE_TYPE_GPN); \ + GpVar thumb = c.newGpVar(kX86VarTypeGpz); \ c.movzx(thumb, reg_pos_ptrB(16)); \ c.and_(thumb, 1); \ c.shl(thumb, 5); \ @@ -1748,8 +1748,8 @@ static const OpSTR STRB_tab[2][3] = { T(OP_STRB) }; #undef T #define OP_STR_(mem_op, arg, sign_op, writeback) \ - GPVar adr = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar data = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar adr = c.newGpVar(kX86VarTypeGpd); \ + GpVar data = c.newGpVar(kX86VarTypeGpd); \ c.mov(adr, reg_pos_ptr(16)); \ c.mov(data, reg_pos_ptr(12)); \ arg; \ @@ -1764,15 +1764,15 @@ static const OpSTR STRB_tab[2][3] = { T(OP_STRB) }; } \ else if(writeback > 0) \ { \ - GPVar tmp_reg = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar tmp_reg = c.newGpVar(kX86VarTypeGpd); \ c.mov(tmp_reg, adr); \ c.sign_op(tmp_reg, rhs); \ c.mov(reg_pos_ptr(16), tmp_reg); \ } \ } \ u32 adr_first = sign_op(cpu->R[REG_POS(i,16)], rhs_first); \ - ECall *ctx = c.call((void*)mem_op##_tab[PROCNUM][classify_adr(adr_first,1)]); \ - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder2()); \ + X86CompilerFuncCall *ctx = c.call((void*)mem_op##_tab[PROCNUM][classify_adr(adr_first,1)]); \ + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); \ ctx->setArgument(0, adr); \ ctx->setArgument(1, data); \ ctx->setReturn(bb_cycles); \ @@ -1893,8 +1893,8 @@ static int OP_LDRD_STRD_POST_INDEX(const u32 i) printf("OP_LDRD_STRD_POST_INDEX: ERROR!!!!\n"); return 0; // TODO: exception } - GPVar Rd = c.newGP(VARIABLE_TYPE_GPD); - GPVar addr = c.newGP(VARIABLE_TYPE_GPD); + GpVar Rd = c.newGpVar(kX86VarTypeGpd); + GpVar addr = c.newGpVar(kX86VarTypeGpd); c.mov(Rd, reg_pos_ptr(16)); c.mov(addr, reg_pos_ptr(16)); @@ -1907,13 +1907,13 @@ static int OP_LDRD_STRD_POST_INDEX(const u32 i) } else { - GPVar idx = c.newGP(VARIABLE_TYPE_GPD); + GpVar idx = c.newGpVar(kX86VarTypeGpd); c.mov(idx, reg_pos_ptr(0)); BIT23(i)?c.add(reg_pos_ptr(16), idx):c.sub(reg_pos_ptr(16), idx); } - ECall *ctx = c.call((void*)(BIT5(i) ? op_strd_tab[PROCNUM][Rd_num] : op_ldrd_tab[PROCNUM][Rd_num])); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder1()); + X86CompilerFuncCall *ctx = c.call((void*)(BIT5(i) ? op_strd_tab[PROCNUM][Rd_num] : op_ldrd_tab[PROCNUM][Rd_num])); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder1()); ctx->setArgument(0, addr); ctx->setReturn(bb_cycles); emit_MMU_aluMemCycles(3, bb_cycles, 0); @@ -1934,8 +1934,8 @@ static int OP_LDRD_STRD_OFFSET_PRE_INDEX(const u32 i) printf("OP_LDRD_STRD_OFFSET_PRE_INDEX: ERROR!!!!\n"); return 0; // TODO: exception } - GPVar Rd = c.newGP(VARIABLE_TYPE_GPD); - GPVar addr = c.newGP(VARIABLE_TYPE_GPD); + GpVar Rd = c.newGpVar(kX86VarTypeGpd); + GpVar addr = c.newGpVar(kX86VarTypeGpd); c.mov(Rd, reg_pos_ptr(16)); c.mov(addr, reg_pos_ptr(16)); @@ -1951,8 +1951,8 @@ static int OP_LDRD_STRD_OFFSET_PRE_INDEX(const u32 i) if (BIT5(i)) // Store { - ECall *ctx = c.call((void*)op_strd_tab[PROCNUM][Rd_num]); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder1()); + X86CompilerFuncCall *ctx = c.call((void*)op_strd_tab[PROCNUM][Rd_num]); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder1()); ctx->setArgument(0, addr); ctx->setReturn(bb_cycles); if (BIT21(i)) // W bit - writeback @@ -1963,8 +1963,8 @@ static int OP_LDRD_STRD_OFFSET_PRE_INDEX(const u32 i) { if (BIT21(i)) // W bit - writeback c.mov(reg_pos_ptr(16), addr); - ECall *ctx = c.call((void*)op_ldrd_tab[PROCNUM][Rd_num]); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder1()); + X86CompilerFuncCall *ctx = c.call((void*)op_ldrd_tab[PROCNUM][Rd_num]); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder1()); ctx->setArgument(0, addr); ctx->setReturn(bb_cycles); emit_MMU_aluMemCycles(3, bb_cycles, 0); @@ -1997,17 +1997,17 @@ static const OP_SWP_SWPB op_swp_tab[2][2] = {{ op_swp<0>, op_swp<1> }, { op_swpb static int op_swp_(const u32 i, int b) { - GPVar addr = c.newGP(VARIABLE_TYPE_GPD); - GPVar Rd = c.newGP(VARIABLE_TYPE_GPN); - GPVar Rs = c.newGP(VARIABLE_TYPE_GPD); + GpVar addr = c.newGpVar(kX86VarTypeGpd); + GpVar Rd = c.newGpVar(kX86VarTypeGpz); + GpVar Rs = c.newGpVar(kX86VarTypeGpd); c.mov(addr, reg_pos_ptr(16)); c.lea(Rd, reg_pos_ptr(12)); if(b) c.movzx(Rs, reg_pos_ptrB(0)); else c.mov(Rs, reg_pos_ptr(0)); - ECall *ctx = c.call((void*)op_swp_tab[b][PROCNUM]); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder3()); + X86CompilerFuncCall *ctx = c.call((void*)op_swp_tab[b][PROCNUM]); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder3()); ctx->setArgument(0, addr); ctx->setArgument(1, Rd); ctx->setArgument(2, Rs); @@ -2183,28 +2183,28 @@ static const LDMOpFunc op_ldm_stm_tab[2][2][2] = {{ { OP_LDM_STM<1,1,-1>, OP_LDM_STM<1,1,+1> }, }}; -static void call_ldm_stm(GPVar adr, u32 bitmask, bool store, int dir) +static void call_ldm_stm(GpVar adr, u32 bitmask, bool store, int dir) { if(bitmask) { - GPVar n = c.newGP(VARIABLE_TYPE_GPD); + GpVar n = c.newGpVar(kX86VarTypeGpd); c.mov(n, popcount(bitmask)); #ifdef ASMJIT_X64 - GPVar regs = c.newGP(VARIABLE_TYPE_GPN); + GpVar regs = c.newGpVar(kX86VarTypeGpz); c.mov(regs, get_reg_list(bitmask, dir)); - ECall *ctx = c.call((void*)op_ldm_stm_tab[PROCNUM][store][dir>0]); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder3()); + X86CompilerFuncCall *ctx = c.call((void*)op_ldm_stm_tab[PROCNUM][store][dir>0]); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder3()); ctx->setArgument(0, adr); ctx->setArgument(1, regs); ctx->setArgument(2, n); #else // same prototype, but we have to handle splitting of a u64 arg manually - GPVar regs_lo = c.newGP(VARIABLE_TYPE_GPD); - GPVar regs_hi = c.newGP(VARIABLE_TYPE_GPD); + GpVar regs_lo = c.newGpVar(kX86VarTypeGpd); + GpVar regs_hi = c.newGpVar(kX86VarTypeGpd); c.mov(regs_lo, (u32)get_reg_list(bitmask, dir)); c.mov(regs_hi, get_reg_list(bitmask, dir) >> 32); - ECall *ctx = c.call((void*)op_ldm_stm_tab[PROCNUM][store][dir>0]); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder4()); + X86CompilerFuncCall *ctx = c.call((void*)op_ldm_stm_tab[PROCNUM][store][dir>0]); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder4()); ctx->setArgument(0, adr); ctx->setArgument(1, regs_lo); ctx->setArgument(2, regs_hi); @@ -2224,7 +2224,7 @@ static int op_ldm_stm(u32 i, bool store, int dir, bool before, bool writeback) u32 bitmask = i & 0xFFFF; u32 pop = popcount(bitmask); - GPVar adr = c.newGP(VARIABLE_TYPE_GPD); + GpVar adr = c.newGpVar(kX86VarTypeGpd); c.mov(adr, reg_pos_ptr(16)); if(before) c.add(adr, 4*dir); @@ -2287,8 +2287,8 @@ static int op_ldm_stm2(u32 i, bool store, int dir, bool before, bool writeback) //printf("ARM%c: %s R%d:%08X, bitmask %02X\n", PROCNUM?'7':'9', (store?"STM":"LDM"), REG_POS(i, 16), cpu->R[REG_POS(i, 16)], bitmask); u32 adr_first = cpu->R[REG_POS(i, 16)]; - GPVar adr = c.newGP(VARIABLE_TYPE_GPD); - GPVar oldmode = c.newGP(VARIABLE_TYPE_GPD); + GpVar adr = c.newGpVar(kX86VarTypeGpd); + GpVar oldmode = c.newGpVar(kX86VarTypeGpd); c.mov(adr, reg_pos_ptr(16)); if(before) @@ -2299,8 +2299,8 @@ static int op_ldm_stm2(u32 i, bool store, int dir, bool before, bool writeback) //if((cpu->CPSR.bits.mode==USR)||(cpu->CPSR.bits.mode==SYS)) { printf("ERROR1\n"); return 1; } //oldmode = armcpu_switchMode(cpu, SYS); c.mov(oldmode, SYS); - ECall *ctx = c.call((void*)armcpu_switchMode); - ctx->setPrototype(CALL_CONV_DEFAULT, FunctionBuilder2()); + X86CompilerFuncCall *ctx = c.call((void*)armcpu_switchMode); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); ctx->setArgument(0, bb_cpu); ctx->setArgument(1, oldmode); ctx->setReturn(oldmode); @@ -2311,8 +2311,8 @@ static int op_ldm_stm2(u32 i, bool store, int dir, bool before, bool writeback) if(!bit15 || store) { //armcpu_switchMode(cpu, oldmode); - ECall *ctx = c.call((void*)armcpu_switchMode); - ctx->setPrototype(CALL_CONV_DEFAULT, FunctionBuilder2()); + X86CompilerFuncCall *ctx = c.call((void*)armcpu_switchMode); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); ctx->setArgument(0, bb_cpu); ctx->setArgument(1, oldmode); } @@ -2386,17 +2386,17 @@ static int OP_BL(const u32 i) { return op_b(i, 1); } static int op_bx(Mem srcreg, bool blx, bool test_thumb) { - GPVar dst = c.newGP(VARIABLE_TYPE_GPD); + GpVar dst = c.newGpVar(kX86VarTypeGpd); c.mov(dst, srcreg); if(test_thumb) { - GPVar mask = c.newGP(VARIABLE_TYPE_GPD); - GPVar thumb = dst; - dst = c.newGP(VARIABLE_TYPE_GPD); + GpVar mask = c.newGpVar(kX86VarTypeGpd); + GpVar thumb = dst; + dst = c.newGpVar(kX86VarTypeGpd); c.mov(dst, thumb); c.and_(thumb, 1); - c.lea(mask, ptr_abs((void*)0xFFFFFFFC, thumb.r64(), TIMES_2)); + c.lea(mask, ptr_abs((void*)0xFFFFFFFC, thumb.r64(), kScale2Times)); c.shl(thumb, 5); c.or_(cpu_ptr_byte(CPSR, 0), thumb.r8Lo()); c.and_(dst, mask); @@ -2419,7 +2419,7 @@ static int OP_BLX_REG(const u32 i) { return op_bx(reg_pos_ptr(0), 1, 1); } //----------------------------------------------------------------------------- static int OP_CLZ(const u32 i) { - GPVar res = c.newGP(VARIABLE_TYPE_GPD); + GpVar res = c.newGpVar(kX86VarTypeGpd); c.mov(res, 0x3F); c.bsr(res, reg_pos_ptr(0)); c.xor_(res, 0x1F); @@ -2433,8 +2433,8 @@ static int OP_CLZ(const u32 i) //----------------------------------------------------------------------------- #define maskPrecalc \ { \ - ECall* ctxM = c.call((void*)maskPrecalc); \ - ctxM->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder0()); \ + X86CompilerFuncCall* ctxM = c.call((void*)maskPrecalc); \ + ctxM->setPrototype(ASMJIT_CALL_CONV, FuncBuilder0()); \ } static int OP_MCR(const u32 i) { @@ -2459,8 +2459,8 @@ static int OP_MCR(const u32 i) u8 opcode1 = ((i>>21)&0x7); // opcode1 u8 opcode2 = ((i>>5)&0x7); // opcode2 - GPVar bb_cp15 = c.newGP(VARIABLE_TYPE_GPN); - GPVar data = c.newGP(VARIABLE_TYPE_GPD); + GpVar bb_cp15 = c.newGpVar(kX86VarTypeGpz); + GpVar data = c.newGpVar(kX86VarTypeGpd); c.mov(data, reg_pos_ptr(12)); c.mov(bb_cp15, (uintptr_t)&cp15); @@ -2470,17 +2470,17 @@ static int OP_MCR(const u32 i) case 1: if((opcode1==0) && (opcode2==0) && (CRm==0)) { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); // On the NDS bit0,2,7,12..19 are R/W, Bit3..6 are always set, all other bits are always zero. //MMU.ARM9_RW_MODE = BIT7(val); - GPVar bb_mmu = c.newGP(VARIABLE_TYPE_GPN); + GpVar bb_mmu = c.newGpVar(kX86VarTypeGpz); c.mov(bb_mmu, (uintptr_t)&MMU); Mem rwmode = mmu_ptr_byte(ARM9_RW_MODE); Mem ldtbit = cpu_ptr_byte(LDTBit, 0); c.test(data, (1<<7)); c.setnz(rwmode); //cpu->intVector = 0xFFFF0000 * (BIT13(val)); - GPVar vec = c.newGP(VARIABLE_TYPE_GPD); + GpVar vec = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, 0xFFFF0000); c.xor_(vec, vec); c.test(data, (1 << 13)); @@ -2639,7 +2639,7 @@ static int OP_MCR(const u32 i) { //MMU.DTCMRegion = DTCMRegion = val & 0x0FFFF000; c.and_(data, 0x0FFFF000); - GPVar bb_mmu = c.newGP(VARIABLE_TYPE_GPN); + GpVar bb_mmu = c.newGpVar(kX86VarTypeGpz); c.mov(bb_mmu, (uintptr_t)&MMU); c.mov(mmu_ptr(DTCMRegion), data); c.mov(cp15_ptr(DTCMRegion), data); @@ -2649,7 +2649,7 @@ static int OP_MCR(const u32 i) { //ITCMRegion = val; //ITCM base is not writeable! - GPVar bb_mmu = c.newGP(VARIABLE_TYPE_GPN); + GpVar bb_mmu = c.newGpVar(kX86VarTypeGpz); c.mov(bb_mmu, (uintptr_t)&MMU); c.mov(mmu_ptr(ITCMRegion), 0); c.mov(cp15_ptr(ITCMRegion), data); @@ -2699,8 +2699,8 @@ static int OP_MRC(const u32 i) u8 opcode1 = ((i>>21)&0x7); // opcode1 u8 opcode2 = ((i>>5)&0x7); // opcode2 - GPVar bb_cp15 = c.newGP(VARIABLE_TYPE_GPN); - GPVar data = c.newGP(VARIABLE_TYPE_GPD); + GpVar bb_cp15 = c.newGpVar(kX86VarTypeGpz); + GpVar data = c.newGpVar(kX86VarTypeGpd); c.mov(bb_cp15, (uintptr_t)&cp15); @@ -2930,23 +2930,23 @@ u32 op_swi(u8 swinum) // TODO: return 0; #else - ECall *ctx = c.call((void*)ARM_swi_tab[PROCNUM][swinum]); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder0()); + X86CompilerFuncCall *ctx = c.call((void*)ARM_swi_tab[PROCNUM][swinum]); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder0()); ctx->setReturn(bb_cycles); c.add(bb_cycles, 3); return 1; #endif } - GPVar oldCPSR = c.newGP(VARIABLE_TYPE_GPD); - GPVar mode = c.newGP(VARIABLE_TYPE_GPD); + GpVar oldCPSR = c.newGpVar(kX86VarTypeGpd); + GpVar mode = c.newGpVar(kX86VarTypeGpd); Mem CPSR = cpu_ptr(CPSR.val); JIT_COMMENT("store CPSR to x86 stack"); c.mov(oldCPSR, CPSR); JIT_COMMENT("enter SVC mode"); c.mov(mode, imm(SVC)); - ECall* ctx = c.call((void*)armcpu_switchMode); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder2()); + X86CompilerFuncCall* ctx = c.call((void*)armcpu_switchMode); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); ctx->setArgument(0, bb_cpu); ctx->setArgument(1, mode); c.unuse(mode); @@ -2955,7 +2955,7 @@ u32 op_swi(u8 swinum) JIT_COMMENT("save old CPSR as new SPSR"); c.mov(cpu_ptr(SPSR.val), oldCPSR); JIT_COMMENT("CPSR: clear T, set I"); - GPVar _cpsr = c.newGP(VARIABLE_TYPE_GPD); + GpVar _cpsr = c.newGpVar(kX86VarTypeGpd); c.mov(_cpsr, CPSR); c.and_(_cpsr, ~(1 << 5)); /* clear T */ c.or_(_cpsr, (1 << 7)); /* set I */ @@ -2978,14 +2978,14 @@ static int OP_BKPT(const u32 i) { printf("JIT: unimplemented OP_BKPT\n"); return // THUMB //----------------------------------------------------------------------------- #define OP_SHIFTS_IMM(x86inst) \ - GPVar rcf = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar rcf = c.newGpVar(kX86VarTypeGpd); \ u8 cf_change = 1; \ const u32 rhs = ((i>>6) & 0x1F); \ if (_REG_NUM(i, 0) == _REG_NUM(i, 3)) \ c.x86inst(reg_pos_thumb(0), rhs); \ else \ { \ - GPVar lhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar lhs = c.newGpVar(kX86VarTypeGpd); \ c.mov(lhs, reg_pos_thumb(3)); \ c.x86inst(lhs, rhs); \ c.mov(reg_pos_thumb(0), lhs); \ @@ -2997,8 +2997,8 @@ static int OP_BKPT(const u32 i) { printf("JIT: unimplemented OP_BKPT\n"); return #define OP_SHIFTS_REG(x86inst, bit) \ u8 cf_change = 1; \ - GPVar imm = c.newGP(VARIABLE_TYPE_GPN); \ - GPVar rcf = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar imm = c.newGpVar(kX86VarTypeGpz); \ + GpVar rcf = c.newGpVar(kX86VarTypeGpd); \ Label __eq32 = c.newLabel(); \ Label __ls32 = c.newLabel(); \ Label __zero = c.newLabel(); \ @@ -3035,7 +3035,7 @@ static int OP_BKPT(const u32 i) { printf("JIT: unimplemented OP_BKPT\n"); return return 1; #define OP_LOGIC(x86inst, _conv) \ - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar rhs = c.newGpVar(kX86VarTypeGpd); \ c.mov(rhs, reg_pos_thumb(3)); \ if (_conv==1) c.not_(rhs); \ c.x86inst(reg_pos_thumb(0), rhs); \ @@ -3051,7 +3051,7 @@ static int OP_LSL_0(const u32 i) c.cmp(reg_pos_thumb(0), 0); else { - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); + GpVar rhs = c.newGpVar(kX86VarTypeGpd); c.mov(rhs, reg_pos_thumb(3)); c.mov(reg_pos_thumb(0), rhs); c.cmp(rhs, 0); @@ -3063,7 +3063,7 @@ static int OP_LSL(const u32 i) { OP_SHIFTS_IMM(shl); } static int OP_LSL_REG(const u32 i) { OP_SHIFTS_REG(shl, 0); } static int OP_LSR_0(const u32 i) { - GPVar rcf = c.newGP(VARIABLE_TYPE_GPD); + GpVar rcf = c.newGpVar(kX86VarTypeGpd); c.test(reg_pos_thumb(3), (1 << 31)); c.setnz(rcf.r8Lo()); SET_NZC_SHIFTS_ZERO(1); @@ -3075,8 +3075,8 @@ static int OP_LSR_REG(const u32 i) { OP_SHIFTS_REG(shr, 31); } static int OP_ASR_0(const u32 i) { u8 cf_change = 1; - GPVar rcf = c.newGP(VARIABLE_TYPE_GPD); - GPVar rhs = c.newGP(VARIABLE_TYPE_GPD); + GpVar rcf = c.newGpVar(kX86VarTypeGpd); + GpVar rhs = c.newGpVar(kX86VarTypeGpd); if (_REG_NUM(i, 0) == _REG_NUM(i, 3)) c.sar(reg_pos_thumb(0), 31); else @@ -3097,8 +3097,8 @@ static int OP_ASR_REG(const u32 i) Label __lt32 = c.newLabel(); Label __done = c.newLabel(); Label __setFlags = c.newLabel(); - GPVar imm = c.newGP(VARIABLE_TYPE_GPN); - GPVar rcf = c.newGP(VARIABLE_TYPE_GPD); + GpVar imm = c.newGpVar(kX86VarTypeGpz); + GpVar rcf = c.newGpVar(kX86VarTypeGpd); c.mov(imm, reg_pos_thumb(3)); c.and_(imm, 0xFF); c.jnz(__gr0); @@ -3130,8 +3130,8 @@ static int OP_ASR_REG(const u32 i) static int OP_ROR_REG(const u32 i) { u8 cf_change = 1; - GPVar imm = c.newGP(VARIABLE_TYPE_GPN); - GPVar rcf = c.newGP(VARIABLE_TYPE_GPD); + GpVar imm = c.newGpVar(kX86VarTypeGpz); + GpVar rcf = c.newGpVar(kX86VarTypeGpd); Label __zero = c.newLabel(); Label __zero_1F = c.newLabel(); Label __done = c.newLabel(); @@ -3177,7 +3177,7 @@ static int OP_NEG(const u32 i) c.neg(reg_pos_thumb(0)); else { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); c.neg(tmp); c.mov(reg_pos_thumb(0), tmp); @@ -3195,7 +3195,7 @@ static int OP_ADD_IMM3(const u32 i) if (imm3 == 0) // mov 2 { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); c.mov(reg_pos_thumb(0), tmp); c.cmp(tmp, 0); @@ -3208,7 +3208,7 @@ static int OP_ADD_IMM3(const u32 i) } else { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); c.add(tmp, imm3); c.mov(reg_pos_thumb(0), tmp); @@ -3228,20 +3228,20 @@ static int OP_ADD_REG(const u32 i) //cpu->R[REG_NUM(i, 0)] = cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)]; if (_REG_NUM(i, 0) == _REG_NUM(i, 3)) { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(6)); c.add(reg_pos_thumb(0), tmp); } else if (_REG_NUM(i, 0) == _REG_NUM(i, 6)) { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); c.add(reg_pos_thumb(0), tmp); } else { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); c.add(tmp, reg_pos_thumb(6)); c.mov(reg_pos_thumb(0), tmp); @@ -3253,7 +3253,7 @@ static int OP_ADD_SPE(const u32 i) { u32 Rd = _REG_NUM(i, 0) | ((i>>4)&8); //cpu->R[Rd] += cpu->R[REG_POS(i, 3)]; - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_ptr(Rd)); c.add(tmp, reg_pos_ptr(3)); c.mov(reg_ptr(Rd), tmp); @@ -3275,7 +3275,7 @@ static int OP_ADD_2SP(const u32 i) { u32 imm = ((i&0xFF)<<2); //cpu->R[REG_NUM(i, 8)] = cpu->R[13] + ((i&0xFF)<<2); - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_ptr(13)); if (imm) c.add(tmp, imm); c.mov(reg_pos_thumb(8), tmp); @@ -3297,7 +3297,7 @@ static int OP_SUB_IMM3(const u32 i) } else { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); c.sub(tmp, imm3); c.mov(reg_pos_thumb(0), tmp); @@ -3317,13 +3317,13 @@ static int OP_SUB_REG(const u32 i) // cpu->R[REG_NUM(i, 0)] = cpu->R[REG_NUM(i, 3)] - cpu->R[REG_NUM(i, 6)]; if (_REG_NUM(i, 0) == _REG_NUM(i, 3)) { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(6)); c.sub(reg_pos_thumb(0), tmp); } else { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); c.sub(tmp, reg_pos_thumb(6)); c.mov(reg_pos_thumb(0), tmp); @@ -3337,7 +3337,7 @@ static int OP_SUB_REG(const u32 i) //----------------------------------------------------------------------------- static int OP_ADC_REG(const u32 i) { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); GET_CARRY(0); c.adc(reg_pos_thumb(0), tmp); @@ -3350,7 +3350,7 @@ static int OP_ADC_REG(const u32 i) //----------------------------------------------------------------------------- static int OP_SBC_REG(const u32 i) { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); GET_CARRY(1); c.sbb(reg_pos_thumb(0), tmp); @@ -3373,7 +3373,7 @@ static int OP_MOV_SPE(const u32 i) { u32 Rd = _REG_NUM(i, 0) | ((i>>4)&8); //cpu->R[Rd] = cpu->R[REG_POS(i, 3)]; - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_ptr(3)); c.mov(reg_ptr(Rd), tmp); if(Rd == 15) @@ -3390,7 +3390,7 @@ static int OP_MOV_SPE(const u32 i) static int OP_MVN(const u32 i) { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); c.not_(tmp); c.cmp(tmp, 0); @@ -3404,7 +3404,7 @@ static int OP_MVN(const u32 i) //----------------------------------------------------------------------------- static int OP_MUL_REG(const u32 i) { - GPVar lhs = c.newGP(VARIABLE_TYPE_GPD); + GpVar lhs = c.newGpVar(kX86VarTypeGpd); c.mov(lhs, reg_pos_thumb(0)); c.imul(lhs, reg_pos_thumb(3)); c.cmp(lhs, 0); @@ -3429,7 +3429,7 @@ static int OP_CMP_IMM8(const u32 i) static int OP_CMP(const u32 i) { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); c.cmp(reg_pos_thumb(0), tmp); SET_NZCV(1); @@ -3439,7 +3439,7 @@ static int OP_CMP(const u32 i) static int OP_CMP_SPE(const u32 i) { u32 Rn = (i&7) | ((i>>4)&8); - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_ptr(3)); c.cmp(reg_ptr(Rn), tmp); SET_NZCV(1); @@ -3448,7 +3448,7 @@ static int OP_CMP_SPE(const u32 i) static int OP_CMN(const u32 i) { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(0)); c.add(tmp, reg_pos_thumb(3)); SET_NZCV(0); @@ -3460,7 +3460,7 @@ static int OP_CMN(const u32 i) //----------------------------------------------------------------------------- static int OP_TST(const u32 i) { - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); + GpVar tmp = c.newGpVar(kX86VarTypeGpd); c.mov(tmp, reg_pos_thumb(3)); c.test(reg_pos_thumb(0), tmp); SET_NZ(0); @@ -3471,8 +3471,8 @@ static int OP_TST(const u32 i) // STR / LDR / STRB / LDRB //----------------------------------------------------------------------------- #define STR_THUMB(mem_op, offset) \ - GPVar addr = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar data = c.newGP(VARIABLE_TYPE_GPD); \ + GpVar addr = c.newGpVar(kX86VarTypeGpd); \ + GpVar data = c.newGpVar(kX86VarTypeGpd); \ u32 adr_first = cpu->R[_REG_NUM(i, 3)]; \ \ c.mov(addr, reg_pos_thumb(3)); \ @@ -3490,16 +3490,16 @@ static int OP_TST(const u32 i) adr_first += cpu->R[_REG_NUM(i, 6)]; \ } \ c.mov(data, reg_pos_thumb(0)); \ - ECall *ctx = c.call((void*)mem_op##_tab[PROCNUM][classify_adr(adr_first,1)]); \ - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder2()); \ + X86CompilerFuncCall *ctx = c.call((void*)mem_op##_tab[PROCNUM][classify_adr(adr_first,1)]); \ + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); \ ctx->setArgument(0, addr); \ ctx->setArgument(1, data); \ ctx->setReturn(bb_cycles); \ return 1; #define LDR_THUMB(mem_op, offset) \ - GPVar addr = c.newGP(VARIABLE_TYPE_GPD); \ - GPVar data = c.newGP(VARIABLE_TYPE_GPN); \ + GpVar addr = c.newGpVar(kX86VarTypeGpd); \ + GpVar data = c.newGpVar(kX86VarTypeGpz); \ u32 adr_first = cpu->R[_REG_NUM(i, 3)]; \ \ c.mov(addr, reg_pos_thumb(3)); \ @@ -3517,8 +3517,8 @@ static int OP_TST(const u32 i) adr_first += cpu->R[_REG_NUM(i, 6)]; \ } \ c.lea(data, reg_pos_thumb(0)); \ - ECall *ctx = c.call((void*)mem_op##_tab[PROCNUM][classify_adr(adr_first,0)]); \ - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder2()); \ + X86CompilerFuncCall *ctx = c.call((void*)mem_op##_tab[PROCNUM][classify_adr(adr_first,0)]); \ + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); \ ctx->setArgument(0, addr); \ ctx->setArgument(1, data); \ ctx->setReturn(bb_cycles); \ @@ -3546,13 +3546,13 @@ static int OP_STR_SPREL(const u32 i) u32 imm = ((i&0xFF)<<2); u32 adr_first = cpu->R[13] + imm; - GPVar addr = c.newGP(VARIABLE_TYPE_GPD); + GpVar addr = c.newGpVar(kX86VarTypeGpd); c.mov(addr, reg_ptr(13)); if (imm) c.add(addr, imm); - GPVar data = c.newGP(VARIABLE_TYPE_GPD); + GpVar data = c.newGpVar(kX86VarTypeGpd); c.mov(data, reg_pos_thumb(8)); - ECall *ctx = c.call((void*)STR_tab[PROCNUM][classify_adr(adr_first,1)]); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder2()); + X86CompilerFuncCall *ctx = c.call((void*)STR_tab[PROCNUM][classify_adr(adr_first,1)]); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); ctx->setArgument(0, addr); ctx->setArgument(1, data); ctx->setReturn(bb_cycles); @@ -3564,13 +3564,13 @@ static int OP_LDR_SPREL(const u32 i) u32 imm = ((i&0xFF)<<2); u32 adr_first = cpu->R[13] + imm; - GPVar addr = c.newGP(VARIABLE_TYPE_GPD); + GpVar addr = c.newGpVar(kX86VarTypeGpd); c.mov(addr, reg_ptr(13)); if (imm) c.add(addr, imm); - GPVar data = c.newGP(VARIABLE_TYPE_GPN); + GpVar data = c.newGpVar(kX86VarTypeGpz); c.lea(data, reg_pos_thumb(8)); - ECall *ctx = c.call((void*)LDR_tab[PROCNUM][classify_adr(adr_first,0)]); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder2()); + X86CompilerFuncCall *ctx = c.call((void*)LDR_tab[PROCNUM][classify_adr(adr_first,0)]); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); ctx->setArgument(0, addr); ctx->setArgument(1, data); ctx->setReturn(bb_cycles); @@ -3581,12 +3581,12 @@ static int OP_LDR_PCREL(const u32 i) { u32 imm = ((i&0xFF)<<2); u32 adr_first = (bb_r15 & 0xFFFFFFFC) + imm; - GPVar addr = c.newGP(VARIABLE_TYPE_GPD); - GPVar data = c.newGP(VARIABLE_TYPE_GPN); + GpVar addr = c.newGpVar(kX86VarTypeGpd); + GpVar data = c.newGpVar(kX86VarTypeGpz); c.mov(addr, adr_first); c.lea(data, reg_pos_thumb(8)); - ECall *ctx = c.call((void*)LDR_tab[PROCNUM][classify_adr(adr_first,0)]); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder2()); + X86CompilerFuncCall *ctx = c.call((void*)LDR_tab[PROCNUM][classify_adr(adr_first,0)]); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder2()); ctx->setArgument(0, addr); ctx->setArgument(1, data); ctx->setReturn(bb_cycles); @@ -3604,7 +3604,7 @@ static int op_ldm_stm_thumb(u32 i, bool store) //if (BIT_N(i, _REG_NUM(i, 8))) // printf("WARNING - %sIA with Rb in Rlist (THUMB)\n", store?"STM":"LDM"); - GPVar adr = c.newGP(VARIABLE_TYPE_GPD); + GpVar adr = c.newGpVar(kX86VarTypeGpd); c.mov(adr, reg_pos_thumb(8)); call_ldm_stm(adr, bitmask, store, 1); @@ -3643,7 +3643,7 @@ static int op_push_pop(u32 i, bool store, bool pc_lr) u32 pop = popcount(bitmask); int dir = store ? -1 : 1; - GPVar adr = c.newGP(VARIABLE_TYPE_GPD); + GpVar adr = c.newGpVar(kX86VarTypeGpd); c.mov(adr, reg_ptr(13)); if(store) c.sub(adr, 4); @@ -3692,7 +3692,7 @@ static int OP_B_UNCOND(const u32 i) static int OP_BLX(const u32 i) { - GPVar dst = c.newGP(VARIABLE_TYPE_GPD); + GpVar dst = c.newGpVar(kX86VarTypeGpd); c.mov(dst, reg_ptr(14)); c.add(dst, (i&0x7FF) << 1); c.and_(dst, 0xFFFFFFFC); @@ -3712,7 +3712,7 @@ static int OP_BL_10(const u32 i) static int OP_BL_11(const u32 i) { - GPVar dst = c.newGP(VARIABLE_TYPE_GPD); + GpVar dst = c.newGpVar(kX86VarTypeGpd); c.mov(dst, reg_ptr(14)); c.add(dst, (i&0x7FF) << 1); c.mov(cpu_ptr(instruct_adr), dst); @@ -3722,8 +3722,8 @@ static int OP_BL_11(const u32 i) static int op_bx_thumb(Mem srcreg, bool blx, bool test_thumb) { - GPVar dst = c.newGP(VARIABLE_TYPE_GPD); - GPVar thumb = c.newGP(VARIABLE_TYPE_GPD); + GpVar dst = c.newGpVar(kX86VarTypeGpd); + GpVar thumb = c.newGpVar(kX86VarTypeGpd); c.mov(dst, srcreg); c.mov(thumb, dst); // * cpu->CPSR.bits.T = BIT0(Rm); c.and_(thumb, 1); // * @@ -3731,14 +3731,14 @@ static int op_bx_thumb(Mem srcreg, bool blx, bool test_thumb) c.mov(reg_ptr(14), bb_next_instruction | 1); if(test_thumb) { - GPVar mask = c.newGP(VARIABLE_TYPE_GPD); - c.lea(mask, ptr_abs((void*)0xFFFFFFFC, thumb.r64(), TIMES_2)); + GpVar mask = c.newGpVar(kX86VarTypeGpd); + c.lea(mask, ptr_abs((void*)0xFFFFFFFC, thumb.r64(), kScale2Times)); c.and_(dst, mask); } else c.and_(dst, 0xFFFFFFFE); - GPVar tmp = c.newGP(VARIABLE_TYPE_GPD); // * + GpVar tmp = c.newGpVar(kX86VarTypeGpd); // * c.mov(tmp, cpu_ptr_byte(CPSR, 0)); // * c.and_(tmp, ~(1<< 5)); // * c.shl(thumb, 5); // * @@ -3970,14 +3970,14 @@ static void emit_branch(int cond, Label to) } else { - GPVar x = c.newGP(VARIABLE_TYPE_GPN); + GpVar x = c.newGpVar(kX86VarTypeGpz); c.movzx(x, flags_ptr); c.and_(x, 0xF0); #if defined(_M_X64) || defined(__x86_64__) c.add(x, offsetof(armcpu_t,cond_table) + cond); c.test(byte_ptr(bb_cpu, x), 1); #else - c.test(byte_ptr_abs((void*)(arm_cond_table + cond), x, TIMES_1), 1); + c.test(byte_ptr_abs((void*)(arm_cond_table + cond), x, kScale1Times), 1); #endif c.unuse(x); c.jz(to); @@ -3992,12 +3992,12 @@ static void emit_armop_call(u32 opcode) return; JIT_COMMENT("call interpreter"); - GPVar arg = c.newGP(VARIABLE_TYPE_GPD); + GpVar arg = c.newGpVar(kX86VarTypeGpd); c.mov(arg, opcode); OpFunc f = bb_thumb ? thumb_instructions_set[PROCNUM][opcode>>6] : arm_instructions_set[PROCNUM][INSTRUCTION_INDEX(opcode)]; - ECall* ctx = c.call((void*)f); - ctx->setPrototype(ASMJIT_CALL_CONV, FunctionBuilder1()); + X86CompilerFuncCall* ctx = c.call((void*)f); + ctx->setPrototype(ASMJIT_CALL_CONV, FuncBuilder1()); ctx->setArgument(0, arg); ctx->setReturn(bb_cycles); } @@ -4075,24 +4075,24 @@ static u32 compile_basicblock() #endif c.clear(); - c.newFunction(ASMJIT_CALL_CONV, FunctionBuilder0()); - c.getFunction()->setHint(FUNCTION_HINT_NAKED, true); - c.getFunction()->setHint(FUNCTION_HINT_PUSH_POP_SEQUENCE, true); + c.newFunc(ASMJIT_CALL_CONV, FuncBuilder0()); + c.getFunc()->setHint(kFuncHintNaked, true); + c.getFunc()->setHint(kX86FuncHintPushPop, true); JIT_COMMENT("CPU ptr"); - bb_cpu = c.newGP(VARIABLE_TYPE_GPN); + bb_cpu = c.newGpVar(kX86VarTypeGpz); c.mov(bb_cpu, (uintptr_t)&ARMPROC); if(has_variable_cycles) { - total_cycles = c.newGP(VARIABLE_TYPE_GPD); + total_cycles = c.newGpVar(kX86VarTypeGpd); JIT_COMMENT("set total_cycles to %d", constant_cycles); c.mov(total_cycles, constant_cycles); } #if (PROFILER_JIT_LEVEL > 0) JIT_COMMENT("Profiler ptr"); - bb_profiler = c.newGP(VARIABLE_TYPE_GPN); + bb_profiler = c.newGpVar(kX86VarTypeGpz); c.mov(bb_profiler, (uintptr_t)&profiler_counter[PROCNUM]); #endif @@ -4108,7 +4108,7 @@ static u32 compile_basicblock() else c.add(profiler_counter_arm(opcode), 1); #endif - bb_cycles = c.newGP(VARIABLE_TYPE_GPD); + bb_cycles = c.newGpVar(kX86VarTypeGpd); u32 cycles = instr_cycles(opcode); if(instr_is_conditional(opcode)) { @@ -4124,7 +4124,7 @@ static u32 compile_basicblock() if(cycles == 0) { JIT_COMMENT("cycles"); - c.lea(total_cycles, ptr(total_cycles.r64(), bb_cycles.r64(), TIMES_1, -1)); + c.lea(total_cycles, ptr(total_cycles.r64(), bb_cycles.r64(), kScaleNone, -1)); } else if(cycles > 1) @@ -4150,14 +4150,14 @@ static u32 compile_basicblock() if(!instr_does_prefetch(opcodes[n-1])) { JIT_COMMENT("!instr_does_prefetch: copy next_instruction (%08X) to instruct_adr (%08X)", cpu->next_instruction, cpu->instruct_adr); - GPVar x = c.newGP(VARIABLE_TYPE_GPD); + GpVar x = c.newGpVar(kX86VarTypeGpd); c.mov(x, cpu_ptr(next_instruction)); c.mov(cpu_ptr(instruct_adr), x); c.unuse(x); } JIT_COMMENT("total cycles (block)"); - GPVar ret = c.newGP(VARIABLE_TYPE_GPD); + GpVar ret = c.newGpVar(kX86VarTypeGpd); if(has_variable_cycles) c.mov(ret, total_cycles); else @@ -4166,14 +4166,14 @@ static u32 compile_basicblock() #if (PROFILER_JIT_LEVEL > 1) JIT_COMMENT("*** profiler - cycles"); u32 padr = ((start_adr & 0x07FFFFFE) >> 1); - bb_profiler_entry = c.newGP(VARIABLE_TYPE_GPN); + bb_profiler_entry = c.newGpVar(kX86VarTypeGpz); c.mov(bb_profiler_entry, (uintptr_t)&profiler_entry[PROCNUM][padr]); c.add(dword_ptr(bb_profiler_entry, offsetof(PROFILER_ENTRY, cycles)), ret); profiler_entry[PROCNUM][padr].addr = start_adr; #endif c.ret(ret); - c.endFunction(); + c.endFunc(); ArmOpCompiled f = (ArmOpCompiled)c.make(); if(c.getError()) diff --git a/desmume/src/types.h b/desmume/src/types.h index e34896ebd..7c7ca1c33 100644 --- a/desmume/src/types.h +++ b/desmume/src/types.h @@ -98,16 +98,16 @@ #ifdef __MINGW32__ #define FASTCALL __attribute__((fastcall)) -#define ASMJIT_CALL_CONV CALL_CONV_GCCFASTCALL +#define ASMJIT_CALL_CONV kX86FuncConvGccFastCall #elif defined (__i386__) && !defined(__clang__) #define FASTCALL __attribute__((regparm(3))) -#define ASMJIT_CALL_CONV CALL_CONV_GCCREGPARM_3 +#define ASMJIT_CALL_CONV kX86FuncConvGccRegParm3 #elif defined(_MSC_VER) || defined(__INTEL_COMPILER) #define FASTCALL -#define ASMJIT_CALL_CONV CALL_CONV_DEFAULT +#define ASMJIT_CALL_CONV kX86FuncConvDefault #else #define FASTCALL -#define ASMJIT_CALL_CONV CALL_CONV_DEFAULT +#define ASMJIT_CALL_CONV kX86FuncConvDefault #endif #ifdef _MSC_VER diff --git a/desmume/src/utils/AsmJit/AsmJit.h b/desmume/src/utils/AsmJit/AsmJit.h index 2ae9c77d5..cbe01490b 100644 --- a/desmume/src/utils/AsmJit/AsmJit.h +++ b/desmume/src/utils/AsmJit/AsmJit.h @@ -5,22 +5,22 @@ // Zlib - See COPYING file in this package. // [Guard] -#ifndef _ASMJIT_H -#define _ASMJIT_H +#ifndef _ASMJIT_ASMJIT_H +#define _ASMJIT_ASMJIT_H //! @mainpage //! -//! @brief AsmJit is complete x86/x64 JIT Assembler for C++ language +//! @brief AsmJit is a complete x86/x64 JIT Assembler for C++ language. //! //! It supports FPU, MMX, 3dNow, SSE, SSE2, SSE3 and SSE4 intrinsics, powerful //! compiler that helps to write portable functions for 32-bit (x86) and 64-bit //! (x64) architectures. AsmJit can be used to create functions at runtime that //! can be called from existing (but also generated) C/C++ code. //! -//! AsmJit is crossplatform library that supports various compilers and +//! AsmJit is a cross-platform library that supports various compilers and //! operating systems. Currently only limitation is x86 (32-bit) or x64 (64-bit) //! processor. Currently tested operating systems are Windows (32-bit and 64-bit), -//! Linux (32-bit and 64-bit) and MacOSX (32-bit). +//! Linux (32-bit and 64-bit) and MacOSX (32-bit and 64-bit). //! //! @section AsmJit_Main_Introduction Introduction //! @@ -51,13 +51,12 @@ //! @section AsmJit_Main_Configuration Configuration, Definitions and Utilities //! //! - @ref AsmJit_Config "Configuration" - Macros used to configure AsmJit. -//! - @ref AsmJit_Util "Utilities" - Utilities and helper classes. //! //! @section AsmJit_Main_HomePage AsmJit Homepage //! //! - http://code.google.com/p/asmjit/ //! -//! @section AsmJit_Main_X86X64Resources External X86/X64 Assembler Resources +//! @section AsmJit_Main_ResourcesX86 External X86/X64 Assembler Resources //! - http://www.agner.org/optimize/ //! - http://www.mark.masmcode.com/ (Assembler Tips) //! - http://avisynth.org/mediawiki/Filter_SDK/Assembler_optimizing (Optimizing) @@ -140,7 +139,7 @@ //! Contains classes related to @c AsmJit::Compiler that can be used //! to generate code using high-level constructs. //! -//! - See @c AsmJit::Compiler class for high level code generation +//! - See @c Compiler class for high level code generation //! documentation - calling conventions, function declaration //! and variables management. @@ -211,12 +210,12 @@ //! // Now you are able to get specific features. //! //! // Processor has SSE2 -//! if (i->features & CPU_FEATURE_SSE2) +//! if (i->features & kX86FeatureSse2) //! { //! // your code... //! } //! // Processor has MMX -//! else if (i->features & CPU_FEATURE__MMX) +//! else if (i->features & kX86Feature_MMX) //! { //! // your code... //! } @@ -250,12 +249,11 @@ //! a.setLogger(&logger); //! @endcode //! -//! You can see that logging goes through @c AsmJit::Assembler. If you are -//! using @c AsmJit::Compiler and you want to log messages in correct assembler -//! order, you should look at @c AsmJit::Compiler::comment() method. It allows -//! you to insert text message into @c AsmJit::Emittable list and -//! @c AsmJit::Compiler will send your message to @c AsmJit::Assembler in -//! correct order. +//! You can see that logging goes through @c Assembler. If you are using +//! @c Compiler and you want to log messages in correct assembler order, +//! you should look at @ref Compiler::comment() method. It allows you to +//! insert text message into items stream so the @c Compiler is able to +//! send messages to @ref Assembler in correct order. //! //! @sa @c AsmJit::Logger, @c AsmJit::FileLogger. @@ -281,7 +279,7 @@ //! free mechanism. It internally uses larger chunks of memory to make //! allocation fast and effective. //! -//! Using @c AsmJit::VirtualMemory::alloc() is crossplatform way how to +//! Using @c AsmJit::VirtualMemory::alloc() is cross-platform way how to //! allocate this kind of memory without worrying about operating system //! and it's API. Each memory block that is no longer needed should be //! freed by @c AsmJit::VirtualMemory::free() method. If you want better @@ -291,12 +289,6 @@ //! @sa @c AsmJit::VirtualMemory, @ AsmJit::MemoryManager. -//! @defgroup AsmJit_Util Utilities and helper classes. -//! -//! Contains some helper classes that's used by AsmJit library. - - - //! @addtogroup AsmJit_Config //! @{ @@ -332,21 +324,19 @@ //! //! There are not other namespaces used in AsmJit library. +// ---------------------------------------------------------------------------- +// [Dependencies - Core] +// ---------------------------------------------------------------------------- -// [Includes] -#include "Build.h" -#include "Assembler.h" -#include "CodeGenerator.h" -#include "Compiler.h" -#include "CpuInfo.h" -#include "Defs.h" -#include "Logger.h" -#include "MemoryManager.h" -#include "MemoryMarker.h" -#include "Operand.h" -#include "Platform.h" -#include "Util.h" +#include "core.h" +// ---------------------------------------------------------------------------- +// [Dependencies - X86 / X64] +// ---------------------------------------------------------------------------- + +#if defined(ASMJIT_X86) || defined(ASMJIT_X64) +#include "x86.h" +#endif // ASMJIT_X86 || ASMJIT_X64 // [Guard] -#endif // _ASMJIT_H +#endif // _ASMJIT_ASMJIT_H diff --git a/desmume/src/utils/AsmJit/AssemblerX86X64.h b/desmume/src/utils/AsmJit/AssemblerX86X64.h deleted file mode 100644 index c8e1a75f0..000000000 --- a/desmume/src/utils/AsmJit/AssemblerX86X64.h +++ /dev/null @@ -1,7826 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_ASSEMBLERX86X64_H -#define _ASMJIT_ASSEMBLERX86X64_H - -#if !defined(_ASMJIT_ASSEMBLER_H) -#warning "AsmJit/AssemblerX86X64.h can be only included by AsmJit/Assembler.h" -#endif // _ASMJIT_ASSEMBLER_H - -// [Dependencies] -#include "Build.h" -#include "Defs.h" -#include "Operand.h" -#include "Util.h" - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -//! @addtogroup AsmJit_Core -//! @{ - -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - -struct CodeGenerator; - -// ============================================================================ -// [AsmJit::AssemblerCore] -// ============================================================================ - -//! @brief AssemblerCore is part of @c Assembler class. -//! -//! @c AssemblerCore class implements part of assembler serializing API. The -//! reason why @c Assembler class was split is that we want to hide exported -//! symbols in dynamically linked libraries. -//! -//! Please always use @c Assembler class instead. -//! -//! @sa @c Assembler. -struct ASMJIT_API AssemblerCore -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Creates Assembler instance. - AssemblerCore(CodeGenerator* codeGenerator) ASMJIT_NOTHROW; - //! @brief Destroys Assembler instance - virtual ~AssemblerCore() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [LabelLink] - // -------------------------------------------------------------------------- - - //! @brief Data structure used to link linked-labels. - struct LabelLink - { - //! @brief Previous link. - LabelLink* prev; - //! @brief Offset. - sysint_t offset; - //! @brief Inlined displacement. - sysint_t displacement; - //! @brief RelocId if link must be absolute when relocated. - sysint_t relocId; - }; - - // -------------------------------------------------------------------------- - // [LabelData] - // -------------------------------------------------------------------------- - - //! @brief Label data. - struct LabelData - { - //! @brief Label offset. - sysint_t offset; - //! @brief Label links chain. - LabelLink* links; - }; - - // -------------------------------------------------------------------------- - // [RelocData] - // -------------------------------------------------------------------------- - - // X86 architecture uses 32-bit absolute addressing model by memory operands, - // but 64-bit mode uses relative addressing model (RIP + displacement). In - // code we are always using relative addressing model for referencing labels - // and embedded data. In 32-bit mode we must patch all references to absolute - // address before we can call generated function. We are patching only memory - // operands. - - //! @brief Code relocation data (relative vs absolute addresses). - struct RelocData - { - enum Type - { - ABSOLUTE_TO_ABSOLUTE = 0, - RELATIVE_TO_ABSOLUTE = 1, - ABSOLUTE_TO_RELATIVE = 2, - ABSOLUTE_TO_RELATIVE_TRAMPOLINE = 3 - }; - - //! @brief Type of relocation. - uint32_t type; - - //! @brief Size of relocation (4 or 8 bytes). - uint32_t size; - - //! @brief Offset from code begin address. - sysint_t offset; - - //! @brief Relative displacement or absolute address. - union - { - //! @brief Relative displacement from code begin address (not to @c offset). - sysint_t destination; - //! @brief Absolute address where to jump; - void* address; - }; - }; - - // -------------------------------------------------------------------------- - // [Code Generator] - // -------------------------------------------------------------------------- - - //! @brief Get code generator. - inline CodeGenerator* getCodeGenerator() const { return _codeGenerator; } - - // -------------------------------------------------------------------------- - // [Memory Management] - // -------------------------------------------------------------------------- - - //! @brief Get zone memory manager. - inline Zone& getZone() ASMJIT_NOTHROW { return _zone; } - - // -------------------------------------------------------------------------- - // [Logging] - // -------------------------------------------------------------------------- - - //! @brief Get logger. - inline Logger* getLogger() const ASMJIT_NOTHROW { return _logger; } - - //! @brief Set logger to @a logger. - virtual void setLogger(Logger* logger) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Error Handling] - // -------------------------------------------------------------------------- - - //! @brief Get error code. - inline uint32_t getError() const ASMJIT_NOTHROW { return _error; } - - //! @brief Set error code. - //! - //! This method is virtual, because higher classes can use it to catch all - //! errors. - virtual void setError(uint32_t error) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Properties] - // -------------------------------------------------------------------------- - - //! @brief Get assembler property. - uint32_t getProperty(uint32_t propertyId); - //! @brief Set assembler property. - void setProperty(uint32_t propertyId, uint32_t value); - - // -------------------------------------------------------------------------- - // [Buffer Getters / Setters] - // -------------------------------------------------------------------------- - - //! @brief Return start of assembler code buffer. - //! - //! Note that buffer address can change if you emit instruction or something - //! else. Use this pointer only when you finished or make sure you do not - //! use returned pointer after emitting. - inline uint8_t* getCode() const ASMJIT_NOTHROW - { return _buffer.getData(); } - - //! @brief Ensure space for next instruction. - //! - //! Note that this method can return false. It's rare and probably you never - //! get this, but in some situations it's still possible. - inline bool ensureSpace() ASMJIT_NOTHROW - { return _buffer.ensureSpace(); } - - //! @brief Return current offset in buffer). - inline sysint_t getOffset() const ASMJIT_NOTHROW - { return _buffer.getOffset(); } - - //! @brief Return current offset in buffer (same as getCffset() + getTramplineSize()). - inline sysint_t getCodeSize() const ASMJIT_NOTHROW - { return _buffer.getOffset() + getTrampolineSize(); } - - //! @brief Get size of all possible trampolines needed to successfuly generate - //! relative jumps to absolute addresses. This value is only non-zero if jmp - //! of call instructions were used with immediate operand (this means jump or - //! call absolute address directly). - //! - //! Currently only _emitJmpOrCallReloc() method can increase trampoline size - //! value. - inline sysint_t getTrampolineSize() const ASMJIT_NOTHROW - { return _trampolineSize; } - - //! @brief Set offset to @a o and returns previous offset. - //! - //! This method can be used to truncate code (previous offset is not - //! recorded) or to overwrite instruction stream at position @a o. - //! - //! @return Previous offset value that can be uset to set offset back later. - inline sysint_t toOffset(sysint_t o) ASMJIT_NOTHROW - { return _buffer.toOffset(o); } - - //! @brief Get capacity of internal code buffer. - inline sysint_t getCapacity() const ASMJIT_NOTHROW - { return _buffer.getCapacity(); } - - //! @brief Clear everything, but not deallocate buffers. - void clear() ASMJIT_NOTHROW; - - //! @brief Free internal buffer and NULL all pointers. - void free() ASMJIT_NOTHROW; - - //! @brief Take internal code buffer and NULL all pointers (you take the ownership). - uint8_t* takeCode() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Stream Setters / Getters] - // -------------------------------------------------------------------------- - - //! @brief Set byte at position @a pos. - inline uint8_t getByteAt(sysint_t pos) const ASMJIT_NOTHROW - { return _buffer.getByteAt(pos); } - - //! @brief Set word at position @a pos. - inline uint16_t getWordAt(sysint_t pos) const ASMJIT_NOTHROW - { return _buffer.getWordAt(pos); } - - //! @brief Set word at position @a pos. - inline uint32_t getDWordAt(sysint_t pos) const ASMJIT_NOTHROW - { return _buffer.getDWordAt(pos); } - - //! @brief Set word at position @a pos. - inline uint64_t getQWordAt(sysint_t pos) const ASMJIT_NOTHROW - { return _buffer.getQWordAt(pos); } - - //! @brief Set byte at position @a pos. - inline void setByteAt(sysint_t pos, uint8_t x) ASMJIT_NOTHROW - { _buffer.setByteAt(pos, x); } - - //! @brief Set word at position @a pos. - inline void setWordAt(sysint_t pos, uint16_t x) ASMJIT_NOTHROW - { _buffer.setWordAt(pos, x); } - - //! @brief Set word at position @a pos. - inline void setDWordAt(sysint_t pos, uint32_t x) ASMJIT_NOTHROW - { _buffer.setDWordAt(pos, x); } - - //! @brief Set word at position @a pos. - inline void setQWordAt(sysint_t pos, uint64_t x) ASMJIT_NOTHROW - { _buffer.setQWordAt(pos, x); } - - //! @brief Set word at position @a pos. - inline int32_t getInt32At(sysint_t pos) const ASMJIT_NOTHROW - { return (int32_t)_buffer.getDWordAt(pos); } - - //! @brief Set int32 at position @a pos. - inline void setInt32At(sysint_t pos, int32_t x) ASMJIT_NOTHROW - { _buffer.setDWordAt(pos, (int32_t)x); } - - //! @brief Set custom variable @a imm at position @a pos. - //! - //! @note This function is used to patch existing code. - void setVarAt(sysint_t pos, sysint_t i, uint8_t isUnsigned, uint32_t size) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Assembler Emitters] - // - // These emitters are not protecting buffer from overrun, this must be - // done is emitX86() methods by: - // if (!canEmit()) return; - // -------------------------------------------------------------------------- - - //! @brief Get whether next instruction can be emitted. - //! - //! This function behaves like @c ensureSpace(), but it also checks if - //! assembler is in error state and in that case it returns @c false. - //! Assembler internally always uses this function before new instruction is - //! emitted. - //! - //! It's implemented like: - //! return ensureSpace() && !getError(); - bool canEmit() ASMJIT_NOTHROW; - - //! @brief Emit Byte to internal buffer. - inline void _emitByte(uint8_t x) ASMJIT_NOTHROW - { _buffer.emitByte(x); } - - //! @brief Emit Word (2 bytes) to internal buffer. - inline void _emitWord(uint16_t x) ASMJIT_NOTHROW - { _buffer.emitWord(x); } - - //! @brief Emit DWord (4 bytes) to internal buffer. - inline void _emitDWord(uint32_t x) ASMJIT_NOTHROW - { _buffer.emitDWord(x); } - - //! @brief Emit QWord (8 bytes) to internal buffer. - inline void _emitQWord(uint64_t x) ASMJIT_NOTHROW - { _buffer.emitQWord(x); } - - //! @brief Emit Int32 (4 bytes) to internal buffer. - inline void _emitInt32(int32_t x) ASMJIT_NOTHROW - { _buffer.emitDWord((uint32_t)x); } - - //! @brief Emit system signed integer (4 or 8 bytes) to internal buffer. - inline void _emitSysInt(sysint_t x) ASMJIT_NOTHROW - { _buffer.emitSysInt(x); } - - //! @brief Emit system unsigned integer (4 or 8 bytes) to internal buffer. - inline void _emitSysUInt(sysuint_t x) ASMJIT_NOTHROW - { _buffer.emitSysUInt(x); } - - //! @brief Emit single @a opCode without operands. - inline void _emitOpCode(uint32_t opCode) ASMJIT_NOTHROW - { - // instruction prefix - if (opCode & 0xFF000000) _emitByte((uint8_t)((opCode & 0xFF000000) >> 24)); - // instruction opcodes - if (opCode & 0x00FF0000) _emitByte((uint8_t)((opCode & 0x00FF0000) >> 16)); - if (opCode & 0x0000FF00) _emitByte((uint8_t)((opCode & 0x0000FF00) >> 8)); - // last opcode is always emitted (can be also 0x00) - _emitByte((uint8_t)(opCode & 0x000000FF)); - } - - //! @brief Emit CS (code segmend) prefix. - //! - //! Behavior of this function is to emit code prefix only if memory operand - //! address uses code segment. Code segment is used through memory operand - //! with attached @c AsmJit::Label. - void _emitSegmentPrefix(const Operand& rm) ASMJIT_NOTHROW; - - //! @brief Emit MODR/M byte. - inline void _emitMod(uint8_t m, uint8_t o, uint8_t r) ASMJIT_NOTHROW - { _emitByte(((m & 0x03) << 6) | ((o & 0x07) << 3) | (r & 0x07)); } - - //! @brief Emit SIB byte. - inline void _emitSib(uint8_t s, uint8_t i, uint8_t b) ASMJIT_NOTHROW - { _emitByte(((s & 0x03) << 6) | ((i & 0x07) << 3) | (b & 0x07)); } - - //! @brief Emit REX prefix (64-bit mode only). - inline void _emitRexR(uint8_t w, uint8_t opReg, uint8_t regCode, bool forceRexPrefix) ASMJIT_NOTHROW - { -#if defined(ASMJIT_X64) - uint8_t r = (opReg & 0x8) != 0; - uint8_t b = (regCode & 0x8) != 0; - - // w Default operand size(0=Default, 1=64-bit). - // r Register field (1=high bit extension of the ModR/M REG field). - // x Index field not used in RexR - // b Base field (1=high bit extension of the ModR/M or SIB Base field). - if (w || r || b || forceRexPrefix) - { - _emitByte(0x40 | (w << 3) | (r << 2) | b); - } -#else - ASMJIT_UNUSED(w); - ASMJIT_UNUSED(opReg); - ASMJIT_UNUSED(regCode); - ASMJIT_UNUSED(forceRexPrefix); -#endif // ASMJIT_X64 - } - - //! @brief Emit REX prefix (64-bit mode only). - inline void _emitRexRM(uint8_t w, uint8_t opReg, const Operand& rm, bool forceRexPrefix) ASMJIT_NOTHROW - { -#if defined(ASMJIT_X64) - uint8_t r = (opReg & 0x8) != 0; - uint8_t x = 0; - uint8_t b = 0; - - if (rm.isReg()) - { - b = (reinterpret_cast(rm).getRegCode() & 0x8) != 0; - } - else if (rm.isMem()) - { - x = ((reinterpret_cast(rm).getIndex() & 0x8) != 0) & (reinterpret_cast(rm).getIndex() != INVALID_VALUE); - b = ((reinterpret_cast(rm).getBase() & 0x8) != 0) & (reinterpret_cast(rm).getBase() != INVALID_VALUE); - } - - // w Default operand size(0=Default, 1=64-bit). - // r Register field (1=high bit extension of the ModR/M REG field). - // x Index field (1=high bit extension of the SIB Index field). - // b Base field (1=high bit extension of the ModR/M or SIB Base field). - if (w || r || x || b || forceRexPrefix) - { - _emitByte(0x40 | (w << 3) | (r << 2) | (x << 1) | b); - } -#else - ASMJIT_UNUSED(w); - ASMJIT_UNUSED(opReg); - ASMJIT_UNUSED(rm); -#endif // ASMJIT_X64 - } - - //! @brief Emit Register / Register - calls _emitMod(3, opReg, r) - inline void _emitModR(uint8_t opReg, uint8_t r) ASMJIT_NOTHROW - { _emitMod(3, opReg, r); } - - //! @brief Emit Register / Register - calls _emitMod(3, opReg, r.code()) - inline void _emitModR(uint8_t opReg, const BaseReg& r) ASMJIT_NOTHROW - { _emitMod(3, opReg, r.getRegCode()); } - - //! @brief Emit register / memory address combination to buffer. - //! - //! This method can hangle addresses from simple to complex ones with - //! index and displacement. - void _emitModM(uint8_t opReg, const Mem& mem, sysint_t immSize) ASMJIT_NOTHROW; - - //! @brief Emit Reg<-Reg or Reg<-Reg|Mem ModRM (can be followed by SIB - //! and displacement) to buffer. - //! - //! This function internally calls @c _emitModM() or _emitModR() that depends - //! to @a op type. - //! - //! @note @a opReg is usually real register ID (see @c R) but some instructions - //! have specific format and in that cases @a opReg is part of opcode. - void _emitModRM(uint8_t opReg, const Operand& op, sysint_t immSize) ASMJIT_NOTHROW; - - //! @brief Emit instruction where register is inlined to opcode. - void _emitX86Inl(uint32_t opCode, uint8_t i16bit, uint8_t rexw, uint8_t reg, bool forceRexPrefix) ASMJIT_NOTHROW; - - //! @brief Emit instruction with reg/memory operand. - void _emitX86RM(uint32_t opCode, uint8_t i16bit, uint8_t rexw, uint8_t o, - const Operand& op, sysint_t immSize, bool forceRexPrefix) ASMJIT_NOTHROW; - - //! @brief Emit FPU instruction with no operands. - void _emitFpu(uint32_t opCode) ASMJIT_NOTHROW; - - //! @brief Emit FPU instruction with one operand @a sti (index of FPU register). - void _emitFpuSTI(uint32_t opCode, uint32_t sti) ASMJIT_NOTHROW; - - //! @brief Emit FPU instruction with one operand @a opReg and memory operand @a mem. - void _emitFpuMEM(uint32_t opCode, uint8_t opReg, const Mem& mem) ASMJIT_NOTHROW; - - //! @brief Emit MMX/SSE instruction. - void _emitMmu(uint32_t opCode, uint8_t rexw, uint8_t opReg, const Operand& src, - sysint_t immSize) ASMJIT_NOTHROW; - - //! @brief Emit displacement. - LabelLink* _emitDisplacement(LabelData& l_data, sysint_t inlinedDisplacement, int size) ASMJIT_NOTHROW; - - //! @brief Emit relative relocation to absolute pointer @a target. It's needed - //! to add what instruction is emitting this, because in x64 mode the relative - //! displacement can be impossible to calculate and in this case the trampoline - //! is used. - void _emitJmpOrCallReloc(uint32_t instruction, void* target) ASMJIT_NOTHROW; - - // Helpers to decrease binary code size. These four emit methods are just - // helpers thats used by assembler. They call emitX86() adding NULLs - // to first, second and third operand, if needed. - - //! @brief Emit X86/FPU or MM/XMM instruction. - void _emitInstruction(uint32_t code) ASMJIT_NOTHROW; - - //! @brief Emit X86/FPU or MM/XMM instruction. - void _emitInstruction(uint32_t code, const Operand* o0) ASMJIT_NOTHROW; - - //! @brief Emit X86/FPU or MM/XMM instruction. - void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1) ASMJIT_NOTHROW; - - //! @brief Emit X86/FPU or MM/XMM instruction. - //! - //! Operands @a o1, @a o2 or @a o3 can be @c NULL if they are not used. - //! - //! Hint: Use @c emitX86() helpers to emit instructions. - void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2) ASMJIT_NOTHROW; - - //! @brief Private method for emitting jcc. - void _emitJcc(uint32_t code, const Label* label, uint32_t hint) ASMJIT_NOTHROW; - - //! @brief Private method for emitting short jcc. - inline void _emitShortJcc(uint32_t code, const Label* label, uint32_t hint) - { - _emitOptions |= EMIT_OPTION_SHORT_JUMP; - _emitJcc(code, label, hint); - } - - // -------------------------------------------------------------------------- - // [Relocation helpers] - // -------------------------------------------------------------------------- - - //! @brief Relocate code to a given address @a dst. - //! - //! @param dst Where the relocated code should me stored. The pointer can be - //! address returned by virtual memory allocator or your own address if you - //! want only to store the code for later reuse (or load, etc...). - //! @param addressBase Base address used for relocation. When using JIT code - //! generation, this will be the same as @a dst, only casted to system - //! integer type. But when generating code for remote process then the value - //! can be different. - //! - //! @retval The bytes used. Code-generator can create trampolines which are - //! used when calling other functions inside the JIT code. However, these - //! trampolines can be unused so the relocCode() returns the exact size needed - //! for the function. - //! - //! A given buffer will be overwritten, to get number of bytes required use - //! @c getCodeSize() . - virtual sysuint_t relocCode(void* dst, sysuint_t addressBase) const ASMJIT_NOTHROW; - - //! @brief Simplifed version of @c relocCode() method. - inline sysuint_t relocCode(void* dst) const ASMJIT_NOTHROW - { - return relocCode(dst, (sysuint_t)dst); - } - - // -------------------------------------------------------------------------- - // [Embed] - // -------------------------------------------------------------------------- - - //! @brief Embed data into instruction stream. - void embed(const void* data, sysuint_t length) ASMJIT_NOTHROW; - //! @brief Embed absolute label pointer (4 or 8 bytes). - void embedLabel(const Label& label) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Align] - // -------------------------------------------------------------------------- - - //! @brief Align target buffer to @a m bytes. - //! - //! Typical usage of this is to align labels at start of the inner loops. - //! - //! Inserts @c nop() instructions or CPU optimized NOPs. - void align(uint32_t m) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Label] - // -------------------------------------------------------------------------- - - //! @brief Create and return new label. - Label newLabel() ASMJIT_NOTHROW; - - //! @brief Register labels (used by @c Compiler). - void registerLabels(sysuint_t count) ASMJIT_NOTHROW; - - //! @brief Bind label to the current offset. - //! - //! @note Label can be bound only once! - void bind(const Label& label) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Make] - // -------------------------------------------------------------------------- - - //! @brief Make is convenience method to make currently serialized code and - //! return pointer to generated function. - //! - //! What you need is only to cast this pointer to your function type and call - //! it. Note that if there was an error and calling @c getError() method not - //! returns @c ERROR_NONE (zero) then this function always return @c NULL and - //! error value remains the same. - virtual void* make() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Links] - // -------------------------------------------------------------------------- - - LabelLink* _newLabelLink() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - //! @brief Zone memory management. - Zone _zone; - - //! @brief Code generator instance. - CodeGenerator* _codeGenerator; - - //! @brief Logger. - Logger* _logger; - - //! @brief Last error code. - uint32_t _error; - - //! @brief Properties. - uint32_t _properties; - - //! @brief Emit flags for next instruction (cleared after emit). - uint32_t _emitOptions; - - //! @brief Binary code buffer. - Buffer _buffer; - - //! @brief Size of possible trampolines. - sysint_t _trampolineSize; - - //! @brief Linked list of unused links (@c LabelLink* structures) - LabelLink* _unusedLinks; - - //! @brief Labels data. - PodVector _labelData; - - //! @brief Relocations data. - PodVector _relocData; - - //! @brief Comment that will be logger by next emitted instruction. After - //! instruction is logger the _comment is set to NULL. - const char* _comment; - - friend struct CompilerCore; - friend struct EInstruction; -}; - -// ============================================================================ -// [AsmJit::AssemblerIntrinsics] -// ============================================================================ - -//! @brief AssemblerIntrinsics is part of @c Assembler class. -//! -//! @c AssemblerIntrinsics class implements part of assembler serializing API. -//! The reason why @c Assembler class was split is that we want to hide exported -//! symbols in dynamically linked libraries. -//! -//! Please always use @c Assembler class instead. -//! -//! @sa @c Assembler. -struct ASMJIT_HIDDEN AssemblerIntrinsics : public AssemblerCore -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - inline AssemblerIntrinsics(CodeGenerator* codeGenerator) ASMJIT_NOTHROW : - AssemblerCore(codeGenerator) - { - } - - // -------------------------------------------------------------------------- - // [Embed] - // -------------------------------------------------------------------------- - - //! @brief Add 8-bit integer data to the instuction stream. - inline void db(uint8_t x) ASMJIT_NOTHROW { embed(&x, 1); } - //! @brief Add 16-bit integer data to the instuction stream. - inline void dw(uint16_t x) ASMJIT_NOTHROW { embed(&x, 2); } - //! @brief Add 32-bit integer data to the instuction stream. - inline void dd(uint32_t x) ASMJIT_NOTHROW { embed(&x, 4); } - //! @brief Add 64-bit integer data to the instuction stream. - inline void dq(uint64_t x) ASMJIT_NOTHROW { embed(&x, 8); } - - //! @brief Add 8-bit integer data to the instuction stream. - inline void dint8(int8_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int8_t)); } - //! @brief Add 8-bit integer data to the instuction stream. - inline void duint8(uint8_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint8_t)); } - - //! @brief Add 16-bit integer data to the instuction stream. - inline void dint16(int16_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int16_t)); } - //! @brief Add 16-bit integer data to the instuction stream. - inline void duint16(uint16_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint16_t)); } - - //! @brief Add 32-bit integer data to the instuction stream. - inline void dint32(int32_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int32_t)); } - //! @brief Add 32-bit integer data to the instuction stream. - inline void duint32(uint32_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint32_t)); } - - //! @brief Add 64-bit integer data to the instuction stream. - inline void dint64(int64_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int64_t)); } - //! @brief Add 64-bit integer data to the instuction stream. - inline void duint64(uint64_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint64_t)); } - - //! @brief Add system-integer data to the instuction stream. - inline void dsysint(sysint_t x) ASMJIT_NOTHROW { embed(&x, sizeof(sysint_t)); } - //! @brief Add system-integer data to the instuction stream. - inline void dsysuint(sysuint_t x) ASMJIT_NOTHROW { embed(&x, sizeof(sysuint_t)); } - - //! @brief Add float data to the instuction stream. - inline void dfloat(float x) ASMJIT_NOTHROW { embed(&x, sizeof(float)); } - //! @brief Add double data to the instuction stream. - inline void ddouble(double x) ASMJIT_NOTHROW { embed(&x, sizeof(double)); } - - //! @brief Add pointer data to the instuction stream. - inline void dptr(void* x) ASMJIT_NOTHROW { embed(&x, sizeof(void*)); } - - //! @brief Add MM data to the instuction stream. - inline void dmm(const MMData& x) ASMJIT_NOTHROW { embed(&x, sizeof(MMData)); } - //! @brief Add XMM data to the instuction stream. - inline void dxmm(const XMMData& x) ASMJIT_NOTHROW { embed(&x, sizeof(XMMData)); } - - //! @brief Add data to the instuction stream. - inline void data(const void* data, sysuint_t size) ASMJIT_NOTHROW { embed(data, size); } - - //! @brief Add data in a given structure instance to the instuction stream. - template - inline void dstruct(const T& x) ASMJIT_NOTHROW { embed(&x, sizeof(T)); } - - // -------------------------------------------------------------------------- - // [X86 Instructions] - // -------------------------------------------------------------------------- - - //! @brief Add with Carry. - inline void adc(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_ADC, &dst, &src); - } - //! @brief Add with Carry. - inline void adc(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_ADC, &dst, &src); - } - //! @brief Add with Carry. - inline void adc(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_ADC, &dst, &src); - } - //! @brief Add with Carry. - inline void adc(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_ADC, &dst, &src); - } - //! @brief Add with Carry. - inline void adc(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_ADC, &dst, &src); - } - - //! @brief Add. - inline void add(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_ADD, &dst, &src); - } - //! @brief Add. - inline void add(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_ADD, &dst, &src); - } - //! @brief Add. - inline void add(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_ADD, &dst, &src); - } - //! @brief Add. - inline void add(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_ADD, &dst, &src); - } - //! @brief Add. - inline void add(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_ADD, &dst, &src); - } - - //! @brief Logical And. - inline void and_(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_AND, &dst, &src); - } - //! @brief Logical And. - inline void and_(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_AND, &dst, &src); - } - //! @brief Logical And. - inline void and_(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_AND, &dst, &src); - } - //! @brief Logical And. - inline void and_(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_AND, &dst, &src); - } - //! @brief Logical And. - inline void and_(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_AND, &dst, &src); - } - - //! @brief Bit Scan Forward. - inline void bsf(const GPReg& dst, const GPReg& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - _emitInstruction(INST_BSF, &dst, &src); - } - //! @brief Bit Scan Forward. - inline void bsf(const GPReg& dst, const Mem& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - _emitInstruction(INST_BSF, &dst, &src); - } - - //! @brief Bit Scan Reverse. - inline void bsr(const GPReg& dst, const GPReg& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - _emitInstruction(INST_BSR, &dst, &src); - } - //! @brief Bit Scan Reverse. - inline void bsr(const GPReg& dst, const Mem& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - _emitInstruction(INST_BSR, &dst, &src); - } - - //! @brief Byte swap (32-bit or 64-bit registers only) (i486). - inline void bswap(const GPReg& dst) - { - ASMJIT_ASSERT(dst.getRegType() == REG_TYPE_GPD || dst.getRegType() == REG_TYPE_GPQ); - _emitInstruction(INST_BSWAP, &dst); - } - - //! @brief Bit test. - inline void bt(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_BT, &dst, &src); - } - //! @brief Bit test. - inline void bt(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_BT, &dst, &src); - } - //! @brief Bit test. - inline void bt(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_BT, &dst, &src); - } - //! @brief Bit test. - inline void bt(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_BT, &dst, &src); - } - - //! @brief Bit test and complement. - inline void btc(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_BTC, &dst, &src); - } - //! @brief Bit test and complement. - inline void btc(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_BTC, &dst, &src); - } - //! @brief Bit test and complement. - inline void btc(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_BTC, &dst, &src); - } - //! @brief Bit test and complement. - inline void btc(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_BTC, &dst, &src); - } - - //! @brief Bit test and reset. - inline void btr(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_BTR, &dst, &src); - } - //! @brief Bit test and reset. - inline void btr(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_BTR, &dst, &src); - } - //! @brief Bit test and reset. - inline void btr(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_BTR, &dst, &src); - } - //! @brief Bit test and reset. - inline void btr(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_BTR, &dst, &src); - } - - //! @brief Bit test and set. - inline void bts(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_BTS, &dst, &src); - } - //! @brief Bit test and set. - inline void bts(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_BTS, &dst, &src); - } - //! @brief Bit test and set. - inline void bts(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_BTS, &dst, &src); - } - //! @brief Bit test and set. - inline void bts(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_BTS, &dst, &src); - } - - //! @brief Call Procedure. - inline void call(const GPReg& dst) - { - ASMJIT_ASSERT(dst.isRegType(REG_TYPE_GPN)); - _emitInstruction(INST_CALL, &dst); - } - //! @brief Call Procedure. - inline void call(const Mem& dst) - { - _emitInstruction(INST_CALL, &dst); - } - //! @brief Call Procedure. - inline void call(const Imm& dst) - { - _emitInstruction(INST_CALL, &dst); - } - //! @brief Call Procedure. - //! @overload - inline void call(void* dst) - { - Imm imm((sysint_t)dst); - _emitInstruction(INST_CALL, &imm); - } - - //! @brief Call Procedure. - inline void call(const Label& label) - { - _emitInstruction(INST_CALL, &label); - } - - //! @brief Convert Byte to Word (Sign Extend). - //! - //! AX <- Sign Extend AL - inline void cbw() - { - _emitInstruction(INST_CBW); - } - - //! @brief Convert Word to DWord (Sign Extend). - //! - //! EAX <- Sign Extend AX - inline void cwde() - { - _emitInstruction(INST_CWDE); - } - -#if defined(ASMJIT_X64) - //! @brief Convert DWord to QWord (Sign Extend). - //! - //! RAX <- Sign Extend EAX - inline void cdqe() - { - _emitInstruction(INST_CDQE); - } -#endif // ASMJIT_X64 - - //! @brief Clear Carry flag - //! - //! This instruction clears the CF flag in the EFLAGS register. - inline void clc() - { - _emitInstruction(INST_CLC); - } - - //! @brief Clear Direction flag - //! - //! This instruction clears the DF flag in the EFLAGS register. - inline void cld() - { - _emitInstruction(INST_CLD); - } - - //! @brief Complement Carry Flag. - //! - //! This instruction complements the CF flag in the EFLAGS register. - //! (CF = NOT CF) - inline void cmc() - { - _emitInstruction(INST_CMC); - } - - //! @brief Conditional Move. - inline void cmov(CONDITION cc, const GPReg& dst, const GPReg& src) - { - _emitInstruction(ConditionToInstruction::toCMovCC(cc), &dst, &src); - } - - //! @brief Conditional Move. - inline void cmov(CONDITION cc, const GPReg& dst, const Mem& src) - { - _emitInstruction(ConditionToInstruction::toCMovCC(cc), &dst, &src); - } - - //! @brief Conditional Move. - inline void cmova (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVA , &dst, &src); } - //! @brief Conditional Move. - inline void cmova (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVA , &dst, &src); } - //! @brief Conditional Move. - inline void cmovae (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVAE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovae (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVAE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovb (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVB , &dst, &src); } - //! @brief Conditional Move. - inline void cmovb (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVB , &dst, &src); } - //! @brief Conditional Move. - inline void cmovbe (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVBE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovbe (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVBE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovc (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVC , &dst, &src); } - //! @brief Conditional Move. - inline void cmovc (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVC , &dst, &src); } - //! @brief Conditional Move. - inline void cmove (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVE , &dst, &src); } - //! @brief Conditional Move. - inline void cmove (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovg (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVG , &dst, &src); } - //! @brief Conditional Move. - inline void cmovg (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVG , &dst, &src); } - //! @brief Conditional Move. - inline void cmovge (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVGE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovge (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVGE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovl (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVL , &dst, &src); } - //! @brief Conditional Move. - inline void cmovl (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVL , &dst, &src); } - //! @brief Conditional Move. - inline void cmovle (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVLE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovle (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVLE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovna (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNA , &dst, &src); } - //! @brief Conditional Move. - inline void cmovna (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNA , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnae(const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNAE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnae(const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNAE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnb (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNB , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnb (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNB , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnbe(const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNBE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnbe(const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNBE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnc (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNC , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnc (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNC , &dst, &src); } - //! @brief Conditional Move. - inline void cmovne (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovne (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovng (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNG , &dst, &src); } - //! @brief Conditional Move. - inline void cmovng (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNG , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnge(const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNGE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnge(const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNGE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnl (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNL , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnl (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNL , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnle(const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNLE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnle(const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNLE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovno (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovno (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnp (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNP , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnp (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNP , &dst, &src); } - //! @brief Conditional Move. - inline void cmovns (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNS , &dst, &src); } - //! @brief Conditional Move. - inline void cmovns (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNS , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnz (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVNZ , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnz (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVNZ , &dst, &src); } - //! @brief Conditional Move. - inline void cmovo (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovo (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovp (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVP , &dst, &src); } - //! @brief Conditional Move. - inline void cmovp (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVP , &dst, &src); } - //! @brief Conditional Move. - inline void cmovpe (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVPE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovpe (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVPE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovpo (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVPO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovpo (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVPO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovs (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVS , &dst, &src); } - //! @brief Conditional Move. - inline void cmovs (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVS , &dst, &src); } - //! @brief Conditional Move. - inline void cmovz (const GPReg& dst, const GPReg& src) { _emitInstruction(INST_CMOVZ , &dst, &src); } - //! @brief Conditional Move. - inline void cmovz (const GPReg& dst, const Mem& src) { _emitInstruction(INST_CMOVZ , &dst, &src); } - - //! @brief Compare Two Operands. - inline void cmp(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_CMP, &dst, &src); - } - //! @brief Compare Two Operands. - inline void cmp(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_CMP, &dst, &src); - } - //! @brief Compare Two Operands. - inline void cmp(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_CMP, &dst, &src); - } - //! @brief Compare Two Operands. - inline void cmp(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_CMP, &dst, &src); - } - //! @brief Compare Two Operands. - inline void cmp(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_CMP, &dst, &src); - } - - //! @brief Compare and Exchange (i486). - inline void cmpxchg(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_CMPXCHG, &dst, &src); - } - //! @brief Compare and Exchange (i486). - inline void cmpxchg(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_CMPXCHG, &dst, &src); - } - - //! @brief Compares the 64-bit value in EDX:EAX with the memory operand (Pentium). - //! - //! If the values are equal, then this instruction stores the 64-bit value - //! in ECX:EBX into the memory operand and sets the zero flag. Otherwise, - //! this instruction copies the 64-bit memory operand into the EDX:EAX - //! registers and clears the zero flag. - inline void cmpxchg8b(const Mem& dst) - { - _emitInstruction(INST_CMPXCHG8B, &dst); - } - -#if defined(ASMJIT_X64) - //! @brief Compares the 128-bit value in RDX:RAX with the memory operand (X64). - //! - //! If the values are equal, then this instruction stores the 128-bit value - //! in RCX:RBX into the memory operand and sets the zero flag. Otherwise, - //! this instruction copies the 128-bit memory operand into the RDX:RAX - //! registers and clears the zero flag. - inline void cmpxchg16b(const Mem& dst) - { - _emitInstruction(INST_CMPXCHG16B, &dst); - } -#endif // ASMJIT_X64 - - //! @brief CPU Identification (i486). - inline void cpuid() - { - _emitInstruction(INST_CPUID); - } - -#if defined(ASMJIT_X86) - //! @brief Decimal adjust AL after addition - //! - //! This instruction adjusts the sum of two packed BCD values to create - //! a packed BCD result. - //! - //! @note This instruction is only available in 32-bit mode. - inline void daa() - { - _emitInstruction(INST_DAA); - } -#endif // ASMJIT_X86 - -#if defined(ASMJIT_X86) - //! @brief Decimal adjust AL after subtraction - //! - //! This instruction adjusts the result of the subtraction of two packed - //! BCD values to create a packed BCD result. - //! - //! @note This instruction is only available in 32-bit mode. - inline void das() - { - _emitInstruction(INST_DAS); - } -#endif // ASMJIT_X86 - - //! @brief Decrement by 1. - //! @note This instruction can be slower than sub(dst, 1) - inline void dec(const GPReg& dst) - { - _emitInstruction(INST_DEC, &dst); - } - //! @brief Decrement by 1. - //! @note This instruction can be slower than sub(dst, 1) - inline void dec(const Mem& dst) - { - _emitInstruction(INST_DEC, &dst); - } - - //! @brief Unsigned divide. - //! - //! This instruction divides (unsigned) the value in the AL, AX, or EAX - //! register by the source operand and stores the result in the AX, - //! DX:AX, or EDX:EAX registers. - inline void div(const GPReg& src) - { - _emitInstruction(INST_DIV, &src); - } - //! @brief Unsigned divide. - //! @overload - inline void div(const Mem& src) - { - _emitInstruction(INST_DIV, &src); - } - - //! @brief Make Stack Frame for Procedure Parameters. - inline void enter(const Imm& imm16, const Imm& imm8) - { - _emitInstruction(INST_ENTER, &imm16, &imm8); - } - - //! @brief Signed divide. - //! - //! This instruction divides (signed) the value in the AL, AX, or EAX - //! register by the source operand and stores the result in the AX, - //! DX:AX, or EDX:EAX registers. - inline void idiv(const GPReg& src) - { - _emitInstruction(INST_IDIV, &src); - } - //! @brief Signed divide. - //! @overload - inline void idiv(const Mem& src) - { - _emitInstruction(INST_IDIV, &src); - } - - //! @brief Signed multiply. - //! - //! Source operand (in a general-purpose register or memory location) - //! is multiplied by the value in the AL, AX, or EAX register (depending - //! on the operand size) and the product is stored in the AX, DX:AX, or - //! EDX:EAX registers, respectively. - inline void imul(const GPReg& src) - { - _emitInstruction(INST_IMUL, &src); - } - //! @overload - inline void imul(const Mem& src) - { - _emitInstruction(INST_IMUL, &src); - } - - //! @brief Signed multiply. - //! - //! Destination operand (the first operand) is multiplied by the source - //! operand (second operand). The destination operand is a general-purpose - //! register and the source operand is an immediate value, a general-purpose - //! register, or a memory location. The product is then stored in the - //! destination operand location. - inline void imul(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_IMUL, &dst, &src); - } - //! @brief Signed multiply. - //! @overload - inline void imul(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_IMUL, &dst, &src); - } - //! @brief Signed multiply. - //! @overload - inline void imul(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_IMUL, &dst, &src); - } - - //! @brief Signed multiply. - //! - //! source operand (which can be a general-purpose register or a memory - //! location) is multiplied by the second source operand (an immediate - //! value). The product is then stored in the destination operand - //! (a general-purpose register). - inline void imul(const GPReg& dst, const GPReg& src, const Imm& imm) - { - _emitInstruction(INST_IMUL, &dst, &src, &imm); - } - //! @overload - inline void imul(const GPReg& dst, const Mem& src, const Imm& imm) - { - _emitInstruction(INST_IMUL, &dst, &src, &imm); - } - - //! @brief Increment by 1. - //! @note This instruction can be slower than add(dst, 1) - inline void inc(const GPReg& dst) - { - _emitInstruction(INST_INC, &dst); - } - //! @brief Increment by 1. - //! @note This instruction can be slower than add(dst, 1) - inline void inc(const Mem& dst) - { - _emitInstruction(INST_INC, &dst); - } - - //! @brief Interrupt 3 - trap to debugger. - inline void int3() - { - _emitInstruction(INST_INT3); - } - - //! @brief Jump to label @a label if condition @a cc is met. - //! - //! This instruction checks the state of one or more of the status flags in - //! the EFLAGS register (CF, OF, PF, SF, and ZF) and, if the flags are in the - //! specified state (condition), performs a jump to the target instruction - //! specified by the destination operand. A condition code (cc) is associated - //! with each instruction to indicate the condition being tested for. If the - //! condition is not satisfied, the jump is not performed and execution - //! continues with the instruction following the Jcc instruction. - inline void j(CONDITION cc, const Label& label, uint32_t hint = HINT_NONE) - { - _emitJcc(ConditionToInstruction::toJCC(cc), &label, hint); - } - - //! @brief Jump to label @a label if condition is met. - inline void ja (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JA , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jae (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JAE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jb (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JB , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jbe (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JBE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jc (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JC , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void je (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jg (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JG , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jge (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JGE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jl (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JL , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jle (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JLE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jna (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNA , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnae(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNAE, &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnb (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNB , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnbe(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNBE, &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnc (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNC , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jne (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jng (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNG , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnge(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNGE, &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnl (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNL , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnle(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNLE, &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jno (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNO , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnp (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNP , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jns (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNS , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnz (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNZ , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jo (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JO , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jp (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JP , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jpe (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JPE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jpo (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JPO , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void js (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JS , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jz (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JZ , &label, hint); } - - //! @brief Short jump to label @a label if condition @a cc is met. - //! @sa j() - inline void short_j(CONDITION cc, const Label& label, uint32_t hint = HINT_NONE) - { - _emitOptions |= EMIT_OPTION_SHORT_JUMP; - j(cc, label, hint); - } - - //! @brief Short jump to label @a label if condition is met. - inline void short_ja (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JA , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jae (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JAE , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jb (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JB , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jbe (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JBE , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jc (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JC , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_je (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JE , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jg (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JG , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jge (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JGE , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jl (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JL , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jle (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JLE , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jna (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNA , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jnae(const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNAE, &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jnb (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNB , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jnbe(const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNBE, &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jnc (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNC , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jne (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNE , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jng (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNG , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jnge(const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNGE, &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jnl (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNL , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jnle(const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNLE, &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jno (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNO , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jnp (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNP , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jns (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNS , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jnz (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JNZ , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jo (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JO , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jp (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JP , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jpe (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JPE , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jpo (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JPO , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_js (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JS , &label, hint); } - //! @brief Short jump to label @a label if condition is met. - inline void short_jz (const Label& label, uint32_t hint = HINT_NONE) { _emitShortJcc(INST_JZ , &label, hint); } - - //! @brief Jump. - //! @overload - inline void jmp(const GPReg& dst) - { - _emitInstruction(INST_JMP, &dst); - } - //! @brief Jump. - //! @overload - inline void jmp(const Mem& dst) - { - _emitInstruction(INST_JMP, &dst); - } - //! @brief Jump. - //! @overload - inline void jmp(const Imm& dst) - { - _emitInstruction(INST_JMP, &dst); - } - - //! @brief Jump. - //! @overload - inline void jmp(void* dst) - { - Imm imm((sysint_t)dst); - _emitInstruction(INST_JMP, &imm); - } - - //! @brief Jump. - //! - //! This instruction transfers program control to a different point - //! in the instruction stream without recording return information. - //! The destination (target) operand specifies the label of the - //! instruction being jumped to. - inline void jmp(const Label& label) - { - _emitInstruction(INST_JMP, &label); - } - - //! @brief Short jump. - //! @sa jmp() - inline void short_jmp(const Label& label) - { - _emitOptions |= EMIT_OPTION_SHORT_JUMP; - _emitInstruction(INST_JMP, &label); - } - - //! @brief Load Effective Address - //! - //! This instruction computes the effective address of the second - //! operand (the source operand) and stores it in the first operand - //! (destination operand). The source operand is a memory address - //! (offset part) specified with one of the processors addressing modes. - //! The destination operand is a general-purpose register. - inline void lea(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_LEA, &dst, &src); - } - - //! @brief High Level Procedure Exit. - inline void leave() - { - _emitInstruction(INST_LEAVE); - } - - //! @brief Move. - //! - //! This instruction copies the second operand (source operand) to the first - //! operand (destination operand). The source operand can be an immediate - //! value, general-purpose register, segment register, or memory location. - //! The destination register can be a general-purpose register, segment - //! register, or memory location. Both operands must be the same size, which - //! can be a byte, a word, or a DWORD. - //! - //! @note To move MMX or SSE registers to/from GP registers or memory, use - //! corresponding functions: @c movd(), @c movq(), etc. Passing MMX or SSE - //! registers to @c mov() is illegal. - inline void mov(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - //! @brief Move. - //! @overload - inline void mov(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - //! @brief Move. - //! @overload - inline void mov(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - //! @brief Move. - //! @overload - inline void mov(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - //! @brief Move. - //! @overload - inline void mov(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - - //! @brief Move from segment register. - //! @overload. - inline void mov(const GPReg& dst, const SegmentReg& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - - //! @brief Move from segment register. - //! @overload. - inline void mov(const Mem& dst, const SegmentReg& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - - //! @brief Move to segment register. - //! @overload. - inline void mov(const SegmentReg& dst, const GPReg& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - - //! @brief Move to segment register. - //! @overload. - inline void mov(const SegmentReg& dst, const Mem& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - - //! @brief Move byte, word, dword or qword from absolute address @a src to - //! AL, AX, EAX or RAX register. - inline void mov_ptr(const GPReg& dst, void* src) - { - ASMJIT_ASSERT(dst.getRegIndex() == 0); - Imm imm((sysint_t)src); - _emitInstruction(INST_MOV_PTR, &dst, &imm); - } - - //! @brief Move byte, word, dword or qword from AL, AX, EAX or RAX register - //! to absolute address @a dst. - inline void mov_ptr(void* dst, const GPReg& src) - { - ASMJIT_ASSERT(src.getRegIndex() == 0); - Imm imm((sysint_t)dst); - _emitInstruction(INST_MOV_PTR, &imm, &src); - } - - //! @brief Move with Sign-Extension. - //! - //! This instruction copies the contents of the source operand (register - //! or memory location) to the destination operand (register) and sign - //! extends the value to 16, 32 or 64-bits. - //! - //! @sa movsxd(). - void movsx(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_MOVSX, &dst, &src); - } - //! @brief Move with Sign-Extension. - //! @overload - void movsx(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVSX, &dst, &src); - } - -#if defined(ASMJIT_X64) - //! @brief Move DWord to QWord with sign-extension. - inline void movsxd(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_MOVSXD, &dst, &src); - } - //! @brief Move DWord to QWord with sign-extension. - //! @overload - inline void movsxd(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVSXD, &dst, &src); - } -#endif // ASMJIT_X64 - - //! @brief Move with Zero-Extend. - //! - //! This instruction copies the contents of the source operand (register - //! or memory location) to the destination operand (register) and zero - //! extends the value to 16 or 32-bits. The size of the converted value - //! depends on the operand-size attribute. - inline void movzx(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_MOVZX, &dst, &src); - } - //! @brief Move with Zero-Extend. - //! @brief Overload - inline void movzx(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVZX, &dst, &src); - } - - //! @brief Unsigned multiply. - //! - //! Source operand (in a general-purpose register or memory location) - //! is multiplied by the value in the AL, AX, or EAX register (depending - //! on the operand size) and the product is stored in the AX, DX:AX, or - //! EDX:EAX registers, respectively. - inline void mul(const GPReg& src) - { - _emitInstruction(INST_MUL, &src); - } - //! @brief Unsigned multiply. - //! @overload - inline void mul(const Mem& src) - { - _emitInstruction(INST_MUL, &src); - } - - //! @brief Two's Complement Negation. - inline void neg(const GPReg& dst) - { - _emitInstruction(INST_NEG, &dst); - } - //! @brief Two's Complement Negation. - inline void neg(const Mem& dst) - { - _emitInstruction(INST_NEG, &dst); - } - - //! @brief No Operation. - //! - //! This instruction performs no operation. This instruction is a one-byte - //! instruction that takes up space in the instruction stream but does not - //! affect the machine context, except the EIP register. The NOP instruction - //! is an alias mnemonic for the XCHG (E)AX, (E)AX instruction. - inline void nop() - { - _emitInstruction(INST_NOP); - } - - //! @brief One's Complement Negation. - inline void not_(const GPReg& dst) - { - _emitInstruction(INST_NOT, &dst); - } - //! @brief One's Complement Negation. - inline void not_(const Mem& dst) - { - _emitInstruction(INST_NOT, &dst); - } - - //! @brief Logical Inclusive OR. - inline void or_(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_OR, &dst, &src); - } - //! @brief Logical Inclusive OR. - inline void or_(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_OR, &dst, &src); - } - //! @brief Logical Inclusive OR. - inline void or_(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_OR, &dst, &src); - } - //! @brief Logical Inclusive OR. - inline void or_(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_OR, &dst, &src); - } - //! @brief Logical Inclusive OR. - inline void or_(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_OR, &dst, &src); - } - - //! @brief Pop a Value from the Stack. - //! - //! This instruction loads the value from the top of the stack to the location - //! specified with the destination operand and then increments the stack pointer. - //! The destination operand can be a general purpose register, memory location, - //! or segment register. - inline void pop(const GPReg& dst) - { - ASMJIT_ASSERT(dst.isRegType(REG_TYPE_GPW) || dst.isRegType(REG_TYPE_GPN)); - _emitInstruction(INST_POP, &dst); - } - - inline void pop(const Mem& dst) - { - ASMJIT_ASSERT(dst.getSize() == 2 || dst.getSize() == sizeof(sysint_t)); - _emitInstruction(INST_POP, &dst); - } - -#if defined(ASMJIT_X86) - //! @brief Pop All General-Purpose Registers. - //! - //! Pop EDI, ESI, EBP, EBX, EDX, ECX, and EAX. - inline void popad() - { - _emitInstruction(INST_POPAD); - } -#endif // ASMJIT_X86 - - //! @brief Pop Stack into EFLAGS Register (32-bit or 64-bit). - inline void popf() - { -#if defined(ASMJIT_X86) - popfd(); -#else - popfq(); -#endif - } - -#if defined(ASMJIT_X86) - //! @brief Pop Stack into EFLAGS Register (32-bit). - inline void popfd() { _emitInstruction(INST_POPFD); } -#else - //! @brief Pop Stack into EFLAGS Register (64-bit). - inline void popfq() { _emitInstruction(INST_POPFQ); } -#endif - - //! @brief Push WORD/DWORD/QWORD Onto the Stack. - //! - //! @note 32-bit architecture pushed DWORD while 64-bit - //! pushes QWORD. 64-bit mode not provides instruction to - //! push 32-bit register/memory. - inline void push(const GPReg& src) - { - ASMJIT_ASSERT(src.isRegType(REG_TYPE_GPW) || src.isRegType(REG_TYPE_GPN)); - _emitInstruction(INST_PUSH, &src); - } - //! @brief Push WORD/DWORD/QWORD Onto the Stack. - inline void push(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == sizeof(sysint_t)); - _emitInstruction(INST_PUSH, &src); - } - //! @brief Push WORD/DWORD/QWORD Onto the Stack. - inline void push(const Imm& src) - { - _emitInstruction(INST_PUSH, &src); - } - -#if defined(ASMJIT_X86) - //! @brief Push All General-Purpose Registers. - //! - //! Push EAX, ECX, EDX, EBX, original ESP, EBP, ESI, and EDI. - inline void pushad() - { - _emitInstruction(INST_PUSHAD); - } -#endif // ASMJIT_X86 - - //! @brief Push EFLAGS Register (32-bit or 64-bit) onto the Stack. - inline void pushf() - { -#if defined(ASMJIT_X86) - pushfd(); -#else - pushfq(); -#endif - } - -#if defined(ASMJIT_X86) - //! @brief Push EFLAGS Register (32-bit) onto the Stack. - inline void pushfd() { _emitInstruction(INST_PUSHFD); } -#else - //! @brief Push EFLAGS Register (64-bit) onto the Stack. - inline void pushfq() { _emitInstruction(INST_PUSHFQ); } -#endif // ASMJIT_X86 - - //! @brief Rotate Bits Left. - //! @note @a src register can be only @c cl. - inline void rcl(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_RCL, &dst, &src); - } - //! @brief Rotate Bits Left. - inline void rcl(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_RCL, &dst, &src); - } - //! @brief Rotate Bits Left. - //! @note @a src register can be only @c cl. - inline void rcl(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_RCL, &dst, &src); - } - //! @brief Rotate Bits Left. - inline void rcl(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_RCL, &dst, &src); - } - - //! @brief Rotate Bits Right. - //! @note @a src register can be only @c cl. - inline void rcr(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_RCR, &dst, &src); - } - //! @brief Rotate Bits Right. - inline void rcr(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_RCR, &dst, &src); - } - //! @brief Rotate Bits Right. - //! @note @a src register can be only @c cl. - inline void rcr(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_RCR, &dst, &src); - } - //! @brief Rotate Bits Right. - inline void rcr(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_RCR, &dst, &src); - } - - //! @brief Read Time-Stamp Counter (Pentium). - inline void rdtsc() - { - _emitInstruction(INST_RDTSC); - } - - //! @brief Read Time-Stamp Counter and Processor ID (New). - inline void rdtscp() - { - _emitInstruction(INST_RDTSCP); - } - - //! @brief Load ECX/RCX BYTEs from DS:[ESI/RSI] to AL. - inline void rep_lodsb() - { - _emitInstruction(INST_REP_LODSB); - } - - //! @brief Load ECX/RCX DWORDs from DS:[ESI/RSI] to EAX. - inline void rep_lodsd() - { - _emitInstruction(INST_REP_LODSD); - } - -#if defined(ASMJIT_X64) - //! @brief Load ECX/RCX QWORDs from DS:[ESI/RSI] to RAX. - inline void rep_lodsq() - { - _emitInstruction(INST_REP_LODSQ); - } -#endif // ASMJIT_X64 - - //! @brief Load ECX/RCX WORDs from DS:[ESI/RSI] to AX. - inline void rep_lodsw() - { - _emitInstruction(INST_REP_LODSW); - } - - //! @brief Move ECX/RCX BYTEs from DS:[ESI/RSI] to ES:[EDI/RDI]. - inline void rep_movsb() - { - _emitInstruction(INST_REP_MOVSB); - } - - //! @brief Move ECX/RCX DWORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. - inline void rep_movsd() - { - _emitInstruction(INST_REP_MOVSD); - } - -#if defined(ASMJIT_X64) - //! @brief Move ECX/RCX QWORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. - inline void rep_movsq() - { - _emitInstruction(INST_REP_MOVSQ); - } -#endif // ASMJIT_X64 - - //! @brief Move ECX/RCX WORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. - inline void rep_movsw() - { - _emitInstruction(INST_REP_MOVSW); - } - - //! @brief Fill ECX/RCX BYTEs at ES:[EDI/RDI] with AL. - inline void rep_stosb() - { - _emitInstruction(INST_REP_STOSB); - } - - //! @brief Fill ECX/RCX DWORDs at ES:[EDI/RDI] with EAX. - inline void rep_stosd() - { - _emitInstruction(INST_REP_STOSD); - } - -#if defined(ASMJIT_X64) - //! @brief Fill ECX/RCX QWORDs at ES:[EDI/RDI] with RAX. - inline void rep_stosq() - { - _emitInstruction(INST_REP_STOSQ); - } -#endif // ASMJIT_X64 - - //! @brief Fill ECX/RCX WORDs at ES:[EDI/RDI] with AX. - inline void rep_stosw() - { - _emitInstruction(INST_REP_STOSW); - } - - //! @brief Repeated find nonmatching BYTEs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repe_cmpsb() - { - _emitInstruction(INST_REPE_CMPSB); - } - - //! @brief Repeated find nonmatching DWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repe_cmpsd() - { - _emitInstruction(INST_REPE_CMPSD); - } - -#if defined(ASMJIT_X64) - //! @brief Repeated find nonmatching QWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repe_cmpsq() - { - _emitInstruction(INST_REPE_CMPSQ); - } -#endif // ASMJIT_X64 - - //! @brief Repeated find nonmatching WORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repe_cmpsw() - { - _emitInstruction(INST_REPE_CMPSW); - } - - //! @brief Find non-AL BYTE starting at ES:[EDI/RDI]. - inline void repe_scasb() - { - _emitInstruction(INST_REPE_SCASB); - } - - //! @brief Find non-EAX DWORD starting at ES:[EDI/RDI]. - inline void repe_scasd() - { - _emitInstruction(INST_REPE_SCASD); - } - -#if defined(ASMJIT_X64) - //! @brief Find non-RAX QWORD starting at ES:[EDI/RDI]. - inline void repe_scasq() - { - _emitInstruction(INST_REPE_SCASQ); - } -#endif // ASMJIT_X64 - - //! @brief Find non-AX WORD starting at ES:[EDI/RDI]. - inline void repe_scasw() - { - _emitInstruction(INST_REPE_SCASW); - } - - //! @brief Repeated find nonmatching BYTEs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repne_cmpsb() - { - _emitInstruction(INST_REPNE_CMPSB); - } - - //! @brief Repeated find nonmatching DWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repne_cmpsd() - { - _emitInstruction(INST_REPNE_CMPSD); - } - -#if defined(ASMJIT_X64) - //! @brief Repeated find nonmatching QWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repne_cmpsq() - { - _emitInstruction(INST_REPNE_CMPSQ); - } -#endif // ASMJIT_X64 - - //! @brief Repeated find nonmatching WORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repne_cmpsw() - { - _emitInstruction(INST_REPNE_CMPSW); - } - - //! @brief Find AL, starting at ES:[EDI/RDI]. - inline void repne_scasb() - { - _emitInstruction(INST_REPNE_SCASB); - } - - //! @brief Find EAX, starting at ES:[EDI/RDI]. - inline void repne_scasd() - { - _emitInstruction(INST_REPNE_SCASD); - } - -#if defined(ASMJIT_X64) - //! @brief Find RAX, starting at ES:[EDI/RDI]. - inline void repne_scasq() - { - _emitInstruction(INST_REPNE_SCASQ); - } -#endif // ASMJIT_X64 - - //! @brief Find AX, starting at ES:[EDI/RDI]. - inline void repne_scasw() - { - _emitInstruction(INST_REPNE_SCASW); - } - - //! @brief Return from Procedure. - inline void ret() - { - _emitInstruction(INST_RET); - } - - //! @brief Return from Procedure. - inline void ret(const Imm& imm16) - { - _emitInstruction(INST_RET, &imm16); - } - - //! @brief Rotate Bits Left. - //! @note @a src register can be only @c cl. - inline void rol(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_ROL, &dst, &src); - } - //! @brief Rotate Bits Left. - inline void rol(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_ROL, &dst, &src); - } - //! @brief Rotate Bits Left. - //! @note @a src register can be only @c cl. - inline void rol(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_ROL, &dst, &src); - } - //! @brief Rotate Bits Left. - inline void rol(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_ROL, &dst, &src); - } - - //! @brief Rotate Bits Right. - //! @note @a src register can be only @c cl. - inline void ror(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_ROR, &dst, &src); - } - //! @brief Rotate Bits Right. - inline void ror(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_ROR, &dst, &src); - } - //! @brief Rotate Bits Right. - //! @note @a src register can be only @c cl. - inline void ror(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_ROR, &dst, &src); - } - //! @brief Rotate Bits Right. - inline void ror(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_ROR, &dst, &src); - } - -#if defined(ASMJIT_X86) - //! @brief Store AH into Flags. - inline void sahf() - { - _emitInstruction(INST_SAHF); - } -#endif // ASMJIT_X86 - - //! @brief Integer subtraction with borrow. - inline void sbb(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_SBB, &dst, &src); - } - //! @brief Integer subtraction with borrow. - inline void sbb(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_SBB, &dst, &src); - } - //! @brief Integer subtraction with borrow. - inline void sbb(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_SBB, &dst, &src); - } - //! @brief Integer subtraction with borrow. - inline void sbb(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_SBB, &dst, &src); - } - //! @brief Integer subtraction with borrow. - inline void sbb(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SBB, &dst, &src); - } - - //! @brief Shift Bits Left. - //! @note @a src register can be only @c cl. - inline void sal(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_SAL, &dst, &src); - } - //! @brief Shift Bits Left. - inline void sal(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_SAL, &dst, &src); - } - //! @brief Shift Bits Left. - //! @note @a src register can be only @c cl. - inline void sal(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_SAL, &dst, &src); - } - //! @brief Shift Bits Left. - inline void sal(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SAL, &dst, &src); - } - - //! @brief Shift Bits Right. - //! @note @a src register can be only @c cl. - inline void sar(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_SAR, &dst, &src); - } - //! @brief Shift Bits Right. - inline void sar(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_SAR, &dst, &src); - } - //! @brief Shift Bits Right. - //! @note @a src register can be only @c cl. - inline void sar(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_SAR, &dst, &src); - } - //! @brief Shift Bits Right. - inline void sar(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SAR, &dst, &src); - } - - //! @brief Set Byte on Condition. - inline void set(CONDITION cc, const GPReg& dst) - { - ASMJIT_ASSERT(dst.getSize() == 1); - _emitInstruction(ConditionToInstruction::toSetCC(cc), &dst); - } - - //! @brief Set Byte on Condition. - inline void set(CONDITION cc, const Mem& dst) - { - ASMJIT_ASSERT(dst.getSize() <= 1); - _emitInstruction(ConditionToInstruction::toSetCC(cc), &dst); - } - - //! @brief Set Byte on Condition. - inline void seta (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETA , &dst); } - //! @brief Set Byte on Condition. - inline void seta (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETA , &dst); } - //! @brief Set Byte on Condition. - inline void setae (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETAE , &dst); } - //! @brief Set Byte on Condition. - inline void setae (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETAE , &dst); } - //! @brief Set Byte on Condition. - inline void setb (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETB , &dst); } - //! @brief Set Byte on Condition. - inline void setb (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETB , &dst); } - //! @brief Set Byte on Condition. - inline void setbe (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETBE , &dst); } - //! @brief Set Byte on Condition. - inline void setbe (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETBE , &dst); } - //! @brief Set Byte on Condition. - inline void setc (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETC , &dst); } - //! @brief Set Byte on Condition. - inline void setc (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETC , &dst); } - //! @brief Set Byte on Condition. - inline void sete (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETE , &dst); } - //! @brief Set Byte on Condition. - inline void sete (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETE , &dst); } - //! @brief Set Byte on Condition. - inline void setg (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETG , &dst); } - //! @brief Set Byte on Condition. - inline void setg (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETG , &dst); } - //! @brief Set Byte on Condition. - inline void setge (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETGE , &dst); } - //! @brief Set Byte on Condition. - inline void setge (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETGE , &dst); } - //! @brief Set Byte on Condition. - inline void setl (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETL , &dst); } - //! @brief Set Byte on Condition. - inline void setl (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETL , &dst); } - //! @brief Set Byte on Condition. - inline void setle (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETLE , &dst); } - //! @brief Set Byte on Condition. - inline void setle (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETLE , &dst); } - //! @brief Set Byte on Condition. - inline void setna (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNA , &dst); } - //! @brief Set Byte on Condition. - inline void setna (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNA , &dst); } - //! @brief Set Byte on Condition. - inline void setnae(const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNAE, &dst); } - //! @brief Set Byte on Condition. - inline void setnae(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNAE, &dst); } - //! @brief Set Byte on Condition. - inline void setnb (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNB , &dst); } - //! @brief Set Byte on Condition. - inline void setnb (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNB , &dst); } - //! @brief Set Byte on Condition. - inline void setnbe(const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNBE, &dst); } - //! @brief Set Byte on Condition. - inline void setnbe(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNBE, &dst); } - //! @brief Set Byte on Condition. - inline void setnc (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNC , &dst); } - //! @brief Set Byte on Condition. - inline void setnc (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNC , &dst); } - //! @brief Set Byte on Condition. - inline void setne (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNE , &dst); } - //! @brief Set Byte on Condition. - inline void setne (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNE , &dst); } - //! @brief Set Byte on Condition. - inline void setng (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNG , &dst); } - //! @brief Set Byte on Condition. - inline void setng (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNG , &dst); } - //! @brief Set Byte on Condition. - inline void setnge(const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNGE, &dst); } - //! @brief Set Byte on Condition. - inline void setnge(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNGE, &dst); } - //! @brief Set Byte on Condition. - inline void setnl (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNL , &dst); } - //! @brief Set Byte on Condition. - inline void setnl (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNL , &dst); } - //! @brief Set Byte on Condition. - inline void setnle(const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNLE, &dst); } - //! @brief Set Byte on Condition. - inline void setnle(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNLE, &dst); } - //! @brief Set Byte on Condition. - inline void setno (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNO , &dst); } - //! @brief Set Byte on Condition. - inline void setno (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNO , &dst); } - //! @brief Set Byte on Condition. - inline void setnp (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNP , &dst); } - //! @brief Set Byte on Condition. - inline void setnp (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNP , &dst); } - //! @brief Set Byte on Condition. - inline void setns (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNS , &dst); } - //! @brief Set Byte on Condition. - inline void setns (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNS , &dst); } - //! @brief Set Byte on Condition. - inline void setnz (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNZ , &dst); } - //! @brief Set Byte on Condition. - inline void setnz (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNZ , &dst); } - //! @brief Set Byte on Condition. - inline void seto (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETO , &dst); } - //! @brief Set Byte on Condition. - inline void seto (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETO , &dst); } - //! @brief Set Byte on Condition. - inline void setp (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETP , &dst); } - //! @brief Set Byte on Condition. - inline void setp (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETP , &dst); } - //! @brief Set Byte on Condition. - inline void setpe (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETPE , &dst); } - //! @brief Set Byte on Condition. - inline void setpe (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETPE , &dst); } - //! @brief Set Byte on Condition. - inline void setpo (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETPO , &dst); } - //! @brief Set Byte on Condition. - inline void setpo (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETPO , &dst); } - //! @brief Set Byte on Condition. - inline void sets (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETS , &dst); } - //! @brief Set Byte on Condition. - inline void sets (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETS , &dst); } - //! @brief Set Byte on Condition. - inline void setz (const GPReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETZ , &dst); } - //! @brief Set Byte on Condition. - inline void setz (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETZ , &dst); } - - //! @brief Shift Bits Left. - //! @note @a src register can be only @c cl. - inline void shl(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_SHL, &dst, &src); - } - //! @brief Shift Bits Left. - inline void shl(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_SHL, &dst, &src); - } - //! @brief Shift Bits Left. - //! @note @a src register can be only @c cl. - inline void shl(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_SHL, &dst, &src); - } - //! @brief Shift Bits Left. - inline void shl(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SHL, &dst, &src); - } - - //! @brief Shift Bits Right. - //! @note @a src register can be only @c cl. - inline void shr(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_SHR, &dst, &src); - } - //! @brief Shift Bits Right. - inline void shr(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_SHR, &dst, &src); - } - //! @brief Shift Bits Right. - //! @note @a src register can be only @c cl. - inline void shr(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_SHR, &dst, &src); - } - //! @brief Shift Bits Right. - inline void shr(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SHR, &dst, &src); - } - - //! @brief Double Precision Shift Left. - //! @note src2 register can be only @c cl register. - inline void shld(const GPReg& dst, const GPReg& src1, const GPReg& src2) - { - _emitInstruction(INST_SHLD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Left. - inline void shld(const GPReg& dst, const GPReg& src1, const Imm& src2) - { - _emitInstruction(INST_SHLD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Left. - //! @note src2 register can be only @c cl register. - inline void shld(const Mem& dst, const GPReg& src1, const GPReg& src2) - { - _emitInstruction(INST_SHLD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Left. - inline void shld(const Mem& dst, const GPReg& src1, const Imm& src2) - { - _emitInstruction(INST_SHLD, &dst, &src1, &src2); - } - - //! @brief Double Precision Shift Right. - //! @note src2 register can be only @c cl register. - inline void shrd(const GPReg& dst, const GPReg& src1, const GPReg& src2) - { - _emitInstruction(INST_SHRD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Right. - inline void shrd(const GPReg& dst, const GPReg& src1, const Imm& src2) - { - _emitInstruction(INST_SHRD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Right. - //! @note src2 register can be only @c cl register. - inline void shrd(const Mem& dst, const GPReg& src1, const GPReg& src2) - { - _emitInstruction(INST_SHRD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Right. - inline void shrd(const Mem& dst, const GPReg& src1, const Imm& src2) - { - _emitInstruction(INST_SHRD, &dst, &src1, &src2); - } - - //! @brief Set Carry Flag to 1. - inline void stc() - { - _emitInstruction(INST_STC); - } - - //! @brief Set Direction Flag to 1. - inline void std() - { - _emitInstruction(INST_STD); - } - - //! @brief Subtract. - inline void sub(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_SUB, &dst, &src); - } - //! @brief Subtract. - inline void sub(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_SUB, &dst, &src); - } - //! @brief Subtract. - inline void sub(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_SUB, &dst, &src); - } - //! @brief Subtract. - inline void sub(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_SUB, &dst, &src); - } - //! @brief Subtract. - inline void sub(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SUB, &dst, &src); - } - - //! @brief Logical Compare. - inline void test(const GPReg& op1, const GPReg& op2) - { - _emitInstruction(INST_TEST, &op1, &op2); - } - //! @brief Logical Compare. - inline void test(const GPReg& op1, const Imm& op2) - { - _emitInstruction(INST_TEST, &op1, &op2); - } - //! @brief Logical Compare. - inline void test(const Mem& op1, const GPReg& op2) - { - _emitInstruction(INST_TEST, &op1, &op2); - } - //! @brief Logical Compare. - inline void test(const Mem& op1, const Imm& op2) - { - _emitInstruction(INST_TEST, &op1, &op2); - } - - //! @brief Undefined instruction - Raise invalid opcode exception. - inline void ud2() - { - _emitInstruction(INST_UD2); - } - - //! @brief Exchange and Add. - inline void xadd(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_XADD, &dst, &src); - } - //! @brief Exchange and Add. - inline void xadd(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_XADD, &dst, &src); - } - - //! @brief Exchange Register/Memory with Register. - inline void xchg(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_XCHG, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xchg(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_XCHG, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xchg(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_XCHG, &src, &dst); - } - - //! @brief Exchange Register/Memory with Register. - inline void xor_(const GPReg& dst, const GPReg& src) - { - _emitInstruction(INST_XOR, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xor_(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_XOR, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xor_(const GPReg& dst, const Imm& src) - { - _emitInstruction(INST_XOR, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xor_(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_XOR, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xor_(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_XOR, &dst, &src); - } - - // -------------------------------------------------------------------------- - // [X87 Instructions (FPU)] - // -------------------------------------------------------------------------- - - //! @brief Compute 2^x - 1 (FPU). - inline void f2xm1() - { - _emitInstruction(INST_F2XM1); - } - - //! @brief Absolute Value of st(0) (FPU). - inline void fabs() - { - _emitInstruction(INST_FABS); - } - - //! @brief Add @a src to @a dst and store result in @a dst (FPU). - //! - //! @note One of dst or src must be st(0). - inline void fadd(const X87Reg& dst, const X87Reg& src) - { - ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); - _emitInstruction(INST_FADD, &dst, &src); - } - - //! @brief Add @a src to st(0) and store result in st(0) (FPU). - //! - //! @note SP-FP or DP-FP determined by @a adr size. - inline void fadd(const Mem& src) - { - _emitInstruction(INST_FADD, &src); - } - - //! @brief Add st(0) to @a dst and POP register stack (FPU). - inline void faddp(const X87Reg& dst = st(1)) - { - _emitInstruction(INST_FADDP, &dst); - } - - //! @brief Load Binary Coded Decimal (FPU). - inline void fbld(const Mem& src) - { - _emitInstruction(INST_FBLD, &src); - } - - //! @brief Store BCD Integer and Pop (FPU). - inline void fbstp(const Mem& dst) - { - _emitInstruction(INST_FBSTP, &dst); - } - - //! @brief Change st(0) Sign (FPU). - inline void fchs() - { - _emitInstruction(INST_FCHS); - } - - //! @brief Clear Exceptions (FPU). - //! - //! Clear floating-point exception flags after checking for pending unmasked - //! floating-point exceptions. - //! - //! Clears the floating-point exception flags (PE, UE, OE, ZE, DE, and IE), - //! the exception summary status flag (ES), the stack fault flag (SF), and - //! the busy flag (B) in the FPU status word. The FCLEX instruction checks - //! for and handles any pending unmasked floating-point exceptions before - //! clearing the exception flags. - inline void fclex() - { - _emitInstruction(INST_FCLEX); - } - - //! @brief FP Conditional Move (FPU). - inline void fcmovb(const X87Reg& src) - { - _emitInstruction(INST_FCMOVB, &src); - } - //! @brief FP Conditional Move (FPU). - inline void fcmovbe(const X87Reg& src) - { - _emitInstruction(INST_FCMOVBE, &src); - } - //! @brief FP Conditional Move (FPU). - inline void fcmove(const X87Reg& src) - { - _emitInstruction(INST_FCMOVE, &src); - } - //! @brief FP Conditional Move (FPU). - inline void fcmovnb(const X87Reg& src) - { - _emitInstruction(INST_FCMOVNB, &src); - } - //! @brief FP Conditional Move (FPU). - inline void fcmovnbe(const X87Reg& src) - { - _emitInstruction(INST_FCMOVNBE, &src); - } - //! @brief FP Conditional Move (FPU). - inline void fcmovne(const X87Reg& src) - { - _emitInstruction(INST_FCMOVNE, &src); - } - //! @brief FP Conditional Move (FPU). - inline void fcmovnu(const X87Reg& src) - { - _emitInstruction(INST_FCMOVNU, &src); - } - //! @brief FP Conditional Move (FPU). - inline void fcmovu(const X87Reg& src) - { - _emitInstruction(INST_FCMOVU, &src); - } - - //! @brief Compare st(0) with @a reg (FPU). - inline void fcom(const X87Reg& reg = st(1)) - { - _emitInstruction(INST_FCOM, ®); - } - //! @brief Compare st(0) with 4-byte or 8-byte FP at @a src (FPU). - inline void fcom(const Mem& src) - { - _emitInstruction(INST_FCOM, &src); - } - - //! @brief Compare st(0) with @a reg and pop the stack (FPU). - inline void fcomp(const X87Reg& reg = st(1)) - { - _emitInstruction(INST_FCOMP, ®); - } - //! @brief Compare st(0) with 4-byte or 8-byte FP at @a adr and pop the - //! stack (FPU). - inline void fcomp(const Mem& mem) - { - _emitInstruction(INST_FCOMP, &mem); - } - - //! @brief Compare st(0) with st(1) and pop register stack twice (FPU). - inline void fcompp() - { - _emitInstruction(INST_FCOMPP); - } - - //! @brief Compare st(0) and @a reg and Set EFLAGS (FPU). - inline void fcomi(const X87Reg& reg) - { - _emitInstruction(INST_FCOMI, ®); - } - - //! @brief Compare st(0) and @a reg and Set EFLAGS and pop the stack (FPU). - inline void fcomip(const X87Reg& reg) - { - _emitInstruction(INST_FCOMIP, ®); - } - - //! @brief Cosine (FPU). - //! - //! This instruction calculates the cosine of the source operand in - //! register st(0) and stores the result in st(0). - inline void fcos() - { - _emitInstruction(INST_FCOS); - } - - //! @brief Decrement Stack-Top Pointer (FPU). - //! - //! Subtracts one from the TOP field of the FPU status word (decrements - //! the top-ofstack pointer). If the TOP field contains a 0, it is set - //! to 7. The effect of this instruction is to rotate the stack by one - //! position. The contents of the FPU data registers and tag register - //! are not affected. - inline void fdecstp() - { - _emitInstruction(INST_FDECSTP); - } - - //! @brief Divide @a dst by @a src (FPU). - //! - //! @note One of @a dst or @a src register must be st(0). - inline void fdiv(const X87Reg& dst, const X87Reg& src) - { - ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); - _emitInstruction(INST_FDIV, &dst, &src); - } - //! @brief Divide st(0) by 32-bit or 64-bit FP value (FPU). - inline void fdiv(const Mem& src) - { - _emitInstruction(INST_FDIV, &src); - } - - //! @brief Divide @a reg by st(0) (FPU). - inline void fdivp(const X87Reg& reg = st(1)) - { - _emitInstruction(INST_FDIVP, ®); - } - - //! @brief Reverse Divide @a dst by @a src (FPU). - //! - //! @note One of @a dst or @a src register must be st(0). - inline void fdivr(const X87Reg& dst, const X87Reg& src) - { - ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); - _emitInstruction(INST_FDIVR, &dst, &src); - } - //! @brief Reverse Divide st(0) by 32-bit or 64-bit FP value (FPU). - inline void fdivr(const Mem& src) - { - _emitInstruction(INST_FDIVR, &src); - } - - //! @brief Reverse Divide @a reg by st(0) (FPU). - inline void fdivrp(const X87Reg& reg = st(1)) - { - _emitInstruction(INST_FDIVRP, ®); - } - - //! @brief Free Floating-Point Register (FPU). - //! - //! Sets the tag in the FPU tag register associated with register @a reg - //! to empty (11B). The contents of @a reg and the FPU stack-top pointer - //! (TOP) are not affected. - inline void ffree(const X87Reg& reg) - { - _emitInstruction(INST_FFREE, ®); - } - - //! @brief Add 16-bit or 32-bit integer to st(0) (FPU). - inline void fiadd(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); - _emitInstruction(INST_FIADD, &src); - } - - //! @brief Compare st(0) with 16-bit or 32-bit Integer (FPU). - inline void ficom(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); - _emitInstruction(INST_FICOM, &src); - } - - //! @brief Compare st(0) with 16-bit or 32-bit Integer and pop the stack (FPU). - inline void ficomp(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); - _emitInstruction(INST_FICOMP, &src); - } - - //! @brief Divide st(0) by 32-bit or 16-bit integer (@a src) (FPU). - inline void fidiv(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); - _emitInstruction(INST_FIDIV, &src); - } - - //! @brief Reverse Divide st(0) by 32-bit or 16-bit integer (@a src) (FPU). - inline void fidivr(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); - _emitInstruction(INST_FIDIVR, &src); - } - - //! @brief Load 16-bit, 32-bit or 64-bit Integer and push it to the stack (FPU). - //! - //! Converts the signed-integer source operand into double extended-precision - //! floating point format and pushes the value onto the FPU register stack. - //! The source operand can be a word, doubleword, or quadword integer. It is - //! loaded without rounding errors. The sign of the source operand is - //! preserved. - inline void fild(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4 || src.getSize() == 8); - _emitInstruction(INST_FILD, &src); - } - - //! @brief Multiply st(0) by 16-bit or 32-bit integer and store it - //! to st(0) (FPU). - inline void fimul(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); - _emitInstruction(INST_FIMUL, &src); - } - - //! @brief Increment Stack-Top Pointer (FPU). - //! - //! Adds one to the TOP field of the FPU status word (increments the - //! top-of-stack pointer). If the TOP field contains a 7, it is set to 0. - //! The effect of this instruction is to rotate the stack by one position. - //! The contents of the FPU data registers and tag register are not affected. - //! This operation is not equivalent to popping the stack, because the tag - //! for the previous top-of-stack register is not marked empty. - inline void fincstp() - { - _emitInstruction(INST_FINCSTP); - } - - //! @brief Initialize Floating-Point Unit (FPU). - //! - //! Initialize FPU after checking for pending unmasked floating-point - //! exceptions. - inline void finit() - { - _emitInstruction(INST_FINIT); - } - - //! @brief Subtract 16-bit or 32-bit integer from st(0) and store result to - //! st(0) (FPU). - inline void fisub(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); - _emitInstruction(INST_FISUB, &src); - } - - //! @brief Reverse Subtract 16-bit or 32-bit integer from st(0) and - //! store result to st(0) (FPU). - inline void fisubr(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); - _emitInstruction(INST_FISUBR, &src); - } - - //! @brief Initialize Floating-Point Unit (FPU). - //! - //! Initialize FPU without checking for pending unmasked floating-point - //! exceptions. - inline void fninit() - { - _emitInstruction(INST_FNINIT); - } - - //! @brief Store st(0) as 16-bit or 32-bit Integer to @a dst (FPU). - inline void fist(const Mem& dst) - { - ASMJIT_ASSERT(dst.getSize() == 2 || dst.getSize() == 4); - _emitInstruction(INST_FIST, &dst); - } - - //! @brief Store st(0) as 16-bit, 32-bit or 64-bit Integer to @a dst and pop - //! stack (FPU). - inline void fistp(const Mem& dst) - { - ASMJIT_ASSERT(dst.getSize() == 2 || dst.getSize() == 4 || dst.getSize() == 8); - _emitInstruction(INST_FISTP, &dst); - } - - //! @brief Push 32-bit, 64-bit or 80-bit Floating Point Value onto the FPU - //! register stack (FPU). - inline void fld(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 4 || src.getSize() == 8 || src.getSize() == 10); - _emitInstruction(INST_FLD, &src); - } - - //! @brief Push @a reg onto the FPU register stack (FPU). - inline void fld(const X87Reg& reg) - { - _emitInstruction(INST_FLD, ®); - } - - //! @brief Push +1.0 onto the FPU register stack (FPU). - inline void fld1() - { - _emitInstruction(INST_FLD1); - } - - //! @brief Push log2(10) onto the FPU register stack (FPU). - inline void fldl2t() - { - _emitInstruction(INST_FLDL2T); - } - - //! @brief Push log2(e) onto the FPU register stack (FPU). - inline void fldl2e() - { - _emitInstruction(INST_FLDL2E); - } - - //! @brief Push pi onto the FPU register stack (FPU). - inline void fldpi() - { - _emitInstruction(INST_FLDPI); - } - - //! @brief Push log10(2) onto the FPU register stack (FPU). - inline void fldlg2() - { - _emitInstruction(INST_FLDLG2); - } - - //! @brief Push ln(2) onto the FPU register stack (FPU). - inline void fldln2() - { - _emitInstruction(INST_FLDLN2); - } - - //! @brief Push +0.0 onto the FPU register stack (FPU). - inline void fldz() - { - _emitInstruction(INST_FLDZ); - } - - //! @brief Load x87 FPU Control Word (2 bytes) (FPU). - inline void fldcw(const Mem& src) - { - _emitInstruction(INST_FLDCW, &src); - } - - //! @brief Load x87 FPU Environment (14 or 28 bytes) (FPU). - inline void fldenv(const Mem& src) - { - _emitInstruction(INST_FLDENV, &src); - } - - //! @brief Multiply @a dst by @a src and store result in @a dst (FPU). - //! - //! @note One of dst or src must be st(0). - inline void fmul(const X87Reg& dst, const X87Reg& src) - { - ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); - _emitInstruction(INST_FMUL, &dst, &src); - } - //! @brief Multiply st(0) by @a src and store result in st(0) (FPU). - //! - //! @note SP-FP or DP-FP determined by @a adr size. - inline void fmul(const Mem& src) - { - _emitInstruction(INST_FMUL, &src); - } - - //! @brief Multiply st(0) by @a dst and POP register stack (FPU). - inline void fmulp(const X87Reg& dst = st(1)) - { - _emitInstruction(INST_FMULP, &dst); - } - - //! @brief Clear Exceptions (FPU). - //! - //! Clear floating-point exception flags without checking for pending - //! unmasked floating-point exceptions. - //! - //! Clears the floating-point exception flags (PE, UE, OE, ZE, DE, and IE), - //! the exception summary status flag (ES), the stack fault flag (SF), and - //! the busy flag (B) in the FPU status word. The FCLEX instruction does - //! not checks for and handles any pending unmasked floating-point exceptions - //! before clearing the exception flags. - inline void fnclex() - { - _emitInstruction(INST_FNCLEX); - } - - //! @brief No Operation (FPU). - inline void fnop() - { - _emitInstruction(INST_FNOP); - } - - //! @brief Save FPU State (FPU). - //! - //! Store FPU environment to m94byte or m108byte without - //! checking for pending unmasked FP exceptions. - //! Then re-initialize the FPU. - inline void fnsave(const Mem& dst) - { - _emitInstruction(INST_FNSAVE, &dst); - } - - //! @brief Store x87 FPU Environment (FPU). - //! - //! Store FPU environment to @a dst (14 or 28 Bytes) without checking for - //! pending unmasked floating-point exceptions. Then mask all floating - //! point exceptions. - inline void fnstenv(const Mem& dst) - { - _emitInstruction(INST_FNSTENV, &dst); - } - - //! @brief Store x87 FPU Control Word (FPU). - //! - //! Store FPU control word to @a dst (2 Bytes) without checking for pending - //! unmasked floating-point exceptions. - inline void fnstcw(const Mem& dst) - { - _emitInstruction(INST_FNSTCW, &dst); - } - - //! @brief Store x87 FPU Status Word (2 Bytes) (FPU). - inline void fnstsw(const GPReg& dst) - { - ASMJIT_ASSERT(dst.isRegCode(REG_AX)); - _emitInstruction(INST_FNSTSW, &dst); - } - //! @brief Store x87 FPU Status Word (2 Bytes) (FPU). - inline void fnstsw(const Mem& dst) - { - _emitInstruction(INST_FNSTSW, &dst); - } - - //! @brief Partial Arctangent (FPU). - //! - //! Replace st(1) with arctan(st(1)/st(0)) and pop the register stack. - inline void fpatan() - { - _emitInstruction(INST_FPATAN); - } - - //! @brief Partial Remainder (FPU). - //! - //! Replace st(0) with the remainder obtained from dividing st(0) by st(1). - inline void fprem() - { - _emitInstruction(INST_FPREM); - } - - //! @brief Partial Remainder (FPU). - //! - //! Replace st(0) with the IEEE remainder obtained from dividing st(0) by - //! st(1). - inline void fprem1() - { - _emitInstruction(INST_FPREM1); - } - - //! @brief Partial Tangent (FPU). - //! - //! Replace st(0) with its tangent and push 1 onto the FPU stack. - inline void fptan() - { - _emitInstruction(INST_FPTAN); - } - - //! @brief Round to Integer (FPU). - //! - //! Rount st(0) to an Integer. - inline void frndint() - { - _emitInstruction(INST_FRNDINT); - } - - //! @brief Restore FPU State (FPU). - //! - //! Load FPU state from src (94 or 108 bytes). - inline void frstor(const Mem& src) - { - _emitInstruction(INST_FRSTOR, &src); - } - - //! @brief Save FPU State (FPU). - //! - //! Store FPU state to 94 or 108-bytes after checking for - //! pending unmasked FP exceptions. Then reinitialize - //! the FPU. - inline void fsave(const Mem& dst) - { - _emitInstruction(INST_FSAVE, &dst); - } - - //! @brief Scale (FPU). - //! - //! Scale st(0) by st(1). - inline void fscale() - { - _emitInstruction(INST_FSCALE); - } - - //! @brief Sine (FPU). - //! - //! This instruction calculates the sine of the source operand in - //! register st(0) and stores the result in st(0). - inline void fsin() - { - _emitInstruction(INST_FSIN); - } - - //! @brief Sine and Cosine (FPU). - //! - //! Compute the sine and cosine of st(0); replace st(0) with - //! the sine, and push the cosine onto the register stack. - inline void fsincos() - { - _emitInstruction(INST_FSINCOS); - } - - //! @brief Square Root (FPU). - //! - //! Calculates square root of st(0) and stores the result in st(0). - inline void fsqrt() - { - _emitInstruction(INST_FSQRT); - } - - //! @brief Store Floating Point Value (FPU). - //! - //! Store st(0) as 32-bit or 64-bit floating point value to @a dst. - inline void fst(const Mem& dst) - { - ASMJIT_ASSERT(dst.getSize() == 4 || dst.getSize() == 8); - _emitInstruction(INST_FST, &dst); - } - - //! @brief Store Floating Point Value (FPU). - //! - //! Store st(0) to @a reg. - inline void fst(const X87Reg& reg) - { - _emitInstruction(INST_FST, ®); - } - - //! @brief Store Floating Point Value and Pop Register Stack (FPU). - //! - //! Store st(0) as 32-bit or 64-bit floating point value to @a dst - //! and pop register stack. - inline void fstp(const Mem& dst) - { - ASMJIT_ASSERT(dst.getSize() == 4 || dst.getSize() == 8 || dst.getSize() == 10); - _emitInstruction(INST_FSTP, &dst); - } - - //! @brief Store Floating Point Value and Pop Register Stack (FPU). - //! - //! Store st(0) to @a reg and pop register stack. - inline void fstp(const X87Reg& reg) - { - _emitInstruction(INST_FSTP, ®); - } - - //! @brief Store x87 FPU Control Word (FPU). - //! - //! Store FPU control word to @a dst (2 Bytes) after checking for pending - //! unmasked floating-point exceptions. - inline void fstcw(const Mem& dst) - { - _emitInstruction(INST_FSTCW, &dst); - } - - //! @brief Store x87 FPU Environment (FPU). - //! - //! Store FPU environment to @a dst (14 or 28 Bytes) after checking for - //! pending unmasked floating-point exceptions. Then mask all floating - //! point exceptions. - inline void fstenv(const Mem& dst) - { - _emitInstruction(INST_FSTENV, &dst); - } - - //! @brief Store x87 FPU Status Word (2 Bytes) (FPU). - inline void fstsw(const GPReg& dst) - { - ASMJIT_ASSERT(dst.isRegCode(REG_AX)); - _emitInstruction(INST_FSTSW, &dst); - } - //! @brief Store x87 FPU Status Word (2 Bytes) (FPU). - inline void fstsw(const Mem& dst) - { - _emitInstruction(INST_FSTSW, &dst); - } - - //! @brief Subtract @a src from @a dst and store result in @a dst (FPU). - //! - //! @note One of dst or src must be st(0). - inline void fsub(const X87Reg& dst, const X87Reg& src) - { - ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); - _emitInstruction(INST_FSUB, &dst, &src); - } - //! @brief Subtract @a src from st(0) and store result in st(0) (FPU). - //! - //! @note SP-FP or DP-FP determined by @a adr size. - inline void fsub(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 4 || src.getSize() == 8); - _emitInstruction(INST_FSUB, &src); - } - - //! @brief Subtract st(0) from @a dst and POP register stack (FPU). - inline void fsubp(const X87Reg& dst = st(1)) - { - _emitInstruction(INST_FSUBP, &dst); - } - - //! @brief Reverse Subtract @a src from @a dst and store result in @a dst (FPU). - //! - //! @note One of dst or src must be st(0). - inline void fsubr(const X87Reg& dst, const X87Reg& src) - { - ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); - _emitInstruction(INST_FSUBR, &dst, &src); - } - - //! @brief Reverse Subtract @a src from st(0) and store result in st(0) (FPU). - //! - //! @note SP-FP or DP-FP determined by @a adr size. - inline void fsubr(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 4 || src.getSize() == 8); - _emitInstruction(INST_FSUBR, &src); - } - - //! @brief Reverse Subtract st(0) from @a dst and POP register stack (FPU). - inline void fsubrp(const X87Reg& dst = st(1)) - { - _emitInstruction(INST_FSUBRP, &dst); - } - - //! @brief Floating point test - Compare st(0) with 0.0. (FPU). - inline void ftst() - { - _emitInstruction(INST_FTST); - } - - //! @brief Unordered Compare st(0) with @a reg (FPU). - inline void fucom(const X87Reg& reg = st(1)) - { - _emitInstruction(INST_FUCOM, ®); - } - - //! @brief Unordered Compare st(0) and @a reg, check for ordered values - //! and Set EFLAGS (FPU). - inline void fucomi(const X87Reg& reg) - { - _emitInstruction(INST_FUCOMI, ®); - } - - //! @brief UnorderedCompare st(0) and @a reg, Check for ordered values - //! and Set EFLAGS and pop the stack (FPU). - inline void fucomip(const X87Reg& reg = st(1)) - { - _emitInstruction(INST_FUCOMIP, ®); - } - - //! @brief Unordered Compare st(0) with @a reg and pop register stack (FPU). - inline void fucomp(const X87Reg& reg = st(1)) - { - _emitInstruction(INST_FUCOMP, ®); - } - - //! @brief Unordered compare st(0) with st(1) and pop register stack twice - //! (FPU). - inline void fucompp() - { - _emitInstruction(INST_FUCOMPP); - } - - inline void fwait() - { - _emitInstruction(INST_FWAIT); - } - - //! @brief Examine st(0) (FPU). - //! - //! Examines the contents of the ST(0) register and sets the condition code - //! flags C0, C2, and C3 in the FPU status word to indicate the class of - //! value or number in the register. - inline void fxam() - { - _emitInstruction(INST_FXAM); - } - - //! @brief Exchange Register Contents (FPU). - //! - //! Exchange content of st(0) with @a reg. - inline void fxch(const X87Reg& reg = st(1)) - { - _emitInstruction(INST_FXCH, ®); - } - - //! @brief Restore FP And MMX(tm) State And Streaming SIMD Extension State - //! (FPU, MMX, SSE). - //! - //! Load FP and MMX(tm) technology and Streaming SIMD Extension state from - //! src (512 bytes). - inline void fxrstor(const Mem& src) - { - _emitInstruction(INST_FXRSTOR, &src); - } - - //! @brief Store FP and MMX(tm) State and Streaming SIMD Extension State - //! (FPU, MMX, SSE). - //! - //! Store FP and MMX(tm) technology state and Streaming SIMD Extension state - //! to dst (512 bytes). - inline void fxsave(const Mem& dst) - { - _emitInstruction(INST_FXSAVE, &dst); - } - - //! @brief Extract Exponent and Significand (FPU). - //! - //! Separate value in st(0) into exponent and significand, store exponent - //! in st(0), and push the significand onto the register stack. - inline void fxtract() - { - _emitInstruction(INST_FXTRACT); - } - - //! @brief Compute y * log2(x). - //! - //! Replace st(1) with (st(1) * log2st(0)) and pop the register stack. - inline void fyl2x() - { - _emitInstruction(INST_FYL2X); - } - - //! @brief Compute y * log_2(x+1). - //! - //! Replace st(1) with (st(1) * (log2st(0) + 1.0)) and pop the register stack. - inline void fyl2xp1() - { - _emitInstruction(INST_FYL2XP1); - } - - // -------------------------------------------------------------------------- - // [MMX] - // -------------------------------------------------------------------------- - - //! @brief Empty MMX state. - inline void emms() - { - _emitInstruction(INST_EMMS); - } - - //! @brief Move DWord (MMX). - inline void movd(const Mem& dst, const MMReg& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord (MMX). - inline void movd(const GPReg& dst, const MMReg& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord (MMX). - inline void movd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord (MMX). - inline void movd(const MMReg& dst, const GPReg& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - - //! @brief Move QWord (MMX). - inline void movq(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } - //! @brief Move QWord (MMX). - inline void movq(const Mem& dst, const MMReg& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#if defined(ASMJIT_X64) - //! @brief Move QWord (MMX). - inline void movq(const GPReg& dst, const MMReg& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#endif - //! @brief Move QWord (MMX). - inline void movq(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#if defined(ASMJIT_X64) - //! @brief Move QWord (MMX). - inline void movq(const MMReg& dst, const GPReg& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#endif - - //! @brief Pack with Signed Saturation (MMX). - inline void packsswb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PACKSSWB, &dst, &src); - } - //! @brief Pack with Signed Saturation (MMX). - inline void packsswb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PACKSSWB, &dst, &src); - } - - //! @brief Pack with Signed Saturation (MMX). - inline void packssdw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PACKSSDW, &dst, &src); - } - //! @brief Pack with Signed Saturation (MMX). - inline void packssdw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PACKSSDW, &dst, &src); - } - - //! @brief Pack with Unsigned Saturation (MMX). - inline void packuswb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PACKUSWB, &dst, &src); - } - //! @brief Pack with Unsigned Saturation (MMX). - inline void packuswb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PACKUSWB, &dst, &src); - } - - //! @brief Packed BYTE Add (MMX). - inline void paddb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PADDB, &dst, &src); - } - //! @brief Packed BYTE Add (MMX). - inline void paddb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDB, &dst, &src); - } - - //! @brief Packed WORD Add (MMX). - inline void paddw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PADDW, &dst, &src); - } - //! @brief Packed WORD Add (MMX). - inline void paddw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDW, &dst, &src); - } - - //! @brief Packed DWORD Add (MMX). - inline void paddd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PADDD, &dst, &src); - } - //! @brief Packed DWORD Add (MMX). - inline void paddd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDD, &dst, &src); - } - - //! @brief Packed Add with Saturation (MMX). - inline void paddsb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PADDSB, &dst, &src); - } - //! @brief Packed Add with Saturation (MMX). - inline void paddsb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDSB, &dst, &src); - } - - //! @brief Packed Add with Saturation (MMX). - inline void paddsw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PADDSW, &dst, &src); - } - //! @brief Packed Add with Saturation (MMX). - inline void paddsw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDSW, &dst, &src); - } - - //! @brief Packed Add Unsigned with Saturation (MMX). - inline void paddusb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PADDUSB, &dst, &src); - } - //! @brief Packed Add Unsigned with Saturation (MMX). - inline void paddusb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDUSB, &dst, &src); - } - - //! @brief Packed Add Unsigned with Saturation (MMX). - inline void paddusw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PADDUSW, &dst, &src); - } - //! @brief Packed Add Unsigned with Saturation (MMX). - inline void paddusw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDUSW, &dst, &src); - } - - //! @brief Logical AND (MMX). - inline void pand(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PAND, &dst, &src); - } - //! @brief Logical AND (MMX). - inline void pand(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PAND, &dst, &src); - } - - //! @brief Logical AND Not (MMX). - inline void pandn(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PANDN, &dst, &src); - } - //! @brief Logical AND Not (MMX). - inline void pandn(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PANDN, &dst, &src); - } - - //! @brief Packed Compare for Equal (BYTES) (MMX). - inline void pcmpeqb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PCMPEQB, &dst, &src); - } - //! @brief Packed Compare for Equal (BYTES) (MMX). - inline void pcmpeqb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQB, &dst, &src); - } - - //! @brief Packed Compare for Equal (WORDS) (MMX). - inline void pcmpeqw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PCMPEQW, &dst, &src); - } - //! @brief Packed Compare for Equal (WORDS) (MMX). - inline void pcmpeqw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQW, &dst, &src); - } - - //! @brief Packed Compare for Equal (DWORDS) (MMX). - inline void pcmpeqd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PCMPEQD, &dst, &src); - } - //! @brief Packed Compare for Equal (DWORDS) (MMX). - inline void pcmpeqd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQD, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (BYTES) (MMX). - inline void pcmpgtb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PCMPGTB, &dst, &src); - } - //! @brief Packed Compare for Greater Than (BYTES) (MMX). - inline void pcmpgtb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTB, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (WORDS) (MMX). - inline void pcmpgtw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PCMPGTW, &dst, &src); - } - //! @brief Packed Compare for Greater Than (WORDS) (MMX). - inline void pcmpgtw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTW, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (DWORDS) (MMX). - inline void pcmpgtd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PCMPGTD, &dst, &src); - } - //! @brief Packed Compare for Greater Than (DWORDS) (MMX). - inline void pcmpgtd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTD, &dst, &src); - } - - //! @brief Packed Multiply High (MMX). - inline void pmulhw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMULHW, &dst, &src); - } - //! @brief Packed Multiply High (MMX). - inline void pmulhw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULHW, &dst, &src); - } - - //! @brief Packed Multiply Low (MMX). - inline void pmullw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMULLW, &dst, &src); - } - //! @brief Packed Multiply Low (MMX). - inline void pmullw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULLW, &dst, &src); - } - - //! @brief Bitwise Logical OR (MMX). - inline void por(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_POR, &dst, &src); - } - //! @brief Bitwise Logical OR (MMX). - inline void por(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_POR, &dst, &src); - } - - //! @brief Packed Multiply and Add (MMX). - inline void pmaddwd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMADDWD, &dst, &src); - } - //! @brief Packed Multiply and Add (MMX). - inline void pmaddwd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMADDWD, &dst, &src); - } - - //! @brief Packed Shift Left Logical (MMX). - inline void pslld(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void pslld(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void pslld(const MMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - - //! @brief Packed Shift Left Logical (MMX). - inline void psllq(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void psllq(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void psllq(const MMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - - //! @brief Packed Shift Left Logical (MMX). - inline void psllw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void psllw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void psllw(const MMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psrad(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psrad(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psrad(const MMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psraw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psraw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psraw(const MMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - - //! @brief Packed Shift Right Logical (MMX). - inline void psrld(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrld(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrld(const MMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - - //! @brief Packed Shift Right Logical (MMX). - inline void psrlq(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrlq(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrlq(const MMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - - //! @brief Packed Shift Right Logical (MMX). - inline void psrlw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrlw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrlw(const MMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - - //! @brief Packed Subtract (MMX). - inline void psubb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSUBB, &dst, &src); - } - //! @brief Packed Subtract (MMX). - inline void psubb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBB, &dst, &src); - } - - //! @brief Packed Subtract (MMX). - inline void psubw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSUBW, &dst, &src); - } - //! @brief Packed Subtract (MMX). - inline void psubw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBW, &dst, &src); - } - - //! @brief Packed Subtract (MMX). - inline void psubd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSUBD, &dst, &src); - } - //! @brief Packed Subtract (MMX). - inline void psubd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBD, &dst, &src); - } - - //! @brief Packed Subtract with Saturation (MMX). - inline void psubsb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSUBSB, &dst, &src); - } - //! @brief Packed Subtract with Saturation (MMX). - inline void psubsb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBSB, &dst, &src); - } - - //! @brief Packed Subtract with Saturation (MMX). - inline void psubsw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSUBSW, &dst, &src); - } - //! @brief Packed Subtract with Saturation (MMX). - inline void psubsw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBSW, &dst, &src); - } - - //! @brief Packed Subtract with Unsigned Saturation (MMX). - inline void psubusb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSUBUSB, &dst, &src); - } - //! @brief Packed Subtract with Unsigned Saturation (MMX). - inline void psubusb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBUSB, &dst, &src); - } - - //! @brief Packed Subtract with Unsigned Saturation (MMX). - inline void psubusw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSUBUSW, &dst, &src); - } - //! @brief Packed Subtract with Unsigned Saturation (MMX). - inline void psubusw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBUSW, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpckhbw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PUNPCKHBW, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpckhbw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHBW, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpckhwd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PUNPCKHWD, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpckhwd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHWD, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpckhdq(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PUNPCKHDQ, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpckhdq(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHDQ, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpcklbw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PUNPCKLBW, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpcklbw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLBW, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpcklwd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PUNPCKLWD, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpcklwd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLWD, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpckldq(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PUNPCKLDQ, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpckldq(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLDQ, &dst, &src); - } - - //! @brief Bitwise Exclusive OR (MMX). - inline void pxor(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PXOR, &dst, &src); - } - //! @brief Bitwise Exclusive OR (MMX). - inline void pxor(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PXOR, &dst, &src); - } - - // ------------------------------------------------------------------------- - // [3dNow] - // ------------------------------------------------------------------------- - - //! @brief Faster EMMS (3dNow!). - //! - //! @note Use only for early AMD processors where is only 3dNow! or SSE. If - //! CPU contains SSE2, it's better to use @c emms() ( @c femms() is mapped - //! to @c emms() ). - inline void femms() - { - _emitInstruction(INST_FEMMS); - } - - //! @brief Packed SP-FP to Integer Convert (3dNow!). - inline void pf2id(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PF2ID, &dst, &src); - } - //! @brief Packed SP-FP to Integer Convert (3dNow!). - inline void pf2id(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PF2ID, &dst, &src); - } - - //! @brief Packed SP-FP to Integer Word Convert (3dNow!). - inline void pf2iw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PF2IW, &dst, &src); - } - //! @brief Packed SP-FP to Integer Word Convert (3dNow!). - inline void pf2iw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PF2IW, &dst, &src); - } - - //! @brief Packed SP-FP Accumulate (3dNow!). - inline void pfacc(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFACC, &dst, &src); - } - //! @brief Packed SP-FP Accumulate (3dNow!). - inline void pfacc(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFACC, &dst, &src); - } - - //! @brief Packed SP-FP Addition (3dNow!). - inline void pfadd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFADD, &dst, &src); - } - //! @brief Packed SP-FP Addition (3dNow!). - inline void pfadd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFADD, &dst, &src); - } - - //! @brief Packed SP-FP Compare - dst == src (3dNow!). - inline void pfcmpeq(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFCMPEQ, &dst, &src); - } - //! @brief Packed SP-FP Compare - dst == src (3dNow!). - inline void pfcmpeq(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFCMPEQ, &dst, &src); - } - - //! @brief Packed SP-FP Compare - dst >= src (3dNow!). - inline void pfcmpge(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFCMPGE, &dst, &src); - } - //! @brief Packed SP-FP Compare - dst >= src (3dNow!). - inline void pfcmpge(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFCMPGE, &dst, &src); - } - - //! @brief Packed SP-FP Compare - dst > src (3dNow!). - inline void pfcmpgt(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFCMPGT, &dst, &src); - } - //! @brief Packed SP-FP Compare - dst > src (3dNow!). - inline void pfcmpgt(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFCMPGT, &dst, &src); - } - - //! @brief Packed SP-FP Maximum (3dNow!). - inline void pfmax(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFMAX, &dst, &src); - } - //! @brief Packed SP-FP Maximum (3dNow!). - inline void pfmax(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFMAX, &dst, &src); - } - - //! @brief Packed SP-FP Minimum (3dNow!). - inline void pfmin(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFMIN, &dst, &src); - } - //! @brief Packed SP-FP Minimum (3dNow!). - inline void pfmin(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFMIN, &dst, &src); - } - - //! @brief Packed SP-FP Multiply (3dNow!). - inline void pfmul(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFMUL, &dst, &src); - } - //! @brief Packed SP-FP Multiply (3dNow!). - inline void pfmul(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFMUL, &dst, &src); - } - - //! @brief Packed SP-FP Negative Accumulate (3dNow!). - inline void pfnacc(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFNACC, &dst, &src); - } - //! @brief Packed SP-FP Negative Accumulate (3dNow!). - inline void pfnacc(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFNACC, &dst, &src); - } - - //! @brief Packed SP-FP Mixed Accumulate (3dNow!). - inline void pfpnaxx(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFPNACC, &dst, &src); - } - //! @brief Packed SP-FP Mixed Accumulate (3dNow!). - inline void pfpnacc(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFPNACC, &dst, &src); - } - - //! @brief Packed SP-FP Reciprocal Approximation (3dNow!). - inline void pfrcp(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFRCP, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal Approximation (3dNow!). - inline void pfrcp(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFRCP, &dst, &src); - } - - //! @brief Packed SP-FP Reciprocal, First Iteration Step (3dNow!). - inline void pfrcpit1(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFRCPIT1, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal, First Iteration Step (3dNow!). - inline void pfrcpit1(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFRCPIT1, &dst, &src); - } - - //! @brief Packed SP-FP Reciprocal, Second Iteration Step (3dNow!). - inline void pfrcpit2(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFRCPIT2, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal, Second Iteration Step (3dNow!). - inline void pfrcpit2(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFRCPIT2, &dst, &src); - } - - //! @brief Packed SP-FP Reciprocal Square Root, First Iteration Step (3dNow!). - inline void pfrsqit1(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFRSQIT1, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal Square Root, First Iteration Step (3dNow!). - inline void pfrsqit1(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFRSQIT1, &dst, &src); - } - - //! @brief Packed SP-FP Reciprocal Square Root Approximation (3dNow!). - inline void pfrsqrt(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFRSQRT, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal Square Root Approximation (3dNow!). - inline void pfrsqrt(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFRSQRT, &dst, &src); - } - - //! @brief Packed SP-FP Subtract (3dNow!). - inline void pfsub(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFSUB, &dst, &src); - } - //! @brief Packed SP-FP Subtract (3dNow!). - inline void pfsub(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFSUB, &dst, &src); - } - - //! @brief Packed SP-FP Reverse Subtract (3dNow!). - inline void pfsubr(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PFSUBR, &dst, &src); - } - //! @brief Packed SP-FP Reverse Subtract (3dNow!). - inline void pfsubr(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PFSUBR, &dst, &src); - } - - //! @brief Packed DWords to SP-FP (3dNow!). - inline void pi2fd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PI2FD, &dst, &src); - } - //! @brief Packed DWords to SP-FP (3dNow!). - inline void pi2fd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PI2FD, &dst, &src); - } - - //! @brief Packed Words to SP-FP (3dNow!). - inline void pi2fw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PI2FW, &dst, &src); - } - //! @brief Packed Words to SP-FP (3dNow!). - inline void pi2fw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PI2FW, &dst, &src); - } - - //! @brief Packed swap DWord (3dNow!) - inline void pswapd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSWAPD, &dst, &src); - } - //! @brief Packed swap DWord (3dNow!) - inline void pswapd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSWAPD, &dst, &src); - } - - // -------------------------------------------------------------------------- - // [SSE] - // -------------------------------------------------------------------------- - - //! @brief Packed SP-FP Add (SSE). - inline void addps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ADDPS, &dst, &src); - } - //! @brief Packed SP-FP Add (SSE). - inline void addps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ADDPS, &dst, &src); - } - - //! @brief Scalar SP-FP Add (SSE). - inline void addss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ADDSS, &dst, &src); - } - //! @brief Scalar SP-FP Add (SSE). - inline void addss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ADDSS, &dst, &src); - } - - //! @brief Bit-wise Logical And Not For SP-FP (SSE). - inline void andnps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ANDNPS, &dst, &src); - } - //! @brief Bit-wise Logical And Not For SP-FP (SSE). - inline void andnps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ANDNPS, &dst, &src); - } - - //! @brief Bit-wise Logical And For SP-FP (SSE). - inline void andps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ANDPS, &dst, &src); - } - //! @brief Bit-wise Logical And For SP-FP (SSE). - inline void andps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ANDPS, &dst, &src); - } - - //! @brief Packed SP-FP Compare (SSE). - inline void cmpps(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_CMPPS, &dst, &src, &imm8); - } - //! @brief Packed SP-FP Compare (SSE). - inline void cmpps(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_CMPPS, &dst, &src, &imm8); - } - - //! @brief Compare Scalar SP-FP Values (SSE). - inline void cmpss(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_CMPSS, &dst, &src, &imm8); - } - //! @brief Compare Scalar SP-FP Values (SSE). - inline void cmpss(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_CMPSS, &dst, &src, &imm8); - } - - //! @brief Scalar Ordered SP-FP Compare and Set EFLAGS (SSE). - inline void comiss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_COMISS, &dst, &src); - } - //! @brief Scalar Ordered SP-FP Compare and Set EFLAGS (SSE). - inline void comiss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_COMISS, &dst, &src); - } - - //! @brief Packed Signed INT32 to Packed SP-FP Conversion (SSE). - inline void cvtpi2ps(const XMMReg& dst, const MMReg& src) - { - _emitInstruction(INST_CVTPI2PS, &dst, &src); - } - //! @brief Packed Signed INT32 to Packed SP-FP Conversion (SSE). - inline void cvtpi2ps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTPI2PS, &dst, &src); - } - - //! @brief Packed SP-FP to Packed INT32 Conversion (SSE). - inline void cvtps2pi(const MMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTPS2PI, &dst, &src); - } - //! @brief Packed SP-FP to Packed INT32 Conversion (SSE). - inline void cvtps2pi(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTPS2PI, &dst, &src); - } - - //! @brief Scalar Signed INT32 to SP-FP Conversion (SSE). - inline void cvtsi2ss(const XMMReg& dst, const GPReg& src) - { - _emitInstruction(INST_CVTSI2SS, &dst, &src); - } - //! @brief Scalar Signed INT32 to SP-FP Conversion (SSE). - inline void cvtsi2ss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTSI2SS, &dst, &src); - } - - //! @brief Scalar SP-FP to Signed INT32 Conversion (SSE). - inline void cvtss2si(const GPReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTSS2SI, &dst, &src); - } - //! @brief Scalar SP-FP to Signed INT32 Conversion (SSE). - inline void cvtss2si(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTSS2SI, &dst, &src); - } - - //! @brief Packed SP-FP to Packed INT32 Conversion (truncate) (SSE). - inline void cvttps2pi(const MMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTTPS2PI, &dst, &src); - } - //! @brief Packed SP-FP to Packed INT32 Conversion (truncate) (SSE). - inline void cvttps2pi(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTTPS2PI, &dst, &src); - } - - //! @brief Scalar SP-FP to Signed INT32 Conversion (truncate) (SSE). - inline void cvttss2si(const GPReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTTSS2SI, &dst, &src); - } - //! @brief Scalar SP-FP to Signed INT32 Conversion (truncate) (SSE). - inline void cvttss2si(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTTSS2SI, &dst, &src); - } - - //! @brief Packed SP-FP Divide (SSE). - inline void divps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_DIVPS, &dst, &src); - } - //! @brief Packed SP-FP Divide (SSE). - inline void divps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_DIVPS, &dst, &src); - } - - //! @brief Scalar SP-FP Divide (SSE). - inline void divss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_DIVSS, &dst, &src); - } - //! @brief Scalar SP-FP Divide (SSE). - inline void divss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_DIVSS, &dst, &src); - } - - //! @brief Load Streaming SIMD Extension Control/Status (SSE). - inline void ldmxcsr(const Mem& src) - { - _emitInstruction(INST_LDMXCSR, &src); - } - - //! @brief Byte Mask Write (SSE). - //! - //! @note The default memory location is specified by DS:EDI. - inline void maskmovq(const MMReg& data, const MMReg& mask) - { - _emitInstruction(INST_MASKMOVQ, &data, &mask); - } - - //! @brief Packed SP-FP Maximum (SSE). - inline void maxps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MAXPS, &dst, &src); - } - //! @brief Packed SP-FP Maximum (SSE). - inline void maxps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MAXPS, &dst, &src); - } - - //! @brief Scalar SP-FP Maximum (SSE). - inline void maxss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MAXSS, &dst, &src); - } - //! @brief Scalar SP-FP Maximum (SSE). - inline void maxss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MAXSS, &dst, &src); - } - - //! @brief Packed SP-FP Minimum (SSE). - inline void minps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MINPS, &dst, &src); - } - //! @brief Packed SP-FP Minimum (SSE). - inline void minps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MINPS, &dst, &src); - } - - //! @brief Scalar SP-FP Minimum (SSE). - inline void minss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MINSS, &dst, &src); - } - //! @brief Scalar SP-FP Minimum (SSE). - inline void minss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MINSS, &dst, &src); - } - - //! @brief Move Aligned Packed SP-FP Values (SSE). - inline void movaps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVAPS, &dst, &src); - } - //! @brief Move Aligned Packed SP-FP Values (SSE). - inline void movaps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVAPS, &dst, &src); - } - - //! @brief Move Aligned Packed SP-FP Values (SSE). - inline void movaps(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVAPS, &dst, &src); - } - - //! @brief Move DWord. - inline void movd(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord. - inline void movd(const GPReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord. - inline void movd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord. - inline void movd(const XMMReg& dst, const GPReg& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - - //! @brief Move QWord (SSE). - inline void movq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } - //! @brief Move QWord (SSE). - inline void movq(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#if defined(ASMJIT_X64) - //! @brief Move QWord (SSE). - inline void movq(const GPReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#endif // ASMJIT_X64 - //! @brief Move QWord (SSE). - inline void movq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#if defined(ASMJIT_X64) - //! @brief Move QWord (SSE). - inline void movq(const XMMReg& dst, const GPReg& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#endif // ASMJIT_X64 - - //! @brief Move 64 Bits Non Temporal (SSE). - inline void movntq(const Mem& dst, const MMReg& src) - { - _emitInstruction(INST_MOVNTQ, &dst, &src); - } - - //! @brief High to Low Packed SP-FP (SSE). - inline void movhlps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVHLPS, &dst, &src); - } - - //! @brief Move High Packed SP-FP (SSE). - inline void movhps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVHPS, &dst, &src); - } - - //! @brief Move High Packed SP-FP (SSE). - inline void movhps(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVHPS, &dst, &src); - } - - //! @brief Move Low to High Packed SP-FP (SSE). - inline void movlhps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVLHPS, &dst, &src); - } - - //! @brief Move Low Packed SP-FP (SSE). - inline void movlps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVLPS, &dst, &src); - } - - //! @brief Move Low Packed SP-FP (SSE). - inline void movlps(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVLPS, &dst, &src); - } - - //! @brief Move Aligned Four Packed SP-FP Non Temporal (SSE). - inline void movntps(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVNTPS, &dst, &src); - } - - //! @brief Move Scalar SP-FP (SSE). - inline void movss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVSS, &dst, &src); - } - - //! @brief Move Scalar SP-FP (SSE). - inline void movss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVSS, &dst, &src); - } - - //! @brief Move Scalar SP-FP (SSE). - inline void movss(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVSS, &dst, &src); - } - - //! @brief Move Unaligned Packed SP-FP Values (SSE). - inline void movups(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVUPS, &dst, &src); - } - //! @brief Move Unaligned Packed SP-FP Values (SSE). - inline void movups(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVUPS, &dst, &src); - } - - //! @brief Move Unaligned Packed SP-FP Values (SSE). - inline void movups(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVUPS, &dst, &src); - } - - //! @brief Packed SP-FP Multiply (SSE). - inline void mulps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MULPS, &dst, &src); - } - //! @brief Packed SP-FP Multiply (SSE). - inline void mulps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MULPS, &dst, &src); - } - - //! @brief Scalar SP-FP Multiply (SSE). - inline void mulss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MULSS, &dst, &src); - } - //! @brief Scalar SP-FP Multiply (SSE). - inline void mulss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MULSS, &dst, &src); - } - - //! @brief Bit-wise Logical OR for SP-FP Data (SSE). - inline void orps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ORPS, &dst, &src); - } - //! @brief Bit-wise Logical OR for SP-FP Data (SSE). - inline void orps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ORPS, &dst, &src); - } - - //! @brief Packed Average (SSE). - inline void pavgb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PAVGB, &dst, &src); - } - //! @brief Packed Average (SSE). - inline void pavgb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PAVGB, &dst, &src); - } - - //! @brief Packed Average (SSE). - inline void pavgw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PAVGW, &dst, &src); - } - //! @brief Packed Average (SSE). - inline void pavgw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PAVGW, &dst, &src); - } - - //! @brief Extract Word (SSE). - inline void pextrw(const GPReg& dst, const MMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRW, &dst, &src, &imm8); - } - - //! @brief Insert Word (SSE). - inline void pinsrw(const MMReg& dst, const GPReg& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRW, &dst, &src, &imm8); - } - //! @brief Insert Word (SSE). - inline void pinsrw(const MMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRW, &dst, &src, &imm8); - } - - //! @brief Packed Signed Integer Word Maximum (SSE). - inline void pmaxsw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMAXSW, &dst, &src); - } - //! @brief Packed Signed Integer Word Maximum (SSE). - inline void pmaxsw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMAXSW, &dst, &src); - } - - //! @brief Packed Unsigned Integer Byte Maximum (SSE). - inline void pmaxub(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMAXUB, &dst, &src); - } - //! @brief Packed Unsigned Integer Byte Maximum (SSE). - inline void pmaxub(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMAXUB, &dst, &src); - } - - //! @brief Packed Signed Integer Word Minimum (SSE). - inline void pminsw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMINSW, &dst, &src); - } - //! @brief Packed Signed Integer Word Minimum (SSE). - inline void pminsw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMINSW, &dst, &src); - } - - //! @brief Packed Unsigned Integer Byte Minimum (SSE). - inline void pminub(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMINUB, &dst, &src); - } - //! @brief Packed Unsigned Integer Byte Minimum (SSE). - inline void pminub(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMINUB, &dst, &src); - } - - //! @brief Move Byte Mask To Integer (SSE). - inline void pmovmskb(const GPReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMOVMSKB, &dst, &src); - } - - //! @brief Packed Multiply High Unsigned (SSE). - inline void pmulhuw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMULHUW, &dst, &src); - } - //! @brief Packed Multiply High Unsigned (SSE). - inline void pmulhuw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULHUW, &dst, &src); - } - - //! @brief Packed Sum of Absolute Differences (SSE). - inline void psadbw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSADBW, &dst, &src); - } - //! @brief Packed Sum of Absolute Differences (SSE). - inline void psadbw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSADBW, &dst, &src); - } - - //! @brief Packed Shuffle word (SSE). - inline void pshufw(const MMReg& dst, const MMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFW, &dst, &src, &imm8); - } - //! @brief Packed Shuffle word (SSE). - inline void pshufw(const MMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFW, &dst, &src, &imm8); - } - - //! @brief Packed SP-FP Reciprocal (SSE). - inline void rcpps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_RCPPS, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal (SSE). - inline void rcpps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_RCPPS, &dst, &src); - } - - //! @brief Scalar SP-FP Reciprocal (SSE). - inline void rcpss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_RCPSS, &dst, &src); - } - //! @brief Scalar SP-FP Reciprocal (SSE). - inline void rcpss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_RCPSS, &dst, &src); - } - - //! @brief Prefetch (SSE). - inline void prefetch(const Mem& mem, const Imm& hint) - { - _emitInstruction(INST_PREFETCH, &mem, &hint); - } - - //! @brief Compute Sum of Absolute Differences (SSE). - inline void psadbw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSADBW, &dst, &src); - } - //! @brief Compute Sum of Absolute Differences (SSE). - inline void psadbw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSADBW, &dst, &src); - } - - //! @brief Packed SP-FP Square Root Reciprocal (SSE). - inline void rsqrtps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_RSQRTPS, &dst, &src); - } - //! @brief Packed SP-FP Square Root Reciprocal (SSE). - inline void rsqrtps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_RSQRTPS, &dst, &src); - } - - //! @brief Scalar SP-FP Square Root Reciprocal (SSE). - inline void rsqrtss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_RSQRTSS, &dst, &src); - } - //! @brief Scalar SP-FP Square Root Reciprocal (SSE). - inline void rsqrtss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_RSQRTSS, &dst, &src); - } - - //! @brief Store fence (SSE). - inline void sfence() - { - _emitInstruction(INST_SFENCE); - } - - //! @brief Shuffle SP-FP (SSE). - inline void shufps(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_SHUFPS, &dst, &src, &imm8); - } - //! @brief Shuffle SP-FP (SSE). - inline void shufps(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_SHUFPS, &dst, &src, &imm8); - } - - //! @brief Packed SP-FP Square Root (SSE). - inline void sqrtps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_SQRTPS, &dst, &src); - } - //! @brief Packed SP-FP Square Root (SSE). - inline void sqrtps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_SQRTPS, &dst, &src); - } - - //! @brief Scalar SP-FP Square Root (SSE). - inline void sqrtss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_SQRTSS, &dst, &src); - } - //! @brief Scalar SP-FP Square Root (SSE). - inline void sqrtss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_SQRTSS, &dst, &src); - } - - //! @brief Store Streaming SIMD Extension Control/Status (SSE). - inline void stmxcsr(const Mem& dst) - { - _emitInstruction(INST_STMXCSR, &dst); - } - - //! @brief Packed SP-FP Subtract (SSE). - inline void subps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_SUBPS, &dst, &src); - } - //! @brief Packed SP-FP Subtract (SSE). - inline void subps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_SUBPS, &dst, &src); - } - - //! @brief Scalar SP-FP Subtract (SSE). - inline void subss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_SUBSS, &dst, &src); - } - //! @brief Scalar SP-FP Subtract (SSE). - inline void subss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_SUBSS, &dst, &src); - } - - //! @brief Unordered Scalar SP-FP compare and set EFLAGS (SSE). - inline void ucomiss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_UCOMISS, &dst, &src); - } - //! @brief Unordered Scalar SP-FP compare and set EFLAGS (SSE). - inline void ucomiss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_UCOMISS, &dst, &src); - } - - //! @brief Unpack High Packed SP-FP Data (SSE). - inline void unpckhps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_UNPCKHPS, &dst, &src); - } - //! @brief Unpack High Packed SP-FP Data (SSE). - inline void unpckhps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_UNPCKHPS, &dst, &src); - } - - //! @brief Unpack Low Packed SP-FP Data (SSE). - inline void unpcklps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_UNPCKLPS, &dst, &src); - } - //! @brief Unpack Low Packed SP-FP Data (SSE). - inline void unpcklps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_UNPCKLPS, &dst, &src); - } - - //! @brief Bit-wise Logical Xor for SP-FP Data (SSE). - inline void xorps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_XORPS, &dst, &src); - } - //! @brief Bit-wise Logical Xor for SP-FP Data (SSE). - inline void xorps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_XORPS, &dst, &src); - } - - // -------------------------------------------------------------------------- - // [SSE2] - // -------------------------------------------------------------------------- - - //! @brief Packed DP-FP Add (SSE2). - inline void addpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ADDPD, &dst, &src); - } - //! @brief Packed DP-FP Add (SSE2). - inline void addpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ADDPD, &dst, &src); - } - - //! @brief Scalar DP-FP Add (SSE2). - inline void addsd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ADDSD, &dst, &src); - } - //! @brief Scalar DP-FP Add (SSE2). - inline void addsd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ADDSD, &dst, &src); - } - - //! @brief Bit-wise Logical And Not For DP-FP (SSE2). - inline void andnpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ANDNPD, &dst, &src); - } - //! @brief Bit-wise Logical And Not For DP-FP (SSE2). - inline void andnpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ANDNPD, &dst, &src); - } - - //! @brief Bit-wise Logical And For DP-FP (SSE2). - inline void andpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ANDPD, &dst, &src); - } - //! @brief Bit-wise Logical And For DP-FP (SSE2). - inline void andpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ANDPD, &dst, &src); - } - - //! @brief Flush Cache Line (SSE2). - inline void clflush(const Mem& mem) - { - _emitInstruction(INST_CLFLUSH, &mem); - } - - //! @brief Packed DP-FP Compare (SSE2). - inline void cmppd(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_CMPPD, &dst, &src, &imm8); - } - //! @brief Packed DP-FP Compare (SSE2). - inline void cmppd(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_CMPPD, &dst, &src, &imm8); - } - - //! @brief Compare Scalar SP-FP Values (SSE2). - inline void cmpsd(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_CMPSD, &dst, &src, &imm8); - } - //! @brief Compare Scalar SP-FP Values (SSE2). - inline void cmpsd(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_CMPSD, &dst, &src, &imm8); - } - - //! @brief Scalar Ordered DP-FP Compare and Set EFLAGS (SSE2). - inline void comisd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_COMISD, &dst, &src); - } - //! @brief Scalar Ordered DP-FP Compare and Set EFLAGS (SSE2). - inline void comisd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_COMISD, &dst, &src); - } - - //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). - inline void cvtdq2pd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTDQ2PD, &dst, &src); - } - //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). - inline void cvtdq2pd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTDQ2PD, &dst, &src); - } - - //! @brief Convert Packed Dword Integers to Packed SP-FP Values (SSE2). - inline void cvtdq2ps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTDQ2PS, &dst, &src); - } - //! @brief Convert Packed Dword Integers to Packed SP-FP Values (SSE2). - inline void cvtdq2ps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTDQ2PS, &dst, &src); - } - - //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvtpd2dq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTPD2DQ, &dst, &src); - } - //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvtpd2dq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTPD2DQ, &dst, &src); - } - - //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvtpd2pi(const MMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTPD2PI, &dst, &src); - } - //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvtpd2pi(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTPD2PI, &dst, &src); - } - - //! @brief Convert Packed DP-FP Values to Packed SP-FP Values (SSE2). - inline void cvtpd2ps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTPD2PS, &dst, &src); - } - //! @brief Convert Packed DP-FP Values to Packed SP-FP Values (SSE2). - inline void cvtpd2ps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTPD2PS, &dst, &src); - } - - //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). - inline void cvtpi2pd(const XMMReg& dst, const MMReg& src) - { - _emitInstruction(INST_CVTPI2PD, &dst, &src); - } - //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). - inline void cvtpi2pd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTPI2PD, &dst, &src); - } - - //! @brief Convert Packed SP-FP Values to Packed Dword Integers (SSE2). - inline void cvtps2dq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTPS2DQ, &dst, &src); - } - //! @brief Convert Packed SP-FP Values to Packed Dword Integers (SSE2). - inline void cvtps2dq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTPS2DQ, &dst, &src); - } - - //! @brief Convert Packed SP-FP Values to Packed DP-FP Values (SSE2). - inline void cvtps2pd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTPS2PD, &dst, &src); - } - //! @brief Convert Packed SP-FP Values to Packed DP-FP Values (SSE2). - inline void cvtps2pd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTPS2PD, &dst, &src); - } - - //! @brief Convert Scalar DP-FP Value to Dword Integer (SSE2). - inline void cvtsd2si(const GPReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTSD2SI, &dst, &src); - } - //! @brief Convert Scalar DP-FP Value to Dword Integer (SSE2). - inline void cvtsd2si(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTSD2SI, &dst, &src); - } - - //! @brief Convert Scalar DP-FP Value to Scalar SP-FP Value (SSE2). - inline void cvtsd2ss(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTSD2SS, &dst, &src); - } - //! @brief Convert Scalar DP-FP Value to Scalar SP-FP Value (SSE2). - inline void cvtsd2ss(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTSD2SS, &dst, &src); - } - - //! @brief Convert Dword Integer to Scalar DP-FP Value (SSE2). - inline void cvtsi2sd(const XMMReg& dst, const GPReg& src) - { - _emitInstruction(INST_CVTSI2SD, &dst, &src); - } - //! @brief Convert Dword Integer to Scalar DP-FP Value (SSE2). - inline void cvtsi2sd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTSI2SD, &dst, &src); - } - - //! @brief Convert Scalar SP-FP Value to Scalar DP-FP Value (SSE2). - inline void cvtss2sd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTSS2SD, &dst, &src); - } - //! @brief Convert Scalar SP-FP Value to Scalar DP-FP Value (SSE2). - inline void cvtss2sd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTSS2SD, &dst, &src); - } - - //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvttpd2pi(const MMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTTPD2PI, &dst, &src); - } - //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvttpd2pi(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTTPD2PI, &dst, &src); - } - - //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvttpd2dq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTTPD2DQ, &dst, &src); - } - //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvttpd2dq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTTPD2DQ, &dst, &src); - } - - //! @brief Convert with Truncation Packed SP-FP Values to Packed Dword Integers (SSE2). - inline void cvttps2dq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTTPS2DQ, &dst, &src); - } - //! @brief Convert with Truncation Packed SP-FP Values to Packed Dword Integers (SSE2). - inline void cvttps2dq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTTPS2DQ, &dst, &src); - } - - //! @brief Convert with Truncation Scalar DP-FP Value to Signed Dword Integer (SSE2). - inline void cvttsd2si(const GPReg& dst, const XMMReg& src) - { - _emitInstruction(INST_CVTTSD2SI, &dst, &src); - } - //! @brief Convert with Truncation Scalar DP-FP Value to Signed Dword Integer (SSE2). - inline void cvttsd2si(const GPReg& dst, const Mem& src) - { - _emitInstruction(INST_CVTTSD2SI, &dst, &src); - } - - //! @brief Packed DP-FP Divide (SSE2). - inline void divpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_DIVPD, &dst, &src); - } - //! @brief Packed DP-FP Divide (SSE2). - inline void divpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_DIVPD, &dst, &src); - } - - //! @brief Scalar DP-FP Divide (SSE2). - inline void divsd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_DIVSD, &dst, &src); - } - //! @brief Scalar DP-FP Divide (SSE2). - inline void divsd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_DIVSD, &dst, &src); - } - - //! @brief Load Fence (SSE2). - inline void lfence() - { - _emitInstruction(INST_LFENCE); - } - - //! @brief Store Selected Bytes of Double Quadword (SSE2). - //! - //! @note Target is DS:EDI. - inline void maskmovdqu(const XMMReg& src, const XMMReg& mask) - { - _emitInstruction(INST_MASKMOVDQU, &src, &mask); - } - - //! @brief Return Maximum Packed Double-Precision FP Values (SSE2). - inline void maxpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MAXPD, &dst, &src); - } - //! @brief Return Maximum Packed Double-Precision FP Values (SSE2). - inline void maxpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MAXPD, &dst, &src); - } - - //! @brief Return Maximum Scalar Double-Precision FP Value (SSE2). - inline void maxsd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MAXSD, &dst, &src); - } - //! @brief Return Maximum Scalar Double-Precision FP Value (SSE2). - inline void maxsd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MAXSD, &dst, &src); - } - - //! @brief Memory Fence (SSE2). - inline void mfence() - { - _emitInstruction(INST_MFENCE); - } - - //! @brief Return Minimum Packed DP-FP Values (SSE2). - inline void minpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MINPD, &dst, &src); - } - //! @brief Return Minimum Packed DP-FP Values (SSE2). - inline void minpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MINPD, &dst, &src); - } - - //! @brief Return Minimum Scalar DP-FP Value (SSE2). - inline void minsd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MINSD, &dst, &src); - } - //! @brief Return Minimum Scalar DP-FP Value (SSE2). - inline void minsd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MINSD, &dst, &src); - } - - //! @brief Move Aligned DQWord (SSE2). - inline void movdqa(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVDQA, &dst, &src); - } - //! @brief Move Aligned DQWord (SSE2). - inline void movdqa(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVDQA, &dst, &src); - } - - //! @brief Move Aligned DQWord (SSE2). - inline void movdqa(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVDQA, &dst, &src); - } - - //! @brief Move Unaligned Double Quadword (SSE2). - inline void movdqu(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVDQU, &dst, &src); - } - //! @brief Move Unaligned Double Quadword (SSE2). - inline void movdqu(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVDQU, &dst, &src); - } - - //! @brief Move Unaligned Double Quadword (SSE2). - inline void movdqu(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVDQU, &dst, &src); - } - - //! @brief Extract Packed SP-FP Sign Mask (SSE2). - inline void movmskps(const GPReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVMSKPS, &dst, &src); - } - - //! @brief Extract Packed DP-FP Sign Mask (SSE2). - inline void movmskpd(const GPReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVMSKPD, &dst, &src); - } - - //! @brief Move Scalar Double-Precision FP Value (SSE2). - inline void movsd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVSD, &dst, &src); - } - //! @brief Move Scalar Double-Precision FP Value (SSE2). - inline void movsd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVSD, &dst, &src); - } - - //! @brief Move Scalar Double-Precision FP Value (SSE2). - inline void movsd(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVSD, &dst, &src); - } - - //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). - inline void movapd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVAPD, &dst, &src); - } - - //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). - inline void movapd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVAPD, &dst, &src); - } - - //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). - inline void movapd(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVAPD, &dst, &src); - } - - //! @brief Move Quadword from XMM to MMX Technology Register (SSE2). - inline void movdq2q(const MMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVDQ2Q, &dst, &src); - } - - //! @brief Move Quadword from MMX Technology to XMM Register (SSE2). - inline void movq2dq(const XMMReg& dst, const MMReg& src) - { - _emitInstruction(INST_MOVQ2DQ, &dst, &src); - } - - //! @brief Move High Packed Double-Precision FP Value (SSE2). - inline void movhpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVHPD, &dst, &src); - } - - //! @brief Move High Packed Double-Precision FP Value (SSE2). - inline void movhpd(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVHPD, &dst, &src); - } - - //! @brief Move Low Packed Double-Precision FP Value (SSE2). - inline void movlpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVLPD, &dst, &src); - } - - //! @brief Move Low Packed Double-Precision FP Value (SSE2). - inline void movlpd(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVLPD, &dst, &src); - } - - //! @brief Store Double Quadword Using Non-Temporal Hint (SSE2). - inline void movntdq(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVNTDQ, &dst, &src); - } - - //! @brief Store Store DWORD Using Non-Temporal Hint (SSE2). - inline void movnti(const Mem& dst, const GPReg& src) - { - _emitInstruction(INST_MOVNTI, &dst, &src); - } - - //! @brief Store Packed Double-Precision FP Values Using Non-Temporal Hint (SSE2). - inline void movntpd(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVNTPD, &dst, &src); - } - - //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). - inline void movupd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVUPD, &dst, &src); - } - - //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). - inline void movupd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVUPD, &dst, &src); - } - - //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). - inline void movupd(const Mem& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVUPD, &dst, &src); - } - - //! @brief Packed DP-FP Multiply (SSE2). - inline void mulpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MULPD, &dst, &src); - } - //! @brief Packed DP-FP Multiply (SSE2). - inline void mulpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MULPD, &dst, &src); - } - - //! @brief Scalar DP-FP Multiply (SSE2). - inline void mulsd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MULSD, &dst, &src); - } - //! @brief Scalar DP-FP Multiply (SSE2). - inline void mulsd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MULSD, &dst, &src); - } - - //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). - inline void orpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ORPD, &dst, &src); - } - //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). - inline void orpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ORPD, &dst, &src); - } - - //! @brief Pack with Signed Saturation (SSE2). - inline void packsswb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PACKSSWB, &dst, &src); - } - //! @brief Pack with Signed Saturation (SSE2). - inline void packsswb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PACKSSWB, &dst, &src); - } - - //! @brief Pack with Signed Saturation (SSE2). - inline void packssdw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PACKSSDW, &dst, &src); - } - //! @brief Pack with Signed Saturation (SSE2). - inline void packssdw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PACKSSDW, &dst, &src); - } - - //! @brief Pack with Unsigned Saturation (SSE2). - inline void packuswb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PACKUSWB, &dst, &src); - } - //! @brief Pack with Unsigned Saturation (SSE2). - inline void packuswb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PACKUSWB, &dst, &src); - } - - //! @brief Packed BYTE Add (SSE2). - inline void paddb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PADDB, &dst, &src); - } - //! @brief Packed BYTE Add (SSE2). - inline void paddb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDB, &dst, &src); - } - - //! @brief Packed WORD Add (SSE2). - inline void paddw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PADDW, &dst, &src); - } - //! @brief Packed WORD Add (SSE2). - inline void paddw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDW, &dst, &src); - } - - //! @brief Packed DWORD Add (SSE2). - inline void paddd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PADDD, &dst, &src); - } - //! @brief Packed DWORD Add (SSE2). - inline void paddd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDD, &dst, &src); - } - - //! @brief Packed QWORD Add (SSE2). - inline void paddq(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PADDQ, &dst, &src); - } - //! @brief Packed QWORD Add (SSE2). - inline void paddq(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDQ, &dst, &src); - } - - //! @brief Packed QWORD Add (SSE2). - inline void paddq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PADDQ, &dst, &src); - } - //! @brief Packed QWORD Add (SSE2). - inline void paddq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDQ, &dst, &src); - } - - //! @brief Packed Add with Saturation (SSE2). - inline void paddsb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PADDSB, &dst, &src); - } - //! @brief Packed Add with Saturation (SSE2). - inline void paddsb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDSB, &dst, &src); - } - - //! @brief Packed Add with Saturation (SSE2). - inline void paddsw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PADDSW, &dst, &src); - } - //! @brief Packed Add with Saturation (SSE2). - inline void paddsw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDSW, &dst, &src); - } - - //! @brief Packed Add Unsigned with Saturation (SSE2). - inline void paddusb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PADDUSB, &dst, &src); - } - //! @brief Packed Add Unsigned with Saturation (SSE2). - inline void paddusb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDUSB, &dst, &src); - } - - //! @brief Packed Add Unsigned with Saturation (SSE2). - inline void paddusw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PADDUSW, &dst, &src); - } - //! @brief Packed Add Unsigned with Saturation (SSE2). - inline void paddusw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PADDUSW, &dst, &src); - } - - //! @brief Logical AND (SSE2). - inline void pand(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PAND, &dst, &src); - } - //! @brief Logical AND (SSE2). - inline void pand(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PAND, &dst, &src); - } - - //! @brief Logical AND Not (SSE2). - inline void pandn(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PANDN, &dst, &src); - } - //! @brief Logical AND Not (SSE2). - inline void pandn(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PANDN, &dst, &src); - } - - //! @brief Spin Loop Hint (SSE2). - inline void pause() - { - _emitInstruction(INST_PAUSE); - } - - //! @brief Packed Average (SSE2). - inline void pavgb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PAVGB, &dst, &src); - } - //! @brief Packed Average (SSE2). - inline void pavgb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PAVGB, &dst, &src); - } - - //! @brief Packed Average (SSE2). - inline void pavgw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PAVGW, &dst, &src); - } - //! @brief Packed Average (SSE2). - inline void pavgw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PAVGW, &dst, &src); - } - - //! @brief Packed Compare for Equal (BYTES) (SSE2). - inline void pcmpeqb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PCMPEQB, &dst, &src); - } - //! @brief Packed Compare for Equal (BYTES) (SSE2). - inline void pcmpeqb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQB, &dst, &src); - } - - //! @brief Packed Compare for Equal (WORDS) (SSE2). - inline void pcmpeqw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PCMPEQW, &dst, &src); - } - //! @brief Packed Compare for Equal (WORDS) (SSE2). - inline void pcmpeqw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQW, &dst, &src); - } - - //! @brief Packed Compare for Equal (DWORDS) (SSE2). - inline void pcmpeqd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PCMPEQD, &dst, &src); - } - //! @brief Packed Compare for Equal (DWORDS) (SSE2). - inline void pcmpeqd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQD, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (BYTES) (SSE2). - inline void pcmpgtb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PCMPGTB, &dst, &src); - } - //! @brief Packed Compare for Greater Than (BYTES) (SSE2). - inline void pcmpgtb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTB, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (WORDS) (SSE2). - inline void pcmpgtw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PCMPGTW, &dst, &src); - } - //! @brief Packed Compare for Greater Than (WORDS) (SSE2). - inline void pcmpgtw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTW, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (DWORDS) (SSE2). - inline void pcmpgtd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PCMPGTD, &dst, &src); - } - //! @brief Packed Compare for Greater Than (DWORDS) (SSE2). - inline void pcmpgtd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTD, &dst, &src); - } - - //! @brief Packed Signed Integer Word Maximum (SSE2). - inline void pmaxsw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMAXSW, &dst, &src); - } - //! @brief Packed Signed Integer Word Maximum (SSE2). - inline void pmaxsw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMAXSW, &dst, &src); - } - - //! @brief Packed Unsigned Integer Byte Maximum (SSE2). - inline void pmaxub(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMAXUB, &dst, &src); - } - //! @brief Packed Unsigned Integer Byte Maximum (SSE2). - inline void pmaxub(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMAXUB, &dst, &src); - } - - //! @brief Packed Signed Integer Word Minimum (SSE2). - inline void pminsw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMINSW, &dst, &src); - } - //! @brief Packed Signed Integer Word Minimum (SSE2). - inline void pminsw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMINSW, &dst, &src); - } - - //! @brief Packed Unsigned Integer Byte Minimum (SSE2). - inline void pminub(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMINUB, &dst, &src); - } - //! @brief Packed Unsigned Integer Byte Minimum (SSE2). - inline void pminub(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMINUB, &dst, &src); - } - - //! @brief Move Byte Mask (SSE2). - inline void pmovmskb(const GPReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVMSKB, &dst, &src); - } - - //! @brief Packed Multiply High (SSE2). - inline void pmulhw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMULHW, &dst, &src); - } - //! @brief Packed Multiply High (SSE2). - inline void pmulhw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULHW, &dst, &src); - } - - //! @brief Packed Multiply High Unsigned (SSE2). - inline void pmulhuw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMULHUW, &dst, &src); - } - //! @brief Packed Multiply High Unsigned (SSE2). - inline void pmulhuw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULHUW, &dst, &src); - } - - //! @brief Packed Multiply Low (SSE2). - inline void pmullw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMULLW, &dst, &src); - } - //! @brief Packed Multiply Low (SSE2). - inline void pmullw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULLW, &dst, &src); - } - - //! @brief Packed Multiply to QWORD (SSE2). - inline void pmuludq(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMULUDQ, &dst, &src); - } - //! @brief Packed Multiply to QWORD (SSE2). - inline void pmuludq(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULUDQ, &dst, &src); - } - - //! @brief Packed Multiply to QWORD (SSE2). - inline void pmuludq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMULUDQ, &dst, &src); - } - //! @brief Packed Multiply to QWORD (SSE2). - inline void pmuludq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULUDQ, &dst, &src); - } - - //! @brief Bitwise Logical OR (SSE2). - inline void por(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_POR, &dst, &src); - } - //! @brief Bitwise Logical OR (SSE2). - inline void por(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_POR, &dst, &src); - } - - //! @brief Packed Shift Left Logical (SSE2). - inline void pslld(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void pslld(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void pslld(const XMMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - - //! @brief Packed Shift Left Logical (SSE2). - inline void psllq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void psllq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void psllq(const XMMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - - //! @brief Packed Shift Left Logical (SSE2). - inline void psllw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void psllw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void psllw(const XMMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - - //! @brief Packed Shift Left Logical (SSE2). - inline void pslldq(const XMMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSLLDQ, &dst, &src); - } - - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psrad(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psrad(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psrad(const XMMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psraw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psraw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psraw(const XMMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - - //! @brief Packed Subtract (SSE2). - inline void psubb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSUBB, &dst, &src); - } - //! @brief Packed Subtract (SSE2). - inline void psubb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBB, &dst, &src); - } - - //! @brief Packed Subtract (SSE2). - inline void psubw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSUBW, &dst, &src); - } - //! @brief Packed Subtract (SSE2). - inline void psubw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBW, &dst, &src); - } - - //! @brief Packed Subtract (SSE2). - inline void psubd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSUBD, &dst, &src); - } - //! @brief Packed Subtract (SSE2). - inline void psubd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBD, &dst, &src); - } - - //! @brief Packed Subtract (SSE2). - inline void psubq(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSUBQ, &dst, &src); - } - //! @brief Packed Subtract (SSE2). - inline void psubq(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBQ, &dst, &src); - } - - //! @brief Packed Subtract (SSE2). - inline void psubq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSUBQ, &dst, &src); - } - //! @brief Packed Subtract (SSE2). - inline void psubq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBQ, &dst, &src); - } - - //! @brief Packed Multiply and Add (SSE2). - inline void pmaddwd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMADDWD, &dst, &src); - } - //! @brief Packed Multiply and Add (SSE2). - inline void pmaddwd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMADDWD, &dst, &src); - } - - //! @brief Shuffle Packed DWORDs (SSE2). - inline void pshufd(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFD, &dst, &src, &imm8); - } - //! @brief Shuffle Packed DWORDs (SSE2). - inline void pshufd(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFD, &dst, &src, &imm8); - } - - //! @brief Shuffle Packed High Words (SSE2). - inline void pshufhw(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFHW, &dst, &src, &imm8); - } - //! @brief Shuffle Packed High Words (SSE2). - inline void pshufhw(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFHW, &dst, &src, &imm8); - } - - //! @brief Shuffle Packed Low Words (SSE2). - inline void pshuflw(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFLW, &dst, &src, &imm8); - } - //! @brief Shuffle Packed Low Words (SSE2). - inline void pshuflw(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFLW, &dst, &src, &imm8); - } - - //! @brief Packed Shift Right Logical (SSE2). - inline void psrld(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrld(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrld(const XMMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlq(const XMMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - - //! @brief DQWord Shift Right Logical (MMX). - inline void psrldq(const XMMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSRLDQ, &dst, &src); - } - - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlw(const XMMReg& dst, const Imm& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - - //! @brief Packed Subtract with Saturation (SSE2). - inline void psubsb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSUBSB, &dst, &src); - } - //! @brief Packed Subtract with Saturation (SSE2). - inline void psubsb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBSB, &dst, &src); - } - - //! @brief Packed Subtract with Saturation (SSE2). - inline void psubsw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSUBSW, &dst, &src); - } - //! @brief Packed Subtract with Saturation (SSE2). - inline void psubsw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBSW, &dst, &src); - } - - //! @brief Packed Subtract with Unsigned Saturation (SSE2). - inline void psubusb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSUBUSB, &dst, &src); - } - //! @brief Packed Subtract with Unsigned Saturation (SSE2). - inline void psubusb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBUSB, &dst, &src); - } - - //! @brief Packed Subtract with Unsigned Saturation (SSE2). - inline void psubusw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSUBUSW, &dst, &src); - } - //! @brief Packed Subtract with Unsigned Saturation (SSE2). - inline void psubusw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSUBUSW, &dst, &src); - } - - //! @brief Unpack High Data (SSE2). - inline void punpckhbw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PUNPCKHBW, &dst, &src); - } - //! @brief Unpack High Data (SSE2). - inline void punpckhbw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHBW, &dst, &src); - } - - //! @brief Unpack High Data (SSE2). - inline void punpckhwd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PUNPCKHWD, &dst, &src); - } - //! @brief Unpack High Data (SSE2). - inline void punpckhwd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHWD, &dst, &src); - } - - //! @brief Unpack High Data (SSE2). - inline void punpckhdq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PUNPCKHDQ, &dst, &src); - } - //! @brief Unpack High Data (SSE2). - inline void punpckhdq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHDQ, &dst, &src); - } - - //! @brief Unpack High Data (SSE2). - inline void punpckhqdq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PUNPCKHQDQ, &dst, &src); - } - //! @brief Unpack High Data (SSE2). - inline void punpckhqdq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHQDQ, &dst, &src); - } - - //! @brief Unpack Low Data (SSE2). - inline void punpcklbw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PUNPCKLBW, &dst, &src); - } - //! @brief Unpack Low Data (SSE2). - inline void punpcklbw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLBW, &dst, &src); - } - - //! @brief Unpack Low Data (SSE2). - inline void punpcklwd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PUNPCKLWD, &dst, &src); - } - //! @brief Unpack Low Data (SSE2). - inline void punpcklwd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLWD, &dst, &src); - } - - //! @brief Unpack Low Data (SSE2). - inline void punpckldq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PUNPCKLDQ, &dst, &src); - } - //! @brief Unpack Low Data (SSE2). - inline void punpckldq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLDQ, &dst, &src); - } - - //! @brief Unpack Low Data (SSE2). - inline void punpcklqdq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PUNPCKLQDQ, &dst, &src); - } - //! @brief Unpack Low Data (SSE2). - inline void punpcklqdq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLQDQ, &dst, &src); - } - - //! @brief Bitwise Exclusive OR (SSE2). - inline void pxor(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PXOR, &dst, &src); - } - //! @brief Bitwise Exclusive OR (SSE2). - inline void pxor(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PXOR, &dst, &src); - } - - //! @brief Shuffle DP-FP (SSE2). - inline void shufpd(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_SHUFPD, &dst, &src, &imm8); - } - //! @brief Shuffle DP-FP (SSE2). - inline void shufpd(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_SHUFPD, &dst, &src, &imm8); - } - - //! @brief Compute Square Roots of Packed DP-FP Values (SSE2). - inline void sqrtpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_SQRTPD, &dst, &src); - } - //! @brief Compute Square Roots of Packed DP-FP Values (SSE2). - inline void sqrtpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_SQRTPD, &dst, &src); - } - - //! @brief Compute Square Root of Scalar DP-FP Value (SSE2). - inline void sqrtsd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_SQRTSD, &dst, &src); - } - //! @brief Compute Square Root of Scalar DP-FP Value (SSE2). - inline void sqrtsd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_SQRTSD, &dst, &src); - } - - //! @brief Packed DP-FP Subtract (SSE2). - inline void subpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_SUBPD, &dst, &src); - } - //! @brief Packed DP-FP Subtract (SSE2). - inline void subpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_SUBPD, &dst, &src); - } - - //! @brief Scalar DP-FP Subtract (SSE2). - inline void subsd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_SUBSD, &dst, &src); - } - //! @brief Scalar DP-FP Subtract (SSE2). - inline void subsd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_SUBSD, &dst, &src); - } - - //! @brief Scalar Unordered DP-FP Compare and Set EFLAGS (SSE2). - inline void ucomisd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_UCOMISD, &dst, &src); - } - //! @brief Scalar Unordered DP-FP Compare and Set EFLAGS (SSE2). - inline void ucomisd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_UCOMISD, &dst, &src); - } - - //! @brief Unpack and Interleave High Packed Double-Precision FP Values (SSE2). - inline void unpckhpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_UNPCKHPD, &dst, &src); - } - //! @brief Unpack and Interleave High Packed Double-Precision FP Values (SSE2). - inline void unpckhpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_UNPCKHPD, &dst, &src); - } - - //! @brief Unpack and Interleave Low Packed Double-Precision FP Values (SSE2). - inline void unpcklpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_UNPCKLPD, &dst, &src); - } - //! @brief Unpack and Interleave Low Packed Double-Precision FP Values (SSE2). - inline void unpcklpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_UNPCKLPD, &dst, &src); - } - - //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). - inline void xorpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_XORPD, &dst, &src); - } - //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). - inline void xorpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_XORPD, &dst, &src); - } - - // -------------------------------------------------------------------------- - // [SSE3] - // -------------------------------------------------------------------------- - - //! @brief Packed DP-FP Add/Subtract (SSE3). - inline void addsubpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ADDSUBPD, &dst, &src); - } - //! @brief Packed DP-FP Add/Subtract (SSE3). - inline void addsubpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ADDSUBPD, &dst, &src); - } - - //! @brief Packed SP-FP Add/Subtract (SSE3). - inline void addsubps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_ADDSUBPS, &dst, &src); - } - //! @brief Packed SP-FP Add/Subtract (SSE3). - inline void addsubps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_ADDSUBPS, &dst, &src); - } - - //! @brief Store Integer with Truncation (SSE3). - inline void fisttp(const Mem& dst) - { - _emitInstruction(INST_FISTTP, &dst); - } - - //! @brief Packed DP-FP Horizontal Add (SSE3). - inline void haddpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_HADDPD, &dst, &src); - } - //! @brief Packed DP-FP Horizontal Add (SSE3). - inline void haddpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_HADDPD, &dst, &src); - } - - //! @brief Packed SP-FP Horizontal Add (SSE3). - inline void haddps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_HADDPS, &dst, &src); - } - //! @brief Packed SP-FP Horizontal Add (SSE3). - inline void haddps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_HADDPS, &dst, &src); - } - - //! @brief Packed DP-FP Horizontal Subtract (SSE3). - inline void hsubpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_HSUBPD, &dst, &src); - } - //! @brief Packed DP-FP Horizontal Subtract (SSE3). - inline void hsubpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_HSUBPD, &dst, &src); - } - - //! @brief Packed SP-FP Horizontal Subtract (SSE3). - inline void hsubps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_HSUBPS, &dst, &src); - } - //! @brief Packed SP-FP Horizontal Subtract (SSE3). - inline void hsubps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_HSUBPS, &dst, &src); - } - - //! @brief Load Unaligned Integer 128 Bits (SSE3). - inline void lddqu(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_LDDQU, &dst, &src); - } - - //! @brief Set Up Monitor Address (SSE3). - inline void monitor() - { - _emitInstruction(INST_MONITOR); - } - - //! @brief Move One DP-FP and Duplicate (SSE3). - inline void movddup(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVDDUP, &dst, &src); - } - //! @brief Move One DP-FP and Duplicate (SSE3). - inline void movddup(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVDDUP, &dst, &src); - } - - //! @brief Move Packed SP-FP High and Duplicate (SSE3). - inline void movshdup(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVSHDUP, &dst, &src); - } - //! @brief Move Packed SP-FP High and Duplicate (SSE3). - inline void movshdup(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVSHDUP, &dst, &src); - } - - //! @brief Move Packed SP-FP Low and Duplicate (SSE3). - inline void movsldup(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_MOVSLDUP, &dst, &src); - } - //! @brief Move Packed SP-FP Low and Duplicate (SSE3). - inline void movsldup(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVSLDUP, &dst, &src); - } - - //! @brief Monitor Wait (SSE3). - inline void mwait() - { - _emitInstruction(INST_MWAIT); - } - - // -------------------------------------------------------------------------- - // [SSSE3] - // -------------------------------------------------------------------------- - - //! @brief Packed SIGN (SSSE3). - inline void psignb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSIGNB, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSIGNB, &dst, &src); - } - - //! @brief Packed SIGN (SSSE3). - inline void psignb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSIGNB, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSIGNB, &dst, &src); - } - - //! @brief Packed SIGN (SSSE3). - inline void psignw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSIGNW, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSIGNW, &dst, &src); - } - - //! @brief Packed SIGN (SSSE3). - inline void psignw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSIGNW, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSIGNW, &dst, &src); - } - - //! @brief Packed SIGN (SSSE3). - inline void psignd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSIGND, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSIGND, &dst, &src); - } - - //! @brief Packed SIGN (SSSE3). - inline void psignd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSIGND, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSIGND, &dst, &src); - } - - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PHADDW, &dst, &src); - } - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHADDW, &dst, &src); - } - - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PHADDW, &dst, &src); - } - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHADDW, &dst, &src); - } - - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PHADDD, &dst, &src); - } - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHADDD, &dst, &src); - } - - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PHADDD, &dst, &src); - } - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHADDD, &dst, &src); - } - - //! @brief Packed Horizontal Add and Saturate (SSSE3). - inline void phaddsw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PHADDSW, &dst, &src); - } - //! @brief Packed Horizontal Add and Saturate (SSSE3). - inline void phaddsw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHADDSW, &dst, &src); - } - - //! @brief Packed Horizontal Add and Saturate (SSSE3). - inline void phaddsw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PHADDSW, &dst, &src); - } - //! @brief Packed Horizontal Add and Saturate (SSSE3). - inline void phaddsw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHADDSW, &dst, &src); - } - - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PHSUBW, &dst, &src); - } - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBW, &dst, &src); - } - - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PHSUBW, &dst, &src); - } - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBW, &dst, &src); - } - - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PHSUBD, &dst, &src); - } - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBD, &dst, &src); - } - - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PHSUBD, &dst, &src); - } - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBD, &dst, &src); - } - - //! @brief Packed Horizontal Subtract and Saturate (SSSE3). - inline void phsubsw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PHSUBSW, &dst, &src); - } - //! @brief Packed Horizontal Subtract and Saturate (SSSE3). - inline void phsubsw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBSW, &dst, &src); - } - - //! @brief Packed Horizontal Subtract and Saturate (SSSE3). - inline void phsubsw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PHSUBSW, &dst, &src); - } - //! @brief Packed Horizontal Subtract and Saturate (SSSE3). - inline void phsubsw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBSW, &dst, &src); - } - - //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). - inline void pmaddubsw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMADDUBSW, &dst, &src); - } - //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). - inline void pmaddubsw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMADDUBSW, &dst, &src); - } - - //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). - inline void pmaddubsw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMADDUBSW, &dst, &src); - } - //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). - inline void pmaddubsw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMADDUBSW, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PABSB, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PABSB, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PABSB, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PABSB, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PABSW, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PABSW, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PABSW, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PABSW, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsd(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PABSD, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsd(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PABSD, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PABSD, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PABSD, &dst, &src); - } - - //! @brief Packed Multiply High with Round and Scale (SSSE3). - inline void pmulhrsw(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PMULHRSW, &dst, &src); - } - //! @brief Packed Multiply High with Round and Scale (SSSE3). - inline void pmulhrsw(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULHRSW, &dst, &src); - } - - //! @brief Packed Multiply High with Round and Scale (SSSE3). - inline void pmulhrsw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMULHRSW, &dst, &src); - } - //! @brief Packed Multiply High with Round and Scale (SSSE3). - inline void pmulhrsw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULHRSW, &dst, &src); - } - - //! @brief Packed Shuffle Bytes (SSSE3). - inline void pshufb(const MMReg& dst, const MMReg& src) - { - _emitInstruction(INST_PSHUFB, &dst, &src); - } - //! @brief Packed Shuffle Bytes (SSSE3). - inline void pshufb(const MMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSHUFB, &dst, &src); - } - - //! @brief Packed Shuffle Bytes (SSSE3). - inline void pshufb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PSHUFB, &dst, &src); - } - //! @brief Packed Shuffle Bytes (SSSE3). - inline void pshufb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PSHUFB, &dst, &src); - } - - //! @brief Packed Shuffle Bytes (SSSE3). - inline void palignr(const MMReg& dst, const MMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); - } - //! @brief Packed Shuffle Bytes (SSSE3). - inline void palignr(const MMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); - } - - //! @brief Packed Shuffle Bytes (SSSE3). - inline void palignr(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); - } - //! @brief Packed Shuffle Bytes (SSSE3). - inline void palignr(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); - } - - // -------------------------------------------------------------------------- - // [SSE4.1] - // -------------------------------------------------------------------------- - - //! @brief Blend Packed DP-FP Values (SSE4.1). - inline void blendpd(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_BLENDPD, &dst, &src, &imm8); - } - //! @brief Blend Packed DP-FP Values (SSE4.1). - inline void blendpd(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_BLENDPD, &dst, &src, &imm8); - } - - //! @brief Blend Packed SP-FP Values (SSE4.1). - inline void blendps(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_BLENDPS, &dst, &src, &imm8); - } - //! @brief Blend Packed SP-FP Values (SSE4.1). - inline void blendps(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_BLENDPS, &dst, &src, &imm8); - } - - //! @brief Variable Blend Packed DP-FP Values (SSE4.1). - inline void blendvpd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_BLENDVPD, &dst, &src); - } - //! @brief Variable Blend Packed DP-FP Values (SSE4.1). - inline void blendvpd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_BLENDVPD, &dst, &src); - } - - //! @brief Variable Blend Packed SP-FP Values (SSE4.1). - inline void blendvps(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_BLENDVPS, &dst, &src); - } - //! @brief Variable Blend Packed SP-FP Values (SSE4.1). - inline void blendvps(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_BLENDVPS, &dst, &src); - } - - //! @brief Dot Product of Packed DP-FP Values (SSE4.1). - inline void dppd(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_DPPD, &dst, &src, &imm8); - } - //! @brief Dot Product of Packed DP-FP Values (SSE4.1). - inline void dppd(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_DPPD, &dst, &src, &imm8); - } - - //! @brief Dot Product of Packed SP-FP Values (SSE4.1). - inline void dpps(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_DPPS, &dst, &src, &imm8); - } - //! @brief Dot Product of Packed SP-FP Values (SSE4.1). - inline void dpps(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_DPPS, &dst, &src, &imm8); - } - - //! @brief Extract Packed SP-FP Value (SSE4.1). - inline void extractps(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_EXTRACTPS, &dst, &src, &imm8); - } - //! @brief Extract Packed SP-FP Value (SSE4.1). - inline void extractps(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_EXTRACTPS, &dst, &src, &imm8); - } - - //! @brief Load Double Quadword Non-Temporal Aligned Hint (SSE4.1). - inline void movntdqa(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_MOVNTDQA, &dst, &src); - } - - //! @brief Compute Multiple Packed Sums of Absolute Difference (SSE4.1). - inline void mpsadbw(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_MPSADBW, &dst, &src, &imm8); - } - //! @brief Compute Multiple Packed Sums of Absolute Difference (SSE4.1). - inline void mpsadbw(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_MPSADBW, &dst, &src, &imm8); - } - - //! @brief Pack with Unsigned Saturation (SSE4.1). - inline void packusdw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PACKUSDW, &dst, &src); - } - //! @brief Pack with Unsigned Saturation (SSE4.1). - inline void packusdw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PACKUSDW, &dst, &src); - } - - //! @brief Variable Blend Packed Bytes (SSE4.1). - inline void pblendvb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PBLENDVB, &dst, &src); - } - //! @brief Variable Blend Packed Bytes (SSE4.1). - inline void pblendvb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PBLENDVB, &dst, &src); - } - - //! @brief Blend Packed Words (SSE4.1). - inline void pblendw(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PBLENDW, &dst, &src, &imm8); - } - //! @brief Blend Packed Words (SSE4.1). - inline void pblendw(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PBLENDW, &dst, &src, &imm8); - } - - //! @brief Compare Packed Qword Data for Equal (SSE4.1). - inline void pcmpeqq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PCMPEQQ, &dst, &src); - } - //! @brief Compare Packed Qword Data for Equal (SSE4.1). - inline void pcmpeqq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQQ, &dst, &src); - } - - //! @brief Extract Byte (SSE4.1). - inline void pextrb(const GPReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRB, &dst, &src, &imm8); - } - //! @brief Extract Byte (SSE4.1). - inline void pextrb(const Mem& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRB, &dst, &src, &imm8); - } - - //! @brief Extract Dword (SSE4.1). - inline void pextrd(const GPReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRD, &dst, &src, &imm8); - } - //! @brief Extract Dword (SSE4.1). - inline void pextrd(const Mem& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRD, &dst, &src, &imm8); - } - - //! @brief Extract Dword (SSE4.1). - inline void pextrq(const GPReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRQ, &dst, &src, &imm8); - } - //! @brief Extract Dword (SSE4.1). - inline void pextrq(const Mem& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRQ, &dst, &src, &imm8); - } - - //! @brief Extract Word (SSE4.1). - inline void pextrw(const GPReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRW, &dst, &src, &imm8); - } - //! @brief Extract Word (SSE4.1). - inline void pextrw(const Mem& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRW, &dst, &src, &imm8); - } - - //! @brief Packed Horizontal Word Minimum (SSE4.1). - inline void phminposuw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PHMINPOSUW, &dst, &src); - } - //! @brief Packed Horizontal Word Minimum (SSE4.1). - inline void phminposuw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PHMINPOSUW, &dst, &src); - } - - //! @brief Insert Byte (SSE4.1). - inline void pinsrb(const XMMReg& dst, const GPReg& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRB, &dst, &src, &imm8); - } - //! @brief Insert Byte (SSE4.1). - inline void pinsrb(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRB, &dst, &src, &imm8); - } - - //! @brief Insert Dword (SSE4.1). - inline void pinsrd(const XMMReg& dst, const GPReg& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRD, &dst, &src, &imm8); - } - //! @brief Insert Dword (SSE4.1). - inline void pinsrd(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRD, &dst, &src, &imm8); - } - - //! @brief Insert Dword (SSE4.1). - inline void pinsrq(const XMMReg& dst, const GPReg& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRQ, &dst, &src, &imm8); - } - //! @brief Insert Dword (SSE4.1). - inline void pinsrq(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRQ, &dst, &src, &imm8); - } - - //! @brief Insert Word (SSE2). - inline void pinsrw(const XMMReg& dst, const GPReg& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRW, &dst, &src, &imm8); - } - //! @brief Insert Word (SSE2). - inline void pinsrw(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRW, &dst, &src, &imm8); - } - - //! @brief Maximum of Packed Word Integers (SSE4.1). - inline void pmaxuw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMAXUW, &dst, &src); - } - //! @brief Maximum of Packed Word Integers (SSE4.1). - inline void pmaxuw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMAXUW, &dst, &src); - } - - //! @brief Maximum of Packed Signed Byte Integers (SSE4.1). - inline void pmaxsb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMAXSB, &dst, &src); - } - //! @brief Maximum of Packed Signed Byte Integers (SSE4.1). - inline void pmaxsb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMAXSB, &dst, &src); - } - - //! @brief Maximum of Packed Signed Dword Integers (SSE4.1). - inline void pmaxsd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMAXSD, &dst, &src); - } - //! @brief Maximum of Packed Signed Dword Integers (SSE4.1). - inline void pmaxsd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMAXSD, &dst, &src); - } - - //! @brief Maximum of Packed Unsigned Dword Integers (SSE4.1). - inline void pmaxud(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMAXUD, &dst, &src); - } - //! @brief Maximum of Packed Unsigned Dword Integers (SSE4.1). - inline void pmaxud(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMAXUD, &dst, &src); - } - - //! @brief Minimum of Packed Signed Byte Integers (SSE4.1). - inline void pminsb(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMINSB, &dst, &src); - } - //! @brief Minimum of Packed Signed Byte Integers (SSE4.1). - inline void pminsb(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMINSB, &dst, &src); - } - - //! @brief Minimum of Packed Word Integers (SSE4.1). - inline void pminuw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMINUW, &dst, &src); - } - //! @brief Minimum of Packed Word Integers (SSE4.1). - inline void pminuw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMINUW, &dst, &src); - } - - //! @brief Minimum of Packed Dword Integers (SSE4.1). - inline void pminud(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMINUD, &dst, &src); - } - //! @brief Minimum of Packed Dword Integers (SSE4.1). - inline void pminud(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMINUD, &dst, &src); - } - - //! @brief Minimum of Packed Dword Integers (SSE4.1). - inline void pminsd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMINSD, &dst, &src); - } - //! @brief Minimum of Packed Dword Integers (SSE4.1). - inline void pminsd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMINSD, &dst, &src); - } - - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVSXBW, &dst, &src); - } - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXBW, &dst, &src); - } - - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVSXBD, &dst, &src); - } - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXBD, &dst, &src); - } - - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVSXBQ, &dst, &src); - } - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXBQ, &dst, &src); - } - - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxwd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVSXWD, &dst, &src); - } - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxwd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXWD, &dst, &src); - } - - //! @brief (SSE4.1). - inline void pmovsxwq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVSXWQ, &dst, &src); - } - //! @brief (SSE4.1). - inline void pmovsxwq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXWQ, &dst, &src); - } - - //! @brief (SSE4.1). - inline void pmovsxdq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVSXDQ, &dst, &src); - } - //! @brief (SSE4.1). - inline void pmovsxdq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXDQ, &dst, &src); - } - - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbw(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVZXBW, &dst, &src); - } - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbw(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXBW, &dst, &src); - } - - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVZXBD, &dst, &src); - } - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXBD, &dst, &src); - } - - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVZXBQ, &dst, &src); - } - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXBQ, &dst, &src); - } - - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxwd(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVZXWD, &dst, &src); - } - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxwd(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXWD, &dst, &src); - } - - //! @brief (SSE4.1). - inline void pmovzxwq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVZXWQ, &dst, &src); - } - //! @brief (SSE4.1). - inline void pmovzxwq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXWQ, &dst, &src); - } - - //! @brief (SSE4.1). - inline void pmovzxdq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMOVZXDQ, &dst, &src); - } - //! @brief (SSE4.1). - inline void pmovzxdq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXDQ, &dst, &src); - } - - //! @brief Multiply Packed Signed Dword Integers (SSE4.1). - inline void pmuldq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMULDQ, &dst, &src); - } - //! @brief Multiply Packed Signed Dword Integers (SSE4.1). - inline void pmuldq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULDQ, &dst, &src); - } - - //! @brief Multiply Packed Signed Integers and Store Low Result (SSE4.1). - inline void pmulld(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PMULLD, &dst, &src); - } - //! @brief Multiply Packed Signed Integers and Store Low Result (SSE4.1). - inline void pmulld(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PMULLD, &dst, &src); - } - - //! @brief Logical Compare (SSE4.1). - inline void ptest(const XMMReg& op1, const XMMReg& op2) - { - _emitInstruction(INST_PTEST, &op1, &op2); - } - //! @brief Logical Compare (SSE4.1). - inline void ptest(const XMMReg& op1, const Mem& op2) - { - _emitInstruction(INST_PTEST, &op1, &op2); - } - - //! Round Packed SP-FP Values @brief (SSE4.1). - inline void roundps(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDPS, &dst, &src, &imm8); - } - //! Round Packed SP-FP Values @brief (SSE4.1). - inline void roundps(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDPS, &dst, &src, &imm8); - } - - //! @brief Round Scalar SP-FP Values (SSE4.1). - inline void roundss(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDSS, &dst, &src, &imm8); - } - //! @brief Round Scalar SP-FP Values (SSE4.1). - inline void roundss(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDSS, &dst, &src, &imm8); - } - - //! @brief Round Packed DP-FP Values (SSE4.1). - inline void roundpd(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDPD, &dst, &src, &imm8); - } - //! @brief Round Packed DP-FP Values (SSE4.1). - inline void roundpd(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDPD, &dst, &src, &imm8); - } - - //! @brief Round Scalar DP-FP Values (SSE4.1). - inline void roundsd(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDSD, &dst, &src, &imm8); - } - //! @brief Round Scalar DP-FP Values (SSE4.1). - inline void roundsd(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDSD, &dst, &src, &imm8); - } - - // -------------------------------------------------------------------------- - // [SSE4.2] - // -------------------------------------------------------------------------- - - //! @brief Accumulate CRC32 Value (polynomial 0x11EDC6F41) (SSE4.2). - inline void crc32(const GPReg& dst, const GPReg& src) - { - ASMJIT_ASSERT(dst.isRegType(REG_TYPE_GPD) || dst.isRegType(REG_TYPE_GPQ)); - _emitInstruction(INST_CRC32, &dst, &src); - } - //! @brief Accumulate CRC32 Value (polynomial 0x11EDC6F41) (SSE4.2). - inline void crc32(const GPReg& dst, const Mem& src) - { - ASMJIT_ASSERT(dst.isRegType(REG_TYPE_GPD) || dst.isRegType(REG_TYPE_GPQ)); - _emitInstruction(INST_CRC32, &dst, &src); - } - - //! @brief Packed Compare Explicit Length Strings, Return Index (SSE4.2). - inline void pcmpestri(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPESTRI, &dst, &src, &imm8); - } - //! @brief Packed Compare Explicit Length Strings, Return Index (SSE4.2). - inline void pcmpestri(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPESTRI, &dst, &src, &imm8); - } - - //! @brief Packed Compare Explicit Length Strings, Return Mask (SSE4.2). - inline void pcmpestrm(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPESTRM, &dst, &src, &imm8); - } - //! @brief Packed Compare Explicit Length Strings, Return Mask (SSE4.2). - inline void pcmpestrm(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPESTRM, &dst, &src, &imm8); - } - - //! @brief Packed Compare Implicit Length Strings, Return Index (SSE4.2). - inline void pcmpistri(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPISTRI, &dst, &src, &imm8); - } - //! @brief Packed Compare Implicit Length Strings, Return Index (SSE4.2). - inline void pcmpistri(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPISTRI, &dst, &src, &imm8); - } - - //! @brief Packed Compare Implicit Length Strings, Return Mask (SSE4.2). - inline void pcmpistrm(const XMMReg& dst, const XMMReg& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPISTRM, &dst, &src, &imm8); - } - //! @brief Packed Compare Implicit Length Strings, Return Mask (SSE4.2). - inline void pcmpistrm(const XMMReg& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPISTRM, &dst, &src, &imm8); - } - - //! @brief Compare Packed Data for Greater Than (SSE4.2). - inline void pcmpgtq(const XMMReg& dst, const XMMReg& src) - { - _emitInstruction(INST_PCMPGTQ, &dst, &src); - } - //! @brief Compare Packed Data for Greater Than (SSE4.2). - inline void pcmpgtq(const XMMReg& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTQ, &dst, &src); - } - - //! @brief Return the Count of Number of Bits Set to 1 (SSE4.2). - inline void popcnt(const GPReg& dst, const GPReg& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - ASMJIT_ASSERT(src.getRegType() == dst.getRegType()); - _emitInstruction(INST_POPCNT, &dst, &src); - } - //! @brief Return the Count of Number of Bits Set to 1 (SSE4.2). - inline void popcnt(const GPReg& dst, const Mem& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - _emitInstruction(INST_POPCNT, &dst, &src); - } - - // ------------------------------------------------------------------------- - // [AMD only] - // ------------------------------------------------------------------------- - - //! @brief Prefetch (3dNow - Amd). - //! - //! Loads the entire 64-byte aligned memory sequence containing the - //! specified memory address into the L1 data cache. The position of - //! the specified memory address within the 64-byte cache line is - //! irrelevant. If a cache hit occurs, or if a memory fault is detected, - //! no bus cycle is initiated and the instruction is treated as a NOP. - inline void amd_prefetch(const Mem& mem) - { - _emitInstruction(INST_AMD_PREFETCH, &mem); - } - - //! @brief Prefetch and set cache to modified (3dNow - Amd). - //! - //! The PREFETCHW instruction loads the prefetched line and sets the - //! cache-line state to Modified, in anticipation of subsequent data - //! writes to the line. The PREFETCH instruction, by contrast, typically - //! sets the cache-line state to Exclusive (depending on the hardware - //! implementation). - inline void amd_prefetchw(const Mem& mem) - { - _emitInstruction(INST_AMD_PREFETCHW, &mem); - } - - // ------------------------------------------------------------------------- - // [Intel only] - // ------------------------------------------------------------------------- - - //! @brief Move Data After Swapping Bytes (SSE3 - Intel Atom). - inline void movbe(const GPReg& dst, const Mem& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - _emitInstruction(INST_MOVBE, &dst, &src); - } - - //! @brief Move Data After Swapping Bytes (SSE3 - Intel Atom). - inline void movbe(const Mem& dst, const GPReg& src) - { - ASMJIT_ASSERT(!src.isGPB()); - _emitInstruction(INST_MOVBE, &dst, &src); - } - - // ------------------------------------------------------------------------- - // [Emit Options] - // ------------------------------------------------------------------------- - - //! @brief Assert LOCK# Signal Prefix. - //! - //! This instruction causes the processor's LOCK# signal to be asserted - //! during execution of the accompanying instruction (turns the - //! instruction into an atomic instruction). In a multiprocessor environment, - //! the LOCK# signal insures that the processor has exclusive use of any shared - //! memory while the signal is asserted. - //! - //! The LOCK prefix can be prepended only to the following instructions and - //! to those forms of the instructions that use a memory operand: ADD, ADC, - //! AND, BTC, BTR, BTS, CMPXCHG, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, - //! and XCHG. An undefined opcode exception will be generated if the LOCK - //! prefix is used with any other instruction. The XCHG instruction always - //! asserts the LOCK# signal regardless of the presence or absence of the LOCK - //! prefix. - //! - //! @sa @c EMIT_OPTION_LOCK_PREFIX. - inline void lock() - { - _emitOptions |= EMIT_OPTION_LOCK_PREFIX; - } - - //! @brief Force REX prefix to be emitted. - //! - //! This option should be used carefully, because there are unencodable - //! combinations. If you want to access ah, bh, ch or dh registers then you - //! can't emit REX prefix and it will cause an illegal instruction error. - //! - //! @note REX prefix is only valid for X64/AMD64 platform. - //! - //! @sa @c EMIT_OPTION_REX_PREFIX. - inline void rex() - { - _emitOptions |= EMIT_OPTION_REX_PREFIX; - } -}; - -// ============================================================================ -// [AsmJit::Assembler] -// ============================================================================ - -//! @brief Assembler - low level code generation. -//! -//! @c Assembler is the main class in AsmJit for generating low level x86/x64 -//! binary stream. It creates internal buffer where opcodes are stored and -//! contains methods that mimics x86/x64 assembler instructions. Code generation -//! should be safe, because basic type-checks are done by the C++ compiler. It's -//! nearly impossible to create invalid instruction (for example -//! mov [eax], [eax] that will not be detected at compile time. -//! -//! Each call to assembler intrinsics directly emits instruction to internal -//! binary stream. Instruction emitting also contains runtime checks so it's -//! impossible to create instruction that is not valid. -//! -//! @c AsmJit::Assembler contains internal buffer where all emitted -//! instructions are stored. Look at @c AsmJit::Buffer for buffer -//! implementation. To generate and allocate memory for function use -//! @c AsmJit::Assembler::make() method that will allocate memory using -//! provided memory manager ( see @c AsmJit::MemoryManager::getGlobal() ) and -//! relocates code to provided address. If you want to create your function -//! manually, you should look at @c AsmJit::VirtualMemory and use -//! @c AsmJit::Assembler::relocCode() method to relocate emitted code into -//! provided memory location. You can also take emitted buffer by @c take() -//! method to do something else with it. If you take buffer, you must free it -//! manually by @c ASMJIT_FREE() macro. -//! -//! @note Always use this class and never use @c AssemblerCore or -//! @c AssemblerIntrinsics classes directly. -//! -//! @section AsmJit_Assembler_CodeGeneration Code Generation -//! -//! To generate code is only needed to create instance of @c AsmJit::Assembler -//! and to use intrinsics. See example how to do that: -//! -//! @code -//! // Use AsmJit namespace. -//! using namespace AsmJit; -//! -//! // Create Assembler instance. -//! Assembler a; -//! -//! // Prolog. -//! a.push(ebp); -//! a.mov(ebp, esp); -//! -//! // Mov 1024 to EAX, EAX is also return value. -//! a.mov(eax, imm(1024)); -//! -//! // Epilog. -//! a.mov(esp, ebp); -//! a.pop(ebp); -//! -//! // Return. -//! a.ret(); -//! @endcode -//! -//! You can see that syntax is very close to Intel one. Only difference is that -//! you are calling functions that emits the binary code for you. All registers -//! are in @c AsmJit namespace, so it's very comfortable to use it (look at -//! first line). There is also used method @c AsmJit::imm() to create an -//! immediate value. Use @c AsmJit::uimm() to create unsigned immediate value. -//! -//! There is also possibility to use memory addresses and immediates. To build -//! memory address use @c ptr(), @c byte_ptr(), @c word_ptr(), @c dword_ptr() -//! or other friend methods. In most cases you needs only @c ptr() method, but -//! there are instructions where you must specify address size, -//! -//! for example (a is @c AsmJit::Assembler instance): -//! -//! @code -//! a.mov(ptr(eax), imm(0)); // mov ptr [eax], 0 -//! a.mov(ptr(eax), edx); // mov ptr [eax], edx -//! @endcode -//! -//! But it's also possible to create complex addresses: -//! -//! @code -//! // eax + ecx*x addresses -//! a.mov(ptr(eax, ecx, TIMES_1), imm(0)); // mov ptr [eax + ecx], 0 -//! a.mov(ptr(eax, ecx, TIMES_2), imm(0)); // mov ptr [eax + ecx * 2], 0 -//! a.mov(ptr(eax, ecx, TIMES_4), imm(0)); // mov ptr [eax + ecx * 4], 0 -//! a.mov(ptr(eax, ecx, TIMES_8), imm(0)); // mov ptr [eax + ecx * 8], 0 -//! // eax + ecx*x + disp addresses -//! a.mov(ptr(eax, ecx, TIMES_1, 4), imm(0)); // mov ptr [eax + ecx + 4], 0 -//! a.mov(ptr(eax, ecx, TIMES_2, 8), imm(0)); // mov ptr [eax + ecx * 2 + 8], 0 -//! a.mov(ptr(eax, ecx, TIMES_4, 12), imm(0)); // mov ptr [eax + ecx * 4 + 12], 0 -//! a.mov(ptr(eax, ecx, TIMES_8, 16), imm(0)); // mov ptr [eax + ecx * 8 + 16], 0 -//! @endcode -//! -//! All addresses shown are using @c AsmJit::ptr() to make memory operand. -//! Some assembler instructions (single operand ones) needs to specify memory -//! operand size. For example calling a.inc(ptr(eax)) can't be -//! used. @c AsmJit::Assembler::inc(), @c AsmJit::Assembler::dec() and similar -//! instructions can't be serialized without specifying how bytes they are -//! operating on. See next code how assembler works: -//! -//! @code -//! // [byte] address -//! a.inc(byte_ptr(eax)); // inc byte ptr [eax] -//! a.dec(byte_ptr(eax)); // dec byte ptr [eax] -//! // [word] address -//! a.inc(word_ptr(eax)); // inc word ptr [eax] -//! a.dec(word_ptr(eax)); // dec word ptr [eax] -//! // [dword] address -//! a.inc(dword_ptr(eax)); // inc dword ptr [eax] -//! a.dec(dword_ptr(eax)); // dec dword ptr [eax] -//! @endcode -//! -//! @section AsmJit_Assembler_CallingJitCode Calling JIT Code -//! -//! While you are over from emitting instructions, you can make your function -//! using @c AsmJit::Assembler::make() method. This method will use memory -//! manager to allocate virtual memory and relocates generated code to it. For -//! memory allocation is used global memory manager by default and memory is -//! freeable, but of course this default behavior can be overridden specifying -//! your memory manager and allocation type. If you want to do with code -//! something else you can always override make() method and do what you want. -//! -//! You can get size of generated code by @c getCodeSize() or @c getOffset() -//! methods. These methods returns you code size (or more precisely current code -//! offset) in bytes. Use takeCode() to take internal buffer (all pointers in -//! @c AsmJit::Assembler instance will be zeroed and current buffer returned) -//! to use it. If you don't take it, @c AsmJit::Assembler destructor will -//! free it automatically. To alloc and run code manually don't use -//! @c malloc()'ed memory, but instead use @c AsmJit::VirtualMemory::alloc() -//! to get memory for executing (specify @c canExecute to @c true) or -//! @c AsmJit::MemoryManager that provides more effective and comfortable way -//! to allocate virtual memory. -//! -//! See next example how to allocate memory where you can execute code created -//! by @c AsmJit::Assembler: -//! -//! @code -//! using namespace AsmJit; -//! -//! Assembler a; -//! -//! // ... your code generation -//! -//! // your function prototype -//! typedef void (*MyFn)(); -//! -//! // make your function -//! MyFn fn = function_cast(a.make()); -//! -//! // call your function -//! fn(); -//! -//! // If you don't need your function again, free it. -//! MemoryManager::getGlobal()->free(fn); -//! @endcode -//! -//! There is also low level alternative how to allocate virtual memory and -//! relocate code to it: -//! -//! @code -//! using namespace AsmJit; -//! -//! Assembler a; -//! // Your code generation ... -//! -//! // Your function prototype. -//! typedef void (*MyFn)(); -//! -//! // Alloc memory for your function. -//! MyFn fn = function_cast( -//! MemoryManager::getGlobal()->alloc(a.getCodeSize()); -//! -//! // Relocate the code (will make the function). -//! a.relocCode(fn); -//! -//! // Call the generated function. -//! fn(); -//! -//! // If you don't need your function anymore, it should be freed. -//! MemoryManager::getGlobal()->free(fn); -//! @endcode -//! -//! @c note This was very primitive example how to call generated code. -//! In real production code you will never alloc and free code for one run, -//! you will usually use generated code many times. -//! -//! @section AsmJit_Assembler_Labels Labels -//! -//! While generating assembler code, you will usually need to create complex -//! code with labels. Labels are fully supported and you can call @c jmp or -//! @c je (and similar) instructions to initialized or yet uninitialized label. -//! Each label expects to be bound into offset. To bind label to specific -//! offset, use @c bind() method. -//! -//! See next example that contains complete code that creates simple memory -//! copy function (in DWORD entities). -//! -//! @code -//! // Example: Usage of Label (32-bit code). -//! // -//! // Create simple DWORD memory copy function: -//! // ASMJIT_STDCALL void copy32(uint32_t* dst, const uint32_t* src, sysuint_t count); -//! using namespace AsmJit; -//! -//! // Assembler instance. -//! Assembler a; -//! -//! // Constants. -//! const int arg_offset = 8; // Arguments offset (STDCALL EBP). -//! const int arg_size = 12; // Arguments size. -//! -//! // Labels. -//! Label L_Loop = a.newLabel(); -//! -//! // Prolog. -//! a.push(ebp); -//! a.mov(ebp, esp); -//! a.push(esi); -//! a.push(edi); -//! -//! // Fetch arguments -//! a.mov(esi, dword_ptr(ebp, arg_offset + 0)); // Get dst. -//! a.mov(edi, dword_ptr(ebp, arg_offset + 4)); // Get src. -//! a.mov(ecx, dword_ptr(ebp, arg_offset + 8)); // Get count. -//! -//! // Bind L_Loop label to here. -//! a.bind(L_Loop); -//! -//! Copy 4 bytes. -//! a.mov(eax, dword_ptr(esi)); -//! a.mov(dword_ptr(edi), eax); -//! -//! // Increment pointers. -//! a.add(esi, 4); -//! a.add(edi, 4); -//! -//! // Repeat loop until (--ecx != 0). -//! a.dec(ecx); -//! a.jz(L_Loop); -//! -//! // Epilog. -//! a.pop(edi); -//! a.pop(esi); -//! a.mov(esp, ebp); -//! a.pop(ebp); -//! -//! // Return: STDCALL convention is to pop stack in called function. -//! a.ret(arg_size); -//! @endcode -//! -//! If you need more abstraction for generating assembler code and you want -//! to hide calling conventions between 32-bit and 64-bit operating systems, -//! look at @c Compiler class that is designed for higher level code -//! generation. -//! -//! @section AsmJit_Assembler_AdvancedCodeGeneration Advanced Code Generation -//! -//! This section describes some advanced generation features of @c Assembler -//! class which can be simply overlooked. The first thing that is very likely -//! needed is generic register support. In previous example the named registers -//! were used. AsmJit contains functions which can convert register index into -//! operand and back. -//! -//! Let's define function which can be used to generate some abstract code: -//! -//! @code -//! // Simple function that generates dword copy. -//! void genCopyDWord( -//! Assembler& a, -//! const GPReg& dst, const GPReg& src, const GPReg& tmp) -//! { -//! a.mov(tmp, dword_ptr(src)); -//! a.mov(dword_ptr(dst), tmp); -//! } -//! @endcode -//! -//! This function can be called like genCopyDWord(a, edi, esi, ebx) -//! or by using existing @ref GPReg instances. This abstraction allows to join -//! more code sections together without rewriting each to use specific registers. -//! You need to take care only about implicit registers which may be used by -//! several instructions (like mul, imul, div, idiv, shifting, etc...). -//! -//! Next, more advanced, but often needed technique is that you can build your -//! own registers allocator. X86 architecture contains 8 general purpose registers, -//! 8 MMX (MM) registers and 8 SSE (XMM) registers. The X64 (AMD64) architecture -//! extends count of general purpose registers and SSE2 registers to 16. Use the -//! @c REG_NUM_BASE constant to get count of GP or XMM registers or @c REG_NUM_GP, -//! @c REG_NUM_MM and @c REG_NUM_XMM constants individually. -//! -//! To build register from index (value from 0 inclusive to REG_NUM_XXX -//! exclusive) use @ref gpd(), @ref gpq() or @ref gpn() functions. To create -//! a 8 or 16-bit register use @ref gpw(), @ref gpb_lo() or @ref gpb_hi(). -//! To create other registers there are similar methods @ref mm(), @ref xmm() and -//! @ref st(). -//! -//! So our function call to genCopyDWord can be also used like this: -//! -//! @code -//! genCopyDWord(a, gpd(REG_INDEX_EDI), gpd(REG_INDEX_ESI), gpd(REG_INDEX_EBX)); -//! @endcode -//! -//! REG_INDEX_XXX are constants defined by @ref REG_INDEX enum. You can use your -//! own register allocator (or register slot manager) to alloc / free registers -//! so REG_INDEX_XXX values can be replaced by your variables (0 to REG_NUM_XXX-1). -//! -//! @sa @c AssemblerCore, @c AssemblerIntrinsics, @c Operand, @c Compiler. -struct ASMJIT_API Assembler : public AssemblerIntrinsics -{ - Assembler(CodeGenerator* codeGenerator = NULL) ASMJIT_NOTHROW; - virtual ~Assembler() ASMJIT_NOTHROW; -}; - -//! @} - -} // AsmJit namespace - -// [Api-End] -#include "ApiEnd.h" - -// [Guard] -#endif // _ASMJIT_ASSEMBLERX86X64_H diff --git a/desmume/src/utils/AsmJit/Compiler.cpp b/desmume/src/utils/AsmJit/Compiler.cpp deleted file mode 100644 index db2b7adf5..000000000 --- a/desmume/src/utils/AsmJit/Compiler.cpp +++ /dev/null @@ -1,272 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// We are using sprintf() here. -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif // _MSC_VER - -// [Dependencies] -#include "Assembler.h" -#include "Compiler.h" -#include "CpuInfo.h" -#include "Logger.h" -#include "Util.h" - -#include -#include -#include - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -// ============================================================================ -// [AsmJit::Emittable] -// ============================================================================ - -Emittable::Emittable(Compiler* c, uint32_t type) ASMJIT_NOTHROW : - _compiler(c), - _next(NULL), - _prev(NULL), - _comment(NULL), - _type((uint8_t)type), - _translated(false), - _reserved0(0), - _reserved1(0), - _offset(INVALID_VALUE) -{ -} - -Emittable::~Emittable() ASMJIT_NOTHROW -{ -} - -void Emittable::prepare(CompilerContext& cc) ASMJIT_NOTHROW -{ - _offset = cc._currentOffset; -} - -Emittable* Emittable::translate(CompilerContext& cc) ASMJIT_NOTHROW -{ - return translated(); -} - -void Emittable::emit(Assembler& a) ASMJIT_NOTHROW -{ -} - -void Emittable::post(Assembler& a) ASMJIT_NOTHROW -{ -} - -int Emittable::getMaxSize() const ASMJIT_NOTHROW -{ - // Default maximum size is -1 which means that it's not known. - return -1; -} - -bool Emittable::_tryUnuseVar(VarData* v) ASMJIT_NOTHROW -{ - return false; -} - -void Emittable::setComment(const char* str) ASMJIT_NOTHROW -{ - _comment = _compiler->getZone().zstrdup(str); -} - -void Emittable::setCommentF(const char* fmt, ...) ASMJIT_NOTHROW -{ - // I'm really not expecting larger inline comments:) - char buf[256]; - - va_list ap; - va_start(ap, fmt); - vsnprintf(buf, 255, fmt, ap); - va_end(ap); - - // I don't know if vsnprintf can produce non-null terminated string, in case - // it can, we terminate it here. - buf[255] = '\0'; - - setComment(buf); -} - -// ============================================================================ -// [AsmJit::EDummy] -// ============================================================================ - -EDummy::EDummy(Compiler* c) ASMJIT_NOTHROW : - Emittable(c, EMITTABLE_DUMMY) -{ -} - -EDummy::~EDummy() ASMJIT_NOTHROW -{ -} - -int EDummy::getMaxSize() const ASMJIT_NOTHROW -{ - return 0; -} - -// ============================================================================ -// [AsmJit::EFunctionEnd] -// ============================================================================ - -EFunctionEnd::EFunctionEnd(Compiler* c) ASMJIT_NOTHROW : - EDummy(c) -{ - _type = EMITTABLE_FUNCTION_END; -} - -EFunctionEnd::~EFunctionEnd() ASMJIT_NOTHROW -{ -} - -Emittable* EFunctionEnd::translate(CompilerContext& cc) ASMJIT_NOTHROW -{ - _translated = true; - return NULL; -} - -// ============================================================================ -// [AsmJit::EComment] -// ============================================================================ - -EComment::EComment(Compiler* c, const char* str) ASMJIT_NOTHROW : - Emittable(c, EMITTABLE_COMMENT) -{ - setComment(str); -} - -EComment::~EComment() ASMJIT_NOTHROW -{ -} - -void EComment::emit(Assembler& a) ASMJIT_NOTHROW -{ - if (a.getLogger()) - { - a.getLogger()->logString(getComment()); - } -} - -int EComment::getMaxSize() const ASMJIT_NOTHROW -{ - return 0; -} - -// ============================================================================ -// [AsmJit::EData] -// ============================================================================ - -EData::EData(Compiler* c, const void* data, sysuint_t length) ASMJIT_NOTHROW : - Emittable(c, EMITTABLE_EMBEDDED_DATA) -{ - _length = length; - memcpy(_data, data, length); -} - -EData::~EData() ASMJIT_NOTHROW -{ -} - -void EData::emit(Assembler& a) ASMJIT_NOTHROW -{ - a.embed(_data, _length); -} - -int EData::getMaxSize() const ASMJIT_NOTHROW -{ - return (int)_length;; -} - -// ============================================================================ -// [AsmJit::EAlign] -// ============================================================================ - -EAlign::EAlign(Compiler* c, uint32_t size) ASMJIT_NOTHROW : - Emittable(c, EMITTABLE_ALIGN), _size(size) -{ -} - -EAlign::~EAlign() ASMJIT_NOTHROW -{ -} - -void EAlign::emit(Assembler& a) ASMJIT_NOTHROW -{ - a.align(_size); -} - -int EAlign::getMaxSize() const ASMJIT_NOTHROW -{ - return (_size > 0) ? (int)_size - 1 : 0; -} - -// ============================================================================ -// [AsmJit::ETarget] -// ============================================================================ - -ETarget::ETarget(Compiler* c, const Label& label) ASMJIT_NOTHROW : - Emittable(c, EMITTABLE_TARGET), - _label(label), - _from(NULL), - _state(NULL), - _jumpsCount(0) -{ -} - -ETarget::~ETarget() ASMJIT_NOTHROW -{ -} - -void ETarget::prepare(CompilerContext& cc) ASMJIT_NOTHROW -{ - _offset = cc._currentOffset++; -} - -Emittable* ETarget::translate(CompilerContext& cc) ASMJIT_NOTHROW -{ - // If this ETarget was already translated, it's needed to change the current - // state and return NULL to tell CompilerContext to process next untranslated - // emittable. - if (_translated) - { - cc._restoreState(_state); - return NULL; - } - - if (cc._unreachable) - { - cc._unreachable = 0; - - // Assign state to the compiler context. - ASMJIT_ASSERT(_state != NULL); - cc._assignState(_state); - } - else - { - _state = cc._saveState(); - } - - return translated(); -} - -void ETarget::emit(Assembler& a) ASMJIT_NOTHROW -{ - a.bind(_label); -} - -int ETarget::getMaxSize() const ASMJIT_NOTHROW -{ - return 0; -} - -} // AsmJit namespace diff --git a/desmume/src/utils/AsmJit/Compiler.h b/desmume/src/utils/AsmJit/Compiler.h deleted file mode 100644 index 71d7284eb..000000000 --- a/desmume/src/utils/AsmJit/Compiler.h +++ /dev/null @@ -1,846 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_COMPILER_H -#define _ASMJIT_COMPILER_H - -// [Dependencies] -#include "Build.h" -#include "Defs.h" -#include "Operand.h" -#include "Util.h" - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - -struct Assembler; -struct CodeGenerator; -struct Compiler; -struct CompilerContext; -struct CompilerCore; -struct CompilerIntrinsics; -struct MemoryManager; - -struct FunctionDefinition; - -struct ForwardJumpData; - -struct VarData; -struct VarAllocRecord; -struct StateData; - -struct Emittable; -struct EAlign; -struct ECall; -struct EComment; -struct EData; -struct EEpilog; -struct EFunction; -struct EFunctionEnd; -struct EInstruction; -struct EJmp; -struct EProlog; -struct ERet; - -// ============================================================================ -// [AsmJit::TypeToId] -// ============================================================================ - -#if !defined(ASMJIT_NODOC) - -#if defined(ASMJIT_HAS_PARTIAL_TEMPLATE_SPECIALIZATION) - -template -struct TypeToId -{ -#if defined(ASMJIT_NODOC) - enum { Id = INVALID_VALUE }; -#endif // ASMJIT_NODOC -}; - -template -struct TypeToId { enum { Id = VARIABLE_TYPE_INTPTR }; }; - -#else - -// Same trict is used in Qt, Boost, Fog and all other libraries that need -// something similar. -// -// It's easy. It's needed to use sizeof() to determine the size -// of return value of this function. If size will be sizeof(char) -// (this is our type) then type is pointer, otherwise it's not. -template -char TypeToId_NoPtiHelper(T*(*)()); -// And specialization. -void* TypeToId_NoPtiHelper(...); - -template -struct TypeToId -{ - // TypeInfo constants - enum - { - // This is the hackery result. - Id = (sizeof(char) == sizeof( TypeToId_NoPtiHelper((T(*)())0) ) - ? VARIABLE_TYPE_INTPTR - : INVALID_VALUE) - }; -}; - -#endif // ASMJIT_HAS_PARTIAL_TEMPLATE_SPECIALIZATION - -#define ASMJIT_DECLARE_TYPE_AS_ID(__T__, __Id__) \ - template<> \ - struct TypeToId<__T__> { enum { Id = __Id__ }; } - -// Declare void type and alternative. -struct Void {}; -ASMJIT_DECLARE_TYPE_AS_ID(void, INVALID_VALUE); -ASMJIT_DECLARE_TYPE_AS_ID(Void, INVALID_VALUE); - -#endif // ASMJIT_NODOC - -// ============================================================================ -// [AsmJit::Function Builder] -// ============================================================================ - -struct FunctionDefinition -{ - //! @brief Get function arguments IDs. - inline const uint32_t* getArguments() const - { - return _arguments; - } - - //! @brief Get function arguments count. - inline uint32_t getArgumentsCount() const - { - return _argumentsCount; - } - - inline uint32_t getArgument(uint32_t id) const - { - ASMJIT_ASSERT(id < _argumentsCount); - return _arguments[id]; - } - - //! @brief Get function return value. - inline uint32_t getReturnValue() const - { - return _returnValue; - } - -protected: - inline void _setDefinition(const uint32_t* arguments, uint32_t argumentsCount, uint32_t returnValue) - { - _arguments = arguments; - _argumentsCount = argumentsCount; - _returnValue = returnValue; - } - - const uint32_t* _arguments; - uint32_t _argumentsCount; - uint32_t _returnValue; -}; - -//! @brief Custom function builder for up to 32 function arguments. -struct FunctionBuilderX : public FunctionDefinition -{ - inline FunctionBuilderX() - { - _setDefinition(_argumentsData, 0, INVALID_VALUE); - } - - template - inline void addArgument() - { - addArgumentRaw(TypeToId::Id); - } - - template - inline void setArgument(uint32_t id) - { - setArgumentRaw(id, TypeToId::Id); - } - - template - inline void setReturnValue() - { - setReturnValueRaw(TypeToId::Id); - } - - inline void addArgumentRaw(uint32_t type) - { - ASMJIT_ASSERT(_argumentsCount < FUNC_MAX_ARGS); - _argumentsData[_argumentsCount++] = type; - } - - inline void setArgumentRaw(uint32_t id, uint32_t type) - { - ASMJIT_ASSERT(id < _argumentsCount); - _argumentsData[id] = type; - } - - inline void setReturnValueRaw(uint32_t returnValue) - { - _returnValue = returnValue; - } - -protected: - uint32_t _argumentsData[FUNC_MAX_ARGS]; -}; - -//! @brief Class used to build function without arguments. -template -struct FunctionBuilder0 : public FunctionDefinition -{ - inline FunctionBuilder0() - { - _setDefinition(NULL, 0, TypeToId::Id); - } -}; - -//! @brief Class used to build function with 1 argument. -template -struct FunctionBuilder1 : public FunctionDefinition -{ - inline FunctionBuilder1() - { - static const uint32_t args[] = - { - TypeToId::Id - }; - _setDefinition(args, ASMJIT_ARRAY_SIZE(args), TypeToId::Id); - } -}; - -//! @brief Class used to build function with 2 arguments. -template -struct FunctionBuilder2 : public FunctionDefinition -{ - inline FunctionBuilder2() - { - static const uint32_t args[] = - { - TypeToId::Id, - TypeToId::Id - }; - _setDefinition(args, ASMJIT_ARRAY_SIZE(args), TypeToId::Id); - } -}; - -//! @brief Class used to build function with 3 arguments. -template -struct FunctionBuilder3 : public FunctionDefinition -{ - inline FunctionBuilder3() - { - static const uint32_t args[] = - { - TypeToId::Id, - TypeToId::Id, - TypeToId::Id - }; - _setDefinition(args, ASMJIT_ARRAY_SIZE(args), TypeToId::Id); - } -}; - -//! @brief Class used to build function with 4 arguments. -template -struct FunctionBuilder4 : public FunctionDefinition -{ - inline FunctionBuilder4() - { - static const uint32_t args[] = - { - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id - }; - _setDefinition(args, ASMJIT_ARRAY_SIZE(args), TypeToId::Id); - } -}; - -//! @brief Class used to build function with 5 arguments. -template -struct FunctionBuilder5 : public FunctionDefinition -{ - inline FunctionBuilder5() - { - static const uint32_t args[] = - { - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id - }; - _setDefinition(args, ASMJIT_ARRAY_SIZE(args), TypeToId::Id); - } -}; - -//! @brief Class used to build function with 6 arguments. -template -struct FunctionBuilder6 : public FunctionDefinition -{ - inline FunctionBuilder6() - { - static const uint32_t args[] = - { - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id - }; - _setDefinition(args, ASMJIT_ARRAY_SIZE(args), TypeToId::Id); - } -}; - -//! @brief Class used to build function with 7 arguments. -template -struct FunctionBuilder7 : public FunctionDefinition -{ - inline FunctionBuilder7() - { - static const uint32_t args[] = - { - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id - }; - _setDefinition(args, ASMJIT_ARRAY_SIZE(args), TypeToId::Id); - } -}; - -//! @brief Class used to build function with 8 arguments. -template -struct FunctionBuilder8 : public FunctionDefinition -{ - inline FunctionBuilder8() - { - static const uint32_t args[] = - { - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id - }; - _setDefinition(args, ASMJIT_ARRAY_SIZE(args), TypeToId::Id); - } -}; - -//! @brief Class used to build function with 9 arguments. -template -struct FunctionBuilder9 : public FunctionDefinition -{ - inline FunctionBuilder9() - { - static const uint32_t args[] = - { - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id - }; - _setDefinition(args, ASMJIT_ARRAY_SIZE(args), TypeToId::Id); - } -}; - -//! @brief Class used to build function with 10 arguments. -template -struct FunctionBuilder10 : public FunctionDefinition -{ - inline FunctionBuilder10() - { - static const uint32_t args[] = - { - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id, - TypeToId::Id - }; - _setDefinition(args, ASMJIT_ARRAY_SIZE(args), TypeToId::Id); - } -}; - -// ============================================================================ -// [AsmJit::Emittable] -// ============================================================================ - -//! @brief Emmitable. -//! -//! Emittable is object that can emit single or more instructions. To -//! create your custom emittable it's needed to override the abstract virtual -//! method @c emit(). -//! -//! When you are finished serializing instructions to the @c Compiler and you -//! call @c Compiler::make(), it will first call @c prepare() method for each -//! emittable in list, then @c translate(), @c emit() and @c post() is the last. -//! Prepare can be used to calculate something that can be only calculated when -//! emitting instructions is finished (for example @c Function uses @c prepare() -//! to relocate memory home for all memory/spilled variables). The @c emit() should -//! be used to emit instruction or multiple instructions into @a Assembler stream, -//! and the @c post() is here to allow emitting embedded data (after function -//! declaration), etc. -struct ASMJIT_API Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create new emittable. - //! - //! Never create @c Emittable by @c new operator or on the stack, use - //! @c Compiler::newObject template to do that. - Emittable(Compiler* c, uint32_t type) ASMJIT_NOTHROW; - - //! @brief Destroy emittable. - //! - //! @note Never destroy emittable using @c delete keyword, @c Compiler - //! manages all emittables in internal memory pool and it will destroy - //! all emittables after you destroy it. - virtual ~Emittable() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit and Helpers] - // -------------------------------------------------------------------------- - - //! @brief Step 1. Extract emittable variables, update statistics, ... - virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; - //! @brief Step 2. Translate instruction, alloc variables, ... - virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; - //! @brief Step 3. Emit to @c Assembler. - virtual void emit(Assembler& a) ASMJIT_NOTHROW; - //! @brief Step 4. Last post step (verify, add data, etc). - virtual void post(Assembler& a) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - //! @brief Get maximum size in bytes of this emittable (in binary). - virtual int getMaxSize() const ASMJIT_NOTHROW; - - //! @brief Try to unuse the variable @a. - //! - //! Returns @c true only if the variable will be unused by the instruction, - //! otherwise @c false is returned. - virtual bool _tryUnuseVar(VarData* v) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Compiler] - // -------------------------------------------------------------------------- - - //! @brief Get associated compiler instance. - inline Compiler* getCompiler() const ASMJIT_NOTHROW { return _compiler; } - - // -------------------------------------------------------------------------- - // [Type / Offset] - // -------------------------------------------------------------------------- - - //! @brief Get emittable type, see @c EMITTABLE_TYPE. - inline uint32_t getType() const ASMJIT_NOTHROW { return _type; } - - //! @brief Get whether the emittable was translated. - inline uint8_t isTranslated() const ASMJIT_NOTHROW { return _translated; } - - //! @brief Get emittable offset in the stream - //! - //! Emittable offset is not byte offset, each emittable increments offset by 1 - //! and this value is then used by register allocator. Emittable offset is - //! set by compiler by the register allocator, don't use it in your code. - inline uint32_t getOffset() const ASMJIT_NOTHROW { return _offset; } - - // -------------------------------------------------------------------------- - // [Emittables List] - // -------------------------------------------------------------------------- - - //! @brief Get previous emittable in list. - inline Emittable* getPrev() const ASMJIT_NOTHROW { return _prev; } - //! @brief Get next emittable in list. - inline Emittable* getNext() const ASMJIT_NOTHROW { return _next; } - - // -------------------------------------------------------------------------- - // [Comment] - // -------------------------------------------------------------------------- - - //! @brief Get comment string. - inline const char* getComment() const ASMJIT_NOTHROW { return _comment; } - - //! @brief Set comment string to @a str. - void setComment(const char* str) ASMJIT_NOTHROW; - - //! @brief Format comment string using @a fmt string and variable argument list. - void setCommentF(const char* fmt, ...) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Protected] - // -------------------------------------------------------------------------- - -protected: - //! @brief Mark emittable as translated and return next. - inline Emittable* translated() ASMJIT_NOTHROW - { - ASMJIT_ASSERT(_translated == false); - - _translated = true; - return _next; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! @brief Compiler where this emittable is connected to. - Compiler* _compiler; - - //! @brief Type of emittable, see @c EMITTABLE_TYPE. - uint8_t _type; - //! @brief Whether the emittable was translated, see @c translate(). - uint8_t _translated; - //! @brief Reserved flags for future use. - uint8_t _reserved0; - //! @brief Reserved flags for future use. - uint8_t _reserved1; - - //! @brief Emittable offset. - uint32_t _offset; - - //! @brief Previous emittable. - Emittable* _prev; - //! @brief Next emittable. - Emittable* _next; - - //! @brief Embedded comment string (also used by a @c Comment emittable). - const char* _comment; - -private: - friend struct CompilerCore; - - ASMJIT_DISABLE_COPY(Emittable) -}; - -// ============================================================================ -// [AsmJit::EDummy] -// ============================================================================ - -//! @brief Dummy emittable, used as a mark. -//! -//! This emittable does nothing and it's only used by @ref Compiler to mark -//! specific location in the code. -struct ASMJIT_API EDummy : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref EDummy instance. - EDummy(Compiler* c) ASMJIT_NOTHROW; - //! @brief Destroy the @ref EDummy instance. - virtual ~EDummy() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - virtual int getMaxSize() const ASMJIT_NOTHROW; - -private: - ASMJIT_DISABLE_COPY(EDummy) -}; - -// ============================================================================ -// [AsmJit::EFunctionEnd] -// ============================================================================ - -//! @brief End of function. -//! -//! This emittable does nothing and it's only used by @ref Compiler to mark -//! specific location in the code. The @c EFunctionEnd is similar to @c EDummy, -//! except that it overrides @c translate() to return @c NULL. -struct ASMJIT_API EFunctionEnd : public EDummy -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref EDummy instance. - EFunctionEnd(Compiler* c) ASMJIT_NOTHROW; - //! @brief Destroy the @ref EDummy instance. - virtual ~EFunctionEnd() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit and Helpers] - // -------------------------------------------------------------------------- - - virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; - -private: - ASMJIT_DISABLE_COPY(EFunctionEnd) -}; - -// ============================================================================ -// [AsmJit::EComment] -// ============================================================================ - -//! @brief Emittable used to emit comment into @c Assembler logger. -//! -//! Comments allows to comment your assembler stream for better debugging -//! and visualization what's happening. Comments are ignored if logger is -//! not set. -//! -//! Comment string can't be modified after comment was created. -struct ASMJIT_API EComment : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref EComment instance. - EComment(Compiler* c, const char* comment) ASMJIT_NOTHROW; - //! @brief Destroy the @ref EComment instance. - virtual ~EComment() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void emit(Assembler& a) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - virtual int getMaxSize() const ASMJIT_NOTHROW; - -private: - friend struct CompilerCore; - - ASMJIT_DISABLE_COPY(EComment) -}; - -// ============================================================================ -// [AsmJit::EData] -// ============================================================================ - -//! @brief Emittable used to emit comment into @c Assembler logger. -//! -//! @note This class is always allocated by @c AsmJit::Compiler. -struct ASMJIT_API EData : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref EData instance. - EData(Compiler* c, const void* data, sysuint_t length) ASMJIT_NOTHROW; - //! @brief Destroy the @ref EData instance. - virtual ~EData() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void emit(Assembler& a) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - virtual int getMaxSize() const ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Data] - // -------------------------------------------------------------------------- - - //! @brief Get pointer to embedded data. - uint8_t* getData() const ASMJIT_NOTHROW { return (uint8_t*)_data; } - - //! @brief Get length of embedded data. - sysuint_t getLength() const ASMJIT_NOTHROW { return _length; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - //! @brief Data length. - sysuint_t _length; - //! @brief Data buffer (that will be embedded to the assembler stream). - uint8_t _data[sizeof(void*)]; - -private: - friend struct CompilerCore; - - ASMJIT_DISABLE_COPY(EData) -}; - -// ============================================================================ -// [AsmJit::EAlign] -// ============================================================================ - -//! @brief Emittable used to align assembler code. -struct ASMJIT_API EAlign : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref EAlign instance. - EAlign(Compiler* c, uint32_t size = 0) ASMJIT_NOTHROW; - //! @brief Destroy the @ref EAlign instance. - virtual ~EAlign() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void emit(Assembler& a) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - virtual int getMaxSize() const ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Align Size] - // -------------------------------------------------------------------------- - - //! @brief Get align size in bytes. - inline uint32_t getSize() const ASMJIT_NOTHROW { return _size; } - //! @brief Set align size in bytes to @a size. - inline void setSize(uint32_t size) ASMJIT_NOTHROW { _size = size; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - //! @brief Align size. - uint32_t _size; - -private: - friend struct CompilerCore; - - ASMJIT_DISABLE_COPY(EAlign) -}; - -// ============================================================================ -// [AsmJit::ETarget] -// ============================================================================ - -//! @brief Target - the bound label. -struct ASMJIT_API ETarget : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref ETarget instance. - ETarget(Compiler* c, const Label& target) ASMJIT_NOTHROW; - //! @brief Destroy the @ref ETarget instance. - virtual ~ETarget() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; - virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; - virtual void emit(Assembler& a) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - virtual int getMaxSize() const ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Methods] - // -------------------------------------------------------------------------- - - //! @brief Return label bound to this target. - inline const Label& getLabel() const ASMJIT_NOTHROW { return _label; } - - //! @brief Get first jmp instruction. - inline EJmp* getFrom() const ASMJIT_NOTHROW { return _from; } - - //! @brief Get register allocator state for this target. - inline StateData* getState() const ASMJIT_NOTHROW { return _state; } - - //! @brief Get number of jumps to this target. - inline uint32_t getJumpsCount() const ASMJIT_NOTHROW { return _jumpsCount; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - //! @brief Label. - Label _label; - //! @brief First jump instruction that points to this target (label). - EJmp* _from; - //! @brief State at this location. - StateData* _state; - - //! @brief Count of jumps to this target (label). - uint32_t _jumpsCount; - -private: - friend struct CompilerContext; - friend struct CompilerCore; - friend struct EInstruction; - friend struct EJmp; - - ASMJIT_DISABLE_COPY(ETarget) -}; - -} // AsmJit namespace - -// [Api-End] -#include "ApiEnd.h" - -// ============================================================================ -// [Platform Specific] -// ============================================================================ - -// [X86 / X64] -#if defined(ASMJIT_X86) || defined(ASMJIT_X64) -#include "CompilerX86X64.h" -#endif // ASMJIT_X86 || ASMJIT_X64 - -// [Guard] -#endif // _ASMJIT_COMPILER_H diff --git a/desmume/src/utils/AsmJit/CompilerX86X64.cpp b/desmume/src/utils/AsmJit/CompilerX86X64.cpp deleted file mode 100644 index d426c7cc1..000000000 --- a/desmume/src/utils/AsmJit/CompilerX86X64.cpp +++ /dev/null @@ -1,7828 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// We are using sprintf() here. -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif // _MSC_VER - -// [Dependencies] -#include "Assembler.h" -#include "CodeGenerator.h" -#include "Compiler.h" -#include "CpuInfo.h" -#include "Logger.h" -#include "Util_p.h" - -#include -#include -#include - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -// ============================================================================ -// [Helpers - Logging] -// ============================================================================ - -// Defined in AssemblerX86X64.cpp. -ASMJIT_HIDDEN char* dumpRegister(char* buf, uint32_t type, uint32_t index) ASMJIT_NOTHROW; -ASMJIT_HIDDEN char* dumpOperand(char* buf, const Operand* op, uint32_t memRegType) ASMJIT_NOTHROW; - -// ============================================================================ -// [Helpers - Variables] -// ============================================================================ - -struct VariableInfo -{ - enum CLASS_INFO - { - CLASS_NONE = 0x00, - CLASS_GP = 0x01, - CLASS_X87 = 0x02, - CLASS_MM = 0x04, - CLASS_XMM = 0x08, - }; - - enum FLAGS - { - FLAG_SP_FP = 0x10, - FLAG_DP_FP = 0x20, - FLAG_VECTOR = 0x40 - }; - - uint32_t code; - uint8_t size; - uint8_t clazz; - uint8_t flags; - uint8_t reserved_0; - char name[8]; -}; - -#define C(c) VariableInfo::CLASS_##c -#define F(f) VariableInfo::FLAG_##f -static const VariableInfo variableInfo[] = -{ - /* 0 */ { REG_TYPE_GPD , 4 , C(GP) , 0 , 0, "GP.D" }, - /* 1 */ { REG_TYPE_GPQ , 8 , C(GP) , 0 , 0, "GP.Q" }, - /* 2 */ { REG_TYPE_X87 , 4 , C(X87), F(SP_FP) , 0, "X87" }, - /* 3 */ { REG_TYPE_X87 , 4 , C(X87), F(SP_FP) , 0, "X87.1F" }, - /* 4 */ { REG_TYPE_X87 , 8 , C(X87), F(DP_FP) , 0, "X87.1D" }, - /* 5 */ { REG_TYPE_MM , 8 , C(MM) , F(VECTOR), 0, "MM" }, - /* 6 */ { REG_TYPE_XMM , 16, C(XMM), 0 , 0, "XMM" }, - /* 7 */ { REG_TYPE_XMM , 4 , C(XMM), F(SP_FP) , 0, "XMM.1F" }, - /* 8 */ { REG_TYPE_XMM , 8 , C(XMM), F(DP_FP) , 0, "XMM.1D" }, - /* 9 */ { REG_TYPE_XMM , 16, C(XMM), F(SP_FP) | F(VECTOR), 0, "XMM.4F" }, - /* 10 */ { REG_TYPE_XMM , 16, C(XMM), F(DP_FP) | F(VECTOR), 0, "XMM.2D" } -}; -#undef F -#undef C - -static uint32_t getVariableClass(uint32_t type) -{ - ASMJIT_ASSERT(type < ASMJIT_ARRAY_SIZE(variableInfo)); - return variableInfo[type].clazz; -} - -static uint32_t getVariableSize(uint32_t type) -{ - ASMJIT_ASSERT(type < ASMJIT_ARRAY_SIZE(variableInfo)); - return variableInfo[type].size; -} - -static uint32_t getVariableRegisterCode(uint32_t type, uint32_t index) -{ - ASMJIT_ASSERT(type < ASMJIT_ARRAY_SIZE(variableInfo)); - return variableInfo[type].code | index; -} - -static bool isVariableInteger(uint32_t type) -{ - ASMJIT_ASSERT(type < ASMJIT_ARRAY_SIZE(variableInfo)); - return (variableInfo[type].clazz & VariableInfo::CLASS_GP) != 0; -} - -static bool isVariableFloat(uint32_t type) -{ - ASMJIT_ASSERT(type < ASMJIT_ARRAY_SIZE(variableInfo)); - return (variableInfo[type].flags & (VariableInfo::FLAG_SP_FP | VariableInfo::FLAG_DP_FP)) != 0; -} - -static GPVar GPVarFromData(VarData* vdata) -{ - GPVar var; - var._var.id = vdata->id; - var._var.size = vdata->size; - var._var.registerCode = variableInfo[vdata->type].code; - var._var.variableType = vdata->type; - return var; -} - -static MMVar MMVarFromData(VarData* vdata) -{ - MMVar var; - var._var.id = vdata->id; - var._var.size = vdata->size; - var._var.registerCode = variableInfo[vdata->type].code; - var._var.variableType = vdata->type; - return var; -} - -static XMMVar XMMVarFromData(VarData* vdata) -{ - XMMVar var; - var._var.id = vdata->id; - var._var.size = vdata->size; - var._var.registerCode = variableInfo[vdata->type].code; - var._var.variableType = vdata->type; - return var; -} - -// ============================================================================ -// [Helpers - Emittables] -// ============================================================================ - -static void delAll(Emittable* first) ASMJIT_NOTHROW -{ - Emittable* cur = first; - - while (cur) - { - Emittable* next = cur->getNext(); - cur->~Emittable(); - cur = next; - } -} - -// ============================================================================ -// [Helpers - Compiler] -// ============================================================================ - -template -inline T* Compiler_newObject(CompilerCore* self) ASMJIT_NOTHROW -{ - void* addr = self->getZone().zalloc(sizeof(T)); - return new(addr) T(reinterpret_cast(self)); -} - -template -inline T* Compiler_newObject(CompilerCore* self, P1 p1) ASMJIT_NOTHROW -{ - void* addr = self->getZone().zalloc(sizeof(T)); - return new(addr) T(reinterpret_cast(self), p1); -} - -template -inline T* Compiler_newObject(CompilerCore* self, P1 p1, P2 p2) ASMJIT_NOTHROW -{ - void* addr = self->getZone().zalloc(sizeof(T)); - return new(addr) T(reinterpret_cast(self), p1, p2); -} - -template -inline T* Compiler_newObject(CompilerCore* self, P1 p1, P2 p2, P3 p3) ASMJIT_NOTHROW -{ - void* addr = self->getZone().zalloc(sizeof(T)); - return new(addr) T(reinterpret_cast(self), p1, p2, p3); -} - -template -inline T* Compiler_newObject(CompilerCore* self, P1 p1, P2 p2, P3 p3, P4 p4) ASMJIT_NOTHROW -{ - void* addr = self->getZone().zalloc(sizeof(T)); - return new(addr) T(reinterpret_cast(self), p1, p2, p3, p4); -} - -template -inline T* Compiler_newObject(CompilerCore* self, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) ASMJIT_NOTHROW -{ - void* addr = self->getZone().zalloc(sizeof(T)); - return new(addr) T(reinterpret_cast(self), p1, p2, p3, p4, p5); -} - -// ============================================================================ -// [AsmJit::FunctionPrototype] -// ============================================================================ - -FunctionPrototype::FunctionPrototype() ASMJIT_NOTHROW -{ - // Safe defaults. - _clear(); -} - -FunctionPrototype::~FunctionPrototype() ASMJIT_NOTHROW -{ -} - -void FunctionPrototype::setPrototype( - uint32_t callingConvention, - const uint32_t* arguments, - uint32_t argumentsCount, - uint32_t returnValue) ASMJIT_NOTHROW -{ - _setCallingConvention(callingConvention); - - if (argumentsCount > 32) argumentsCount = 32; - _setPrototype(arguments, argumentsCount, returnValue); -} - -uint32_t FunctionPrototype::findArgumentByRegisterCode(uint32_t regCode) const ASMJIT_NOTHROW -{ - uint32_t type = regCode & REG_TYPE_MASK; - uint32_t idx = regCode & REG_INDEX_MASK; - - uint32_t clazz; - uint32_t i; - - switch (type) - { - case REG_TYPE_GPD: - case REG_TYPE_GPQ: - clazz = VariableInfo::CLASS_GP; - break; - - case REG_TYPE_MM: - clazz = VariableInfo::CLASS_MM; - break; - - case REG_TYPE_XMM: - clazz = VariableInfo::CLASS_XMM; - break; - - default: - return INVALID_VALUE; - } - - for (i = 0; i < _argumentsCount; i++) - { - const Argument& arg = _arguments[i]; - if ((getVariableClass(arg.variableType) & clazz) != 0 && (arg.registerIndex == idx)) - return i; - } - - return INVALID_VALUE; -} - -void FunctionPrototype::_clear() ASMJIT_NOTHROW -{ - _callingConvention = CALL_CONV_NONE; - _calleePopsStack = false; - - _argumentsCount = 0; - _argumentsDirection = ARGUMENT_DIR_RIGHT_TO_LEFT; - _argumentsStackSize = 0; - - _returnValue = INVALID_VALUE; - - Util::memset32(_argumentsGPList , INVALID_VALUE, ASMJIT_ARRAY_SIZE(_argumentsGPList )); - Util::memset32(_argumentsXMMList, INVALID_VALUE, ASMJIT_ARRAY_SIZE(_argumentsXMMList)); - - _argumentsGP = 0; - _argumentsMM = 0; - _argumentsXMM = 0; - - _preservedGP = 0; - _preservedMM = 0; - _preservedXMM = 0; - - _passedGP = 0; - _passedMM = 0; - _passedXMM = 0; -} - -void FunctionPrototype::_setCallingConvention(uint32_t callingConvention) ASMJIT_NOTHROW -{ - // Safe defaults. - _clear(); - - _callingConvention = callingConvention; - - // -------------------------------------------------------------------------- - // [X86 Calling Conventions] - // -------------------------------------------------------------------------- - -#if defined(ASMJIT_X86) - _preservedGP = (1 << REG_INDEX_EBX) | - (1 << REG_INDEX_ESP) | - (1 << REG_INDEX_EBP) | - (1 << REG_INDEX_ESI) | - (1 << REG_INDEX_EDI) ; - _preservedXMM = 0; - - switch (_callingConvention) - { - case CALL_CONV_CDECL: - break; - - case CALL_CONV_STDCALL: - _calleePopsStack = true; - break; - - case CALL_CONV_MSTHISCALL: - _calleePopsStack = true; - _argumentsGPList[0] = REG_INDEX_ECX; - - _argumentsGP = (1 << REG_INDEX_ECX); - break; - - case CALL_CONV_MSFASTCALL: - _calleePopsStack = true; - _argumentsGPList[0] = REG_INDEX_ECX; - _argumentsGPList[1] = REG_INDEX_EDX; - - _argumentsGP = (1 << REG_INDEX_ECX) | - (1 << REG_INDEX_EDX) ; - break; - - case CALL_CONV_BORLANDFASTCALL: - _calleePopsStack = true; - _argumentsDirection = ARGUMENT_DIR_LEFT_TO_RIGHT; - _argumentsGPList[0] = REG_INDEX_EAX; - _argumentsGPList[1] = REG_INDEX_EDX; - _argumentsGPList[2] = REG_INDEX_ECX; - - _argumentsGP = (1 << REG_INDEX_EAX) | - (1 << REG_INDEX_EDX) | - (1 << REG_INDEX_ECX) ; - break; - - case CALL_CONV_GCCFASTCALL: - _calleePopsStack = true; - _argumentsGPList[0] = REG_INDEX_ECX; - _argumentsGPList[1] = REG_INDEX_EDX; - - _argumentsGP = (1 << REG_INDEX_ECX) | - (1 << REG_INDEX_EDX) ; - break; - - case CALL_CONV_GCCREGPARM_1: - _calleePopsStack = false; - _argumentsGPList[0] = REG_INDEX_EAX; - - _argumentsGP = (1 << REG_INDEX_EAX) ; - break; - - case CALL_CONV_GCCREGPARM_2: - _calleePopsStack = false; - _argumentsGPList[0] = REG_INDEX_EAX; - _argumentsGPList[1] = REG_INDEX_EDX; - - _argumentsGP = (1 << REG_INDEX_EAX) | - (1 << REG_INDEX_EDX) ; - break; - - case CALL_CONV_GCCREGPARM_3: - _calleePopsStack = false; - _argumentsGPList[0] = REG_INDEX_EAX; - _argumentsGPList[1] = REG_INDEX_EDX; - _argumentsGPList[2] = REG_INDEX_ECX; - - _argumentsGP = (1 << REG_INDEX_EAX) | - (1 << REG_INDEX_EDX) | - (1 << REG_INDEX_ECX) ; - break; - - default: - // Illegal calling convention. - ASMJIT_ASSERT(0); - } -#endif // ASMJIT_X86 - - // -------------------------------------------------------------------------- - // [X64 Calling Conventions] - // -------------------------------------------------------------------------- - -#if defined(ASMJIT_X64) - switch (_callingConvention) - { - case CALL_CONV_X64W: - _argumentsGPList[0] = REG_INDEX_RCX; - _argumentsGPList[1] = REG_INDEX_RDX; - _argumentsGPList[2] = REG_INDEX_R8; - _argumentsGPList[3] = REG_INDEX_R9; - - _argumentsXMMList[0] = REG_INDEX_XMM0; - _argumentsXMMList[1] = REG_INDEX_XMM1; - _argumentsXMMList[2] = REG_INDEX_XMM2; - _argumentsXMMList[3] = REG_INDEX_XMM3; - - _argumentsGP = (1 << REG_INDEX_RCX ) | - (1 << REG_INDEX_RDX ) | - (1 << REG_INDEX_R8 ) | - (1 << REG_INDEX_R9 ) ; - - _argumentsXMM = (1 << REG_INDEX_XMM0 ) | - (1 << REG_INDEX_XMM1 ) | - (1 << REG_INDEX_XMM2 ) | - (1 << REG_INDEX_XMM3 ) ; - - _preservedGP = (1 << REG_INDEX_RBX ) | - (1 << REG_INDEX_RSP ) | - (1 << REG_INDEX_RBP ) | - (1 << REG_INDEX_RSI ) | - (1 << REG_INDEX_RDI ) | - (1 << REG_INDEX_R12 ) | - (1 << REG_INDEX_R13 ) | - (1 << REG_INDEX_R14 ) | - (1 << REG_INDEX_R15 ) ; - - _preservedXMM = (1 << REG_INDEX_XMM6 ) | - (1 << REG_INDEX_XMM7 ) | - (1 << REG_INDEX_XMM8 ) | - (1 << REG_INDEX_XMM9 ) | - (1 << REG_INDEX_XMM10) | - (1 << REG_INDEX_XMM11) | - (1 << REG_INDEX_XMM12) | - (1 << REG_INDEX_XMM13) | - (1 << REG_INDEX_XMM14) | - (1 << REG_INDEX_XMM15) ; - break; - - case CALL_CONV_X64U: - _argumentsGPList[0] = REG_INDEX_RDI; - _argumentsGPList[1] = REG_INDEX_RSI; - _argumentsGPList[2] = REG_INDEX_RDX; - _argumentsGPList[3] = REG_INDEX_RCX; - _argumentsGPList[4] = REG_INDEX_R8; - _argumentsGPList[5] = REG_INDEX_R9; - - _argumentsXMMList[0] = REG_INDEX_XMM0; - _argumentsXMMList[1] = REG_INDEX_XMM1; - _argumentsXMMList[2] = REG_INDEX_XMM2; - _argumentsXMMList[3] = REG_INDEX_XMM3; - _argumentsXMMList[4] = REG_INDEX_XMM4; - _argumentsXMMList[5] = REG_INDEX_XMM5; - _argumentsXMMList[6] = REG_INDEX_XMM6; - _argumentsXMMList[7] = REG_INDEX_XMM7; - - _argumentsGP = (1 << REG_INDEX_RDI ) | - (1 << REG_INDEX_RSI ) | - (1 << REG_INDEX_RDX ) | - (1 << REG_INDEX_RCX ) | - (1 << REG_INDEX_R8 ) | - (1 << REG_INDEX_R9 ) ; - - _argumentsXMM = (1 << REG_INDEX_XMM0 ) | - (1 << REG_INDEX_XMM1 ) | - (1 << REG_INDEX_XMM2 ) | - (1 << REG_INDEX_XMM3 ) | - (1 << REG_INDEX_XMM4 ) | - (1 << REG_INDEX_XMM5 ) | - (1 << REG_INDEX_XMM6 ) | - (1 << REG_INDEX_XMM7 ) ; - - _preservedGP = (1 << REG_INDEX_RBX ) | - (1 << REG_INDEX_RSP ) | - (1 << REG_INDEX_RBP ) | - (1 << REG_INDEX_R12 ) | - (1 << REG_INDEX_R13 ) | - (1 << REG_INDEX_R14 ) | - (1 << REG_INDEX_R15 ) ; - break; - - default: - // Illegal calling convention. - ASMJIT_ASSERT(0); - } -#endif // ASMJIT_X64 -} - -void FunctionPrototype::_setPrototype( - const uint32_t* argumentsData, - uint32_t argumentsCount, - uint32_t returnValue) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(argumentsCount <= 32); - - int32_t i; - - int32_t posGP = 0; - int32_t posXMM = 0; - int32_t stackOffset = 0; - - _returnValue = returnValue; - - for (i = 0; i < (sysint_t)argumentsCount; i++) - { - Argument& a = _arguments[i]; - a.variableType = argumentsData[i]; - a.registerIndex = INVALID_VALUE; - a.stackOffset = INVALID_VALUE; - } - - _argumentsCount = (uint32_t)argumentsCount; - if (_argumentsCount == 0) return; - - // -------------------------------------------------------------------------- - // [X86 Calling Conventions (32-bit)] - // -------------------------------------------------------------------------- - -#if defined(ASMJIT_X86) - // Register arguments (Integer), always left-to-right. - for (i = 0; i != argumentsCount; i++) - { - Argument& a = _arguments[i]; - if (isVariableInteger(a.variableType) && posGP < 16 && _argumentsGPList[posGP] != INVALID_VALUE) - { - a.registerIndex = _argumentsGPList[posGP++]; - _passedGP |= Util::maskFromIndex(a.registerIndex); - } - } - - // Stack arguments. - bool ltr = _argumentsDirection == ARGUMENT_DIR_LEFT_TO_RIGHT; - sysint_t istart = ltr ? 0 : (sysint_t)argumentsCount - 1; - sysint_t iend = ltr ? (sysint_t)argumentsCount : -1; - sysint_t istep = ltr ? 1 : -1; - - for (i = istart; i != iend; i += istep) - { - Argument& a = _arguments[i]; - if (a.registerIndex != INVALID_VALUE) continue; - - if (isVariableInteger(a.variableType)) - { - stackOffset -= 4; - a.stackOffset = stackOffset; - } - else if (isVariableFloat(a.variableType)) - { - int32_t size = (int32_t)variableInfo[a.variableType].size; - stackOffset -= size; - a.stackOffset = stackOffset; - } - } -#endif // ASMJIT_X86 - - // -------------------------------------------------------------------------- - // [X64 Calling Conventions (64-bit)] - // -------------------------------------------------------------------------- - -#if defined(ASMJIT_X64) - // Windows 64-bit specific. - if (_callingConvention == CALL_CONV_X64W) - { - sysint_t max = argumentsCount < 4 ? argumentsCount : 4; - - // Register arguments (Integer / FP), always left to right. - for (i = 0; i != max; i++) - { - Argument& a = _arguments[i]; - - if (isVariableInteger(a.variableType)) - { - a.registerIndex = _argumentsGPList[i]; - _passedGP |= Util::maskFromIndex(a.registerIndex); - } - else if (isVariableFloat(a.variableType)) - { - a.registerIndex = _argumentsXMMList[i]; - _passedXMM |= Util::maskFromIndex(a.registerIndex); - } - } - - // Stack arguments (always right-to-left). - for (i = argumentsCount - 1; i != -1; i--) - { - Argument& a = _arguments[i]; - if (a.isAssigned()) continue; - - if (isVariableInteger(a.variableType)) - { - stackOffset -= 8; // Always 8 bytes. - a.stackOffset = stackOffset; - } - else if (isVariableFloat(a.variableType)) - { - int32_t size = (int32_t)variableInfo[a.variableType].size; - stackOffset -= size; - a.stackOffset = stackOffset; - } - } - - // 32 bytes shadow space (X64W calling convention specific). - stackOffset -= 4 * 8; - } - // Linux/Unix 64-bit (AMD64 calling convention). - else - { - // Register arguments (Integer), always left to right. - for (i = 0; i != argumentsCount; i++) - { - Argument& a = _arguments[i]; - if (isVariableInteger(a.variableType) && posGP < 32 && _argumentsGPList[posGP] != INVALID_VALUE) - { - a.registerIndex = _argumentsGPList[posGP++]; - _passedGP |= Util::maskFromIndex(a.registerIndex); - } - } - - // Register arguments (FP), always left to right. - for (i = 0; i != argumentsCount; i++) - { - Argument& a = _arguments[i]; - if (isVariableFloat(a.variableType)) - { - a.registerIndex = _argumentsXMMList[posXMM++]; - _passedXMM |= Util::maskFromIndex(a.registerIndex); - } - } - - // Stack arguments. - for (i = argumentsCount - 1; i != -1; i--) - { - Argument& a = _arguments[i]; - if (a.isAssigned()) continue; - - if (isVariableInteger(a.variableType)) - { - stackOffset -= 8; - a.stackOffset = stackOffset; - } - else if (isVariableFloat(a.variableType)) - { - int32_t size = (int32_t)variableInfo[a.variableType].size; - - stackOffset -= size; - a.stackOffset = stackOffset; - } - } - } -#endif // ASMJIT_X64 - - // Modify stack offset (all function parameters will be in positive stack - // offset that is never zero). - for (i = 0; i < (sysint_t)argumentsCount; i++) - { - if (_arguments[i].registerIndex == INVALID_VALUE) - _arguments[i].stackOffset += sizeof(sysint_t) - stackOffset; - } - - _argumentsStackSize = (uint32_t)(-stackOffset); -} - -void FunctionPrototype::_setReturnValue(uint32_t valueId) ASMJIT_NOTHROW -{ - // TODO. -} - -// ============================================================================ -// [AsmJit::EVariableHint] -// ============================================================================ - -EVariableHint::EVariableHint(Compiler* c, VarData* vdata, uint32_t hintId, uint32_t hintValue) ASMJIT_NOTHROW : - Emittable(c, EMITTABLE_VARIABLE_HINT), - _vdata(vdata), - _hintId(hintId), - _hintValue(hintValue) -{ - ASMJIT_ASSERT(_vdata != NULL); -} - -EVariableHint::~EVariableHint() ASMJIT_NOTHROW -{ -} - -void EVariableHint::prepare(CompilerContext& cc) ASMJIT_NOTHROW -{ - _offset = cc._currentOffset; - - // First emittable (begin of variable scope). - if (_vdata->firstEmittable == NULL) _vdata->firstEmittable = this; - - Emittable* oldLast = _vdata->lastEmittable; - - // Last emittable (end of variable scope). - _vdata->lastEmittable = this; - - switch (_hintId) - { - case VARIABLE_HINT_ALLOC: - case VARIABLE_HINT_SPILL: - case VARIABLE_HINT_SAVE: - if (!cc._isActive(_vdata)) cc._addActive(_vdata); - break; - case VARIABLE_HINT_SAVE_AND_UNUSE: - if (!cc._isActive(_vdata)) cc._addActive(_vdata); - break; - case VARIABLE_HINT_UNUSE: - if (oldLast) oldLast->_tryUnuseVar(_vdata); - break; - } -} - -Emittable* EVariableHint::translate(CompilerContext& cc) ASMJIT_NOTHROW -{ - switch (_hintId) - { - case VARIABLE_HINT_ALLOC: - cc.allocVar(_vdata, _hintValue, VARIABLE_ALLOC_READ); - break; - case VARIABLE_HINT_SPILL: - if (_vdata->state == VARIABLE_STATE_REGISTER) - cc.spillVar(_vdata); - break; - case VARIABLE_HINT_SAVE: - case VARIABLE_HINT_SAVE_AND_UNUSE: - if (_vdata->state == VARIABLE_STATE_REGISTER && _vdata->changed) - { - cc.emitSaveVar(_vdata, _vdata->registerIndex); - _vdata->changed = false; - } - if (_hintId == VARIABLE_HINT_SAVE_AND_UNUSE) goto unuse; - break; - case VARIABLE_HINT_UNUSE: -unuse: - cc.unuseVar(_vdata, VARIABLE_STATE_UNUSED); - goto end; - } - - cc._unuseVarOnEndOfScope(this, _vdata); - -end: - return translated(); -} - -int EVariableHint::getMaxSize() const ASMJIT_NOTHROW -{ - // Variable hint is NOP, but it can generate other emittables which can do - // something. - return 0; -} - -// ============================================================================ -// [AsmJit::EInstruction] -// ============================================================================ - -EInstruction::EInstruction(Compiler* c, uint32_t code, Operand* operandsData, uint32_t operandsCount) ASMJIT_NOTHROW : - Emittable(c, EMITTABLE_INSTRUCTION) -{ - _code = code; - _emitOptions = c->_emitOptions; - // Each created instruction takes emit options and clears it. - c->_emitOptions = 0; - - _operands = operandsData; - _operandsCount = operandsCount; - _memOp = NULL; - - _variables = NULL; - _variablesCount = 0; - - uint32_t i; - for (i = 0; i < operandsCount; i++) - { - if (_operands[i].isMem()) - { - _memOp = reinterpret_cast(&_operands[i]); - break; - } - } - - const InstructionDescription* id = &instructionDescription[_code]; - _isSpecial = id->isSpecial(); - _isFPU = id->isFPU(); - _isGPBLoUsed = false; - _isGPBHiUsed = false; - - if (_isSpecial) - { - // ${SPECIAL_INSTRUCTION_HANDLING_BEGIN} - switch (_code) - { - case INST_CPUID: - // Special... - break; - - case INST_CBW: - case INST_CDQE: - case INST_CWDE: - // Special... - break; - - case INST_CMPXCHG: - case INST_CMPXCHG8B: -#if defined(ASMJIT_X64) - case INST_CMPXCHG16B: -#endif // ASMJIT_X64 - // Special... - break; - -#if defined(ASMJIT_X86) - case INST_DAA: - case INST_DAS: - // Special... - break; -#endif // ASMJIT_X86 - - case INST_IMUL: - switch (operandsCount) - { - case 2: - // IMUL dst, src is not special instruction. - _isSpecial = false; - break; - case 3: - if (!(_operands[0].isVar() && _operands[1].isVar() && _operands[2].isVarMem())) - { - // Only IMUL dst_hi, dst_lo, reg/mem is special, all others don't. - _isSpecial = false; - } - break; - } - break; - case INST_MUL: - case INST_IDIV: - case INST_DIV: - // Special... - break; - - case INST_MOV_PTR: - // Special... - break; - - case INST_LAHF: - case INST_SAHF: - // Special... - break; - - case INST_MASKMOVQ: - case INST_MASKMOVDQU: - // Special... - break; - - case INST_ENTER: - case INST_LEAVE: - // Special... - break; - - case INST_RET: - // Special... - break; - - case INST_MONITOR: - case INST_MWAIT: - // Special... - break; - - case INST_POP: - case INST_POPAD: - case INST_POPFD: - case INST_POPFQ: - // Special... - break; - - case INST_PUSH: - case INST_PUSHAD: - case INST_PUSHFD: - case INST_PUSHFQ: - // Special... - break; - - case INST_RCL: - case INST_RCR: - case INST_ROL: - case INST_ROR: - case INST_SAL: - case INST_SAR: - case INST_SHL: - case INST_SHR: - // Rot instruction is special only if last operand is variable (register). - _isSpecial = _operands[1].isVar(); - break; - - case INST_SHLD: - case INST_SHRD: - // Shld/Shrd instruction is special only if last operand is variable (register). - _isSpecial = _operands[2].isVar(); - break; - - case INST_RDTSC: - case INST_RDTSCP: - // Special... - break; - - case INST_REP_LODSB: - case INST_REP_LODSD: - case INST_REP_LODSQ: - case INST_REP_LODSW: - case INST_REP_MOVSB: - case INST_REP_MOVSD: - case INST_REP_MOVSQ: - case INST_REP_MOVSW: - case INST_REP_STOSB: - case INST_REP_STOSD: - case INST_REP_STOSQ: - case INST_REP_STOSW: - case INST_REPE_CMPSB: - case INST_REPE_CMPSD: - case INST_REPE_CMPSQ: - case INST_REPE_CMPSW: - case INST_REPE_SCASB: - case INST_REPE_SCASD: - case INST_REPE_SCASQ: - case INST_REPE_SCASW: - case INST_REPNE_CMPSB: - case INST_REPNE_CMPSD: - case INST_REPNE_CMPSQ: - case INST_REPNE_CMPSW: - case INST_REPNE_SCASB: - case INST_REPNE_SCASD: - case INST_REPNE_SCASQ: - case INST_REPNE_SCASW: - // Special... - break; - - default: - ASMJIT_ASSERT(0); - } - // ${SPECIAL_INSTRUCTION_HANDLING_END} - } -} - -EInstruction::~EInstruction() ASMJIT_NOTHROW -{ -} - -void EInstruction::prepare(CompilerContext& cc) ASMJIT_NOTHROW -{ -#define __GET_VARIABLE(__vardata__) \ - { \ - VarData* _candidate = __vardata__; \ - \ - for (var = cur; ;) \ - { \ - if (var == _variables) \ - { \ - var = cur++; \ - var->vdata = _candidate; \ - var->vflags = 0; \ - var->regMask = 0xFFFFFFFF; \ - break; \ - } \ - \ - var--; \ - \ - if (var->vdata == _candidate) \ - { \ - break; \ - } \ - } \ - \ - ASMJIT_ASSERT(var != NULL); \ - } - - _offset = cc._currentOffset; - - const InstructionDescription* id = &instructionDescription[_code]; - - uint32_t i, len = _operandsCount; - uint32_t variablesCount = 0; - - for (i = 0; i < len; i++) - { - Operand& o = _operands[i]; - - if (o.isVar()) - { - ASMJIT_ASSERT(o.getId() != INVALID_VALUE); - VarData* vdata = _compiler->_getVarData(o.getId()); - ASMJIT_ASSERT(vdata != NULL); - - if (reinterpret_cast(&o)->isGPVar()) - { - if (reinterpret_cast(&o)->isGPBLo()) { _isGPBLoUsed = true; vdata->registerGPBLoCount++; }; - if (reinterpret_cast(&o)->isGPBHi()) { _isGPBHiUsed = true; vdata->registerGPBHiCount++; }; - } - - if (vdata->workOffset != _offset) - { - if (!cc._isActive(vdata)) cc._addActive(vdata); - - vdata->workOffset = _offset; - variablesCount++; - } - } - else if (o.isMem()) - { - if ((o.getId() & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(o.getId()); - ASMJIT_ASSERT(vdata != NULL); - - cc._markMemoryUsed(vdata); - - if (vdata->workOffset != _offset) - { - if (!cc._isActive(vdata)) cc._addActive(vdata); - - vdata->workOffset = _offset; - variablesCount++; - } - } - else if ((o._mem.base & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(o._mem.base); - ASMJIT_ASSERT(vdata != NULL); - - if (vdata->workOffset != _offset) - { - if (!cc._isActive(vdata)) cc._addActive(vdata); - - vdata->workOffset = _offset; - variablesCount++; - } - } - - if ((o._mem.index & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(o._mem.index); - ASMJIT_ASSERT(vdata != NULL); - - if (vdata->workOffset != _offset) - { - if (!cc._isActive(vdata)) cc._addActive(vdata); - - vdata->workOffset = _offset; - variablesCount++; - } - } - } - } - - if (!variablesCount) - { - cc._currentOffset++; - return; - } - - _variables = reinterpret_cast(_compiler->getZone().zalloc(sizeof(VarAllocRecord) * variablesCount)); - if (!_variables) - { - _compiler->setError(ERROR_NO_HEAP_MEMORY); - cc._currentOffset++; - return; - } - - _variablesCount = variablesCount; - - VarAllocRecord* cur = _variables; - VarAllocRecord* var = NULL; - - bool _isGPBUsed = _isGPBLoUsed | _isGPBHiUsed; - uint32_t gpRestrictMask = Util::maskUpToIndex(REG_NUM_GP); - -#if defined(ASMJIT_X64) - if (_isGPBHiUsed) - { - gpRestrictMask &= Util::maskFromIndex(REG_INDEX_EAX) | - Util::maskFromIndex(REG_INDEX_EBX) | - Util::maskFromIndex(REG_INDEX_ECX) | - Util::maskFromIndex(REG_INDEX_EDX) | - Util::maskFromIndex(REG_INDEX_EBP) | - Util::maskFromIndex(REG_INDEX_ESI) | - Util::maskFromIndex(REG_INDEX_EDI) ; - } -#endif // ASMJIT_X64 - - for (i = 0; i < len; i++) - { - Operand& o = _operands[i]; - - if (o.isVar()) - { - VarData* vdata = _compiler->_getVarData(o.getId()); - ASMJIT_ASSERT(vdata != NULL); - - __GET_VARIABLE(vdata) - var->vflags |= VARIABLE_ALLOC_REGISTER; - - if (_isGPBUsed) - { -#if defined(ASMJIT_X86) - if (reinterpret_cast(&o)->isGPB()) - { - var->regMask &= Util::maskFromIndex(REG_INDEX_EAX) | - Util::maskFromIndex(REG_INDEX_EBX) | - Util::maskFromIndex(REG_INDEX_ECX) | - Util::maskFromIndex(REG_INDEX_EDX) ; - } -#else - // Restrict all BYTE registers to RAX/RBX/RCX/RDX if HI BYTE register - // is used (REX prefix makes HI BYTE addressing unencodable). - if (_isGPBHiUsed) - { - if (reinterpret_cast(&o)->isGPB()) - { - var->regMask &= Util::maskFromIndex(REG_INDEX_EAX) | - Util::maskFromIndex(REG_INDEX_EBX) | - Util::maskFromIndex(REG_INDEX_ECX) | - Util::maskFromIndex(REG_INDEX_EDX) ; - } - } -#endif // ASMJIT_X86/X64 - } - - if (isSpecial()) - { - // ${SPECIAL_INSTRUCTION_HANDLING_BEGIN} - switch (_code) - { - case INST_CPUID: - switch (i) - { - case 0: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - case 1: - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EBX); - gpRestrictMask &= ~var->regMask; - break; - case 2: - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_ECX); - gpRestrictMask &= ~var->regMask; - break; - case 3: - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EDX); - gpRestrictMask &= ~var->regMask; - break; - - default: - ASMJIT_ASSERT(0); - } - break; - - case INST_CBW: - case INST_CDQE: - case INST_CWDE: - switch (i) - { - case 0: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - - default: - ASMJIT_ASSERT(0); - } - break; - - case INST_CMPXCHG: - switch (i) - { - case 0: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - case 1: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE; - break; - case 2: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ; - break; - - default: - ASMJIT_ASSERT(0); - } - break; - - case INST_CMPXCHG8B: -#if defined(ASMJIT_X64) - case INST_CMPXCHG16B: -#endif // ASMJIT_X64 - switch (i) - { - case 0: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EDX); - gpRestrictMask &= ~var->regMask; - break; - case 1: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - case 2: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_ECX); - gpRestrictMask &= ~var->regMask; - break; - case 3: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EBX); - gpRestrictMask &= ~var->regMask; - break; - - default: - ASMJIT_ASSERT(0); - } - break; - -#if defined(ASMJIT_X86) - case INST_DAA: - case INST_DAS: - ASMJIT_ASSERT(i == 0); - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; -#endif // ASMJIT_X86 - - case INST_IMUL: - case INST_MUL: - case INST_IDIV: - case INST_DIV: - switch (i) - { - case 0: - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EDX); - gpRestrictMask &= ~var->regMask; - break; - case 1: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - case 2: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ; - break; - - default: - ASMJIT_ASSERT(0); - } - break; - - case INST_MOV_PTR: - switch (i) - { - case 0: - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - case 1: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - default: - ASMJIT_ASSERT(0); - } - break; - - case INST_LAHF: - ASMJIT_ASSERT(i == 0); - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - - case INST_SAHF: - ASMJIT_ASSERT(i == 0); - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - - case INST_MASKMOVQ: - case INST_MASKMOVDQU: - switch (i) - { - case 0: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EDI); - gpRestrictMask &= ~var->regMask; - break; - case 1: - case 2: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ; - break; - } - break; - - case INST_ENTER: - case INST_LEAVE: - // TODO: SPECIAL INSTRUCTION. - break; - - case INST_RET: - // TODO: SPECIAL INSTRUCTION. - break; - - case INST_MONITOR: - case INST_MWAIT: - // TODO: MONITOR/MWAIT (COMPILER). - break; - - case INST_POP: - // TODO: SPECIAL INSTRUCTION. - break; - - case INST_POPAD: - case INST_POPFD: - case INST_POPFQ: - // TODO: SPECIAL INSTRUCTION. - break; - - case INST_PUSH: - // TODO: SPECIAL INSTRUCTION. - break; - - case INST_PUSHAD: - case INST_PUSHFD: - case INST_PUSHFQ: - // TODO: SPECIAL INSTRUCTION. - break; - - case INST_RCL: - case INST_RCR: - case INST_ROL: - case INST_ROR: - case INST_SAL: - case INST_SAR: - case INST_SHL: - case INST_SHR: - switch (i) - { - case 0: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE; - break; - case 1: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_ECX); - gpRestrictMask &= ~var->regMask; - break; - - default: - ASMJIT_ASSERT(0); - } - break; - - case INST_SHLD: - case INST_SHRD: - switch (i) - { - case 0: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE; - break; - case 1: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ; - break; - case 2: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_ECX); - gpRestrictMask &= ~var->regMask; - break; - - default: - ASMJIT_ASSERT(0); - } - break; - - case INST_RDTSC: - case INST_RDTSCP: - switch (i) - { - case 0: - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EDX); - gpRestrictMask &= ~var->regMask; - break; - case 1: - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - case 2: - ASMJIT_ASSERT(_code == INST_RDTSCP); - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_ECX); - gpRestrictMask &= ~var->regMask; - break; - - default: - ASMJIT_ASSERT(0); - } - break; - - case INST_REP_LODSB: - case INST_REP_LODSD: - case INST_REP_LODSQ: - case INST_REP_LODSW: - switch (i) - { - case 0: - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - case 1: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_ESI); - gpRestrictMask &= ~var->regMask; - break; - case 2: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_ECX); - gpRestrictMask &= ~var->regMask; - break; - default: - ASMJIT_ASSERT(0); - } - break; - - case INST_REP_MOVSB: - case INST_REP_MOVSD: - case INST_REP_MOVSQ: - case INST_REP_MOVSW: - case INST_REPE_CMPSB: - case INST_REPE_CMPSD: - case INST_REPE_CMPSQ: - case INST_REPE_CMPSW: - case INST_REPNE_CMPSB: - case INST_REPNE_CMPSD: - case INST_REPNE_CMPSQ: - case INST_REPNE_CMPSW: - switch (i) - { - case 0: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EDI); - gpRestrictMask &= ~var->regMask; - break; - case 1: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_ESI); - gpRestrictMask &= ~var->regMask; - break; - case 2: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_ECX); - gpRestrictMask &= ~var->regMask; - break; - default: - ASMJIT_ASSERT(0); - } - break; - - case INST_REP_STOSB: - case INST_REP_STOSD: - case INST_REP_STOSQ: - case INST_REP_STOSW: - switch (i) - { - case 0: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EDI); - gpRestrictMask &= ~var->regMask; - break; - case 1: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - case 2: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_ECX); - gpRestrictMask &= ~var->regMask; - break; - default: - ASMJIT_ASSERT(0); - } - break; - - case INST_REPE_SCASB: - case INST_REPE_SCASD: - case INST_REPE_SCASQ: - case INST_REPE_SCASW: - case INST_REPNE_SCASB: - case INST_REPNE_SCASD: - case INST_REPNE_SCASQ: - case INST_REPNE_SCASW: - switch (i) - { - case 0: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EDI); - gpRestrictMask &= ~var->regMask; - break; - case 1: - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_EAX); - gpRestrictMask &= ~var->regMask; - break; - case 2: - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE | VARIABLE_ALLOC_SPECIAL; - var->regMask = Util::maskFromIndex(REG_INDEX_ECX); - gpRestrictMask &= ~var->regMask; - break; - default: - ASMJIT_ASSERT(0); - } - break; - - default: - ASMJIT_ASSERT(0); - } - // ${SPECIAL_INSTRUCTION_HANDLING_END} - } - else - { - if (i == 0) - { - // CMP/TEST instruction. - if (id->code == INST_CMP || id->code == INST_TEST) - { - // Read-only case. - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ; - } - // CVTTSD2SI/CVTTSS2SI instructions. - else if (id->code == INST_CVTTSD2SI || id->code == INST_CVTTSS2SI) - { - // In 32-bit mode the whole destination is replaced. In 64-bit mode - // we need to check whether the destination operand size is 64-bits. -#if defined(ASMJIT_X64) - if (_operands[0].isRegType(REG_TYPE_GPQ)) - { -#endif // ASMJIT_X64 - // Write-only case. - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE; -#if defined(ASMJIT_X64) - } - else - { - // Read/Write. - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE; - } -#endif // ASMJIT_X64 - } - // MOV/MOVSS/MOVSD instructions. - // - // If instruction is MOV (source replaces the destination) or - // MOVSS/MOVSD and source operand is memory location then register - // allocator should know that previous destination value is lost - // (write only operation). - else if ((id->isMov()) || - ((id->code == INST_MOVSS || id->code == INST_MOVSD) /* && _operands[1].isMem() */) || - (id->code == INST_IMUL && _operandsCount == 3 && !isSpecial())) - { - // Write-only case. - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE; - } - else if (id->code == INST_LEA) - { - // Write. - vdata->registerWriteCount++; - var->vflags |= VARIABLE_ALLOC_WRITE; - } - else - { - // Read/Write. - vdata->registerRWCount++; - var->vflags |= VARIABLE_ALLOC_READWRITE; - } - } - else - { - // Second, third, ... operands are read-only. - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_READ; - } - - if (!_memOp && i < 2 && (id->oflags[i] & InstructionDescription::O_MEM) != 0) - { - var->vflags |= VARIABLE_ALLOC_MEMORY; - } - } - - // If variable must be in specific register we could add some hint to allocator. - if (var->vflags & VARIABLE_ALLOC_SPECIAL) - { - vdata->prefRegisterMask |= Util::maskFromIndex(var->regMask); - cc._newRegisterHomeIndex(vdata, Util::findFirstBit(var->regMask)); - } - } - else if (o.isMem()) - { - if ((o.getId() & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(o.getId()); - ASMJIT_ASSERT(vdata != NULL); - - __GET_VARIABLE(vdata) - - if (i == 0) - { - // If variable is MOV instruction type (source replaces the destination) - // or variable is MOVSS/MOVSD instruction then register allocator should - // know that previous destination value is lost (write only operation). - if (id->isMov() || ((id->code == INST_MOVSS || id->code == INST_MOVSD))) - { - // Write only case. - vdata->memoryWriteCount++; - } - else - { - vdata->memoryRWCount++; - } - } - else - { - vdata->memoryReadCount++; - } - } - else if ((o._mem.base & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(reinterpret_cast(o).getBase()); - ASMJIT_ASSERT(vdata != NULL); - - __GET_VARIABLE(vdata) - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_REGISTER | VARIABLE_ALLOC_READ; - var->regMask &= gpRestrictMask; - } - - if ((o._mem.index & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(reinterpret_cast(o).getIndex()); - ASMJIT_ASSERT(vdata != NULL); - - __GET_VARIABLE(vdata) - vdata->registerReadCount++; - var->vflags |= VARIABLE_ALLOC_REGISTER | VARIABLE_ALLOC_READ; - var->regMask &= gpRestrictMask; - } - } - } - - // Traverse all variables and update firstEmittable / lastEmittable. This - // function is called from iterator that scans emittables using forward - // direction so we can use this knowledge to optimize the process. - // - // Similar to ECall::prepare(). - for (i = 0; i < _variablesCount; i++) - { - VarData* v = _variables[i].vdata; - - // Update GP register allocator restrictions. - if (isVariableInteger(v->type)) - { - if (_variables[i].regMask == 0xFFFFFFFF) _variables[i].regMask &= gpRestrictMask; - } - - // Update first/last emittable (begin of variable scope). - if (v->firstEmittable == NULL) v->firstEmittable = this; - v->lastEmittable = this; - } - - // There are some instructions that can be used to clear register or to set - // register to some value (ideal case is all zeros or all ones). - // - // xor/pxor reg, reg ; Set all bits in reg to 0. - // sub/psub reg, reg ; Set all bits in reg to 0. - // andn reg, reg ; Set all bits in reg to 0. - // pcmpgt reg, reg ; Set all bits in reg to 0. - // pcmpeq reg, reg ; Set all bits in reg to 1. - - if (_variablesCount == 1 && - _operandsCount > 1 && - _operands[0].isVar() && - _operands[1].isVar() && - !_memOp) - { - switch (_code) - { - // XOR Instructions. - case INST_XOR: - case INST_XORPD: - case INST_XORPS: - case INST_PXOR: - - // ANDN Instructions. - case INST_PANDN: - - // SUB Instructions. - case INST_SUB: - case INST_PSUBB: - case INST_PSUBW: - case INST_PSUBD: - case INST_PSUBQ: - case INST_PSUBSB: - case INST_PSUBSW: - case INST_PSUBUSB: - case INST_PSUBUSW: - - // PCMPEQ Instructions. - case INST_PCMPEQB: - case INST_PCMPEQW: - case INST_PCMPEQD: - case INST_PCMPEQQ: - - // PCMPGT Instructions. - case INST_PCMPGTB: - case INST_PCMPGTW: - case INST_PCMPGTD: - case INST_PCMPGTQ: - // Clear the read flag. This prevents variable alloc/spill. - _variables[0].vflags = VARIABLE_ALLOC_WRITE; - _variables[0].vdata->registerReadCount--; - break; - } - } - cc._currentOffset++; - -#undef __GET_VARIABLE -} - -Emittable* EInstruction::translate(CompilerContext& cc) ASMJIT_NOTHROW -{ - uint32_t i; - uint32_t variablesCount = _variablesCount; - - if (variablesCount > 0) - { - // These variables are used by the instruction and we set current offset - // to their work offsets -> getSpillCandidate never return the variable - // used this instruction. - for (i = 0; i < variablesCount; i++) - { - _variables->vdata->workOffset = cc._currentOffset; - } - - // Alloc variables used by the instruction (special first). - for (i = 0; i < variablesCount; i++) - { - VarAllocRecord& r = _variables[i]; - // Alloc variables with specific register first. - if ((r.vflags & VARIABLE_ALLOC_SPECIAL) != 0) - cc.allocVar(r.vdata, r.regMask, r.vflags); - } - - for (i = 0; i < variablesCount; i++) - { - VarAllocRecord& r = _variables[i]; - // Alloc variables without specific register last. - if ((r.vflags & VARIABLE_ALLOC_SPECIAL) == 0) - cc.allocVar(r.vdata, r.regMask, r.vflags); - } - - cc.translateOperands(_operands, _operandsCount); - } - - if (_memOp && (_memOp->getId() & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(_memOp->getId()); - ASMJIT_ASSERT(vdata != NULL); - - switch (vdata->state) - { - case VARIABLE_STATE_UNUSED: - vdata->state = VARIABLE_STATE_MEMORY; - break; - case VARIABLE_STATE_REGISTER: - vdata->changed = false; - cc.unuseVar(vdata, VARIABLE_STATE_MEMORY); - break; - } - } - - for (i = 0; i < variablesCount; i++) - { - cc._unuseVarOnEndOfScope(this, &_variables[i]); - } - - return translated(); -} - -void EInstruction::emit(Assembler& a) ASMJIT_NOTHROW -{ - a._comment = _comment; - a._emitOptions = _emitOptions; - - if (isSpecial()) - { - // ${SPECIAL_INSTRUCTION_HANDLING_BEGIN} - switch (_code) - { - case INST_CPUID: - a._emitInstruction(_code); - return; - - case INST_CBW: - case INST_CDQE: - case INST_CWDE: - a._emitInstruction(_code); - return; - - case INST_CMPXCHG: - a._emitInstruction(_code, &_operands[1], &_operands[2]); - return; - - case INST_CMPXCHG8B: -#if defined(ASMJIT_X64) - case INST_CMPXCHG16B: -#endif // ASMJIT_X64 - a._emitInstruction(_code, &_operands[4]); - return; - -#if defined(ASMJIT_X86) - case INST_DAA: - case INST_DAS: - a._emitInstruction(_code); - return; -#endif // ASMJIT_X86 - - case INST_IMUL: - case INST_MUL: - case INST_IDIV: - case INST_DIV: - // INST dst_lo (implicit), dst_hi (implicit), src (explicit) - ASMJIT_ASSERT(_operandsCount == 3); - a._emitInstruction(_code, &_operands[2]); - return; - - case INST_MOV_PTR: - break; - - case INST_LAHF: - case INST_SAHF: - a._emitInstruction(_code); - return; - - case INST_MASKMOVQ: - case INST_MASKMOVDQU: - a._emitInstruction(_code, &_operands[1], &_operands[2]); - return; - - case INST_ENTER: - case INST_LEAVE: - // TODO: SPECIAL INSTRUCTION. - break; - - case INST_RET: - // TODO: SPECIAL INSTRUCTION. - break; - - case INST_MONITOR: - case INST_MWAIT: - // TODO: MONITOR/MWAIT (COMPILER). - break; - - case INST_POP: - case INST_POPAD: - case INST_POPFD: - case INST_POPFQ: - // TODO: SPECIAL INSTRUCTION. - break; - - case INST_PUSH: - case INST_PUSHAD: - case INST_PUSHFD: - case INST_PUSHFQ: - // TODO: SPECIAL INSTRUCTION. - break; - - case INST_RCL: - case INST_RCR: - case INST_ROL: - case INST_ROR: - case INST_SAL: - case INST_SAR: - case INST_SHL: - case INST_SHR: - a._emitInstruction(_code, &_operands[0], &cl); - return; - - case INST_SHLD: - case INST_SHRD: - a._emitInstruction(_code, &_operands[0], &_operands[1], &cl); - return; - - case INST_RDTSC: - case INST_RDTSCP: - a._emitInstruction(_code); - return; - - case INST_REP_LODSB: - case INST_REP_LODSD: - case INST_REP_LODSQ: - case INST_REP_LODSW: - case INST_REP_MOVSB: - case INST_REP_MOVSD: - case INST_REP_MOVSQ: - case INST_REP_MOVSW: - case INST_REP_STOSB: - case INST_REP_STOSD: - case INST_REP_STOSQ: - case INST_REP_STOSW: - case INST_REPE_CMPSB: - case INST_REPE_CMPSD: - case INST_REPE_CMPSQ: - case INST_REPE_CMPSW: - case INST_REPE_SCASB: - case INST_REPE_SCASD: - case INST_REPE_SCASQ: - case INST_REPE_SCASW: - case INST_REPNE_CMPSB: - case INST_REPNE_CMPSD: - case INST_REPNE_CMPSQ: - case INST_REPNE_CMPSW: - case INST_REPNE_SCASB: - case INST_REPNE_SCASD: - case INST_REPNE_SCASQ: - case INST_REPNE_SCASW: - a._emitInstruction(_code); - return; - - default: - ASMJIT_ASSERT(0); - } - // ${SPECIAL_INSTRUCTION_HANDLING_END} - } - - switch (_operandsCount) - { - case 0: - a._emitInstruction(_code); - break; - case 1: - a._emitInstruction(_code, &_operands[0]); - break; - case 2: - a._emitInstruction(_code, &_operands[0], &_operands[1]); - break; - case 3: - a._emitInstruction(_code, &_operands[0], &_operands[1], &_operands[2]); - break; - default: - ASMJIT_ASSERT(0); - break; - } -} - -int EInstruction::getMaxSize() const ASMJIT_NOTHROW -{ - // TODO: Do something more exact. - return 15; -} - -bool EInstruction::_tryUnuseVar(VarData* v) ASMJIT_NOTHROW -{ - for (uint32_t i = 0; i < _variablesCount; i++) - { - if (_variables[i].vdata == v) - { - _variables[i].vflags |= VARIABLE_ALLOC_UNUSE_AFTER_USE; - return true; - } - } - - return false; -} - -ETarget* EInstruction::getJumpTarget() const ASMJIT_NOTHROW -{ - return NULL; -} - -// ============================================================================ -// [AsmJit::EJmp] -// ============================================================================ - -EJmp::EJmp(Compiler* c, uint32_t code, Operand* operandsData, uint32_t operandsCount) ASMJIT_NOTHROW : - EInstruction(c, code, operandsData, operandsCount) -{ - _jumpTarget = _compiler->_getTarget(_operands[0].getId()); - _jumpTarget->_jumpsCount++; - - _jumpNext = _jumpTarget->_from; - _jumpTarget->_from = this; - - // The 'jmp' is always taken, conditional jump can contain hint, we detect it. - _isTaken = (getCode() == INST_JMP) || - (operandsCount > 1 && - operandsData[1].isImm() && - reinterpret_cast(&operandsData[1])->getValue() == HINT_TAKEN); -} - -EJmp::~EJmp() ASMJIT_NOTHROW -{ -} - -void EJmp::prepare(CompilerContext& cc) ASMJIT_NOTHROW -{ - _offset = cc._currentOffset; - - // Update _isTaken to true if this is conditional backward jump. This behavior - // can be overridden by using HINT_NOT_TAKEN when using the instruction. - if (getCode() != INST_JMP && - _operandsCount == 1 && - _jumpTarget->getOffset() < getOffset()) - { - _isTaken = true; - } - - // Now patch all variables where jump location is in the active range. - if (_jumpTarget->getOffset() != INVALID_VALUE && cc._active) - { - VarData* first = cc._active; - VarData* var = first; - uint32_t jumpOffset = _jumpTarget->getOffset(); - - do { - if (var->firstEmittable) - { - ASMJIT_ASSERT(var->lastEmittable != NULL); - uint32_t start = var->firstEmittable->getOffset(); - uint32_t end = var->lastEmittable->getOffset(); - - if (jumpOffset >= start && jumpOffset <= end) var->lastEmittable = this; - } - var = var->nextActive; - } while (var != first); - } - - cc._currentOffset++; -} - -Emittable* EJmp::translate(CompilerContext& cc) ASMJIT_NOTHROW -{ - // Translate using EInstruction. - Emittable* ret = EInstruction::translate(cc); - - // We jump with emittable if its INST_JUMP (not based on condiiton) and it - // points into yet unknown location. - if (_code == INST_JMP && !_jumpTarget->isTranslated()) - { - cc.addBackwardCode(this); - ret = _jumpTarget; - } - else - { - _state = cc._saveState(); - if (_jumpTarget->isTranslated()) - { - _doJump(cc); - } - else - { - // State is not known, so we need to call _doJump() later. Compiler will - // do it for us. - cc.addForwardJump(this); - _jumpTarget->_state = _state; - } - - // Mark next code as unreachable, cleared by a next label (ETarget). - if (_code == INST_JMP) cc._unreachable = 1; - } - - // Need to traverse over all active variables and unuse them if their scope ends - // here. - if (cc._active) - { - VarData* first = cc._active; - VarData* var = first; - - do { - cc._unuseVarOnEndOfScope(this, var); - var = var->nextActive; - } while (var != first); - } - - return ret; -} - -void EJmp::emit(Assembler& a) ASMJIT_NOTHROW -{ - static const uint MAXIMUM_SHORT_JMP_SIZE = 127; - - // Try to minimize size of jump using SHORT jump (8-bit displacement) by - // traversing into the target and calculating the maximum code size. We - // end when code size reaches MAXIMUM_SHORT_JMP_SIZE. - if (!(_emitOptions & EMIT_OPTION_SHORT_JUMP) && getJumpTarget()->getOffset() > getOffset()) - { - // Calculate the code size. - uint codeSize = 0; - Emittable* cur = this->getNext(); - Emittable* target = getJumpTarget(); - - while (cur) - { - if (cur == target) - { - // Target found, we can tell assembler to generate short form of jump. - _emitOptions |= EMIT_OPTION_SHORT_JUMP; - goto end; - } - - int s = cur->getMaxSize(); - if (s == -1) break; - - codeSize += (uint)s; - if (codeSize > MAXIMUM_SHORT_JMP_SIZE) break; - - cur = cur->getNext(); - } - } - -end: - EInstruction::emit(a); -} - -void EJmp::_doJump(CompilerContext& cc) ASMJIT_NOTHROW -{ - // The state have to be already known. The _doJump() method is called by - // translate() or by Compiler in case that it's forward jump. - ASMJIT_ASSERT(_jumpTarget->getState()); - - if (getCode() == INST_JMP || (isTaken() && _jumpTarget->getOffset() < getOffset())) - { - // Instruction type is JMP or conditional jump that should be taken (likely). - // We can set state here instead of jumping out, setting state and jumping - // to _jumpTarget. - // - // NOTE: We can't use this technique if instruction is forward conditional - // jump. The reason is that when generating code we can't change state here, - // because the next instruction depends on it. - cc._restoreState(_jumpTarget->getState(), _jumpTarget->getOffset()); - } - else - { - // Instruction type is JMP or conditional jump that should be not normally - // taken. If we need add code that will switch between different states we - // add it after the end of function body (after epilog, using 'ExtraBlock'). - Compiler* compiler = cc.getCompiler(); - - Emittable* ext = cc.getExtraBlock(); - Emittable* old = compiler->setCurrentEmittable(ext); - - cc._restoreState(_jumpTarget->getState(), _jumpTarget->getOffset()); - - if (compiler->getCurrentEmittable() != ext) - { - // Add the jump to the target. - compiler->jmp(_jumpTarget->_label); - ext = compiler->getCurrentEmittable(); - - // The cc._restoreState() method emitted some instructions so we need to - // patch the jump. - Label L = compiler->newLabel(); - compiler->setCurrentEmittable(cc.getExtraBlock()); - compiler->bind(L); - - // Finally, patch the jump target. - ASMJIT_ASSERT(_operandsCount > 0); - _operands[0] = L; // Operand part (Label). - _jumpTarget = compiler->_getTarget(L.getId()); // Emittable part (ETarget). - } - - cc.setExtraBlock(ext); - compiler->setCurrentEmittable(old); - - // Assign state back. - cc._assignState(_state); - } -} - -ETarget* EJmp::getJumpTarget() const ASMJIT_NOTHROW -{ - return _jumpTarget; -} - -// ============================================================================ -// [AsmJit::EFunction] -// ============================================================================ - -EFunction::EFunction(Compiler* c) ASMJIT_NOTHROW : Emittable(c, EMITTABLE_FUNCTION) -{ - _argumentVariables = NULL; - Util::memset32(_hints, INVALID_VALUE, ASMJIT_ARRAY_SIZE(_hints)); - - // Stack is always aligned to 16-bytes when using 64-bit OS. - _isStackAlignedByOsTo16Bytes = CompilerUtil::isStack16ByteAligned(); - - // Manual aligning is autodetected by prepare() method. - _isStackAlignedByFnTo16Bytes = false; - - // Just clear to safe defaults. - _isNaked = false; - _isEspAdjusted = false; - _isCaller = false; - - _pePushPop = true; - _emitEMMS = false; - _emitSFence = false; - _emitLFence = false; - - _finished = false; - - _modifiedAndPreservedGP = 0; - _modifiedAndPreservedMM = 0; - _modifiedAndPreservedXMM = 0; - - _pePushPopStackSize = 0; - _peMovStackSize = 0; - _peAdjustStackSize = 0; - - _memStackSize = 0; - _memStackSize16 = 0; - - _functionCallStackSize = 0; - - _entryLabel = c->newLabel(); - _exitLabel = c->newLabel(); - - _prolog = Compiler_newObject(c, this); - _epilog = Compiler_newObject(c, this); - _end = Compiler_newObject(c); -} - -EFunction::~EFunction() ASMJIT_NOTHROW -{ -} - -void EFunction::prepare(CompilerContext& cc) ASMJIT_NOTHROW -{ - _offset = cc._currentOffset++; -} - -int EFunction::getMaxSize() const ASMJIT_NOTHROW -{ - // EFunction is NOP. - return 0; -} - -void EFunction::setPrototype( - uint32_t callingConvention, - const uint32_t* arguments, - uint32_t argumentsCount, - uint32_t returnValue) ASMJIT_NOTHROW -{ - _functionPrototype.setPrototype(callingConvention, arguments, argumentsCount, returnValue); -} - -void EFunction::setHint(uint32_t hint, uint32_t value) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(hint < ASMJIT_ARRAY_SIZE(_hints)); - _hints[hint] = value; -} - -void EFunction::_createVariables() ASMJIT_NOTHROW -{ - uint32_t i, count = _functionPrototype.getArgumentsCount(); - if (count == 0) return; - - _argumentVariables = reinterpret_cast(_compiler->getZone().zalloc(count * sizeof(VarData*))); - if (_argumentVariables == NULL) - { - _compiler->setError(ERROR_NO_HEAP_MEMORY); - return; - } - - char argNameStorage[64]; - char* argName = NULL; - - bool debug = _compiler->getLogger() != NULL; - if (debug) argName = argNameStorage; - - for (i = 0; i < count; i++) - { - FunctionPrototype::Argument& a = _functionPrototype.getArguments()[i]; - if (debug) snprintf(argName, ASMJIT_ARRAY_SIZE(argNameStorage), "arg_%u", i); - - uint32_t size = getVariableSize(a.variableType); - VarData* vdata = _compiler->_newVarData(argName, a.variableType, size); - - if (a.registerIndex != (uint32_t)INVALID_VALUE) - { - vdata->isRegArgument = true; - vdata->registerIndex = a.registerIndex; - } - - if (a.stackOffset != (int32_t)INVALID_VALUE) - { - vdata->isMemArgument = true; - vdata->homeMemoryOffset = a.stackOffset; - } - - _argumentVariables[i] = vdata; - } -} - -void EFunction::_prepareVariables(Emittable* first) ASMJIT_NOTHROW -{ - uint32_t i, count = _functionPrototype.getArgumentsCount(); - if (count == 0) return; - - for (i = 0; i < count; i++) - { - VarData* vdata = _argumentVariables[i]; - - // This is where variable scope starts. - vdata->firstEmittable = first; - // If this will not be changed then it will be deallocated immediately. - vdata->lastEmittable = first; - } -} - -void EFunction::_allocVariables(CompilerContext& cc) ASMJIT_NOTHROW -{ - uint32_t i, count = _functionPrototype.getArgumentsCount(); - if (count == 0) return; - - for (i = 0; i < count; i++) - { - VarData* vdata = _argumentVariables[i]; - - if (vdata->firstEmittable != NULL || - vdata->isRegArgument || - vdata->isMemArgument) - { - // Variable is used. - if (vdata->registerIndex != INVALID_VALUE) - { - vdata->state = VARIABLE_STATE_REGISTER; - // If variable is in register -> mark it as changed so it will not be - // lost by first spill. - vdata->changed = true; - cc._allocatedVariable(vdata); - } - else if (vdata->isMemArgument) - { - vdata->state = VARIABLE_STATE_MEMORY; - } - } - else - { - // Variable is not used. - vdata->registerIndex = INVALID_VALUE; - } - } -} - -void EFunction::_preparePrologEpilog(CompilerContext& cc) ASMJIT_NOTHROW -{ - const CpuInfo* cpuInfo = getCpuInfo(); - - _pePushPop = true; - _emitEMMS = false; - _emitSFence = false; - _emitLFence = false; - - uint32_t accessibleMemoryBelowStack = 0; - if (_functionPrototype.getCallingConvention() == CALL_CONV_X64U) - accessibleMemoryBelowStack = 128; - - if (_isCaller && (cc._memBytesTotal > 0 || _isStackAlignedByOsTo16Bytes)) - _isEspAdjusted = true; - - if (cc._memBytesTotal > accessibleMemoryBelowStack) - _isEspAdjusted = true; - - if (_hints[FUNCTION_HINT_NAKED] != INVALID_VALUE) - _isNaked = (bool)_hints[FUNCTION_HINT_NAKED]; - - if (_hints[FUNCTION_HINT_PUSH_POP_SEQUENCE] != INVALID_VALUE) - _pePushPop = (bool)_hints[FUNCTION_HINT_PUSH_POP_SEQUENCE]; - - if (_hints[FUNCTION_HINT_EMMS] != INVALID_VALUE) - _emitEMMS = (bool)_hints[FUNCTION_HINT_EMMS]; - - if (_hints[FUNCTION_HINT_SFENCE] != INVALID_VALUE) - _emitSFence = (bool)_hints[FUNCTION_HINT_SFENCE]; - - if (_hints[FUNCTION_HINT_LFENCE] != INVALID_VALUE) - _emitLFence = (bool)_hints[FUNCTION_HINT_LFENCE]; - - // Updated to respect comment from issue #47, align also when using MMX code. - if (!_isStackAlignedByOsTo16Bytes && !_isNaked && (cc._mem16BlocksCount + (cc._mem8BlocksCount > 0))) - { - // Have to align stack to 16-bytes. - _isStackAlignedByFnTo16Bytes = true; - _isEspAdjusted = true; - } - - _modifiedAndPreservedGP = cc._modifiedGPRegisters & _functionPrototype.getPreservedGP() & ~Util::maskFromIndex(REG_INDEX_ESP); - _modifiedAndPreservedMM = cc._modifiedMMRegisters & _functionPrototype.getPreservedMM(); - _modifiedAndPreservedXMM = cc._modifiedXMMRegisters & _functionPrototype.getPreservedXMM(); - - _movDqaInstruction = (_isStackAlignedByOsTo16Bytes || !_isNaked) ? INST_MOVDQA : INST_MOVDQU; - - // Prolog & Epilog stack size. - { - int32_t memGP = Util::bitCount(_modifiedAndPreservedGP) * sizeof(sysint_t); - int32_t memMM = Util::bitCount(_modifiedAndPreservedMM) * 8; - int32_t memXMM = Util::bitCount(_modifiedAndPreservedXMM) * 16; - - if (_pePushPop) - { - _pePushPopStackSize = memGP; - _peMovStackSize = memXMM + Util::alignTo16(memMM); - } - else - { - _pePushPopStackSize = 0; - _peMovStackSize = memXMM + Util::alignTo16(memMM + memGP); - } - } - - if (_isStackAlignedByFnTo16Bytes) - { - _peAdjustStackSize += Util::deltaTo16(_pePushPopStackSize); - } - else - { - int32_t v = 16 - sizeof(sysint_t); - if (!_isNaked) v -= sizeof(sysint_t); - - v -= _pePushPopStackSize & 15; - if (v < 0) v += 16; - _peAdjustStackSize = v; - - //_peAdjustStackSize += Util::deltaTo16(_pePushPopStackSize + v); - } - - // Memory stack size. - _memStackSize = cc._memBytesTotal; - _memStackSize16 = Util::alignTo16(_memStackSize); - - if (_isNaked) - { - cc._argumentsBaseReg = REG_INDEX_ESP; - cc._argumentsBaseOffset = (_isEspAdjusted) - ? (_functionCallStackSize + _memStackSize16 + _peMovStackSize + _pePushPopStackSize + _peAdjustStackSize) - : (_pePushPopStackSize); - } - else - { - cc._argumentsBaseReg = REG_INDEX_EBP; - cc._argumentsBaseOffset = sizeof(sysint_t); - } - - cc._variablesBaseReg = REG_INDEX_ESP; - cc._variablesBaseOffset = _functionCallStackSize; - if (!_isEspAdjusted) - cc._variablesBaseOffset = -_memStackSize16 - _peMovStackSize - _peAdjustStackSize; -} - -void EFunction::_dumpFunction(CompilerContext& cc) ASMJIT_NOTHROW -{ - Logger* logger = _compiler->getLogger(); - ASMJIT_ASSERT(logger != NULL); - - uint32_t i; - char _buf[1024]; - char* p; - - // Log function prototype. - { - uint32_t argumentsCount = _functionPrototype.getArgumentsCount(); - bool first = true; - - logger->logString("; Function Prototype:\n"); - logger->logString(";\n"); - - for (i = 0; i < argumentsCount; i++) - { - const FunctionPrototype::Argument& a = _functionPrototype.getArguments()[i]; - VarData* vdata = _argumentVariables[i]; - - if (first) - { - logger->logString("; IDX| Type | Sz | Home |\n"); - logger->logString("; ---+----------+----+----------------+\n"); - } - - char* memHome = memHome = _buf; - - if (a.registerIndex != INVALID_VALUE) - { - BaseReg regOp(a.registerIndex | REG_TYPE_GPN, 0); - dumpOperand(memHome, ®Op, REG_TYPE_GPN)[0] = '\0'; - } - else - { - Mem memOp; - memOp._mem.base = REG_INDEX_ESP; - memOp._mem.displacement = a.stackOffset; - dumpOperand(memHome, &memOp, REG_TYPE_GPN)[0] = '\0'; - } - - logger->logFormat("; %-3u| %-9s| %-3u| %-15s|\n", - // Argument index. - i, - // Argument type. - vdata->type < _VARIABLE_TYPE_COUNT ? variableInfo[vdata->type].name : "invalid", - // Argument size. - vdata->size, - // Argument memory home. - memHome - ); - - first = false; - } - logger->logString(";\n"); - } - - // Log variables. - { - uint32_t variablesCount = (uint32_t)_compiler->_varData.getLength(); - bool first = true; - - logger->logString("; Variables:\n"); - logger->logString(";\n"); - - for (i = 0; i < variablesCount; i++) - { - VarData* vdata = _compiler->_varData[i]; - - // If this variable is not related to this function then skip it. - if (vdata->scope != this) continue; - - // Get some information about variable type. - const VariableInfo& vinfo = variableInfo[vdata->type]; - - if (first) - { - logger->logString("; ID | Type | Sz | Home | Register Access | Memory Access |\n"); - logger->logString("; ---+----------+----+----------------+-------------------+-------------------+\n"); - } - - char* memHome = (char*)"[None]"; - if (vdata->homeMemoryData != NULL) - { - VarMemBlock* memBlock = reinterpret_cast(vdata->homeMemoryData); - memHome = _buf; - - Mem memOp; - if (vdata->isMemArgument) - { - const FunctionPrototype::Argument& a = _functionPrototype.getArguments()[i]; - - memOp._mem.base = cc._argumentsBaseReg; - memOp._mem.displacement += cc._argumentsBaseOffset; - memOp._mem.displacement += a.stackOffset; - } - else - { - memOp._mem.base = cc._variablesBaseReg; - memOp._mem.displacement += cc._variablesBaseOffset; - memOp._mem.displacement += memBlock->offset; - } - dumpOperand(memHome, &memOp, REG_TYPE_GPN)[0] = '\0'; - } - - logger->logFormat("; %-3u| %-9s| %-3u| %-15s| r=%-4uw=%-4ux=%-4u| r=%-4uw=%-4ux=%-4u|\n", - // Variable id. - (uint)(i & OPERAND_ID_VALUE_MASK), - // Variable type. - vdata->type < _VARIABLE_TYPE_COUNT ? vinfo.name : "invalid", - // Variable size. - vdata->size, - // Variable memory home. - memHome, - // Register access count. - (unsigned int)vdata->registerReadCount, - (unsigned int)vdata->registerWriteCount, - (unsigned int)vdata->registerRWCount, - // Memory access count. - (unsigned int)vdata->memoryReadCount, - (unsigned int)vdata->memoryWriteCount, - (unsigned int)vdata->memoryRWCount - ); - first = false; - } - logger->logString(";\n"); - } - - // Log modified registers. - { - p = _buf; - - uint32_t r; - uint32_t modifiedRegisters = 0; - - for (r = 0; r < 3; r++) - { - bool first = true; - uint32_t regs; - uint32_t type; - - switch (r) - { - case 0: - regs = cc._modifiedGPRegisters; - type = REG_TYPE_GPN; - p = Util::mycpy(p, "; GP : "); - break; - case 1: - regs = cc._modifiedMMRegisters; - type = REG_TYPE_MM; - p = Util::mycpy(p, "; MM : "); - break; - case 2: - regs = cc._modifiedXMMRegisters; - type = REG_TYPE_XMM; - p = Util::mycpy(p, "; XMM: "); - break; - default: - ASMJIT_ASSERT(0); - } - - for (i = 0; i < REG_NUM_BASE; i++) - { - if ((regs & Util::maskFromIndex(i)) != 0) - { - if (!first) { *p++ = ','; *p++ = ' '; } - p = dumpRegister(p, type, i); - first = false; - modifiedRegisters++; - } - } - *p++ = '\n'; - } - *p = '\0'; - - logger->logFormat("; Modified registers (%u):\n", (unsigned int)modifiedRegisters); - logger->logString(_buf); - } - - logger->logString("\n"); -} - -void EFunction::_emitProlog(CompilerContext& cc) ASMJIT_NOTHROW -{ - uint32_t i, mask; - uint32_t preservedGP = _modifiedAndPreservedGP; - uint32_t preservedMM = _modifiedAndPreservedMM; - uint32_t preservedXMM = _modifiedAndPreservedXMM; - - int32_t stackSubtract = - _functionCallStackSize + - _memStackSize16 + - _peMovStackSize + - _peAdjustStackSize; - int32_t nspPos; - - if (_compiler->getLogger()) - { - // Here function prolog starts. - _compiler->comment("Prolog"); - } - - // Emit standard prolog entry code (but don't do it if function is set to be - // naked). - // - // Also see the _prologEpilogStackAdjust variable. If function is naked (so - // prolog and epilog will not contain "push ebp" and "mov ebp, esp", we need - // to adjust stack by 8 bytes in 64-bit mode (this will give us that stack - // will remain aligned to 16 bytes). - if (!_isNaked) - { - _compiler->emit(INST_PUSH, nbp); - _compiler->emit(INST_MOV, nbp, nsp); - } - - // Align manually stack-pointer to 16-bytes. - if (_isStackAlignedByFnTo16Bytes) - { - ASMJIT_ASSERT(!_isNaked); - _compiler->emit(INST_AND, nsp, imm(-16)); - } - - // Save GP registers using PUSH/POP. - if (preservedGP && _pePushPop) - { - for (i = 0, mask = 1; i < REG_NUM_GP; i++, mask <<= 1) - { - if (preservedGP & mask) _compiler->emit(INST_PUSH, gpn(i)); - } - } - - if (_isEspAdjusted) - { - nspPos = _memStackSize16; - if (stackSubtract) _compiler->emit(INST_SUB, nsp, imm(stackSubtract)); - } - else - { - nspPos = -(_peMovStackSize + _peAdjustStackSize); - //if (_pePushPop) nspPos += Util::bitCount(preservedGP) * sizeof(sysint_t); - } - - // Save XMM registers using MOVDQA/MOVDQU. - if (preservedXMM) - { - for (i = 0, mask = 1; i < REG_NUM_XMM; i++, mask <<= 1) - { - if (preservedXMM & mask) - { - _compiler->emit(_movDqaInstruction, dqword_ptr(nsp, nspPos), xmm(i)); - nspPos += 16; - } - } - } - - // Save MM registers using MOVQ. - if (preservedMM) - { - for (i = 0, mask = 1; i < 8; i++, mask <<= 1) - { - if (preservedMM & mask) - { - _compiler->emit(INST_MOVQ, qword_ptr(nsp, nspPos), mm(i)); - nspPos += 8; - } - } - } - - // Save GP registers using MOV. - if (preservedGP && !_pePushPop) - { - for (i = 0, mask = 1; i < REG_NUM_GP; i++, mask <<= 1) - { - if (preservedGP & mask) - { - _compiler->emit(INST_MOV, sysint_ptr(nsp, nspPos), gpn(i)); - nspPos += sizeof(sysint_t); - } - } - } - - if (_compiler->getLogger()) - { - _compiler->comment("Body"); - } -} - -void EFunction::_emitEpilog(CompilerContext& cc) ASMJIT_NOTHROW -{ - const CpuInfo* cpuInfo = getCpuInfo(); - - uint32_t i, mask; - uint32_t preservedGP = _modifiedAndPreservedGP; - uint32_t preservedMM = _modifiedAndPreservedMM; - uint32_t preservedXMM = _modifiedAndPreservedXMM; - - int32_t stackAdd = - _functionCallStackSize + - _memStackSize16 + - _peMovStackSize + - _peAdjustStackSize; - int32_t nspPos; - - nspPos = (_isEspAdjusted) - ? (_memStackSize16) - : -(_peMovStackSize + _peAdjustStackSize); - - if (_compiler->getLogger()) - { - _compiler->comment("Epilog"); - } - - // Restore XMM registers using MOVDQA/MOVDQU. - if (preservedXMM) - { - for (i = 0, mask = 1; i < REG_NUM_XMM; i++, mask <<= 1) - { - if (preservedXMM & mask) - { - _compiler->emit(_movDqaInstruction, xmm(i), dqword_ptr(nsp, nspPos)); - nspPos += 16; - } - } - } - - // Restore MM registers using MOVQ. - if (preservedMM) - { - for (i = 0, mask = 1; i < 8; i++, mask <<= 1) - { - if (preservedMM & mask) - { - _compiler->emit(INST_MOVQ, mm(i), qword_ptr(nsp, nspPos)); - nspPos += 8; - } - } - } - - // Restore GP registers using MOV. - if (preservedGP && !_pePushPop) - { - for (i = 0, mask = 1; i < REG_NUM_GP; i++, mask <<= 1) - { - if (preservedGP & mask) - { - _compiler->emit(INST_MOV, gpn(i), sysint_ptr(nsp, nspPos)); - nspPos += sizeof(sysint_t); - } - } - } - - if (_isEspAdjusted && stackAdd != 0) - _compiler->emit(INST_ADD, nsp, imm(stackAdd)); - - // Restore GP registers using POP. - if (preservedGP && _pePushPop) - { - for (i = REG_NUM_GP - 1, mask = 1 << i; (int32_t)i >= 0; i--, mask >>= 1) - { - if (preservedGP & mask) - { - _compiler->emit(INST_POP, gpn(i)); - } - } - } - - // Emit Emms. - if (_emitEMMS) _compiler->emit(INST_EMMS); - - // Emit SFence / LFence / MFence. - if ( _emitSFence && _emitLFence) _compiler->emit(INST_MFENCE); // MFence == SFence & LFence. - if ( _emitSFence && !_emitLFence) _compiler->emit(INST_SFENCE); // Only SFence. - if (!_emitSFence && _emitLFence) _compiler->emit(INST_LFENCE); // Only LFence. - - // Emit standard epilog leave code (if needed). - if (!_isNaked) - { - if (cpuInfo->vendorId == CPU_VENDOR_AMD) - { - // AMD seems to prefer LEAVE instead of MOV/POP sequence. - _compiler->emit(INST_LEAVE); - } - else - { - _compiler->emit(INST_MOV, nsp, nbp); - _compiler->emit(INST_POP, nbp); - } - } - - // Emit return using correct instruction. - if (_functionPrototype.getCalleePopsStack()) - _compiler->emit(INST_RET, imm((int16_t)_functionPrototype.getArgumentsStackSize())); - else - _compiler->emit(INST_RET); -} - -void EFunction::reserveStackForFunctionCall(int32_t size) -{ - size = Util::alignTo16(size); - - if (size > _functionCallStackSize) _functionCallStackSize = size; - _isCaller = true; -} - -// ============================================================================ -// [AsmJit::EProlog] -// ============================================================================ - -EProlog::EProlog(Compiler* c, EFunction* f) ASMJIT_NOTHROW : - Emittable(c, EMITTABLE_PROLOG), - _function(f) -{ -} - -EProlog::~EProlog() ASMJIT_NOTHROW -{ -} - -void EProlog::prepare(CompilerContext& cc) ASMJIT_NOTHROW -{ - _offset = cc._currentOffset++; - _function->_prepareVariables(this); -} - -Emittable* EProlog::translate(CompilerContext& cc) ASMJIT_NOTHROW -{ - _function->_allocVariables(cc); - return translated(); -} - -// ============================================================================ -// [AsmJit::EEpilog] -// ============================================================================ - -EEpilog::EEpilog(Compiler* c, EFunction* f) ASMJIT_NOTHROW : - Emittable(c, EMITTABLE_EPILOG), - _function(f) -{ -} - -EEpilog::~EEpilog() ASMJIT_NOTHROW -{ -} - -void EEpilog::prepare(CompilerContext& cc) ASMJIT_NOTHROW -{ - _offset = cc._currentOffset++; -} - -Emittable* EEpilog::translate(CompilerContext& cc) ASMJIT_NOTHROW -{ - return translated(); -} - -// ============================================================================ -// [AsmJit::ECall] -// ============================================================================ - -ECall::ECall(Compiler* c, EFunction* caller, const Operand* target) ASMJIT_NOTHROW : - Emittable(c, EMITTABLE_CALL), - _caller(caller), - _target(*target), - _args(NULL), - _gpParams(0), - _mmParams(0), - _xmmParams(0), - _variablesCount(0), - _variables(NULL) -{ -} - -ECall::~ECall() ASMJIT_NOTHROW -{ - memset(_argumentToVarRecord, 0, sizeof(VarCallRecord*) * FUNC_MAX_ARGS); -} - -void ECall::prepare(CompilerContext& cc) ASMJIT_NOTHROW -{ - // Prepare is similar to EInstruction::prepare(). We collect unique variables - // and update statistics, but we don't use standard alloc/free register calls. - // - // The calling function is also unique in variable allocator point of view, - // because we need to alloc some variables that may be destroyed be the - // callee (okay, may not, but this is not guaranteed). - _offset = cc._currentOffset; - - // Tell EFunction that another function will be called inside. It needs this - // information to reserve stack for the call and to mark esp adjustable. - getCaller()->reserveStackForFunctionCall( - (int32_t)getPrototype().getArgumentsStackSize()); - - uint32_t i; - uint32_t argumentsCount = getPrototype().getArgumentsCount(); - uint32_t operandsCount = argumentsCount; - uint32_t variablesCount = 0; - - // Create registers used as arguments mask. - for (i = 0; i < argumentsCount; i++) - { - const FunctionPrototype::Argument& fArg = getPrototype().getArguments()[i]; - - if (fArg.registerIndex != INVALID_VALUE) - { - switch (fArg.variableType) - { - case VARIABLE_TYPE_GPD: - case VARIABLE_TYPE_GPQ: - _gpParams |= Util::maskFromIndex(fArg.registerIndex); - break; - case VARIABLE_TYPE_MM: - _mmParams |= Util::maskFromIndex(fArg.registerIndex); - break; - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - _xmmParams |= Util::maskFromIndex(fArg.registerIndex); - break; - default: - ASMJIT_ASSERT(0); - } - } - else - { - cc.getFunction()->mustAdjustEsp(); - } - } - - // Call address. - operandsCount++; - - // The first and the second return value. - if (!_ret[0].isNone()) operandsCount++; - if (!_ret[1].isNone()) operandsCount++; - -#define __GET_VARIABLE(__vardata__) \ - { \ - VarData* _candidate = __vardata__; \ - \ - for (var = cur; ;) \ - { \ - if (var == _variables) \ - { \ - var = cur++; \ - var->vdata = _candidate; \ - break; \ - } \ - \ - var--; \ - \ - if (var->vdata == _candidate) \ - { \ - break; \ - } \ - } \ - \ - ASMJIT_ASSERT(var != NULL); \ - } - - for (i = 0; i < operandsCount; i++) - { - Operand& o = (i < argumentsCount) - ? (_args[i]) - : (i == argumentsCount ? _target : _ret[i - argumentsCount - 1]); - - if (o.isVar()) - { - ASMJIT_ASSERT(o.getId() != INVALID_VALUE); - VarData* vdata = _compiler->_getVarData(o.getId()); - ASMJIT_ASSERT(vdata != NULL); - - if (vdata->workOffset == _offset) continue; - if (!cc._isActive(vdata)) cc._addActive(vdata); - - vdata->workOffset = _offset; - variablesCount++; - } - else if (o.isMem()) - { - if ((o.getId() & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(o.getId()); - ASMJIT_ASSERT(vdata != NULL); - - cc._markMemoryUsed(vdata); - if (!cc._isActive(vdata)) cc._addActive(vdata); - - continue; - } - else if ((o._mem.base & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(o._mem.base); - ASMJIT_ASSERT(vdata != NULL); - - if (vdata->workOffset == _offset) continue; - if (!cc._isActive(vdata)) cc._addActive(vdata); - - vdata->workOffset = _offset; - variablesCount++; - } - - if ((o._mem.index & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(o._mem.index); - ASMJIT_ASSERT(vdata != NULL); - - if (vdata->workOffset == _offset) continue; - if (!cc._isActive(vdata)) cc._addActive(vdata); - - vdata->workOffset = _offset; - variablesCount++; - } - } - } - - // Traverse all active variables and set their firstCallable pointer to this - // call. This information can be used to choose between the preserved-first - // and preserved-last register allocation. - if (cc._active) - { - VarData* first = cc._active; - VarData* active = first; - do { - if (active->firstCallable == NULL) active->firstCallable = this; - active = active->nextActive; - } while (active != first); - } - - if (!variablesCount) - { - cc._currentOffset++; - return; - } - - _variables = reinterpret_cast(_compiler->getZone().zalloc(sizeof(VarCallRecord) * variablesCount)); - if (!_variables) - { - _compiler->setError(ERROR_NO_HEAP_MEMORY); - cc._currentOffset++; - return; - } - - _variablesCount = variablesCount; - memset(_variables, 0, sizeof(VarCallRecord) * variablesCount); - - VarCallRecord* cur = _variables; - VarCallRecord* var = NULL; - - for (i = 0; i < operandsCount; i++) - { - Operand& o = (i < argumentsCount) - ? (_args[i]) - : (i == argumentsCount ? _target : _ret[i - argumentsCount - 1]); - - if (o.isVar()) - { - VarData* vdata = _compiler->_getVarData(o.getId()); - ASMJIT_ASSERT(vdata != NULL); - - __GET_VARIABLE(vdata) - _argumentToVarRecord[i] = var; - - if (i < argumentsCount) - { - const FunctionPrototype::Argument& fArg = getPrototype().getArguments()[i]; - - if (fArg.registerIndex != INVALID_VALUE) - { - cc._newRegisterHomeIndex(vdata, fArg.registerIndex); - - switch (fArg.variableType) - { - case VARIABLE_TYPE_GPD: - case VARIABLE_TYPE_GPQ: - var->flags |= VarCallRecord::FLAG_IN_GP; - var->inCount++; - break; - - case VARIABLE_TYPE_MM: - var->flags |= VarCallRecord::FLAG_IN_MM; - var->inCount++; - break; - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - var->flags |= VarCallRecord::FLAG_IN_XMM; - var->inCount++; - break; - - default: - ASMJIT_ASSERT(0); - } - } - else - { - var->inCount++; - } - - vdata->registerReadCount++; - } - else if (i == argumentsCount) - { - uint32_t mask = ~getPrototype().getPreservedGP() & - ~getPrototype().getPassedGP() & - Util::maskUpToIndex(REG_NUM_GP); - - cc._newRegisterHomeIndex(vdata, Util::findFirstBit(mask)); - cc._newRegisterHomeMask(vdata, mask); - - var->flags |= VarCallRecord::FLAG_CALL_OPERAND_REG; - vdata->registerReadCount++; - } - else - { - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - case VARIABLE_TYPE_GPQ: - if (i == argumentsCount+1) - var->flags |= VarCallRecord::FLAG_OUT_EAX; - else - var->flags |= VarCallRecord::FLAG_OUT_EDX; - break; - - case VARIABLE_TYPE_X87: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_X87_1D: -#if defined(ASMJIT_X86) - if (i == argumentsCount+1) - var->flags |= VarCallRecord::FLAG_OUT_ST0; - else - var->flags |= VarCallRecord::FLAG_OUT_ST1; -#else - if (i == argumentsCount+1) - var->flags |= VarCallRecord::FLAG_OUT_XMM0; - else - var->flags |= VarCallRecord::FLAG_OUT_XMM1; -#endif - break; - - case VARIABLE_TYPE_MM: - var->flags |= VarCallRecord::FLAG_OUT_MM0; - break; - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_2D: - if (i == argumentsCount+1) - var->flags |= VarCallRecord::FLAG_OUT_XMM0; - else - var->flags |= VarCallRecord::FLAG_OUT_XMM1; - break; - - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_1D: -#if defined(ASMJIT_X86) - if (i == argumentsCount+1) - var->flags |= VarCallRecord::FLAG_OUT_ST0; - else - var->flags |= VarCallRecord::FLAG_OUT_ST1; -#else - if (i == argumentsCount+1) - var->flags |= VarCallRecord::FLAG_OUT_XMM0; - else - var->flags |= VarCallRecord::FLAG_OUT_XMM1; -#endif - break; - - default: - ASMJIT_ASSERT(0); - } - - vdata->registerWriteCount++; - } - } - else if (o.isMem()) - { - ASMJIT_ASSERT(i == argumentsCount); - - if ((o.getId() & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(o.getId()); - ASMJIT_ASSERT(vdata != NULL); - - vdata->memoryReadCount++; - } - else if ((o._mem.base & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(reinterpret_cast(o).getBase()); - ASMJIT_ASSERT(vdata != NULL); - - vdata->registerReadCount++; - - __GET_VARIABLE(vdata) - var->flags |= VarCallRecord::FLAG_CALL_OPERAND_REG | VarCallRecord::FLAG_CALL_OPERAND_MEM; - } - - if ((o._mem.index & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(reinterpret_cast(o).getIndex()); - ASMJIT_ASSERT(vdata != NULL); - - vdata->registerReadCount++; - - __GET_VARIABLE(vdata) - var->flags |= VarCallRecord::FLAG_CALL_OPERAND_REG | VarCallRecord::FLAG_CALL_OPERAND_MEM; - } - } - } - - // Traverse all variables and update firstEmittable / lastEmittable. This - // function is called from iterator that scans emittables using forward - // direction so we can use this knowledge to optimize the process. - // - // Same code is in EInstruction::prepare(). - for (i = 0; i < _variablesCount; i++) - { - VarData* v = _variables[i].vdata; - - // First emittable (begin of variable scope). - if (v->firstEmittable == NULL) v->firstEmittable = this; - - // Last emittable (end of variable scope). - v->lastEmittable = this; - } - - cc._currentOffset++; - -#undef __GET_VARIABLE -} - -Emittable* ECall::translate(CompilerContext& cc) ASMJIT_NOTHROW -{ - uint32_t i; - uint32_t preserved, mask; - - uint32_t temporaryGpReg; - uint32_t temporaryXmmReg; - - uint32_t offset = cc._currentOffset; - Compiler* compiler = cc.getCompiler(); - - // Constants. - const FunctionPrototype::Argument* targs = getPrototype().getArguments(); - - uint32_t argumentsCount = getPrototype().getArgumentsCount(); - uint32_t variablesCount = _variablesCount; - - // Processed arguments. - uint8_t processed[FUNC_MAX_ARGS] = { 0 }; - - compiler->comment("Function Call"); - - // These variables are used by the instruction and we set current offset - // to their work offsets -> The getSpillCandidate() method never returns - // the variable used by this instruction. - for (i = 0; i < variablesCount; i++) - { - _variables[i].vdata->workOffset = offset; - - // Init back-reference to VarCallRecord. - _variables[i].vdata->tempPtr = &_variables[i]; - } - - // -------------------------------------------------------------------------- - // STEP 1: - // - // Spill variables which are not used by the function call and have to - // be destroyed. These registers may be used by callee. - // -------------------------------------------------------------------------- - - preserved = getPrototype().getPreservedGP(); - for (i = 0, mask = 1; i < REG_NUM_GP; i++, mask <<= 1) - { - VarData* vdata = cc._state.gp[i]; - if (vdata && vdata->workOffset != offset && (preserved & mask) == 0) - { - cc.spillGPVar(vdata); - } - } - - preserved = getPrototype().getPreservedMM(); - for (i = 0, mask = 1; i < REG_NUM_MM; i++, mask <<= 1) - { - VarData* vdata = cc._state.mm[i]; - if (vdata && vdata->workOffset != offset && (preserved & mask) == 0) - { - cc.spillMMVar(vdata); - } - } - - preserved = getPrototype().getPreservedXMM(); - for (i = 0, mask = 1; i < REG_NUM_XMM; i++, mask <<= 1) - { - VarData* vdata = cc._state.xmm[i]; - if (vdata && vdata->workOffset != offset && (preserved & mask) == 0) - { - cc.spillXMMVar(vdata); - } - } - - // -------------------------------------------------------------------------- - // STEP 2: - // - // Move all arguments to the stack which all already in registers. - // -------------------------------------------------------------------------- - - for (i = 0; i < argumentsCount; i++) - { - if (processed[i]) continue; - - const FunctionPrototype::Argument& argType = targs[i]; - if (argType.registerIndex != INVALID_VALUE) continue; - - Operand& operand = _args[i]; - - if (operand.isVar()) - { - VarCallRecord* rec = _argumentToVarRecord[i]; - VarData* vdata = compiler->_getVarData(operand.getId()); - - if (vdata->registerIndex != INVALID_VALUE) - { - _moveAllocatedVariableToStack(cc, - vdata, argType); - - rec->inDone++; - processed[i] = true; - } - } - } - - // -------------------------------------------------------------------------- - // STEP 3: - // - // Spill all non-preserved variables we moved to stack in STEP #2. - // -------------------------------------------------------------------------- - - for (i = 0; i < argumentsCount; i++) - { - VarCallRecord* rec = _argumentToVarRecord[i]; - if (!rec || processed[i]) continue; - - if (rec->inDone >= rec->inCount) - { - VarData* vdata = rec->vdata; - if (vdata->registerIndex == INVALID_VALUE) continue; - - if (rec->outCount) - { - // Variable will be rewritten by function return value, it's not needed - // to spill it. It will be allocated again by ECall. - cc.unuseVar(rec->vdata, VARIABLE_STATE_UNUSED); - } - else - { - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - case VARIABLE_TYPE_GPQ: - if ((getPrototype().getPreservedGP() & Util::maskFromIndex(vdata->registerIndex)) == 0) - cc.spillGPVar(vdata); - break; - case VARIABLE_TYPE_MM: - if ((getPrototype().getPreservedMM() & Util::maskFromIndex(vdata->registerIndex)) == 0) - cc.spillMMVar(vdata); - break; - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_2D: - if ((getPrototype().getPreservedXMM() & Util::maskFromIndex(vdata->registerIndex)) == 0) - cc.spillXMMVar(vdata); - break; - } - } - } - } - - // -------------------------------------------------------------------------- - // STEP 4: - // - // Get temporary register that we can use to pass input function arguments. - // Now it's safe to do, because the non-needed variables should be spilled. - // -------------------------------------------------------------------------- - - temporaryGpReg = _findTemporaryGpRegister(cc); - temporaryXmmReg = _findTemporaryXmmRegister(cc); - - // If failed to get temporary register then we need just to pick one. - if (temporaryGpReg == INVALID_VALUE) - { - // TODO. - } - if (temporaryXmmReg == INVALID_VALUE) - { - // TODO. - } - - // -------------------------------------------------------------------------- - // STEP 5: - // - // Move all remaining arguments to the stack (we can use temporary register). - // or allocate it to the primary register. Also move immediates. - // -------------------------------------------------------------------------- - - for (i = 0; i < argumentsCount; i++) - { - if (processed[i]) continue; - - const FunctionPrototype::Argument& argType = targs[i]; - if (argType.registerIndex != INVALID_VALUE) continue; - - Operand& operand = _args[i]; - - if (operand.isVar()) - { - VarCallRecord* rec = _argumentToVarRecord[i]; - VarData* vdata = compiler->_getVarData(operand.getId()); - - _moveSpilledVariableToStack(cc, - vdata, argType, - temporaryGpReg, temporaryXmmReg); - - rec->inDone++; - processed[i] = true; - } - else if (operand.isImm()) - { - // TODO. - } - } - - // -------------------------------------------------------------------------- - // STEP 6: - // - // Allocate arguments to registers. - // -------------------------------------------------------------------------- - - bool didWork; - - do { - didWork = false; - - for (i = 0; i < argumentsCount; i++) - { - if (processed[i]) continue; - - VarCallRecord* rsrc = _argumentToVarRecord[i]; - - Operand& osrc = _args[i]; - ASMJIT_ASSERT(osrc.isVar()); - VarData* vsrc = compiler->_getVarData(osrc.getId()); - - const FunctionPrototype::Argument& srcArgType = targs[i]; - VarData* vdst = _getOverlappingVariable(cc, srcArgType); - - if (vsrc == vdst) - { - rsrc->inDone++; - processed[i] = true; - - didWork = true; - continue; - } - else if (vdst != NULL) - { - VarCallRecord* rdst = reinterpret_cast(vdst->tempPtr); - - if (rdst->inDone >= rdst->inCount && (rdst->flags & VarCallRecord::FLAG_CALL_OPERAND_REG) == 0) - { - // Safe to spill. - if (rdst->outCount || vdst->lastEmittable == this) - cc.unuseVar(vdst, VARIABLE_STATE_UNUSED); - else - cc.spillVar(vdst); - vdst = NULL; - } - else - { - uint32_t x = getPrototype().findArgumentByRegisterCode( - getVariableRegisterCode(vsrc->type, vsrc->registerIndex)); - bool doSpill = true; - - if ((getVariableClass(vdst->type) & VariableInfo::CLASS_GP) != 0) - { - // Try to emit mov to register which is possible for call() operand. - if (x == INVALID_VALUE && (rdst->flags & VarCallRecord::FLAG_CALL_OPERAND_REG) != 0) - { - uint32_t rIndex; - uint32_t rBit; - - // The mask which contains registers which are not-preserved - // (these that might be clobbered by the callee) and which are - // not used to pass function arguments. Each register contained - // in this mask is ideal to be used by call() instruction. - uint32_t possibleMask = ~getPrototype().getPreservedGP() & - ~getPrototype().getPassedGP() & - Util::maskUpToIndex(REG_NUM_GP); - - if (possibleMask != 0) - { - for (rIndex = 0, rBit = 1; rIndex < REG_NUM_GP; rIndex++, rBit <<= 1) - { - if ((possibleMask & rBit) != 0) - { - if (cc._state.gp[rIndex] == NULL) - { - // This is the best possible solution, the register is - // free. We do not need to continue with this loop, the - // rIndex will be used by the call(). - break; - } - else - { - // Wait until the register is freed or try to find another. - doSpill = false; - didWork = true; - } - } - } - } - else - { - // Try to find a register which is free and which is not used - // to pass a function argument. - possibleMask = getPrototype().getPreservedGP(); - - for (rIndex = 0, rBit = 1; rIndex < REG_NUM_GP; rIndex++, rBit <<= 1) - { - if ((possibleMask & rBit) != 0) - { - // Found one. - if (cc._state.gp[rIndex] == NULL) break; - } - } - } - - if (rIndex < REG_NUM_GP) - { - if (temporaryGpReg == vsrc->registerIndex) temporaryGpReg = rIndex; - compiler->emit(INST_MOV, gpn(rIndex), gpn(vsrc->registerIndex)); - - cc._state.gp[vsrc->registerIndex] = NULL; - cc._state.gp[rIndex] = vsrc; - - vsrc->registerIndex = rIndex; - cc._allocatedGPRegister(rIndex); - - doSpill = false; - didWork = true; - } - } - // Emit xchg instead of spill/alloc if possible. - else if (x != INVALID_VALUE) - { - const FunctionPrototype::Argument& dstArgType = targs[x]; - if (getVariableClass(dstArgType.variableType) == getVariableClass(srcArgType.variableType)) - { - uint32_t dstIndex = vdst->registerIndex; - uint32_t srcIndex = vsrc->registerIndex; - - if (srcIndex == dstArgType.registerIndex) - { -#if defined(ASMJIT_X64) - if (vdst->type != VARIABLE_TYPE_GPD || vsrc->type != VARIABLE_TYPE_GPD) - compiler->emit(INST_XCHG, gpq(dstIndex), gpq(srcIndex)); - else -#endif - compiler->emit(INST_XCHG, gpd(dstIndex), gpd(srcIndex)); - - cc._state.gp[srcIndex] = vdst; - cc._state.gp[dstIndex] = vsrc; - - vdst->registerIndex = srcIndex; - vsrc->registerIndex = dstIndex; - - rdst->inDone++; - rsrc->inDone++; - - processed[i] = true; - processed[x] = true; - - doSpill = false; - } - } - } - } - - if (doSpill) - { - cc.spillVar(vdst); - vdst = NULL; - } - } - } - - if (vdst == NULL) - { - VarCallRecord* rec = reinterpret_cast(vsrc->tempPtr); - - _moveSrcVariableToRegister(cc, vsrc, srcArgType); - - switch (srcArgType.variableType) - { - case VARIABLE_TYPE_GPD: - case VARIABLE_TYPE_GPQ: - cc._markGPRegisterModified(srcArgType.registerIndex); - break; - case VARIABLE_TYPE_MM: - cc._markMMRegisterModified(srcArgType.registerIndex); - break; - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_2D: - cc._markMMRegisterModified(srcArgType.registerIndex); - break; - } - - rec->inDone++; - processed[i] = true; - } - } - } while (didWork); - - // -------------------------------------------------------------------------- - // STEP 7: - // - // Allocate operand used by CALL instruction. - // -------------------------------------------------------------------------- - - for (i = 0; i < variablesCount; i++) - { - VarCallRecord& r = _variables[i]; - if ((r.flags & VarCallRecord::FLAG_CALL_OPERAND_REG) && - (r.vdata->registerIndex == INVALID_VALUE)) - { - // If the register is not allocated and the call form is 'call reg' then - // it's possible to keep it in memory. - if ((r.flags & VarCallRecord::FLAG_CALL_OPERAND_MEM) == 0) - { - _target = GPVarFromData(r.vdata).m(); - break; - } - - if (temporaryGpReg == INVALID_VALUE) - temporaryGpReg = _findTemporaryGpRegister(cc); - - cc.allocGPVar(r.vdata, - Util::maskFromIndex(temporaryGpReg), - VARIABLE_ALLOC_REGISTER | VARIABLE_ALLOC_READ); - } - } - - cc.translateOperands(&_target, 1); - - // -------------------------------------------------------------------------- - // STEP 8: - // - // Spill all preserved variables. - // -------------------------------------------------------------------------- - - preserved = getPrototype().getPreservedGP(); - for (i = 0, mask = 1; i < REG_NUM_GP; i++, mask <<= 1) - { - VarData* vdata = cc._state.gp[i]; - if (vdata && (preserved & mask) == 0) - { - VarCallRecord* rec = reinterpret_cast(vdata->tempPtr); - if (rec && (rec->outCount || rec->flags & VarCallRecord::FLAG_UNUSE_AFTER_USE || vdata->lastEmittable == this)) - cc.unuseVar(vdata, VARIABLE_STATE_UNUSED); - else - cc.spillGPVar(vdata); - } - } - - preserved = getPrototype().getPreservedMM(); - for (i = 0, mask = 1; i < REG_NUM_MM; i++, mask <<= 1) - { - VarData* vdata = cc._state.mm[i]; - if (vdata && (preserved & mask) == 0) - { - VarCallRecord* rec = reinterpret_cast(vdata->tempPtr); - if (rec && (rec->outCount || vdata->lastEmittable == this)) - cc.unuseVar(vdata, VARIABLE_STATE_UNUSED); - else - cc.spillMMVar(vdata); - } - } - - preserved = getPrototype().getPreservedXMM(); - for (i = 0, mask = 1; i < REG_NUM_XMM; i++, mask <<= 1) - { - VarData* vdata = cc._state.xmm[i]; - if (vdata && (preserved & mask) == 0) - { - VarCallRecord* rec = reinterpret_cast(vdata->tempPtr); - if (rec && (rec->outCount || vdata->lastEmittable == this)) - cc.unuseVar(vdata, VARIABLE_STATE_UNUSED); - else - cc.spillXMMVar(vdata); - } - } - - // -------------------------------------------------------------------------- - // STEP 9: - // - // Emit CALL instruction. - // -------------------------------------------------------------------------- - - compiler->emit(INST_CALL, _target); - - // Restore the stack offset. - if (getPrototype().getCalleePopsStack()) - { - int32_t s = (int32_t)getPrototype().getArgumentsStackSize(); - if (s) compiler->emit(INST_SUB, nsp, imm(s)); - } - - // -------------------------------------------------------------------------- - // STEP 10: - // - // Prepare others for return value(s) and cleanup. - // -------------------------------------------------------------------------- - - // Clear temp data, see AsmJit::VarData::temp why it's needed. - for (i = 0; i < variablesCount; i++) - { - VarCallRecord* rec = &_variables[i]; - VarData* vdata = rec->vdata; - - if (rec->flags & (VarCallRecord::FLAG_OUT_EAX | VarCallRecord::FLAG_OUT_EDX)) - { - if (getVariableClass(vdata->type) & VariableInfo::CLASS_GP) - { - cc.allocGPVar(vdata, - Util::maskFromIndex((rec->flags & VarCallRecord::FLAG_OUT_EAX) != 0 - ? REG_INDEX_EAX - : REG_INDEX_EDX), - VARIABLE_ALLOC_REGISTER | VARIABLE_ALLOC_WRITE); - vdata->changed = true; - } - } - - if (rec->flags & (VarCallRecord::FLAG_OUT_MM0)) - { - if (getVariableClass(vdata->type) & VariableInfo::CLASS_MM) - { - cc.allocMMVar(vdata, Util::maskFromIndex(REG_INDEX_MM0), - VARIABLE_ALLOC_REGISTER | VARIABLE_ALLOC_WRITE); - vdata->changed = true; - } - } - - if (rec->flags & (VarCallRecord::FLAG_OUT_XMM0 | VarCallRecord::FLAG_OUT_XMM1)) - { - if (getVariableClass(vdata->type) & VariableInfo::CLASS_XMM) - { - cc.allocXMMVar(vdata, - Util::maskFromIndex((rec->flags & VarCallRecord::FLAG_OUT_XMM0) != 0 - ? REG_INDEX_XMM0 - : REG_INDEX_XMM1), - VARIABLE_ALLOC_REGISTER | VARIABLE_ALLOC_WRITE); - vdata->changed = true; - } - } - - if (rec->flags & (VarCallRecord::FLAG_OUT_ST0 | VarCallRecord::FLAG_OUT_ST1)) - { - if (getVariableClass(vdata->type) & VariableInfo::CLASS_XMM) - { - Mem mem(cc._getVarMem(vdata)); - cc.unuseVar(vdata, VARIABLE_STATE_MEMORY); - - switch (vdata->type) - { - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - { - mem.setSize(4); - compiler->emit(INST_FSTP, mem); - break; - } - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - { - mem.setSize(8); - compiler->emit(INST_FSTP, mem); - break; - } - default: - { - compiler->comment("*** WARNING: Can't convert float return value to untyped XMM\n"); - break; - } - } - } - } - - // Cleanup. - vdata->tempPtr = NULL; - } - - for (i = 0; i < variablesCount; i++) - { - cc._unuseVarOnEndOfScope(this, &_variables[i]); - } - - return translated(); -} - -int ECall::getMaxSize() const ASMJIT_NOTHROW -{ - // TODO: Not optimal. - return 15; -} - -bool ECall::_tryUnuseVar(VarData* v) ASMJIT_NOTHROW -{ - for (uint32_t i = 0; i < _variablesCount; i++) - { - if (_variables[i].vdata == v) - { - _variables[i].flags |= VarCallRecord::FLAG_UNUSE_AFTER_USE; - return true; - } - } - - return false; -} - -uint32_t ECall::_findTemporaryGpRegister(CompilerContext& cc) ASMJIT_NOTHROW -{ - uint32_t i; - uint32_t mask; - - uint32_t passedGP = getPrototype().getPassedGP(); - uint32_t candidate = INVALID_VALUE; - - // Find all registers used to pass function arguments. We shouldn't use these - // if possible. - for (i = 0, mask = 1; i < REG_NUM_GP; i++, mask <<= 1) - { - if (cc._state.gp[i] == NULL) - { - // If this register is used to pass arguments to function, we will mark - // it and use it only if there is no other one. - if ((passedGP & mask) != 0) - candidate = i; - else - return i; - } - } - - return candidate; -} - -uint32_t ECall::_findTemporaryXmmRegister(CompilerContext& cc) ASMJIT_NOTHROW -{ - uint32_t i; - uint32_t mask; - - uint32_t passedXMM = getPrototype().getPassedXMM(); - uint32_t candidate = INVALID_VALUE; - - // Find all registers used to pass function arguments. We shouldn't use these - // if possible. - for (i = 0, mask = 1; i < REG_NUM_XMM; i++, mask <<= 1) - { - if (cc._state.xmm[i] == NULL) - { - // If this register is used to pass arguments to function, we will mark - // it and use it only if there is no other one. - if ((passedXMM & mask) != 0) - candidate = i; - else - return i; - } - } - - return candidate; -} - -VarData* ECall::_getOverlappingVariable(CompilerContext& cc, - const FunctionPrototype::Argument& argType) const ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(argType.variableType != INVALID_VALUE); - - switch (argType.variableType) - { - case VARIABLE_TYPE_GPD: - case VARIABLE_TYPE_GPQ: - return cc._state.gp[argType.registerIndex]; - case VARIABLE_TYPE_MM: - return cc._state.mm[argType.registerIndex]; - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_2D: - return cc._state.xmm[argType.registerIndex]; - } - - return NULL; -} - -void ECall::_moveAllocatedVariableToStack(CompilerContext& cc, VarData* vdata, const FunctionPrototype::Argument& argType) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(argType.registerIndex == INVALID_VALUE); - ASMJIT_ASSERT(vdata->registerIndex != INVALID_VALUE); - - Compiler* compiler = cc.getCompiler(); - - uint32_t src = vdata->registerIndex; - Mem dst = ptr(nsp, -(int)sizeof(sysint_t) + argType.stackOffset); - - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - switch (argType.variableType) - { - case VARIABLE_TYPE_GPD: - compiler->emit(INST_MOV, dst, gpd(src)); - return; -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOV, dst, gpq(src)); - return; -#endif // ASMJIT_X64 - } - break; - -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - switch (argType.variableType) - { - case VARIABLE_TYPE_GPD: - compiler->emit(INST_MOV, dst, gpd(src)); - return; - case VARIABLE_TYPE_GPQ: - compiler->emit(INST_MOV, dst, gpq(src)); - return; - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVQ, dst, gpq(src)); - return; - } - break; -#endif // ASMJIT_X64 - - case VARIABLE_TYPE_MM: - switch (argType.variableType) - { - case VARIABLE_TYPE_GPD: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_XMM_1F: - compiler->emit(INST_MOVD, dst, mm(src)); - return; - case VARIABLE_TYPE_GPQ: - case VARIABLE_TYPE_MM: - case VARIABLE_TYPE_X87_1D: - case VARIABLE_TYPE_XMM_1D: - compiler->emit(INST_MOVQ, dst, mm(src)); - return; - } - break; - - // We allow incompatible types here, because the called can convert them - // to correct format before function is called. - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_2D: - switch (argType.variableType) - { - case VARIABLE_TYPE_XMM: - compiler->emit(INST_MOVDQU, dst, xmm(src)); - return; - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - compiler->emit(INST_MOVUPS, dst, xmm(src)); - return; - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_MOVUPD, dst, xmm(src)); - return; - } - break; - - case VARIABLE_TYPE_XMM_1F: - switch (argType.variableType) - { - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_MOVSS, dst, xmm(src)); - return; - } - break; - - case VARIABLE_TYPE_XMM_1D: - switch (argType.variableType) - { - case VARIABLE_TYPE_X87_1D: - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_MOVSD, dst, xmm(src)); - return; - } - break; - } - - compiler->setError(ERROR_INCOMPATIBLE_ARGUMENT); -} - -void ECall::_moveSpilledVariableToStack(CompilerContext& cc, - VarData* vdata, const FunctionPrototype::Argument& argType, - uint32_t temporaryGpReg, - uint32_t temporaryXmmReg) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(argType.registerIndex == INVALID_VALUE); - ASMJIT_ASSERT(vdata->registerIndex == INVALID_VALUE); - - Compiler* compiler = cc.getCompiler(); - - Mem src = cc._getVarMem(vdata); - Mem dst = ptr(nsp, -(int)sizeof(sysint_t) + argType.stackOffset); - - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - switch (argType.variableType) - { - case VARIABLE_TYPE_GPD: - compiler->emit(INST_MOV, gpd(temporaryGpReg), src); - compiler->emit(INST_MOV, dst, gpd(temporaryGpReg)); - return; -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOV, gpd(temporaryGpReg), src); - compiler->emit(INST_MOV, dst, gpq(temporaryGpReg)); - return; -#endif // ASMJIT_X64 - } - break; - -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - switch (argType.variableType) - { - case VARIABLE_TYPE_GPD: - compiler->emit(INST_MOV, gpd(temporaryGpReg), src); - compiler->emit(INST_MOV, dst, gpd(temporaryGpReg)); - return; - case VARIABLE_TYPE_GPQ: - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOV, gpq(temporaryGpReg), src); - compiler->emit(INST_MOV, dst, gpq(temporaryGpReg)); - return; - } - break; -#endif // ASMJIT_X64 - - case VARIABLE_TYPE_MM: - switch (argType.variableType) - { - case VARIABLE_TYPE_GPD: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_XMM_1F: - compiler->emit(INST_MOV, gpd(temporaryGpReg), src); - compiler->emit(INST_MOV, dst, gpd(temporaryGpReg)); - return; - case VARIABLE_TYPE_GPQ: - case VARIABLE_TYPE_MM: - case VARIABLE_TYPE_X87_1D: - case VARIABLE_TYPE_XMM_1D: - // TODO - return; - } - break; - - // We allow incompatible types here, because the called can convert them - // to correct format before function is called. - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_2D: - switch (argType.variableType) - { - case VARIABLE_TYPE_XMM: - compiler->emit(INST_MOVDQU, xmm(temporaryXmmReg), src); - compiler->emit(INST_MOVDQU, dst, xmm(temporaryXmmReg)); - return; - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - compiler->emit(INST_MOVUPS, xmm(temporaryXmmReg), src); - compiler->emit(INST_MOVUPS, dst, xmm(temporaryXmmReg)); - return; - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_MOVUPD, xmm(temporaryXmmReg), src); - compiler->emit(INST_MOVUPD, dst, xmm(temporaryXmmReg)); - return; - } - break; - - case VARIABLE_TYPE_XMM_1F: - switch (argType.variableType) - { - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_MOVSS, xmm(temporaryXmmReg), src); - compiler->emit(INST_MOVSS, dst, xmm(temporaryXmmReg)); - return; - } - break; - - case VARIABLE_TYPE_XMM_1D: - switch (argType.variableType) - { - case VARIABLE_TYPE_X87_1D: - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_MOVSD, xmm(temporaryXmmReg), src); - compiler->emit(INST_MOVSD, dst, xmm(temporaryXmmReg)); - return; - } - break; - } - - compiler->setError(ERROR_INCOMPATIBLE_ARGUMENT); -} - -void ECall::_moveSrcVariableToRegister(CompilerContext& cc, - VarData* vdata, const FunctionPrototype::Argument& argType) ASMJIT_NOTHROW -{ - uint32_t dst = argType.registerIndex; - uint32_t src = vdata->registerIndex; - - Compiler* compiler = cc.getCompiler(); - - if (src != INVALID_VALUE) - { - switch (argType.variableType) - { - case VARIABLE_TYPE_GPD: - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: -#endif // ASMJIT_X64 - compiler->emit(INST_MOV, gpd(dst), gpd(src)); - return; - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVD, gpd(dst), mm(src)); - return; - } - break; - -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - compiler->emit(INST_MOV, gpd(dst), gpd(src)); - return; - case VARIABLE_TYPE_GPQ: - compiler->emit(INST_MOV, gpq(dst), gpq(src)); - return; - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVQ, gpq(dst), mm(src)); - return; - } - break; -#endif // ASMJIT_X64 - - case VARIABLE_TYPE_MM: - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - compiler->emit(INST_MOVD, gpd(dst), gpd(src)); - return; -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - compiler->emit(INST_MOVQ, gpq(dst), gpq(src)); - return; -#endif // ASMJIT_X64 - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVQ, mm(dst), mm(src)); - return; - } - break; - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_2D: - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - compiler->emit(INST_MOVD, xmm(dst), gpd(src)); - return; -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - compiler->emit(INST_MOVQ, xmm(dst), gpq(src)); - return; -#endif // ASMJIT_X64 - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVQ, xmm(dst), mm(src)); - return; - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_MOVDQA, xmm(dst), xmm(src)); - return; - } - break; - - case VARIABLE_TYPE_XMM_1F: - switch (vdata->type) - { - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVQ, xmm(dst), mm(src)); - return; - - case VARIABLE_TYPE_XMM: - compiler->emit(INST_MOVDQA, xmm(dst), xmm(src)); - return; - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - compiler->emit(INST_MOVSS, xmm(dst), xmm(src)); - return; - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_CVTSD2SS, xmm(dst), xmm(src)); - return; - } - break; - - case VARIABLE_TYPE_XMM_1D: - switch (vdata->type) - { - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVQ, xmm(dst), mm(src)); - return; - - case VARIABLE_TYPE_XMM: - compiler->emit(INST_MOVDQA, xmm(dst), xmm(src)); - return; - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - compiler->emit(INST_CVTSS2SD, xmm(dst), xmm(src)); - return; - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_MOVSD, xmm(dst), xmm(src)); - return; - } - break; - } - } - else - { - Mem mem = cc._getVarMem(vdata); - - switch (argType.variableType) - { - case VARIABLE_TYPE_GPD: - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: -#endif // ASMJIT_X64 - compiler->emit(INST_MOV, gpd(dst), mem); - return; - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVD, gpd(dst), mem); - return; - } - break; - -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - compiler->emit(INST_MOV, gpd(dst), mem); - return; - case VARIABLE_TYPE_GPQ: - compiler->emit(INST_MOV, gpq(dst), mem); - return; - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVQ, gpq(dst), mem); - return; - } - break; -#endif // ASMJIT_X64 - - case VARIABLE_TYPE_MM: - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - compiler->emit(INST_MOVD, gpd(dst), mem); - return; -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - compiler->emit(INST_MOVQ, gpq(dst), mem); - return; -#endif // ASMJIT_X64 - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVQ, mm(dst), mem); - return; - } - break; - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_2D: - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - compiler->emit(INST_MOVD, xmm(dst), mem); - return; -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - compiler->emit(INST_MOVQ, xmm(dst), mem); - return; -#endif // ASMJIT_X64 - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVQ, xmm(dst), mem); - return; - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_MOVDQA, xmm(dst), mem); - return; - } - break; - - case VARIABLE_TYPE_XMM_1F: - switch (vdata->type) - { - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVQ, xmm(dst), mem); - return; - - case VARIABLE_TYPE_XMM: - compiler->emit(INST_MOVDQA, xmm(dst), mem); - return; - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - compiler->emit(INST_MOVSS, xmm(dst), mem); - return; - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_CVTSD2SS, xmm(dst), mem); - return; - } - break; - - case VARIABLE_TYPE_XMM_1D: - switch (vdata->type) - { - case VARIABLE_TYPE_MM: - compiler->emit(INST_MOVQ, xmm(dst), mem); - return; - - case VARIABLE_TYPE_XMM: - compiler->emit(INST_MOVDQA, xmm(dst), mem); - return; - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - compiler->emit(INST_CVTSS2SD, xmm(dst), mem); - return; - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_MOVSD, xmm(dst), mem); - return; - } - break; - } - } - - compiler->setError(ERROR_INCOMPATIBLE_ARGUMENT); -} - -// Prototype & Arguments Management. -void ECall::_setPrototype( - uint32_t callingConvention, - const uint32_t* arguments, - uint32_t argumentsCount, - uint32_t returnValue) ASMJIT_NOTHROW -{ - _functionPrototype.setPrototype(callingConvention, arguments, argumentsCount, returnValue); - - _args = reinterpret_cast( - getCompiler()->getZone().zalloc(sizeof(Operand) * argumentsCount)); - memset(_args, 0, sizeof(Operand) * argumentsCount); -} - -bool ECall::setArgument(uint32_t i, const BaseVar& var) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(i < _functionPrototype.getArgumentsCount()); - if (i >= _functionPrototype.getArgumentsCount()) return false; - - _args[i] = var; - return true; -} - -bool ECall::setArgument(uint32_t i, const Imm& imm) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(i < _functionPrototype.getArgumentsCount()); - if (i >= _functionPrototype.getArgumentsCount()) return false; - - _args[i] = imm; - return true; -} - -bool ECall::setReturn(const Operand& first, const Operand& second) ASMJIT_NOTHROW -{ - _ret[0] = first; - _ret[1] = second; - - return true; -} - -// ============================================================================ -// [AsmJit::ERet] -// ============================================================================ - -ERet::ERet(Compiler* c, EFunction* function, const Operand* first, const Operand* second) ASMJIT_NOTHROW : - Emittable(c, EMITTABLE_RET), - _function(function) -{ - if (first ) _ret[0] = *first; - if (second) _ret[1] = *second; - -/* - // TODO:? - - // Check whether the return value is compatible. - uint32_t retValType = function->getPrototype().getReturnValue(); - bool valid = false; - - switch (retValType) - { - case VARIABLE_TYPE_GPD: - case VARIABLE_TYPE_GPQ: - if ((_ret[0].isVar() && (reinterpret_cast(_ret[0]).isGPVar())) || - (_ret[0].isImm())) - { - valid = true; - } - break; - - case VARIABLE_TYPE_X87: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_X87_1D: - if ((_ret[0].isVar() && (reinterpret_cast(_ret[0]).isX87Var() || - reinterpret_cast(_ret[0]).isXMMVar() )) ) - { - valid = true; - } - break; - - case VARIABLE_TYPE_MM: - break; - - case INVALID_VALUE: - if (_ret[0].isNone() && - _ret[1].isNone()) - { - valid = true; - } - break; - - default: - break; - } - - // Incompatible return value. - if (!valid) - { - c->setError(ERROR_INCOMPATIBLE_RETURN_VALUE); - } -*/ -} - -ERet::~ERet() ASMJIT_NOTHROW -{ -} - -void ERet::prepare(CompilerContext& cc) ASMJIT_NOTHROW -{ - _offset = cc._currentOffset; - - uint32_t retValType = getFunction()->getPrototype().getReturnValue(); - if (retValType != INVALID_VALUE) - { - uint32_t i; - for (i = 0; i < 2; i++) - { - Operand& o = _ret[i]; - - if (o.isVar()) - { - ASMJIT_ASSERT(o.getId() != INVALID_VALUE); - VarData* vdata = _compiler->_getVarData(o.getId()); - ASMJIT_ASSERT(vdata != NULL); - - // First emittable (begin of variable scope). - if (vdata->firstEmittable == NULL) vdata->firstEmittable = this; - - // Last emittable (end of variable scope). - vdata->lastEmittable = this; - - if (vdata->workOffset == _offset) continue; - if (!cc._isActive(vdata)) cc._addActive(vdata); - - vdata->workOffset = _offset; - vdata->registerReadCount++; - - if (isVariableInteger(vdata->type) && isVariableInteger(retValType)) - { - cc._newRegisterHomeIndex(vdata, (i == 0) ? REG_INDEX_EAX : REG_INDEX_EDX); - } - } - } - } - - cc._currentOffset++; -} - -Emittable* ERet::translate(CompilerContext& cc) ASMJIT_NOTHROW -{ - Compiler* compiler = cc.getCompiler(); - - // Check whether the return value is compatible. - uint32_t retValType = getFunction()->getPrototype().getReturnValue(); - uint32_t i; - - switch ((int)retValType) - { - case VARIABLE_TYPE_GPD: - case VARIABLE_TYPE_GPQ: - for (i = 0; i < 2; i++) - { - uint32_t dstIndex = (i == 0) ? REG_INDEX_EAX : REG_INDEX_EDX; - uint32_t srcIndex; - - if (_ret[i].isVar()) - { - if (reinterpret_cast(_ret[i]).isGPVar()) - { - VarData* vdata = compiler->_getVarData(_ret[i].getId()); - ASMJIT_ASSERT(vdata != NULL); - - srcIndex = vdata->registerIndex; - if (srcIndex == INVALID_VALUE) - compiler->emit(INST_MOV, gpn(dstIndex), cc._getVarMem(vdata)); - else if (dstIndex != srcIndex) - compiler->emit(INST_MOV, gpn(dstIndex), gpn(srcIndex)); - } - } - else if (_ret[i].isImm()) - { - compiler->emit(INST_MOV, gpn(dstIndex), _ret[i]); - } - } - break; - - case VARIABLE_TYPE_X87: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_X87_1D: - // There is case that we need to return two values (Unix-ABI specific): - // - FLD #2 - //- FLD #1 - i = 2; - do { - i--; - uint32_t dsti = i; - uint32_t srci; - - if (_ret[i].isVar()) - { - if (reinterpret_cast(_ret[i]).isX87Var()) - { - // TODO: X87. - } - else if (reinterpret_cast(_ret[i]).isXMMVar()) - { - VarData* vdata = compiler->_getVarData(_ret[i].getId()); - ASMJIT_ASSERT(vdata != NULL); - - srci = vdata->registerIndex; - if (srci != INVALID_VALUE) cc.saveXMMVar(vdata); - - switch (vdata->type) - { - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - compiler->emit(INST_FLD, _BaseVarMem(reinterpret_cast(_ret[i]), 4)); - break; - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - compiler->emit(INST_FLD, _BaseVarMem(reinterpret_cast(_ret[i]), 8)); - break; - } - } - } - } while (i != 0); - break; - - case VARIABLE_TYPE_MM: - for (i = 0; i < 2; i++) - { - uint32_t dsti = i; - uint32_t srci; - - if (_ret[i].isVar()) - { - if (reinterpret_cast(_ret[i]).isGPVar()) - { - VarData* vdata = compiler->_getVarData(_ret[i].getId()); - ASMJIT_ASSERT(vdata != NULL); - - srci = vdata->registerIndex; - uint32_t inst = _ret[i].isRegType(REG_TYPE_GPQ) ? INST_MOVQ : INST_MOVD; - - if (srci == INVALID_VALUE) - compiler->emit(inst, mm(dsti), cc._getVarMem(vdata)); - else -#if defined(ASMJIT_X86) - compiler->emit(inst, mm(dsti), gpd(srci)); -#else - compiler->emit(inst, mm(dsti), _ret[i].isRegType(REG_TYPE_GPQ) ? gpq(srci) : gpd(srci)); -#endif - } - else if (reinterpret_cast(_ret[i]).isMMVar()) - { - VarData* vdata = compiler->_getVarData(_ret[i].getId()); - ASMJIT_ASSERT(vdata != NULL); - - srci = vdata->registerIndex; - uint32_t inst = INST_MOVQ; - - if (srci == INVALID_VALUE) - compiler->emit(inst, mm(dsti), cc._getVarMem(vdata)); - else if (dsti != srci) - compiler->emit(inst, mm(dsti), mm(srci)); - } - else if (reinterpret_cast(_ret[i]).isXMMVar()) - { - VarData* vdata = compiler->_getVarData(_ret[i].getId()); - ASMJIT_ASSERT(vdata != NULL); - - srci = vdata->registerIndex; - uint32_t inst = INST_MOVQ; - if (reinterpret_cast(_ret[i]).getVariableType() == VARIABLE_TYPE_XMM_1F) inst = INST_MOVD; - - if (srci == INVALID_VALUE) - compiler->emit(inst, mm(dsti), cc._getVarMem(vdata)); - else - compiler->emit(inst, mm(dsti), xmm(srci)); - } - } - } - break; - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_2D: - for (i = 0; i < 2; i++) - { - uint32_t dsti = i; - uint32_t srci; - - if (_ret[i].isVar()) - { - if (reinterpret_cast(_ret[i]).isGPVar()) - { - VarData* vdata = compiler->_getVarData(_ret[i].getId()); - ASMJIT_ASSERT(vdata != NULL); - - srci = vdata->registerIndex; - uint32_t inst = _ret[i].isRegType(REG_TYPE_GPQ) ? INST_MOVQ : INST_MOVD; - - if (srci == INVALID_VALUE) - compiler->emit(inst, xmm(dsti), cc._getVarMem(vdata)); - else -#if defined(ASMJIT_X86) - compiler->emit(inst, xmm(dsti), gpd(srci)); -#else - compiler->emit(inst, xmm(dsti), _ret[i].isRegType(REG_TYPE_GPQ) ? gpq(srci) : gpd(srci)); -#endif - } - else if (reinterpret_cast(_ret[i]).isX87Var()) - { - // TODO: X87. - } - else if (reinterpret_cast(_ret[i]).isMMVar()) - { - VarData* vdata = compiler->_getVarData(_ret[i].getId()); - ASMJIT_ASSERT(vdata != NULL); - - srci = vdata->registerIndex; - if (srci == INVALID_VALUE) - compiler->emit(INST_MOVQ, xmm(dsti), cc._getVarMem(vdata)); - else - compiler->emit(INST_MOVQ, xmm(dsti), mm(srci)); - } - else if (reinterpret_cast(_ret[i]).isXMMVar()) - { - VarData* vdata = compiler->_getVarData(_ret[i].getId()); - ASMJIT_ASSERT(vdata != NULL); - - srci = vdata->registerIndex; - if (srci == INVALID_VALUE) - compiler->emit(INST_MOVDQA, xmm(dsti), cc._getVarMem(vdata)); - else if (dsti != srci) - compiler->emit(INST_MOVDQA, xmm(dsti), xmm(srci)); - } - } - } - break; - - case VARIABLE_TYPE_XMM_1F: - for (i = 0; i < 2; i++) - { - uint32_t dsti = i; - uint32_t srci; - - if (_ret[i].isVar()) - { - if (reinterpret_cast(_ret[i]).isX87Var()) - { - // TODO: X87. - } - else if (reinterpret_cast(_ret[i]).isXMMVar()) - { - VarData* vdata = compiler->_getVarData(_ret[i].getId()); - ASMJIT_ASSERT(vdata != NULL); - - srci = vdata->registerIndex; - switch (vdata->type) - { - case VARIABLE_TYPE_XMM: - if (srci == INVALID_VALUE) - compiler->emit(INST_MOVDQA, xmm(dsti), cc._getVarMem(vdata)); - else if (dsti != srci) - compiler->emit(INST_MOVDQA, xmm(dsti), xmm(srci)); - break; - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - if (srci == INVALID_VALUE) - compiler->emit(INST_MOVSS, xmm(dsti), cc._getVarMem(vdata)); - else - compiler->emit(INST_MOVSS, xmm(dsti), xmm(srci)); - break; - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - if (srci == INVALID_VALUE) - compiler->emit(INST_CVTSD2SS, xmm(dsti), cc._getVarMem(vdata)); - else if (dsti != srci) - compiler->emit(INST_CVTSD2SS, xmm(dsti), xmm(srci)); - break; - } - } - } - } - break; - - case VARIABLE_TYPE_XMM_1D: - for (i = 0; i < 2; i++) - { - uint32_t dsti = i; - uint32_t srci; - - if (_ret[i].isVar()) - { - if (reinterpret_cast(_ret[i]).isX87Var()) - { - // TODO: X87. - } - else if (reinterpret_cast(_ret[i]).isXMMVar()) - { - VarData* vdata = compiler->_getVarData(_ret[i].getId()); - ASMJIT_ASSERT(vdata != NULL); - - srci = vdata->registerIndex; - switch (vdata->type) - { - case VARIABLE_TYPE_XMM: - if (srci == INVALID_VALUE) - compiler->emit(INST_MOVDQA, xmm(dsti), cc._getVarMem(vdata)); - else if (dsti != srci) - compiler->emit(INST_MOVDQA, xmm(dsti), xmm(srci)); - break; - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - if (srci == INVALID_VALUE) - compiler->emit(INST_CVTSS2SD, xmm(dsti), cc._getVarMem(vdata)); - else - compiler->emit(INST_CVTSS2SD, xmm(dsti), xmm(srci)); - break; - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - if (srci == INVALID_VALUE) - compiler->emit(INST_MOVSD, xmm(dsti), cc._getVarMem(vdata)); - else - compiler->emit(INST_MOVSD, xmm(dsti), xmm(srci)); - break; - } - } - } - } - break; - - case INVALID_VALUE: - default: - break; - } - - if (shouldEmitJumpToEpilog()) - { - cc._unreachable = 1; - } - - for (i = 0; i < 2; i++) - { - if (_ret[i].isVar()) - { - VarData* vdata = compiler->_getVarData(_ret[i].getId()); - cc._unuseVarOnEndOfScope(this, vdata); - } - } - - return translated(); -} - -void ERet::emit(Assembler& a) ASMJIT_NOTHROW -{ - if (shouldEmitJumpToEpilog()) - { - a.jmp(getFunction()->getExitLabel()); - } -} - -int ERet::getMaxSize() const ASMJIT_NOTHROW -{ - return shouldEmitJumpToEpilog() ? 15 : 0; -} - -bool ERet::shouldEmitJumpToEpilog() const ASMJIT_NOTHROW -{ - // Iterate over next emittables. If we found emittable that emits real - // instruction then we must return @c true. - Emittable* e = this->getNext(); - - while (e) - { - switch (e->getType()) - { - // Non-interesting emittables. - case EMITTABLE_COMMENT: - case EMITTABLE_DUMMY: - case EMITTABLE_ALIGN: - case EMITTABLE_BLOCK: - case EMITTABLE_VARIABLE_HINT: - case EMITTABLE_TARGET: - break; - - // Interesting emittables. - case EMITTABLE_EMBEDDED_DATA: - case EMITTABLE_INSTRUCTION: - case EMITTABLE_JUMP_TABLE: - case EMITTABLE_CALL: - case EMITTABLE_RET: - return true; - - // These emittables shouldn't be here. We are inside function, after - // prolog. - case EMITTABLE_FUNCTION: - case EMITTABLE_PROLOG: - break; - - // Stop station, we can't go forward from here. - case EMITTABLE_EPILOG: - return false; - } - e = e->getNext(); - } - - return false; -} - -// ============================================================================ -// [AsmJit::CompilerContext - Construction / Destruction] -// ============================================================================ - -CompilerContext::CompilerContext(Compiler* compiler) ASMJIT_NOTHROW : - _zone(8192 - sizeof(Zone::Chunk) - 32) -{ - _compiler = compiler; - _clear(); - - _emitComments = compiler->getLogger() != NULL; -} - -CompilerContext::~CompilerContext() ASMJIT_NOTHROW -{ -} - -// ============================================================================ -// [AsmJit::CompilerContext - Clear] -// ============================================================================ - -void CompilerContext::_clear() ASMJIT_NOTHROW -{ - _zone.clear(); - _function = NULL; - - _start = NULL; - _stop = NULL; - - _state.clear(); - _active = NULL; - - _forwardJumps = NULL; - - _currentOffset = 0; - _unreachable = 0; - - _modifiedGPRegisters = 0; - _modifiedMMRegisters = 0; - _modifiedXMMRegisters = 0; - - _allocableEBP = true; - - _adjustESP = 0; - - _argumentsBaseReg = INVALID_VALUE; // Used by patcher. - _argumentsBaseOffset = 0; // Used by patcher. - _argumentsActualDisp = 0; // Used by translate(). - - _variablesBaseReg = INVALID_VALUE; // Used by patcher. - _variablesBaseOffset = 0; // Used by patcher. - _variablesActualDisp = 0; // Used by translate() - - _memUsed = NULL; - _memFree = NULL; - - _mem4BlocksCount = 0; - _mem8BlocksCount = 0; - _mem16BlocksCount = 0; - - _memBytesTotal = 0; - - _backCode.clear(); - _backPos = 0; -} - -// ============================================================================ -// [AsmJit::CompilerContext - Construction / Destruction] -// ============================================================================ - -void CompilerContext::allocVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW -{ - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: -#endif // ASMJIT_X64 - allocGPVar(vdata, regMask, vflags); - break; - - case VARIABLE_TYPE_X87: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_X87_1D: - // TODO: X87 VARIABLES NOT IMPLEMENTED. - break; - - case VARIABLE_TYPE_MM: - allocMMVar(vdata, regMask, vflags); - break; - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - allocXMMVar(vdata, regMask, vflags); - break; - } - - _postAlloc(vdata, vflags); -} - -void CompilerContext::saveVar(VarData* vdata) ASMJIT_NOTHROW -{ - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: -#endif // ASMJIT_X64 - saveGPVar(vdata); - break; - - case VARIABLE_TYPE_X87: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_X87_1D: - // TODO: X87 VARIABLES NOT IMPLEMENTED. - break; - - case VARIABLE_TYPE_MM: - saveMMVar(vdata); - break; - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - saveXMMVar(vdata); - break; - } -} - -void CompilerContext::spillVar(VarData* vdata) ASMJIT_NOTHROW -{ - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: -#endif // ASMJIT_X64 - spillGPVar(vdata); - break; - - case VARIABLE_TYPE_X87: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_X87_1D: - // TODO: X87 VARIABLES NOT IMPLEMENTED. - break; - - case VARIABLE_TYPE_MM: - spillMMVar(vdata); - break; - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - spillXMMVar(vdata); - break; - } -} - -void CompilerContext::unuseVar(VarData* vdata, uint32_t toState) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(toState != VARIABLE_STATE_REGISTER); - - if (vdata->state == VARIABLE_STATE_REGISTER) - { - uint32_t registerIndex = vdata->registerIndex; - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: -#endif // ASMJIT_X64 - _state.gp[registerIndex] = NULL; - _freedGPRegister(registerIndex); - break; - - case VARIABLE_TYPE_X87: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_X87_1D: - // TODO: X87 VARIABLES NOT IMPLEMENTED. - break; - - case VARIABLE_TYPE_MM: - _state.mm[registerIndex] = NULL; - _freedMMRegister(registerIndex); - break; - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - _state.xmm[registerIndex] = NULL; - _freedXMMRegister(registerIndex); - break; - } - } - - vdata->state = toState; - vdata->changed = false; - vdata->registerIndex = INVALID_VALUE; -} - -void CompilerContext::allocGPVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW -{ - // Fix the regMask (0 or full bit-array means that any register may be used). - if (regMask == 0) regMask = Util::maskUpToIndex(REG_NUM_GP); - regMask &= Util::maskUpToIndex(REG_NUM_GP); - - // Working variables. - uint32_t i; - uint32_t mask; - - // Last register code (aka home). - uint32_t home = vdata->homeRegisterIndex; - // New register code. - uint32_t idx = INVALID_VALUE; - - // Preserved GP variables. - uint32_t preservedGP = vdata->scope->getPrototype().getPreservedGP(); - - // Spill candidate. - VarData* spillCandidate = NULL; - - // Whether to alloc the non-preserved variables first. - bool nonPreservedFirst = true; - if (getFunction()->_isCaller) - { - nonPreservedFirst = vdata->firstCallable == NULL || - vdata->firstCallable->getOffset() >= vdata->lastEmittable->getOffset(); - } - - // -------------------------------------------------------------------------- - // [Already Allocated] - // -------------------------------------------------------------------------- - - // Go away if variable is already allocated. - if (vdata->state == VARIABLE_STATE_REGISTER) - { - uint32_t oldIndex = vdata->registerIndex; - - // Already allocated in the right register. - if (Util::maskFromIndex(oldIndex) & regMask) return; - - // Try to find unallocated register first. - mask = regMask & ~_state.usedGP; - if (mask != 0) - { - idx = Util::findFirstBit( - (nonPreservedFirst && (mask & ~preservedGP) != 0) ? mask & ~preservedGP : mask); - } - // Then find the allocated and later exchange. - else - { - idx = Util::findFirstBit(regMask & _state.usedGP); - } - ASMJIT_ASSERT(idx != INVALID_VALUE); - - VarData* other = _state.gp[idx]; - emitExchangeVar(vdata, idx, vflags, other); - - _state.gp[oldIndex] = other; - _state.gp[idx ] = vdata; - - if (other) - other->registerIndex = oldIndex; - else - _freedGPRegister(oldIndex); - - // Update VarData. - vdata->state = VARIABLE_STATE_REGISTER; - vdata->registerIndex = idx; - vdata->homeRegisterIndex = idx; - - _allocatedGPRegister(idx); - return; - } - - // -------------------------------------------------------------------------- - // [Find Unused GP] - // -------------------------------------------------------------------------- - - // If regMask contains restricted registers which may be used then everything - // is handled in this block. - if (regMask != Util::maskUpToIndex(REG_NUM_GP)) - { - // Try to find unallocated register first. - mask = regMask & ~_state.usedGP; - if (mask != 0) - { - idx = Util::findFirstBit( - (nonPreservedFirst && (mask & ~preservedGP) != 0) ? (mask & ~preservedGP) : mask); - ASMJIT_ASSERT(idx != INVALID_VALUE); - } - // Then find the allocated and later spill. - else - { - idx = Util::findFirstBit(regMask & _state.usedGP); - ASMJIT_ASSERT(idx != INVALID_VALUE); - - // Spill register we need. - spillCandidate = _state.gp[idx]; - - // Jump to spill part of allocation. - goto L_Spill; - } - } - - // Home register code. - if (idx == INVALID_VALUE && home != INVALID_VALUE) - { - if ((_state.usedGP & (1U << home)) == 0) idx = home; - } - - // We start from 1, because EAX/RAX register is sometimes explicitly - // needed. So we trying to prevent reallocation in near future. - if (idx == INVALID_VALUE) - { - for (i = 1, mask = (1 << i); i < REG_NUM_GP; i++, mask <<= 1) - { - if ((_state.usedGP & mask) == 0 && (i != REG_INDEX_EBP || _allocableEBP) && (i != REG_INDEX_ESP)) - { - // Convenience to alloc non-preserved first or non-preserved last. - if (nonPreservedFirst) - { - if (idx != INVALID_VALUE && (preservedGP & mask) != 0) continue; - idx = i; - // If current register is preserved, we should try to find different - // one that is not. This can save one push / pop in prolog / epilog. - if ((preservedGP & mask) == 0) break; - } - else - { - if (idx != INVALID_VALUE && (preservedGP & mask) == 0) continue; - idx = i; - // The opposite. - if ((preservedGP & mask) != 0) break; - } - } - } - } - - // If not found, try EAX/RAX. - if (idx == INVALID_VALUE && (_state.usedGP & 1) == 0) - { - idx = REG_INDEX_EAX; - } - - // -------------------------------------------------------------------------- - // [Spill] - // -------------------------------------------------------------------------- - - // If register is still not found, spill other variable. - if (idx == INVALID_VALUE) - { - if (spillCandidate == NULL) - { - spillCandidate = _getSpillCandidateGP(); - } - - // Spill candidate not found? - if (spillCandidate == NULL) - { - _compiler->setError(ERROR_NOT_ENOUGH_REGISTERS); - return; - } - -L_Spill: - - // Prevented variables can't be spilled. _getSpillCandidate() never returns - // prevented variables, but when jumping to L_spill it can happen. - if (spillCandidate->workOffset == _currentOffset) - { - _compiler->setError(ERROR_REGISTERS_OVERLAP); - return; - } - - idx = spillCandidate->registerIndex; - spillGPVar(spillCandidate); - } - - // -------------------------------------------------------------------------- - // [Alloc] - // -------------------------------------------------------------------------- - - if (vdata->state == VARIABLE_STATE_MEMORY && (vflags & VARIABLE_ALLOC_READ) != 0) - { - emitLoadVar(vdata, idx); - } - - // Update VarData. - vdata->state = VARIABLE_STATE_REGISTER; - vdata->registerIndex = idx; - vdata->homeRegisterIndex = idx; - - // Update StateData. - _allocatedVariable(vdata); -} - -void CompilerContext::saveGPVar(VarData* vdata) ASMJIT_NOTHROW -{ - // Can't save variable that isn't allocated. - ASMJIT_ASSERT(vdata->state == VARIABLE_STATE_REGISTER); - ASMJIT_ASSERT(vdata->registerIndex != INVALID_VALUE); - - uint32_t idx = vdata->registerIndex; - emitSaveVar(vdata, idx); - - // Update VarData. - vdata->changed = false; -} - -void CompilerContext::spillGPVar(VarData* vdata) ASMJIT_NOTHROW -{ - // Can't spill variable that isn't allocated. - ASMJIT_ASSERT(vdata->state == VARIABLE_STATE_REGISTER); - ASMJIT_ASSERT(vdata->registerIndex != INVALID_VALUE); - - uint32_t idx = vdata->registerIndex; - - if (vdata->changed) emitSaveVar(vdata, idx); - - // Update VarData. - vdata->registerIndex = INVALID_VALUE; - vdata->state = VARIABLE_STATE_MEMORY; - vdata->changed = false; - - // Update StateData. - _state.gp[idx] = NULL; - _freedGPRegister(idx); -} - -void CompilerContext::allocMMVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW -{ - // Fix the regMask (0 or full bit-array means that any register may be used). - if (regMask == 0) regMask = Util::maskUpToIndex(REG_NUM_MM); - regMask &= Util::maskUpToIndex(REG_NUM_MM); - - // Working variables. - uint32_t i; - uint32_t mask; - - // Last register code (aka home). - uint32_t home = vdata->homeRegisterIndex; - // New register code. - uint32_t idx = INVALID_VALUE; - - // Preserved MM variables. - // - // NOTE: Currently MM variables are not preserved and there is no calling - // convention known to me that does that. But on the other side it's possible - // to write such calling convention. - uint32_t preservedMM = vdata->scope->getPrototype().getPreservedMM(); - - // Spill candidate. - VarData* spillCandidate = NULL; - - // Whether to alloc non-preserved first or last. - bool nonPreservedFirst = true; - if (this->getFunction()->_isCaller) - { - nonPreservedFirst = vdata->firstCallable == NULL || - vdata->firstCallable->getOffset() >= vdata->lastEmittable->getOffset(); - } - - // -------------------------------------------------------------------------- - // [Already Allocated] - // -------------------------------------------------------------------------- - - // Go away if variable is already allocated. - if (vdata->state == VARIABLE_STATE_REGISTER) - { - uint32_t oldIndex = vdata->registerIndex; - - // Already allocated in the right register. - if (Util::maskFromIndex(oldIndex) & regMask) return; - - // Try to find unallocated register first. - mask = regMask & ~_state.usedMM; - if (mask != 0) - { - idx = Util::findFirstBit( - (nonPreservedFirst && (mask & ~preservedMM) != 0) ? mask & ~preservedMM : mask); - } - // Then find the allocated and later exchange. - else - { - idx = Util::findFirstBit(regMask & _state.usedMM); - } - ASMJIT_ASSERT(idx != INVALID_VALUE); - - VarData* other = _state.mm[idx]; - if (other) spillMMVar(other); - - emitMoveVar(vdata, idx, vflags); - _freedMMRegister(oldIndex); - _state.mm[idx] = vdata; - - // Update VarData. - vdata->state = VARIABLE_STATE_REGISTER; - vdata->registerIndex = idx; - vdata->homeRegisterIndex = idx; - - _allocatedMMRegister(idx); - return; - } - - // -------------------------------------------------------------------------- - // [Find Unused MM] - // -------------------------------------------------------------------------- - - // If regMask contains restricted registers which may be used then everything - // is handled in this block. - if (regMask != Util::maskUpToIndex(REG_NUM_MM)) - { - // Try to find unallocated register first. - mask = regMask & ~_state.usedMM; - if (mask != 0) - { - idx = Util::findFirstBit( - (nonPreservedFirst && (mask & ~preservedMM) != 0) ? mask & ~preservedMM : mask); - ASMJIT_ASSERT(idx != INVALID_VALUE); - } - // Then find the allocated and later spill. - else - { - idx = Util::findFirstBit(regMask & _state.usedMM); - ASMJIT_ASSERT(idx != INVALID_VALUE); - - // Spill register we need. - spillCandidate = _state.mm[idx]; - - // Jump to spill part of allocation. - goto L_Spill; - } - } - - // Home register code. - if (idx == INVALID_VALUE && home != INVALID_VALUE) - { - if ((_state.usedMM & (1U << home)) == 0) idx = home; - } - - if (idx == INVALID_VALUE) - { - for (i = 0, mask = (1 << i); i < REG_NUM_MM; i++, mask <<= 1) - { - if ((_state.usedMM & mask) == 0) - { - // Convenience to alloc non-preserved first or non-preserved last. - if (nonPreservedFirst) - { - if (idx != INVALID_VALUE && (preservedMM & mask) != 0) continue; - idx = i; - // If current register is preserved, we should try to find different - // one that is not. This can save one push / pop in prolog / epilog. - if ((preservedMM & mask) == 0) break; - } - else - { - if (idx != INVALID_VALUE && (preservedMM & mask) == 0) continue; - idx = i; - // The opposite. - if ((preservedMM & mask) != 0) break; - } - } - } - } - - // -------------------------------------------------------------------------- - // [Spill] - // -------------------------------------------------------------------------- - - // If register is still not found, spill other variable. - if (idx == INVALID_VALUE) - { - if (spillCandidate == NULL) spillCandidate = _getSpillCandidateMM(); - - // Spill candidate not found? - if (spillCandidate == NULL) - { - _compiler->setError(ERROR_NOT_ENOUGH_REGISTERS); - return; - } - -L_Spill: - - // Prevented variables can't be spilled. _getSpillCandidate() never returns - // prevented variables, but when jumping to L_spill it can happen. - if (spillCandidate->workOffset == _currentOffset) - { - _compiler->setError(ERROR_REGISTERS_OVERLAP); - return; - } - - idx = spillCandidate->registerIndex; - spillMMVar(spillCandidate); - } - - // -------------------------------------------------------------------------- - // [Alloc] - // -------------------------------------------------------------------------- - - if (vdata->state == VARIABLE_STATE_MEMORY && (vflags & VARIABLE_ALLOC_READ) != 0) - { - emitLoadVar(vdata, idx); - } - - // Update VarData. - vdata->state = VARIABLE_STATE_REGISTER; - vdata->registerIndex = idx; - vdata->homeRegisterIndex = idx; - - // Update StateData. - _allocatedVariable(vdata); -} - -void CompilerContext::saveMMVar(VarData* vdata) ASMJIT_NOTHROW -{ - // Can't save variable that isn't allocated. - ASMJIT_ASSERT(vdata->state == VARIABLE_STATE_REGISTER); - ASMJIT_ASSERT(vdata->registerIndex != INVALID_VALUE); - - uint32_t idx = vdata->registerIndex; - emitSaveVar(vdata, idx); - - // Update VarData. - vdata->changed = false; -} - -void CompilerContext::spillMMVar(VarData* vdata) ASMJIT_NOTHROW -{ - // Can't spill variable that isn't allocated. - ASMJIT_ASSERT(vdata->state == VARIABLE_STATE_REGISTER); - ASMJIT_ASSERT(vdata->registerIndex != INVALID_VALUE); - - uint32_t idx = vdata->registerIndex; - - if (vdata->changed) emitSaveVar(vdata, idx); - - // Update VarData. - vdata->registerIndex = INVALID_VALUE; - vdata->state = VARIABLE_STATE_MEMORY; - vdata->changed = false; - - // Update StateData. - _state.mm[idx] = NULL; - _freedMMRegister(idx); -} - -void CompilerContext::allocXMMVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW -{ - // Fix the regMask (0 or full bit-array means that any register may be used). - if (regMask == 0) regMask = Util::maskUpToIndex(REG_NUM_XMM); - regMask &= Util::maskUpToIndex(REG_NUM_XMM); - - // Working variables. - uint32_t i; - uint32_t mask; - - // Last register code (aka home). - uint32_t home = vdata->homeRegisterIndex; - // New register code. - uint32_t idx = INVALID_VALUE; - - // Preserved XMM variables. - uint32_t preservedXMM = vdata->scope->getPrototype().getPreservedXMM(); - - // Spill candidate. - VarData* spillCandidate = NULL; - - // Whether to alloc non-preserved first or last. - bool nonPreservedFirst = true; - if (this->getFunction()->_isCaller) - { - nonPreservedFirst = vdata->firstCallable == NULL || - vdata->firstCallable->getOffset() >= vdata->lastEmittable->getOffset(); - } - - // -------------------------------------------------------------------------- - // [Already Allocated] - // -------------------------------------------------------------------------- - - // Go away if variable is already allocated. - if (vdata->state == VARIABLE_STATE_REGISTER) - { - uint32_t oldIndex = vdata->registerIndex; - - // Already allocated in the right register. - if (Util::maskFromIndex(oldIndex) & regMask) return; - - // Try to find unallocated register first. - mask = regMask & ~_state.usedXMM; - if (mask != 0) - { - idx = Util::findFirstBit( - (nonPreservedFirst && (mask & ~preservedXMM) != 0) ? mask & ~preservedXMM : mask); - } - // Then find the allocated and later exchange. - else - { - idx = Util::findFirstBit(regMask & _state.usedXMM); - } - ASMJIT_ASSERT(idx != INVALID_VALUE); - - VarData* other = _state.xmm[idx]; - if (other) spillXMMVar(other); - - emitMoveVar(vdata, idx, vflags); - _freedXMMRegister(oldIndex); - _state.xmm[idx] = vdata; - - // Update VarData. - vdata->state = VARIABLE_STATE_REGISTER; - vdata->registerIndex = idx; - vdata->homeRegisterIndex = idx; - - _allocatedXMMRegister(idx); - return; - } - - // -------------------------------------------------------------------------- - // [Find Unused XMM] - // -------------------------------------------------------------------------- - - // If regMask contains restricted registers which may be used then everything - // is handled in this block. - if (regMask != Util::maskUpToIndex(REG_NUM_XMM)) - { - // Try to find unallocated register first. - mask = regMask & ~_state.usedXMM; - if (mask != 0) - { - idx = Util::findFirstBit( - (nonPreservedFirst && (mask & ~preservedXMM) != 0) ? mask & ~preservedXMM : mask); - ASMJIT_ASSERT(idx != INVALID_VALUE); - } - // Then find the allocated and later spill. - else - { - idx = Util::findFirstBit(regMask & _state.usedXMM); - ASMJIT_ASSERT(idx != INVALID_VALUE); - - // Spill register we need. - spillCandidate = _state.xmm[idx]; - - // Jump to spill part of allocation. - goto L_Spill; - } - } - - // Home register code. - if (idx == INVALID_VALUE && home != INVALID_VALUE) - { - if ((_state.usedXMM & (1U << home)) == 0) idx = home; - } - - if (idx == INVALID_VALUE) - { - for (i = 0, mask = (1 << i); i < REG_NUM_XMM; i++, mask <<= 1) - { - if ((_state.usedXMM & mask) == 0) - { - // Convenience to alloc non-preserved first or non-preserved last. - if (nonPreservedFirst) - { - if (idx != INVALID_VALUE && (preservedXMM & mask) != 0) continue; - idx = i; - // If current register is preserved, we should try to find different - // one that is not. This can save one push / pop in prolog / epilog. - if ((preservedXMM & mask) == 0) break; - } - else - { - if (idx != INVALID_VALUE && (preservedXMM & mask) == 0) continue; - idx = i; - // The opposite. - if ((preservedXMM & mask) != 0) break; - } - } - } - } - - // -------------------------------------------------------------------------- - // [Spill] - // -------------------------------------------------------------------------- - - // If register is still not found, spill other variable. - if (idx == INVALID_VALUE) - { - if (spillCandidate == NULL) spillCandidate = _getSpillCandidateXMM(); - - // Spill candidate not found? - if (spillCandidate == NULL) - { - _compiler->setError(ERROR_NOT_ENOUGH_REGISTERS); - return; - } - -L_Spill: - - // Prevented variables can't be spilled. _getSpillCandidate() never returns - // prevented variables, but when jumping to L_spill it can happen. - if (spillCandidate->workOffset == _currentOffset) - { - _compiler->setError(ERROR_REGISTERS_OVERLAP); - return; - } - - idx = spillCandidate->registerIndex; - spillXMMVar(spillCandidate); - } - - // -------------------------------------------------------------------------- - // [Alloc] - // -------------------------------------------------------------------------- - - if (vdata->state == VARIABLE_STATE_MEMORY && (vflags & VARIABLE_ALLOC_READ) != 0) - { - emitLoadVar(vdata, idx); - } - - // Update VarData. - vdata->state = VARIABLE_STATE_REGISTER; - vdata->registerIndex = idx; - vdata->homeRegisterIndex = idx; - - // Update StateData. - _allocatedVariable(vdata); -} - -void CompilerContext::saveXMMVar(VarData* vdata) ASMJIT_NOTHROW -{ - // Can't save variable that isn't allocated. - ASMJIT_ASSERT(vdata->state == VARIABLE_STATE_REGISTER); - ASMJIT_ASSERT(vdata->registerIndex != INVALID_VALUE); - - uint32_t idx = vdata->registerIndex; - emitSaveVar(vdata, idx); - - // Update VarData. - vdata->changed = false; -} - -void CompilerContext::spillXMMVar(VarData* vdata) ASMJIT_NOTHROW -{ - // Can't spill variable that isn't allocated. - ASMJIT_ASSERT(vdata->state == VARIABLE_STATE_REGISTER); - ASMJIT_ASSERT(vdata->registerIndex != INVALID_VALUE); - - uint32_t idx = vdata->registerIndex; - - if (vdata->changed) emitSaveVar(vdata, idx); - - // Update VarData. - vdata->registerIndex = INVALID_VALUE; - vdata->state = VARIABLE_STATE_MEMORY; - vdata->changed = false; - - // Update StateData. - _state.xmm[idx] = NULL; - _freedXMMRegister(idx); -} - -void CompilerContext::emitLoadVar(VarData* vdata, uint32_t regIndex) ASMJIT_NOTHROW -{ - Mem m = _getVarMem(vdata); - - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - _compiler->emit(INST_MOV, gpd(regIndex), m); - if (_emitComments) goto addComment; - break; -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - _compiler->emit(INST_MOV, gpq(regIndex), m); - if (_emitComments) goto addComment; - break; -#endif // ASMJIT_X64 - - case VARIABLE_TYPE_X87: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_X87_1D: - // TODO: X87 VARIABLES NOT IMPLEMENTED. - break; - - case VARIABLE_TYPE_MM: - _compiler->emit(INST_MOVQ, mm(regIndex), m); - if (_emitComments) goto addComment; - break; - - case VARIABLE_TYPE_XMM: - _compiler->emit(INST_MOVDQA, xmm(regIndex), m); - if (_emitComments) goto addComment; - break; - case VARIABLE_TYPE_XMM_1F: - _compiler->emit(INST_MOVSS, xmm(regIndex), m); - if (_emitComments) goto addComment; - break; - case VARIABLE_TYPE_XMM_1D: - _compiler->emit(INST_MOVSD, xmm(regIndex), m); - if (_emitComments) goto addComment; - break; - case VARIABLE_TYPE_XMM_4F: - _compiler->emit(INST_MOVAPS, xmm(regIndex), m); - if (_emitComments) goto addComment; - break; - case VARIABLE_TYPE_XMM_2D: - _compiler->emit(INST_MOVAPD, xmm(regIndex), m); - if (_emitComments) goto addComment; - break; - } - return; - -addComment: - _compiler->getCurrentEmittable()->setCommentF("Alloc %s", vdata->name); -} - -void CompilerContext::emitSaveVar(VarData* vdata, uint32_t regIndex) ASMJIT_NOTHROW -{ - // Caller must ensure that variable is allocated. - ASMJIT_ASSERT(regIndex != INVALID_VALUE); - - Mem m = _getVarMem(vdata); - - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - _compiler->emit(INST_MOV, m, gpd(regIndex)); - if (_emitComments) goto addComment; - break; -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - _compiler->emit(INST_MOV, m, gpq(regIndex)); - if (_emitComments) goto addComment; - break; -#endif // ASMJIT_X64 - - case VARIABLE_TYPE_X87: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_X87_1D: - // TODO: X87 VARIABLES NOT IMPLEMENTED. - break; - - case VARIABLE_TYPE_MM: - _compiler->emit(INST_MOVQ, m, mm(regIndex)); - if (_emitComments) goto addComment; - break; - - case VARIABLE_TYPE_XMM: - _compiler->emit(INST_MOVDQA, m, xmm(regIndex)); - if (_emitComments) goto addComment; - break; - case VARIABLE_TYPE_XMM_1F: - _compiler->emit(INST_MOVSS, m, xmm(regIndex)); - if (_emitComments) goto addComment; - break; - case VARIABLE_TYPE_XMM_1D: - _compiler->emit(INST_MOVSD, m, xmm(regIndex)); - if (_emitComments) goto addComment; - break; - case VARIABLE_TYPE_XMM_4F: - _compiler->emit(INST_MOVAPS, m, xmm(regIndex)); - if (_emitComments) goto addComment; - break; - case VARIABLE_TYPE_XMM_2D: - _compiler->emit(INST_MOVAPD, m, xmm(regIndex)); - if (_emitComments) goto addComment; - break; - } - return; - -addComment: - _compiler->getCurrentEmittable()->setCommentF("Spill %s", vdata->name); -} - -void CompilerContext::emitMoveVar(VarData* vdata, uint32_t regIndex, uint32_t vflags) ASMJIT_NOTHROW -{ - // Caller must ensure that variable is allocated. - ASMJIT_ASSERT(vdata->registerIndex != INVALID_VALUE); - - if ((vflags & VARIABLE_ALLOC_READ) == 0) return; - - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - _compiler->emit(INST_MOV, gpd(regIndex), gpd(vdata->registerIndex)); - break; -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - _compiler->emit(INST_MOV, gpq(regIndex), gpq(vdata->registerIndex)); - break; -#endif // ASMJIT_X64 - - case VARIABLE_TYPE_X87: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_X87_1D: - // TODO: X87 VARIABLES NOT IMPLEMENTED. - break; - - case VARIABLE_TYPE_MM: - _compiler->emit(INST_MOVQ, mm(regIndex), mm(vdata->registerIndex)); - break; - - case VARIABLE_TYPE_XMM: - _compiler->emit(INST_MOVDQA, xmm(regIndex), xmm(vdata->registerIndex)); - break; - case VARIABLE_TYPE_XMM_1F: - _compiler->emit(INST_MOVSS, xmm(regIndex), xmm(vdata->registerIndex)); - break; - case VARIABLE_TYPE_XMM_1D: - _compiler->emit(INST_MOVSD, xmm(regIndex), xmm(vdata->registerIndex)); - break; - case VARIABLE_TYPE_XMM_4F: - _compiler->emit(INST_MOVAPS, xmm(regIndex), xmm(vdata->registerIndex)); - break; - case VARIABLE_TYPE_XMM_2D: - _compiler->emit(INST_MOVAPD, xmm(regIndex), xmm(vdata->registerIndex)); - break; - } -} - -void CompilerContext::emitExchangeVar(VarData* vdata, uint32_t regIndex, uint32_t vflags, VarData* other) ASMJIT_NOTHROW -{ - // Caller must ensure that variable is allocated. - ASMJIT_ASSERT(vdata->registerIndex != INVALID_VALUE); - - // If other is not valid then we can just emit MOV (or other similar instruction). - if (other == NULL) - { - emitMoveVar(vdata, regIndex, vflags); - return; - } - - // If we need to alloc for write-only operation then we can move other - // variable away instead of exchanging them. - if ((vflags & VARIABLE_ALLOC_READ) == 0) - { - emitMoveVar(other, vdata->registerIndex, VARIABLE_ALLOC_READ); - return; - } - - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - _compiler->emit(INST_XCHG, gpd(regIndex), gpd(vdata->registerIndex)); - break; -#if defined(ASMJIT_X64) - case VARIABLE_TYPE_GPQ: - _compiler->emit(INST_XCHG, gpq(regIndex), gpq(vdata->registerIndex)); - break; -#endif // ASMJIT_X64 - - case VARIABLE_TYPE_X87: - case VARIABLE_TYPE_X87_1F: - case VARIABLE_TYPE_X87_1D: - // TODO: X87 VARIABLES NOT IMPLEMENTED. - break; - - // NOTE: MM and XMM registers shoudln't be exchanged using this way, it's - // correct, but it sucks. - - case VARIABLE_TYPE_MM: - { - MMReg a = mm(regIndex); - MMReg b = mm(vdata->registerIndex); - - _compiler->emit(INST_PXOR, a, b); - _compiler->emit(INST_PXOR, b, a); - _compiler->emit(INST_PXOR, a, b); - break; - } - - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - { - XMMReg a = xmm(regIndex); - XMMReg b = xmm(vdata->registerIndex); - - _compiler->emit(INST_XORPS, a, b); - _compiler->emit(INST_XORPS, b, a); - _compiler->emit(INST_XORPS, a, b); - break; - } - - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - { - XMMReg a = xmm(regIndex); - XMMReg b = xmm(vdata->registerIndex); - - _compiler->emit(INST_XORPD, a, b); - _compiler->emit(INST_XORPD, b, a); - _compiler->emit(INST_XORPD, a, b); - break; - } - - case VARIABLE_TYPE_XMM: - { - XMMReg a = xmm(regIndex); - XMMReg b = xmm(vdata->registerIndex); - - _compiler->emit(INST_PXOR, a, b); - _compiler->emit(INST_PXOR, b, a); - _compiler->emit(INST_PXOR, a, b); - break; - } - } -} - -void CompilerContext::_postAlloc(VarData* vdata, uint32_t vflags) ASMJIT_NOTHROW -{ - if (vflags & VARIABLE_ALLOC_WRITE) vdata->changed = true; -} - -void CompilerContext::_markMemoryUsed(VarData* vdata) ASMJIT_NOTHROW -{ - if (vdata->homeMemoryData != NULL) return; - - VarMemBlock* mem = _allocMemBlock(vdata->size); - if (!mem) return; - - vdata->homeMemoryData = mem; -} - -Mem CompilerContext::_getVarMem(VarData* vdata) ASMJIT_NOTHROW -{ - Mem m; - m._mem.id = vdata->id; - if (!vdata->isMemArgument) m._mem.displacement = _adjustESP; - - _markMemoryUsed(vdata); - return m; -} - -static int32_t getSpillScore(VarData* v, uint32_t currentOffset) -{ - int32_t score = 0; - - ASMJIT_ASSERT(v->lastEmittable != NULL); - uint32_t lastOffset = v->lastEmittable->getOffset(); - - if (lastOffset >= currentOffset) - score += (int32_t)(lastOffset - currentOffset); - - // Each write access decreases probability of spill. - score -= (int32_t)v->registerWriteCount + (int32_t)v->registerRWCount; - // Each read-only access increases probability of spill. - score += (int32_t)v->registerReadCount; - - // Each memory access increases probability of spill. - score += (int32_t)v->memoryWriteCount + (int32_t)v->memoryRWCount; - score += (int32_t)v->memoryReadCount; - - return score; -} - -VarData* CompilerContext::_getSpillCandidateGP() ASMJIT_NOTHROW -{ - return _getSpillCandidateGeneric(_state.gp, REG_NUM_GP); -} - -VarData* CompilerContext::_getSpillCandidateMM() ASMJIT_NOTHROW -{ - return _getSpillCandidateGeneric(_state.mm, REG_NUM_MM); -} - -VarData* CompilerContext::_getSpillCandidateXMM() ASMJIT_NOTHROW -{ - return _getSpillCandidateGeneric(_state.xmm, REG_NUM_XMM); -} - -VarData* CompilerContext::_getSpillCandidateGeneric(VarData** varArray, uint32_t count) ASMJIT_NOTHROW -{ - uint32_t i; - - VarData* candidate = NULL; - uint32_t candidatePriority = 0; - int32_t candidateScore = 0; - - uint32_t currentOffset = _compiler->getCurrentEmittable()->getOffset(); - - for (i = 0; i < count; i++) - { - // Get variable. - VarData* vdata = varArray[i]; - - // Never spill variables needed for next instruction. - if (vdata == NULL || vdata->workOffset == _currentOffset) continue; - - uint32_t variablePriority = vdata->priority; - int32_t variableScore = getSpillScore(vdata, currentOffset); - - if ((candidate == NULL) || - (variablePriority > candidatePriority) || - (variablePriority == candidatePriority && variableScore > candidateScore)) - { - candidate = vdata; - candidatePriority = variablePriority; - candidateScore = variableScore; - } - } - - return candidate; -} - -void CompilerContext::_addActive(VarData* vdata) ASMJIT_NOTHROW -{ - // Never call with variable that is already in active list. - ASMJIT_ASSERT(vdata->nextActive == NULL); - ASMJIT_ASSERT(vdata->prevActive == NULL); - - if (_active == NULL) - { - vdata->nextActive = vdata; - vdata->prevActive = vdata; - - _active = vdata; - } - else - { - VarData* vlast = _active->prevActive; - - vlast->nextActive = vdata; - _active->prevActive = vdata; - - vdata->nextActive = _active; - vdata->prevActive = vlast; - } -} - -void CompilerContext::_freeActive(VarData* vdata) ASMJIT_NOTHROW -{ - VarData* next = vdata->nextActive; - VarData* prev = vdata->prevActive; - - if (prev == next) - { - _active = NULL; - } - else - { - if (_active == vdata) _active = next; - prev->nextActive = next; - next->prevActive = prev; - } - - vdata->nextActive = NULL; - vdata->prevActive = NULL; -} - -void CompilerContext::_freeAllActive() ASMJIT_NOTHROW -{ - if (_active == NULL) return; - - VarData* cur = _active; - for (;;) - { - VarData* next = cur->nextActive; - cur->nextActive = NULL; - cur->prevActive = NULL; - if (next == _active) break; - } - - _active = NULL; -} - -void CompilerContext::_allocatedVariable(VarData* vdata) ASMJIT_NOTHROW -{ - uint32_t idx = vdata->registerIndex; - - switch (vdata->type) - { - case VARIABLE_TYPE_GPD: - case VARIABLE_TYPE_GPQ: - _state.gp[idx] = vdata; - _allocatedGPRegister(idx); - break; - - case VARIABLE_TYPE_MM: - _state.mm[idx] = vdata; - _allocatedMMRegister(idx); - break; - - case VARIABLE_TYPE_XMM: - case VARIABLE_TYPE_XMM_1F: - case VARIABLE_TYPE_XMM_4F: - case VARIABLE_TYPE_XMM_1D: - case VARIABLE_TYPE_XMM_2D: - _state.xmm[idx] = vdata; - _allocatedXMMRegister(idx); - break; - - default: - ASMJIT_ASSERT(0); - break; - } -} - -void CompilerContext::translateOperands(Operand* operands, uint32_t count) ASMJIT_NOTHROW -{ - uint32_t i; - - // Translate variables to registers. - for (i = 0; i < count; i++) - { - Operand& o = operands[i]; - - if (o.isVar()) - { - VarData* vdata = _compiler->_getVarData(o.getId()); - ASMJIT_ASSERT(vdata != NULL); - - o._reg.op = OPERAND_REG; - o._reg.code |= vdata->registerIndex; - } - else if (o.isMem()) - { - if ((o.getId() & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - // Memory access. We just increment here actual displacement. - VarData* vdata = _compiler->_getVarData(o.getId()); - ASMJIT_ASSERT(vdata != NULL); - - o._mem.displacement += vdata->isMemArgument - ? _argumentsActualDisp - : _variablesActualDisp; - // NOTE: This is not enough, variable position will be patched later - // by CompilerContext::_patchMemoryOperands(). - } - else if ((o._mem.base & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(o._mem.base); - ASMJIT_ASSERT(vdata != NULL); - - o._mem.base = vdata->registerIndex; - } - - if ((o._mem.index & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(o._mem.index); - ASMJIT_ASSERT(vdata != NULL); - - o._mem.index = vdata->registerIndex; - } - } - } -} - -void CompilerContext::addBackwardCode(EJmp* from) ASMJIT_NOTHROW -{ - _backCode.append(from); -} - -void CompilerContext::addForwardJump(EJmp* inst) ASMJIT_NOTHROW -{ - ForwardJumpData* j = - reinterpret_cast(_zone.zalloc(sizeof(ForwardJumpData))); - if (j == NULL) { _compiler->setError(ERROR_NO_HEAP_MEMORY); return; } - - j->inst = inst; - j->state = _saveState(); - j->next = _forwardJumps; - _forwardJumps = j; -} - -StateData* CompilerContext::_saveState() ASMJIT_NOTHROW -{ - // Get count of variables stored in memory. - uint32_t memVarsCount = 0; - VarData* cur = _active; - if (cur) - { - do { - if (cur->state == VARIABLE_STATE_MEMORY) memVarsCount++; - cur = cur->nextActive; - } while (cur != _active); - } - - // Alloc StateData structure (using zone allocator) and copy current state into it. - StateData* state = _compiler->_newStateData(memVarsCount); - memcpy(state, &_state, sizeof(StateData)); - - // Clear changed flags. - state->changedGP = 0; - state->changedMM = 0; - state->changedXMM = 0; - - uint i; - uint mask; - - // Save variables stored in REGISTERs and CHANGE flag. - for (i = 0, mask = 1; i < REG_NUM_GP; i++, mask <<= 1) - { - if (state->gp[i] && state->gp[i]->changed) state->changedGP |= mask; - } - - for (i = 0, mask = 1; i < REG_NUM_MM; i++, mask <<= 1) - { - if (state->mm[i] && state->mm[i]->changed) state->changedMM |= mask; - } - - for (i = 0, mask = 1; i < REG_NUM_XMM; i++, mask <<= 1) - { - if (state->xmm[i] && state->xmm[i]->changed) state->changedXMM |= mask; - } - - // Save variables stored in MEMORY. - state->memVarsCount = memVarsCount; - memVarsCount = 0; - - cur = _active; - if (cur) - { - do { - if (cur->state == VARIABLE_STATE_MEMORY) state->memVarsData[memVarsCount++] = cur; - cur = cur->nextActive; - } while (cur != _active); - } - - // Finished. - return state; -} - -void CompilerContext::_assignState(StateData* state) ASMJIT_NOTHROW -{ - Compiler* compiler = getCompiler(); - - memcpy(&_state, state, sizeof(StateData)); - _state.memVarsCount = 0; - - uint i, mask; - VarData* vdata; - - // Unuse all variables first. - vdata = _active; - if (vdata) - { - do { - vdata->state = VARIABLE_STATE_UNUSED; - vdata = vdata->nextActive; - } while (vdata != _active); - } - - // Assign variables stored in memory which are not unused. - for (i = 0; i < state->memVarsCount; i++) - { - state->memVarsData[i]->state = VARIABLE_STATE_MEMORY; - } - - // Assign allocated variables. - for (i = 0, mask = 1; i < REG_NUM_GP; i++, mask <<= 1) - { - if ((vdata = _state.gp[i]) != NULL) - { - vdata->state = VARIABLE_STATE_REGISTER; - vdata->registerIndex = i; - vdata->changed = (_state.changedGP & mask) != 0; - } - } - - for (i = 0, mask = 1; i < REG_NUM_MM; i++, mask <<= 1) - { - if ((vdata = _state.mm[i]) != NULL) - { - vdata->state = VARIABLE_STATE_REGISTER; - vdata->registerIndex = i; - vdata->changed = (_state.changedMM & mask) != 0; - } - } - - for (i = 0, mask = 1; i < REG_NUM_XMM; i++, mask <<= 1) - { - if ((vdata = _state.xmm[i]) != NULL) - { - vdata->state = VARIABLE_STATE_REGISTER; - vdata->registerIndex = i; - vdata->changed = (_state.changedXMM & mask) != 0; - } - } -} - -void CompilerContext::_restoreState(StateData* state, uint32_t targetOffset) ASMJIT_NOTHROW -{ - // 16 + 8 + 16 = GP + MMX + XMM registers. - static const uint STATE_REGS_COUNT = 16 + 8 + 16; - - StateData* fromState = &_state; - StateData* toState = state; - - // No change, rare... - if (fromState == toState) return; - - uint base; - uint i; - - // -------------------------------------------------------------------------- - // Set target state to all variables. vdata->tempInt is target state in this - // function. - // -------------------------------------------------------------------------- - - { - // UNUSED. - VarData* vdata = _active; - if (vdata) - { - do { - vdata->tempInt = VARIABLE_STATE_UNUSED; - vdata = vdata->nextActive; - } while (vdata != _active); - } - - // MEMORY. - for (i = 0; i < toState->memVarsCount; i++) - { - toState->memVarsData[i]->tempInt = VARIABLE_STATE_MEMORY; - } - - // REGISTER. - for (i = 0; i < StateData::NUM_REGS; i++) - { - if ((vdata = toState->regs[i]) != NULL) vdata->tempInt = VARIABLE_STATE_REGISTER; - } - } - - // -------------------------------------------------------------------------- - // [GP-Registers Switch] - // -------------------------------------------------------------------------- - - // TODO. -#if 0 - for (i = 0; i < REG_NUM_GP; i++) - { - VarData* fromVar = fromState->gp[i]; - VarData* toVar = toState->gp[i]; - - if (fromVar != toVar) - { - if (fromVar != NULL) - { - if (toVar != NULL) - { - if (fromState->gp[to - } - else - { - // It is possible that variable that was saved in state currently not - // exists (tempInt is target scope!). - if (fromVar->tempInt == VARIABLE_STATE_UNUSED) - { - unuseVar(fromVar, VARIABLE_STATE_UNUSED); - } - else - { - spillVar(fromVar); - } - } - } - } - else if (fromVar != NULL) - { - uint32_t mask = Util::maskFromIndex(i); - // Variables are the same, we just need to compare changed flags. - if ((fromState->changedGP & mask) && !(toState->changedGP & mask)) saveVar(fromVar); - } - } -#endif - - // Spill. - for (base = 0, i = 0; i < STATE_REGS_COUNT; i++) - { - // Change the base offset (from base offset the register index can be - // calculated). - if (i == 16 || i == 16 + 8) base = i; - uint32_t regIndex = i - base; - - VarData* fromVar = fromState->regs[i]; - VarData* toVar = toState->regs[i]; - - if (fromVar != toVar) - { - - // Spill the register. - if (fromVar != NULL) - { - // It is possible that variable that was saved in state currently not - // exists (tempInt is target scope!). - if (fromVar->tempInt == VARIABLE_STATE_UNUSED) - { - unuseVar(fromVar, VARIABLE_STATE_UNUSED); - } - else - { - spillVar(fromVar); - } - } - } - else if (fromVar != NULL) - { - uint32_t mask = Util::maskFromIndex(regIndex); - // Variables are the same, we just need to compare changed flags. - if ((fromState->changedGP & mask) && !(toState->changedGP & mask)) - { - saveVar(fromVar); - } - } - } - - // Alloc. - for (base = 0, i = 0; i < STATE_REGS_COUNT; i++) - { - if (i == 16 || i == 24) base = i; - - VarData* fromVar = fromState->regs[i]; - VarData* toVar = toState->regs[i]; - - if (fromVar != toVar) - { - uint32_t regIndex = i - base; - - // Alloc register - if (toVar != NULL) - { - allocVar(toVar, Util::maskFromIndex(regIndex), VARIABLE_ALLOC_READ); - } - } - - // TODO: - //if (toVar) - //{ - // toVar->changed = to->changed; - //} - } - - // -------------------------------------------------------------------------- - // Update used masks. - // -------------------------------------------------------------------------- - - _state.usedGP = state->usedGP; - _state.usedMM = state->usedMM; - _state.usedXMM = state->usedXMM; - - // -------------------------------------------------------------------------- - // Update changed masks and cleanup. - // -------------------------------------------------------------------------- - - { - VarData* vdata = _active; - if (vdata) - { - do { - if (vdata->tempInt != VARIABLE_STATE_REGISTER) - { - vdata->state = (int)vdata->tempInt; - vdata->changed = false; - } - - vdata->tempInt = 0; - vdata = vdata->nextActive; - } while (vdata != _active); - } - } -} - -VarMemBlock* CompilerContext::_allocMemBlock(uint32_t size) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(size != 0); - - // First try to find mem blocks. - VarMemBlock* mem = _memFree; - VarMemBlock* prev = NULL; - - while (mem) - { - VarMemBlock* next = mem->nextFree; - - if (mem->size == size) - { - if (prev) - prev->nextFree = next; - else - _memFree = next; - - mem->nextFree = NULL; - return mem; - } - - prev = mem; - mem = next; - } - - // Never mind, create new. - mem = reinterpret_cast(_zone.zalloc(sizeof(VarMemBlock))); - if (!mem) - { - _compiler->setError(ERROR_NO_HEAP_MEMORY); - return NULL; - } - - mem->offset = 0; - mem->size = size; - - mem->nextUsed = _memUsed; - mem->nextFree = NULL; - - _memUsed = mem; - - switch (size) - { - case 16: _mem16BlocksCount++; break; - case 8: _mem8BlocksCount++; break; - case 4: _mem4BlocksCount++; break; - } - - return mem; -} - -void CompilerContext::_freeMemBlock(VarMemBlock* mem) ASMJIT_NOTHROW -{ - // Add mem to free blocks. - mem->nextFree = _memFree; - _memFree = mem; -} - -void CompilerContext::_allocMemoryOperands() ASMJIT_NOTHROW -{ - VarMemBlock* mem; - - // Variables are allocated in this order: - // 1. 16-byte variables. - // 2. 8-byte variables. - // 3. 4-byte variables. - // 4. All others. - - uint32_t start16 = 0; - uint32_t start8 = start16 + _mem16BlocksCount * 16; - uint32_t start4 = start8 + _mem8BlocksCount * 8; - uint32_t startX = (start4 + _mem4BlocksCount * 4 + 15) & ~15; - - for (mem = _memUsed; mem; mem = mem->nextUsed) - { - uint32_t size = mem->size; - uint32_t offset; - - switch (size) - { - case 16: - offset = start16; - start16 += 16; - break; - - case 8: - offset = start8; - start8 += 8; - break; - - case 4: - offset = start4; - start4 += 4; - break; - - default: - // Align to 16 bytes if size is 16 or more. - if (size >= 16) - { - size = (size + 15) & ~15; - startX = (startX + 15) & ~15; - } - offset = startX; - startX += size; - break; - } - - mem->offset = (int32_t)offset; - _memBytesTotal += size; - } -} - -void CompilerContext::_patchMemoryOperands(Emittable* start, Emittable* stop) ASMJIT_NOTHROW -{ - Emittable* cur; - - for (cur = start;; cur = cur->getNext()) - { - if (cur->getType() == EMITTABLE_INSTRUCTION) - { - Mem* mem = reinterpret_cast(cur)->_memOp; - - if (mem && (mem->_mem.id & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_VAR) - { - VarData* vdata = _compiler->_getVarData(mem->_mem.id); - ASMJIT_ASSERT(vdata != NULL); - - if (vdata->isMemArgument) - { - mem->_mem.base = _argumentsBaseReg; - mem->_mem.displacement += vdata->homeMemoryOffset; - mem->_mem.displacement += _argumentsBaseOffset; - } - else - { - VarMemBlock* mb = reinterpret_cast(vdata->homeMemoryData); - ASMJIT_ASSERT(mb != NULL); - - mem->_mem.base = _variablesBaseReg; - mem->_mem.displacement += mb->offset; - mem->_mem.displacement += _variablesBaseOffset; - } - } - } - if (cur == stop) break; - } -} - -// ============================================================================ -// [AsmJit::CompilerUtil] -// ============================================================================ - -bool CompilerUtil::isStack16ByteAligned() -{ - // Stack is always aligned to 16-bytes when using 64-bit OS. - bool result = (sizeof(sysuint_t) == 8); - - // Modern Linux, APPLE and UNIX guarantees stack alignment to 16 bytes by - // default. I'm really not sure about all UNIX operating systems, because - // 16-byte alignment is an addition to the older specification. -#if (defined(__linux__) || \ - defined(__linux) || \ - defined(linux) || \ - defined(__unix__) || \ - defined(__FreeBSD__) || \ - defined(__NetBSD__) || \ - defined(__OpenBSD__) || \ - defined(__DARWIN__) || \ - defined(__APPLE__) ) - result = true; -#endif // __linux__ - - return result; -} - -// ============================================================================ -// [AsmJit::CompilerCore - Construction / Destruction] -// ============================================================================ - -CompilerCore::CompilerCore(CodeGenerator* codeGenerator) ASMJIT_NOTHROW : - _zone(16384 - sizeof(Zone::Chunk) - 32), - _codeGenerator(codeGenerator != NULL ? codeGenerator : CodeGenerator::getGlobal()), - _logger(NULL), - _error(0), - _properties((1 << PROPERTY_OPTIMIZE_ALIGN)), - _emitOptions(0), - _finished(false), - _first(NULL), - _last(NULL), - _current(NULL), - _function(NULL), - _varNameId(0), - _cc(NULL) -{ -} - -CompilerCore::~CompilerCore() ASMJIT_NOTHROW -{ - free(); -} - -// ============================================================================ -// [AsmJit::CompilerCore - Logging] -// ============================================================================ - -void CompilerCore::setLogger(Logger* logger) ASMJIT_NOTHROW -{ - _logger = logger; -} - -// ============================================================================ -// [AsmJit::CompilerCore - Error Handling] -// ============================================================================ - -void CompilerCore::setError(uint32_t error) ASMJIT_NOTHROW -{ - _error = error; - if (_error == ERROR_NONE) return; - - if (_logger) - { - _logger->logFormat("*** COMPILER ERROR: %s (%u).\n", - getErrorString(error), - (unsigned int)error); - } -} - -// ============================================================================ -// [AsmJit::CompilerCore - Properties] -// ============================================================================ - -uint32_t CompilerCore::getProperty(uint32_t propertyId) -{ - return (_properties & (1 << propertyId)) != 0; -} - -void CompilerCore::setProperty(uint32_t propertyId, uint32_t value) -{ - if (value) - _properties |= (1 << propertyId); - else - _properties &= ~(1 << propertyId); -} - -// ============================================================================ -// [AsmJit::CompilerCore - Buffer] -// ============================================================================ - -void CompilerCore::clear() ASMJIT_NOTHROW -{ - _finished = false; - - delAll(_first); - _first = NULL; - _last = NULL; - _current = NULL; - - _zone.freeAll(); - _targetData.clear(); - _varData.clear(); - - _cc = NULL; - - if (_error) setError(ERROR_NONE); -} - -void CompilerCore::free() ASMJIT_NOTHROW -{ - clear(); - - _targetData.free(); - _varData.free(); -} - -// ============================================================================ -// [AsmJit::CompilerCore - Emittables] -// ============================================================================ - -void CompilerCore::addEmittable(Emittable* emittable) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(emittable != NULL); - ASMJIT_ASSERT(emittable->_prev == NULL); - ASMJIT_ASSERT(emittable->_next == NULL); - - if (_current == NULL) - { - if (!_first) - { - _first = emittable; - _last = emittable; - } - else - { - emittable->_next = _first; - _first->_prev = emittable; - _first = emittable; - } - } - else - { - Emittable* prev = _current; - Emittable* next = _current->_next; - - emittable->_prev = prev; - emittable->_next = next; - - prev->_next = emittable; - if (next) - next->_prev = emittable; - else - _last = emittable; - } - - _current = emittable; -} - -void CompilerCore::addEmittableAfter(Emittable* emittable, Emittable* ref) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(emittable != NULL); - ASMJIT_ASSERT(emittable->_prev == NULL); - ASMJIT_ASSERT(emittable->_next == NULL); - ASMJIT_ASSERT(ref != NULL); - - Emittable* prev = ref; - Emittable* next = ref->_next; - - emittable->_prev = prev; - emittable->_next = next; - - prev->_next = emittable; - if (next) - next->_prev = emittable; - else - _last = emittable; -} - -void CompilerCore::removeEmittable(Emittable* emittable) ASMJIT_NOTHROW -{ - Emittable* prev = emittable->_prev; - Emittable* next = emittable->_next; - - if (_first == emittable) { _first = next; } else { prev->_next = next; } - if (_last == emittable) { _last = prev; } else { next->_prev = prev; } - - emittable->_prev = NULL; - emittable->_next = NULL; - - if (emittable == _current) _current = prev; -} - -Emittable* CompilerCore::setCurrentEmittable(Emittable* current) ASMJIT_NOTHROW -{ - Emittable* old = _current; - _current = current; - return old; -} - -// ============================================================================ -// [AsmJit::CompilerCore - Logging] -// ============================================================================ - -void CompilerCore::comment(const char* fmt, ...) ASMJIT_NOTHROW -{ - char buf[128]; - char* p = buf; - - if (fmt) - { - *p++ = ';'; - *p++ = ' '; - - va_list ap; - va_start(ap, fmt); - p += vsnprintf(p, 100, fmt, ap); - va_end(ap); - } - - *p++ = '\n'; - *p = '\0'; - - addEmittable(Compiler_newObject(this, buf)); -} - -// ============================================================================ -// [AsmJit::CompilerCore - Function Builder] -// ============================================================================ - -EFunction* CompilerCore::newFunction_( - uint32_t callingConvention, - const uint32_t* arguments, - uint32_t argumentsCount, - uint32_t returnValue) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(_function == NULL); - EFunction* f = _function = Compiler_newObject(this); - - f->setPrototype(callingConvention, arguments, argumentsCount, returnValue); - addEmittable(f); - - bind(f->_entryLabel); - addEmittable(f->_prolog); - - _varNameId = 0; - - f->_createVariables(); - return f; -} - -EFunction* CompilerCore::endFunction() ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(_function != NULL); - EFunction* f = _function; - - bind(f->_exitLabel); - addEmittable(f->_epilog); - addEmittable(f->_end); - - f->_finished = true; - _function = NULL; - - return f; -} - -// ============================================================================ -// [AsmJit::CompilerCore - EmitInstruction] -// ============================================================================ - -void CompilerCore::_emitInstruction(uint32_t code) ASMJIT_NOTHROW -{ - EInstruction* e = newInstruction(code, NULL, 0); - if (!e) return; - - addEmittable(e); - if (_cc) { e->_offset = _cc->_currentOffset; e->prepare(*_cc); } -} - -void CompilerCore::_emitInstruction(uint32_t code, const Operand* o0) ASMJIT_NOTHROW -{ - Operand* operands = reinterpret_cast(_zone.zalloc(1 * sizeof(Operand))); - if (!operands) return; - - operands[0] = *o0; - - EInstruction* e = newInstruction(code, operands, 1); - if (!e) return; - - addEmittable(e); - if (_cc) { e->_offset = _cc->_currentOffset; e->prepare(*_cc); } -} - -void CompilerCore::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1) ASMJIT_NOTHROW -{ - Operand* operands = reinterpret_cast(_zone.zalloc(2 * sizeof(Operand))); - if (!operands) return; - - operands[0] = *o0; - operands[1] = *o1; - - EInstruction* e = newInstruction(code, operands, 2); - if (!e) return; - - addEmittable(e); - if (_cc) { e->_offset = _cc->_currentOffset; e->prepare(*_cc); } -} - -void CompilerCore::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2) ASMJIT_NOTHROW -{ - Operand* operands = reinterpret_cast(_zone.zalloc(3 * sizeof(Operand))); - if (!operands) return; - - operands[0] = *o0; - operands[1] = *o1; - operands[2] = *o2; - - EInstruction* e = newInstruction(code, operands, 3); - if (!e) return; - - addEmittable(e); - if (_cc) { e->_offset = _cc->_currentOffset; e->prepare(*_cc); } -} - -void CompilerCore::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3) ASMJIT_NOTHROW -{ - Operand* operands = reinterpret_cast(_zone.zalloc(4 * sizeof(Operand))); - if (!operands) return; - - operands[0] = *o0; - operands[1] = *o1; - operands[2] = *o2; - operands[3] = *o3; - - EInstruction* e = newInstruction(code, operands, 4); - if (!e) return; - - addEmittable(e); - if (_cc) { e->_offset = _cc->_currentOffset; e->prepare(*_cc); } -} - -void CompilerCore::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3, const Operand* o4) ASMJIT_NOTHROW -{ - Operand* operands = reinterpret_cast(_zone.zalloc(5 * sizeof(Operand))); - if (!operands) return; - - operands[0] = *o0; - operands[1] = *o1; - operands[2] = *o2; - operands[3] = *o3; - operands[4] = *o4; - - EInstruction* e = newInstruction(code, operands, 5); - if (!e) return; - - addEmittable(e); - if (_cc) { e->_offset = _cc->_currentOffset; e->prepare(*_cc); } -} - -void CompilerCore::_emitJcc(uint32_t code, const Label* label, uint32_t hint) ASMJIT_NOTHROW -{ - if (!hint) - { - _emitInstruction(code, label); - } - else - { - Imm imm(hint); - _emitInstruction(code, label, &imm); - } -} - -ECall* CompilerCore::_emitCall(const Operand* o0) ASMJIT_NOTHROW -{ - EFunction* fn = getFunction(); - if (!fn) { setError(ERROR_NO_FUNCTION); return NULL; } - - ECall* eCall = Compiler_newObject(this, fn, o0); - if (!eCall) { setError(ERROR_NO_HEAP_MEMORY); return NULL; } - - addEmittable(eCall); - return eCall; -} - -void CompilerCore::_emitReturn(const Operand* first, const Operand* second) ASMJIT_NOTHROW -{ - EFunction* fn = getFunction(); - if (!fn) { setError(ERROR_NO_FUNCTION); return; } - - ERet* eRet = Compiler_newObject(this, fn, first, second); - if (!eRet) { setError(ERROR_NO_HEAP_MEMORY); return; } - - addEmittable(eRet); -} - -// ============================================================================ -// [AsmJit::CompilerCore - Embed] -// ============================================================================ - -void CompilerCore::embed(const void* data, sysuint_t size) ASMJIT_NOTHROW -{ - // Align length to 16 bytes. - sysuint_t alignedSize = (size + 15) & ~15; - - EData* e = - new(_zone.zalloc(sizeof(EData) - sizeof(void*) + alignedSize)) - EData(reinterpret_cast(this), data, size); - addEmittable(e); -} - -// ============================================================================ -// [AsmJit::CompilerCore - Align] -// ============================================================================ - -void CompilerCore::align(uint32_t m) ASMJIT_NOTHROW -{ - addEmittable(Compiler_newObject(this, m)); -} - -// ============================================================================ -// [AsmJit::CompilerCore - Label] -// ============================================================================ - -Label CompilerCore::newLabel() ASMJIT_NOTHROW -{ - Label label; - label._base.id = (uint32_t)_targetData.getLength() | OPERAND_ID_TYPE_LABEL; - - ETarget* target = Compiler_newObject(this, label); - _targetData.append(target); - - return label; -} - -void CompilerCore::bind(const Label& label) ASMJIT_NOTHROW -{ - uint32_t id = label.getId() & OPERAND_ID_VALUE_MASK; - ASMJIT_ASSERT(id != INVALID_VALUE); - ASMJIT_ASSERT(id < _targetData.getLength()); - - addEmittable(_targetData[id]); -} - -// ============================================================================ -// [AsmJit::CompilerCore - Variables] -// ============================================================================ - -VarData* CompilerCore::_newVarData(const char* name, uint32_t type, uint32_t size) ASMJIT_NOTHROW -{ - VarData* vdata = reinterpret_cast(_zone.zalloc(sizeof(VarData))); - if (vdata == NULL) return NULL; - - char nameBuffer[32]; - if (name == NULL) - { - sprintf(nameBuffer, "var_%d", _varNameId); - name = nameBuffer; - _varNameId++; - } - - vdata->scope = getFunction(); - vdata->firstEmittable = NULL; - vdata->firstCallable = NULL; - vdata->lastEmittable = NULL; - - vdata->name = _zone.zstrdup(name); - vdata->id = (uint32_t)_varData.getLength() | OPERAND_ID_TYPE_VAR; - vdata->type = type; - vdata->size = size; - - vdata->homeRegisterIndex = INVALID_VALUE; - vdata->prefRegisterMask = 0; - - vdata->homeMemoryData = NULL; - - vdata->registerIndex = INVALID_VALUE; - vdata->workOffset = INVALID_VALUE; - - vdata->nextActive = NULL; - vdata->prevActive = NULL; - - vdata->priority = 10; - vdata->calculated = false; - vdata->isRegArgument = false; - vdata->isMemArgument = false; - - vdata->state = VARIABLE_STATE_UNUSED; - vdata->changed = false; - vdata->saveOnUnuse = false; - - vdata->registerReadCount = 0; - vdata->registerWriteCount = 0; - vdata->registerRWCount = 0; - - vdata->registerGPBLoCount = 0; - vdata->registerGPBHiCount = 0; - - vdata->memoryReadCount = 0; - vdata->memoryWriteCount = 0; - vdata->memoryRWCount = 0; - - vdata->tempPtr = NULL; - - _varData.append(vdata); - return vdata; -} - -GPVar CompilerCore::newGP(uint32_t variableType, const char* name) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT((variableType < _VARIABLE_TYPE_COUNT) && - (variableInfo[variableType].clazz & VariableInfo::CLASS_GP) != 0); - -#if defined(ASMJIT_X86) - if (variableInfo[variableType].size > 4) - { - variableType = VARIABLE_TYPE_GPD; - if (_logger) - { - _logger->logString("*** COMPILER WARNING: Translated QWORD variable to DWORD, FIX YOUR CODE! ***\n"); - } - } -#endif // ASMJIT_X86 - - VarData* vdata = _newVarData(name, variableType, variableInfo[variableType].size); - return GPVarFromData(vdata); -} - -GPVar CompilerCore::argGP(uint32_t index) ASMJIT_NOTHROW -{ - GPVar var; - EFunction* f = getFunction(); - - if (f) - { - const FunctionPrototype& prototype = f->getPrototype(); - if (index < prototype.getArgumentsCount()) - { - VarData* vdata = getFunction()->_argumentVariables[index]; - - var._var.id = vdata->id; - var._var.size = vdata->size; - var._var.registerCode = variableInfo[vdata->type].code; - var._var.variableType = vdata->type; - } - } - - return var; -} - -MMVar CompilerCore::newMM(uint32_t variableType, const char* name) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT((variableType < _VARIABLE_TYPE_COUNT) && - (variableInfo[variableType].clazz & VariableInfo::CLASS_MM) != 0); - - VarData* vdata = _newVarData(name, variableType, 8); - return MMVarFromData(vdata); -} - -MMVar CompilerCore::argMM(uint32_t index) ASMJIT_NOTHROW -{ - MMVar var; - EFunction* f = getFunction(); - - if (f) - { - const FunctionPrototype& prototype = f->getPrototype(); - if (index < prototype.getArgumentsCount()) - { - VarData* vdata = getFunction()->_argumentVariables[index]; - - var._var.id = vdata->id; - var._var.size = vdata->size; - var._var.registerCode = variableInfo[vdata->type].code; - var._var.variableType = vdata->type; - } - } - - return var; -} - -XMMVar CompilerCore::newXMM(uint32_t variableType, const char* name) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT((variableType < _VARIABLE_TYPE_COUNT) && - (variableInfo[variableType].clazz & VariableInfo::CLASS_XMM) != 0); - - VarData* vdata = _newVarData(name, variableType, 16); - return XMMVarFromData(vdata); -} - -XMMVar CompilerCore::argXMM(uint32_t index) ASMJIT_NOTHROW -{ - XMMVar var; - EFunction* f = getFunction(); - - if (f) - { - const FunctionPrototype& prototype = f->getPrototype(); - if (index < prototype.getArgumentsCount()) - { - VarData* vdata = getFunction()->_argumentVariables[index]; - - var._var.id = vdata->id; - var._var.size = vdata->size; - var._var.registerCode = variableInfo[vdata->type].code; - var._var.variableType = vdata->type; - } - } - - return var; -} - -void CompilerCore::_vhint(BaseVar& var, uint32_t hintId, uint32_t hintValue) ASMJIT_NOTHROW -{ - if (var.getId() == INVALID_VALUE) - return; - - VarData* vdata = _getVarData(var.getId()); - ASMJIT_ASSERT(vdata != NULL); - - EVariableHint* e = Compiler_newObject(this, vdata, hintId, hintValue); - addEmittable(e); -} - -void CompilerCore::alloc(BaseVar& var) ASMJIT_NOTHROW -{ - _vhint(var, VARIABLE_HINT_ALLOC, INVALID_VALUE); -} - -void CompilerCore::alloc(BaseVar& var, uint32_t regIndex) ASMJIT_NOTHROW -{ - if (regIndex > 31) - return; - - _vhint(var, VARIABLE_HINT_ALLOC, 1 << regIndex); -} - -void CompilerCore::alloc(BaseVar& var, const BaseReg& reg) ASMJIT_NOTHROW -{ - _vhint(var, VARIABLE_HINT_ALLOC, 1 << reg.getRegIndex()); -} - -void CompilerCore::save(BaseVar& var) ASMJIT_NOTHROW -{ - _vhint(var, VARIABLE_HINT_SAVE, INVALID_VALUE); -} - -void CompilerCore::spill(BaseVar& var) ASMJIT_NOTHROW -{ - _vhint(var, VARIABLE_HINT_SPILL, INVALID_VALUE); -} - -void CompilerCore::unuse(BaseVar& var) ASMJIT_NOTHROW -{ - _vhint(var, VARIABLE_HINT_UNUSE, INVALID_VALUE); -} - -uint32_t CompilerCore::getPriority(BaseVar& var) const ASMJIT_NOTHROW -{ - if (var.getId() == INVALID_VALUE) - return INVALID_VALUE; - - VarData* vdata = _getVarData(var.getId()); - ASMJIT_ASSERT(vdata != NULL); - - return vdata->priority; -} - -void CompilerCore::setPriority(BaseVar& var, uint32_t priority) ASMJIT_NOTHROW -{ - if (var.getId() == INVALID_VALUE) - return; - - VarData* vdata = _getVarData(var.getId()); - ASMJIT_ASSERT(vdata != NULL); - - if (priority > 100) priority = 100; - vdata->priority = (uint8_t)priority; -} - -bool CompilerCore::getSaveOnUnuse(BaseVar& var) const ASMJIT_NOTHROW -{ - if (var.getId() == INVALID_VALUE) - return false; - - VarData* vdata = _getVarData(var.getId()); - ASMJIT_ASSERT(vdata != NULL); - - return (bool)vdata->saveOnUnuse; -} - -void CompilerCore::setSaveOnUnuse(BaseVar& var, bool value) ASMJIT_NOTHROW -{ - if (var.getId() == INVALID_VALUE) - return; - - VarData* vdata = _getVarData(var.getId()); - ASMJIT_ASSERT(vdata != NULL); - - vdata->saveOnUnuse = value; -} - -void CompilerCore::rename(BaseVar& var, const char* name) ASMJIT_NOTHROW -{ - if (var.getId() == INVALID_VALUE) - return; - - VarData* vdata = _getVarData(var.getId()); - ASMJIT_ASSERT(vdata != NULL); - - vdata->name = _zone.zstrdup(name); -} - -// ============================================================================ -// [AsmJit::CompilerCore - State] -// ============================================================================ - -StateData* CompilerCore::_newStateData(uint32_t memVarsCount) ASMJIT_NOTHROW -{ - StateData* state = reinterpret_cast(_zone.zalloc(sizeof(StateData) + memVarsCount * sizeof(void*))); - return state; -} - -// ============================================================================ -// [AsmJit::CompilerCore - Make] -// ============================================================================ - -void* CompilerCore::make() ASMJIT_NOTHROW -{ - Assembler a(_codeGenerator); - - a._properties = _properties; - a.setLogger(_logger); - - serialize(a); - - if (this->getError()) - { - return NULL; - } - - if (a.getError()) - { - setError(a.getError()); - return NULL; - } - - void* result = a.make(); - - if (_logger) - { - _logger->logFormat("*** COMPILER SUCCESS - Wrote %u bytes, code: %u, trampolines: %u.\n\n", - (unsigned int)a.getCodeSize(), - (unsigned int)a.getOffset(), - (unsigned int)a.getTrampolineSize()); - } - - return result; -} - -void CompilerCore::serialize(Assembler& a) ASMJIT_NOTHROW -{ - // Context. - CompilerContext cc(reinterpret_cast(this)); - - Emittable* start = _first; - Emittable* stop = NULL; - - // Register all labels. - a.registerLabels(_targetData.getLength()); - - // Make code. - for (;;) - { - _cc = NULL; - - // ------------------------------------------------------------------------ - // Find a function. - for (;;) - { - if (start == NULL) return; - if (start->getType() == EMITTABLE_FUNCTION) - break; - else - start->emit(a); - - start = start->getNext(); - } - // ------------------------------------------------------------------------ - - // ------------------------------------------------------------------------ - // Setup code generation context. - Emittable* cur; - - cc._function = reinterpret_cast(start); - cc._start = start; - cc._stop = stop = cc._function->getEnd(); - cc._extraBlock = stop->getPrev(); - - // Detect whether the function generation was finished. - if (!cc._function->_finished || cc._function->getEnd()->getPrev() == NULL) - { - setError(ERROR_INCOMPLETE_FUNCTION); - return; - } - // ------------------------------------------------------------------------ - - // ------------------------------------------------------------------------ - // Step 1: - // - Assign/increment offset to each emittable. - // - Extract variables from instructions. - // - Prepare variables for register allocator: - // - Update read(r) / write(w) / overwrite(x) statistics. - // - Update register / memory usage statistics. - // - Find scope (first / last emittable) of variables. - for (cur = start; ; cur = cur->getNext()) - { - cur->prepare(cc); - if (cur == stop) break; - } - // ------------------------------------------------------------------------ - - // We set compiler context also to Compiler so new emitted instructions - // can call prepare() to itself. - _cc = &cc; - - // ------------------------------------------------------------------------ - // Step 2: - // - Translate special instructions (imul, cmpxchg8b, ...). - // - Alloc registers. - // - Translate forward jumps. - // - Alloc memory operands (variables related). - // - Emit function prolog. - // - Emit function epilog. - // - Patch memory operands (variables related). - // - Dump function prototype and variable statistics (if enabled). - - // Translate special instructions and run alloc registers. - cur = start; - - do { - do { - // Assign current offset for each emittable back to CompilerContext. - cc._currentOffset = cur->_offset; - // Assign previous emittable to compiler so each variable spill/alloc will - // be emitted before. - _current = cur->getPrev(); - - cur = cur->translate(cc); - } while (cur); - - cc._unreachable = true; - - sysuint_t len = cc._backCode.getLength(); - while (cc._backPos < len) - { - cur = cc._backCode[cc._backPos++]->getNext(); - if (!cur->isTranslated()) break; - - cur = NULL; - } - } while (cur); - - // Translate forward jumps. - { - ForwardJumpData* j = cc._forwardJumps; - while (j) - { - cc._assignState(j->state); - _current = j->inst->getPrev(); - j->inst->_doJump(cc); - j = j->next; - } - } - - // Alloc memory operands (variables related). - cc._allocMemoryOperands(); - - // Emit function prolog / epilog. - cc._function->_preparePrologEpilog(cc); - - _current = cc._function->_prolog; - cc._function->_emitProlog(cc); - - _current = cc._function->_epilog; - cc._function->_emitEpilog(cc); - - // Patch memory operands (variables related). - _current = _last; - cc._patchMemoryOperands(start, stop); - - // Dump function prototype and variable statistics (if enabled). - if (_logger) - { - cc._function->_dumpFunction(cc); - } - // ------------------------------------------------------------------------ - - // ------------------------------------------------------------------------ - // Hack: need to register labels that was created by the Step 2. - if (a._labelData.getLength() < _targetData.getLength()) - { - a.registerLabels(_targetData.getLength() - a._labelData.getLength()); - } - - Emittable* extraBlock = cc._extraBlock; - - // Step 3: - // - Emit instructions to Assembler stream. - for (cur = start; ; cur = cur->getNext()) - { - cur->emit(a); - if (cur == extraBlock) break; - } - // ------------------------------------------------------------------------ - - // ------------------------------------------------------------------------ - // Step 4: - // - Emit everything else (post action). - for (cur = start; ; cur = cur->getNext()) - { - cur->post(a); - if (cur == extraBlock) break; - } - // ------------------------------------------------------------------------ - - start = extraBlock->getNext(); - cc._clear(); - } -} - -// ============================================================================ -// [AsmJit::Compiler - Construction / Destruction] -// ============================================================================ - -Compiler::Compiler(CodeGenerator* codeGenerator) ASMJIT_NOTHROW : - CompilerIntrinsics(codeGenerator) -{ -} - -Compiler::~Compiler() ASMJIT_NOTHROW -{ -} - -} // AsmJit namespace - -// [Api-End] -#include "ApiEnd.h" diff --git a/desmume/src/utils/AsmJit/CompilerX86X64.h b/desmume/src/utils/AsmJit/CompilerX86X64.h deleted file mode 100644 index 812a342e7..000000000 --- a/desmume/src/utils/AsmJit/CompilerX86X64.h +++ /dev/null @@ -1,8922 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_COMPILERX86X64_H -#define _ASMJIT_COMPILERX86X64_H - -#if !defined(_ASMJIT_COMPILER_H) -#warning "AsmJit/CompilerX86X64.h can be only included by AsmJit/Compiler.h" -#endif // _ASMJIT_COMPILER_H - -// [Dependencies] -#include "Build.h" -#include "Assembler.h" -#include "Defs.h" -#include "Operand.h" -#include "Util.h" - -#include - -// A little bit C++. -#include - -// [Api-Begin] -#include "ApiBegin.h" - -//! @internal -//! -//! @brief Mark methods not supported by @ref Compiler. These methods are -//! usually used only in function prologs/epilogs or to manage stack. -#define ASMJIT_NOT_SUPPORTED_BY_COMPILER 0 - -namespace AsmJit { - -//! @addtogroup AsmJit_Compiler -//! @{ - -// ============================================================================ -// [AsmJit::TypeToId] -// ============================================================================ - -// Skip documenting this. -#if !defined(ASMJIT_NODOC) - -ASMJIT_DECLARE_TYPE_AS_ID(int8_t, VARIABLE_TYPE_GPD); -ASMJIT_DECLARE_TYPE_AS_ID(uint8_t, VARIABLE_TYPE_GPD); - -ASMJIT_DECLARE_TYPE_AS_ID(int16_t, VARIABLE_TYPE_GPD); -ASMJIT_DECLARE_TYPE_AS_ID(uint16_t, VARIABLE_TYPE_GPD); - -ASMJIT_DECLARE_TYPE_AS_ID(int32_t, VARIABLE_TYPE_GPD); -ASMJIT_DECLARE_TYPE_AS_ID(uint32_t, VARIABLE_TYPE_GPD); - -#if defined(ASMJIT_X64) -ASMJIT_DECLARE_TYPE_AS_ID(int64_t, VARIABLE_TYPE_GPQ); -ASMJIT_DECLARE_TYPE_AS_ID(uint64_t, VARIABLE_TYPE_GPQ); -#endif // ASMJIT_X64 - -ASMJIT_DECLARE_TYPE_AS_ID(float, VARIABLE_TYPE_FLOAT); -ASMJIT_DECLARE_TYPE_AS_ID(double, VARIABLE_TYPE_DOUBLE); - -#endif // !ASMJIT_NODOC - -// ============================================================================ -// [AsmJit::FunctionPrototype] -// ============================================================================ - -//! @brief Calling convention and function argument handling. -struct ASMJIT_API FunctionPrototype -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref FunctionPrototype instance. - FunctionPrototype() ASMJIT_NOTHROW; - //! @brief Destroy the @ref FunctionPrototype instance. - ~FunctionPrototype() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Argument] - // -------------------------------------------------------------------------- - - //! @brief Function argument location. - struct Argument - { - //! @brief Variable type, see @c VARIABLE_TYPE. - uint32_t variableType; - //! @brief Register index if argument is passed through register, otherwise - //! @c INVALID_VALUE. - uint32_t registerIndex; - //! @brief Stack offset if argument is passed through stack, otherwise - //! @c INVALID_VALUE. - int32_t stackOffset; - - //! @brief Get whether the argument is assigned, for private use only. - inline bool isAssigned() const ASMJIT_NOTHROW - { return registerIndex != INVALID_VALUE || stackOffset != (int32_t)INVALID_VALUE; } - }; - - // -------------------------------------------------------------------------- - // [Methods] - // -------------------------------------------------------------------------- - - //! @brief Set function prototype. - //! - //! This will set function calling convention and setup arguments variables. - //! - //! @note This function will allocate variables, it can be called only once. - void setPrototype( - uint32_t callingConvention, - const uint32_t* arguments, - uint32_t argumentsCount, - uint32_t returnValue) ASMJIT_NOTHROW; - - //! @brief Get function calling convention, see @c CALL_CONV. - inline uint32_t getCallingConvention() const ASMJIT_NOTHROW { return _callingConvention; } - - //! @brief Get whether the callee pops the stack. - inline uint32_t getCalleePopsStack() const ASMJIT_NOTHROW { return _calleePopsStack; } - - //! @brief Get function arguments. - inline Argument* getArguments() ASMJIT_NOTHROW { return _arguments; } - //! @brief Get function arguments (const version). - inline const Argument* getArguments() const ASMJIT_NOTHROW { return _arguments; } - - //! @brief Get count of arguments. - inline uint32_t getArgumentsCount() const ASMJIT_NOTHROW { return _argumentsCount; } - - //! @brief Get function return value or @ref INVALID_VALUE if it's void. - inline uint32_t getReturnValue() const ASMJIT_NOTHROW { return _returnValue; } - - //! @brief Get direction of arguments passed on the stack. - //! - //! Direction should be always @c ARGUMENT_DIR_RIGHT_TO_LEFT. - //! - //! @note This is related to used calling convention, it's not affected by - //! number of function arguments or their types. - inline uint32_t getArgumentsDirection() const ASMJIT_NOTHROW { return _argumentsDirection; } - - //! @brief Get stack size needed for function arguments passed on the stack. - inline uint32_t getArgumentsStackSize() const ASMJIT_NOTHROW { return _argumentsStackSize; } - - //! @brief Get registers used to pass first integer parameters by current - //! calling convention. - //! - //! @note This is related to used calling convention, it's not affected by - //! number of function arguments or their types. - inline const uint32_t* getArgumentsGPList() const ASMJIT_NOTHROW { return _argumentsGPList; } - - //! @brief Get registers used to pass first SP-FP or DP-FPparameters by - //! current calling convention. - //! - //! @note This is related to used calling convention, it's not affected by - //! number of function arguments or their types. - inline const uint32_t* getArgumentsXMMList() const ASMJIT_NOTHROW { return _argumentsXMMList; } - - //! @brief Get bitmask of GP registers which might be used for arguments. - inline uint32_t getArgumentsGP() const ASMJIT_NOTHROW { return _argumentsGP; } - //! @brief Get bitmask of MM registers which might be used for arguments. - inline uint32_t getArgumentsMM() const ASMJIT_NOTHROW { return _argumentsMM; } - //! @brief Get bitmask of XMM registers which might be used for arguments. - inline uint32_t getArgumentsXMM() const ASMJIT_NOTHROW { return _argumentsXMM; } - - //! @brief Get bitmask of general purpose registers that's preserved - //! (non-volatile). - //! - //! @note This is related to used calling convention, it's not affected by - //! number of function arguments or their types. - inline uint32_t getPreservedGP() const ASMJIT_NOTHROW { return _preservedGP; } - - //! @brief Get bitmask of MM registers that's preserved (non-volatile). - //! - //! @note No standardized calling function is not preserving MM registers. - //! This member is here for extension writers who need for some reason custom - //! calling convention that can be called through code generated by AsmJit - //! (or other runtime code generator). - inline uint32_t getPreservedMM() const ASMJIT_NOTHROW { return _preservedMM; } - - //! @brief Return bitmask of XMM registers that's preserved (non-volatile). - //! - //! @note This is related to used calling convention, it's not affected by - //! number of function arguments or their types. - inline uint32_t getPreservedXMM() const ASMJIT_NOTHROW { return _preservedXMM; } - - //! @brief Get mask of all GP registers used to pass function arguments. - inline uint32_t getPassedGP() const ASMJIT_NOTHROW { return _passedGP; } - //! @brief Get mask of all MM registers used to pass function arguments. - inline uint32_t getPassedMM() const ASMJIT_NOTHROW { return _passedMM; } - //! @brief Get mask of all XMM registers used to pass function arguments. - inline uint32_t getPassedXMM() const ASMJIT_NOTHROW { return _passedXMM; } - - //! @brief Find argument (id) by the register code. Used mainly by @ref ECall - //! emittable. - uint32_t findArgumentByRegisterCode(uint32_t regCode) const ASMJIT_NOTHROW; - -protected: - - // -------------------------------------------------------------------------- - // [Private] - // -------------------------------------------------------------------------- - - void _clear() ASMJIT_NOTHROW; - void _setCallingConvention(uint32_t callingConvention) ASMJIT_NOTHROW; - void _setPrototype( - const uint32_t* arguments, - uint32_t argumentsCount, - uint32_t returnValue) ASMJIT_NOTHROW; - void _setReturnValue(uint32_t valueId) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! @brief Calling convention. - uint32_t _callingConvention; - //! @brief Whether callee pops stack. - uint32_t _calleePopsStack; - - //! @brief List of arguments, their register codes or stack locations. - Argument _arguments[FUNC_MAX_ARGS]; - - //! @brief Function return value. - uint32_t _returnValue; - - //! @brief Count of arguments (in @c _argumentsList). - uint32_t _argumentsCount; - //! @brief Direction for arguments passed on the stack, see @c ARGUMENT_DIR. - uint32_t _argumentsDirection; - //! @brief Count of bytes consumed by arguments on the stack. - uint32_t _argumentsStackSize; - - //! @brief List of registers that's used for first GP arguments. - uint32_t _argumentsGPList[16]; - //! @brief List of registers that's used for first XMM arguments. - uint32_t _argumentsXMMList[16]; - - //! @brief Bitmask for preserved GP registers. - uint32_t _argumentsGP; - //! @brief Bitmask for preserved MM registers. - uint32_t _argumentsMM; - //! @brief Bitmask for preserved XMM registers. - uint32_t _argumentsXMM; - - //! @brief Bitmask for preserved GP registers. - uint32_t _preservedGP; - //! @brief Bitmask for preserved MM registers. - uint32_t _preservedMM; - //! @brief Bitmask for preserved XMM registers. - uint32_t _preservedXMM; - - // Set by _setPrototype(). - - //! @brief Bitmask for GP registers used as function arguments. - uint32_t _passedGP; - //! @brief Bitmask for GP registers used as function arguments. - uint32_t _passedMM; - //! @brief Bitmask for GP registers used as function arguments. - uint32_t _passedXMM; -}; - -// ============================================================================ -// [AsmJit::VarData] -// ============================================================================ - -//! @brief Variable data (used internally by @c Compiler). -struct VarData -{ - // -------------------------------------------------------------------------- - // [Scope] - // -------------------------------------------------------------------------- - - //! @brief Scope (NULL if variable is global). - EFunction* scope; - - //! @brief The first emittable where the variable is accessed. - //! - //! @note If this member is @c NULL then variable is unused. - Emittable* firstEmittable; - //! @brief The first callable (ECall) which is after the @c firstEmittable. - ECall* firstCallable; - //! @brief The last emittable where the variable is accessed. - Emittable* lastEmittable; - - // -------------------------------------------------------------------------- - // [Id / Name] - // -------------------------------------------------------------------------- - - //! @brief Variable name. - const char* name; - //! @brief Variable id. - uint32_t id; - //! @brief Variable type. - uint32_t type; - //! @brief Variable size. - uint32_t size; - - // -------------------------------------------------------------------------- - // [Home] - // -------------------------------------------------------------------------- - - //! @brief Home register index or @c INVALID_VALUE (used by register allocator). - uint32_t homeRegisterIndex; - //! @brief Preferred register index. - uint32_t prefRegisterMask; - - //! @brief Home memory address offset. - int32_t homeMemoryOffset; - //! @brief Used by @c CompilerContext, do not touch (NULL when created). - void* homeMemoryData; - - // -------------------------------------------------------------------------- - // [Actual] - // -------------------------------------------------------------------------- - - //! @brief Actual register index (connected with actual @c StateData). - uint32_t registerIndex; - //! @brief Actual working offset. This member is set before register allocator - //! is called. If workOffset is same as CompilerContext::_currentOffset then - //! this variable is probably used in next instruction and can't be spilled. - uint32_t workOffset; - - //! @brief Next active variable in circular double-linked list. - VarData* nextActive; - //! @brief Previous active variable in circular double-linked list. - VarData* prevActive; - - // -------------------------------------------------------------------------- - // [Flags] - // -------------------------------------------------------------------------- - - //! @brief Variable priority. - uint8_t priority; - //! @brief Whether variable content can be calculated by simple instruction - //! - //! This is used mainly by mmx or sse2 code and variable allocator will - //! never reserve space for this variable. Calculated variables are for - //! example all zeros, all ones, etc. - uint8_t calculated; - //! @brief Whether variable is argument passed through register. - uint8_t isRegArgument; - //! @brief Whether variable is argument passed through memory. - uint8_t isMemArgument; - - //! @brief Variable state (connected with actual @c StateData). - uint8_t state; - //! @brief Whether variable was changed (connected with actual @c StateData). - uint8_t changed; - //! @brief Save on unuse (at end of the variable scope). - uint8_t saveOnUnuse; - - // -------------------------------------------------------------------------- - // [Statistics] - // -------------------------------------------------------------------------- - - //! @brief Register read statistics (used by instructions where this variable needs - //! to be read only). - uint32_t registerReadCount; - //! @brief Register write statistics (used by instructions where this variable needs - //! to be write only). - uint32_t registerWriteCount; - //! @brief Register read+write statistics (used by instructions where this variable - //! needs to be read and write). - uint32_t registerRWCount; - - //! @brief Register GPB.LO statistics (for code generator). - uint32_t registerGPBLoCount; - //! @brief Register GPB.HI statistics (for code generator). - uint32_t registerGPBHiCount; - - //! @brief Memory read statistics. - uint32_t memoryReadCount; - //! @brief Memory write statistics. - uint32_t memoryWriteCount; - //! @brief Memory read+write statistics. - uint32_t memoryRWCount; - - // -------------------------------------------------------------------------- - // [Temporary] - // -------------------------------------------------------------------------- - - //! @brief Temporary data that can be used in prepare/translate stage. - //! - //! Initial value is NULL and each emittable/code that will use it must also - //! clear it. - //! - //! This temporary data is designed to be used by algorithms that need to - //! set some state into the variables, do something and then cleanup. See - //! state-switch and function call. - union - { - void* tempPtr; - sysint_t tempInt; - }; -}; - -// ============================================================================ -// [AsmJit::VarMemBlock] -// ============================================================================ - -struct VarMemBlock -{ - int32_t offset; - uint32_t size; - - VarMemBlock* nextUsed; - VarMemBlock* nextFree; -}; - -// ============================================================================ -// [AsmJit::VarAllocRecord] -// ============================================================================ - -//! @brief Variable alloc record (for each instruction that uses variables). -//! -//! Variable record contains pointer to variable data and register allocation -//! flags. These flags are important to determine the best alloc instruction. -struct VarAllocRecord -{ - //! @brief Variable data (the structure owned by @c Compiler). - VarData* vdata; - //! @brief Variable alloc flags, see @c VARIABLE_ALLOC. - uint32_t vflags; - //! @brief Register mask (default is 0). - uint32_t regMask; -}; - -// ============================================================================ -// [AsmJit::VarCallRecord] -// ============================================================================ - -//! @brief Variable call-fn record (for each callable that uses variables). -//! -//! This record contains variables that are used to call a function (using -//! @c ECall emittable). Each variable contains the registers where it must -//! be and registers where the value will be returned. -struct VarCallRecord -{ - //! @brief Variable data (the structure owned by @c Compiler). - VarData* vdata; - uint32_t flags; - - uint8_t inCount; - uint8_t inDone; - - uint8_t outCount; - uint8_t outDone; - - enum FLAGS - { - FLAG_IN_GP = 0x0001, - FLAG_IN_MM = 0x0002, - FLAG_IN_XMM = 0x0004, - FLAG_IN_STACK = 0x0008, - - FLAG_OUT_EAX = 0x0010, - FLAG_OUT_EDX = 0x0020, - FLAG_OUT_ST0 = 0x0040, - FLAG_OUT_ST1 = 0x0080, - FLAG_OUT_MM0 = 0x0100, - FLAG_OUT_XMM0 = 0x0400, - FLAG_OUT_XMM1 = 0x0800, - - FLAG_IN_MEM_PTR = 0x1000, - FLAG_CALL_OPERAND_REG = 0x2000, - FLAG_CALL_OPERAND_MEM = 0x4000, - - FLAG_UNUSE_AFTER_USE = 0x8000 - }; -}; - -// ============================================================================ -// [AsmJit::VarHintRecord] -// ============================================================================ - -struct VarHintRecord -{ - VarData* vdata; - uint32_t hint; -}; - -// ============================================================================ -// [AsmJit::StateData] -// ============================================================================ - -//! @brief State data. -struct StateData -{ - enum { NUM_REGS = 16 + 8 + 16 }; - - inline void clear() ASMJIT_NOTHROW - { - memset(this, 0, sizeof(*this)); - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - union - { - //! @brief All allocated variables in one array. - VarData* regs[NUM_REGS]; - - struct - { - //! @brief Allocated GP registers. - VarData* gp[16]; - //! @brief Allocated MM registers. - VarData* mm[8]; - //! @brief Allocated XMM registers. - VarData* xmm[16]; - }; - }; - - //! @brief Used GP registers bitmask. - uint32_t usedGP; - //! @brief Used MM registers bitmask. - uint32_t usedMM; - //! @brief Used XMM registers bitmask. - uint32_t usedXMM; - - //! @brief Changed GP registers bitmask. - uint32_t changedGP; - //! @brief Changed MM registers bitmask. - uint32_t changedMM; - //! @brief Changed XMM registers bitmask. - uint32_t changedXMM; - - //! @brief Count of variables in @c memVarsData. - uint32_t memVarsCount; - //! @brief Variables stored in memory (@c VARIABLE_STATE_MEMORY). - //! - //! When saving / restoring state it's important to keep registers which are - //! still in memory. Register is always unused when it is going out-of-scope. - //! All variables which are not here are unused (@c VARIABLE_STATE_UNUSED). - VarData* memVarsData[1]; -}; - -// ============================================================================ -// [AsmJit::ForwardJumpData] -// ============================================================================ - -struct ForwardJumpData -{ - EJmp* inst; - StateData* state; - ForwardJumpData* next; -}; - -// ============================================================================ -// [AsmJit::EVariableHint] -// ============================================================================ - -//! @brief Variable hint. -struct ASMJIT_API EVariableHint : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref EVariableHint instance. - EVariableHint(Compiler* c, VarData* vdata, uint32_t hintId, uint32_t hintValue) ASMJIT_NOTHROW; - //! @brief Destroy the @ref EVariableHInt instance. - virtual ~EVariableHint() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; - virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - virtual int getMaxSize() const ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Hint] - // -------------------------------------------------------------------------- - - //! @brief Get assigned variable (data). - inline VarData* getVar() const ASMJIT_NOTHROW { return _vdata; } - - //! @brief Get hint it (see @ref VARIABLE_HINT). - inline uint32_t getHintId() const ASMJIT_NOTHROW { return _hintId; } - //! @brief Get hint value. - inline uint32_t getHintValue() const ASMJIT_NOTHROW { return _hintValue; } - - //! @brief Set hint it (see @ref VARIABLE_HINT). - inline void setHintId(uint32_t hintId) ASMJIT_NOTHROW { _hintId = hintId; } - //! @brief Set hint value. - inline void setHintValue(uint32_t hintValue) ASMJIT_NOTHROW { _hintValue = hintValue; } - - VarData* _vdata; - uint32_t _hintId; - uint32_t _hintValue; -}; - -// ============================================================================ -// [AsmJit::EInstruction] -// ============================================================================ - -//! @brief Emittable that represents single instruction and its operands. -struct ASMJIT_API EInstruction : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref EInstruction instance. - EInstruction(Compiler* c, uint32_t code, Operand* operandsData, uint32_t operandsCount) ASMJIT_NOTHROW; - //! @brief Destroy the @ref EInstruction instance. - virtual ~EInstruction() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; - virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; - - virtual void emit(Assembler& a) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - virtual int getMaxSize() const ASMJIT_NOTHROW; - virtual bool _tryUnuseVar(VarData* v) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Instruction Code] - // -------------------------------------------------------------------------- - - //! @brief Get whether the instruction is special. - inline bool isSpecial() const ASMJIT_NOTHROW { return _isSpecial; } - - //! @brief Get whether the instruction is FPU. - inline bool isFPU() const ASMJIT_NOTHROW { return _isFPU; } - - //! @brief Get instruction code, see @c INST_CODE. - inline uint32_t getCode() const ASMJIT_NOTHROW { return _code; } - - //! @brief Set instruction code to @a code. - //! - //! Please do not modify instruction code if you are not know what you are - //! doing. Incorrect instruction code or operands can raise assertion() at - //! runtime. - inline void setCode(uint32_t code) ASMJIT_NOTHROW { _code = code; } - - // -------------------------------------------------------------------------- - // [Operands] - // -------------------------------------------------------------------------- - - //! @brief Get count of operands in operands array (number between 0 to 2 inclusive). - inline uint32_t getOperandsCount() const ASMJIT_NOTHROW { return _operandsCount; } - - //! @brief Get operands array (3 operands total). - inline Operand* getOperands() ASMJIT_NOTHROW { return _operands; } - //! @brief Get operands array (3 operands total). - inline const Operand* getOperands() const ASMJIT_NOTHROW { return _operands; } - - //! @brief Get memory operand. - inline Mem* getMemOp() ASMJIT_NOTHROW { return _memOp; } - //! @brief Set memory operand. - inline void setMemOp(Mem* op) ASMJIT_NOTHROW { _memOp = op; } - - // -------------------------------------------------------------------------- - // [Variables] - // -------------------------------------------------------------------------- - - //! @brief Get count of variables in instruction operands (and in variables array). - inline uint32_t getVariablesCount() const ASMJIT_NOTHROW { return _variablesCount; } - - //! @brief Get operands array (3 operands total). - inline VarAllocRecord* getVariables() ASMJIT_NOTHROW { return _variables; } - //! @brief Get operands array (3 operands total). - inline const VarAllocRecord* getVariables() const ASMJIT_NOTHROW { return _variables; } - - // -------------------------------------------------------------------------- - // [Jump] - // -------------------------------------------------------------------------- - - //! @brief Get possible jump target. - //! - //! If this instruction is conditional or normal jump then return value is - //! label location (ETarget instance), otherwise return value is @c NULL. - virtual ETarget* getJumpTarget() const ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - //! @brief Instruction code, see @c INST_CODE. - uint32_t _code; - - //! @brief Emit options, see @c EMIT_OPTIONS. - uint32_t _emitOptions; - - //! @brief Operands count. - uint32_t _operandsCount; - - //! @brief Variables count. - uint32_t _variablesCount; - - //! @brief Operands. - Operand* _operands; - //! @brief Memory operand (if instruction contains any). - Mem* _memOp; - - //! @brief Variables (extracted from operands). - VarAllocRecord* _variables; - - //! @brief Whether the instruction is special. - bool _isSpecial; - //! @brief Whether the instruction is FPU. - bool _isFPU; - - //! @brief Whether the one of the operands is GPB.Lo register. - bool _isGPBLoUsed; - //! @brief Whether the one of the operands is GPB.Hi register. - bool _isGPBHiUsed; - - friend struct EFunction; - friend struct CompilerContext; - friend struct CompilerCore; - -private: - ASMJIT_DISABLE_COPY(EInstruction) -}; - -// ============================================================================ -// [AsmJit::EJmp] -// ============================================================================ - -//! @brief Emittable that represents single instruction that can jump somewhere. -struct ASMJIT_API EJmp : public EInstruction -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - EJmp(Compiler* c, uint32_t code, Operand* operandsData, uint32_t operandsCount) ASMJIT_NOTHROW; - virtual ~EJmp() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; - virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; - virtual void emit(Assembler& a) ASMJIT_NOTHROW; - - void _doJump(CompilerContext& cc) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Jump] - // -------------------------------------------------------------------------- - - virtual ETarget* getJumpTarget() const ASMJIT_NOTHROW; - - inline EJmp* getJumpNext() const ASMJIT_NOTHROW { return _jumpNext; } - inline bool isTaken() const ASMJIT_NOTHROW { return _isTaken; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - ETarget* _jumpTarget; - EJmp *_jumpNext; - StateData* _state; - bool _isTaken; - - friend struct EFunction; - friend struct CompilerContext; - friend struct CompilerCore; - -private: - ASMJIT_DISABLE_COPY(EJmp) -}; - -// ============================================================================ -// [AsmJit::EFunction] -// ============================================================================ - -//! @brief Function emittable used to generate C/C++ functions. -//! -//! Functions are base blocks for generating assembler output. Each generated -//! assembler stream needs standard entry and leave sequences thats compatible -//! to the operating system conventions - Application Binary Interface (ABI). -//! -//! Function class can be used to generate entry (prolog) and leave (epilog) -//! sequences that is compatible to a given calling convention and to allocate -//! and manage variables that can be allocated to registers or spilled. -//! -//! @note To create function use @c AsmJit::Compiler::newFunction() method, do -//! not create @c EFunction instances using other ways. -//! -//! @sa @c State, @c Var. -struct ASMJIT_API EFunction : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create new @c Function instance. - //! - //! @note Always use @c AsmJit::Compiler::newFunction() to create @c Function - //! instance. - EFunction(Compiler* c) ASMJIT_NOTHROW; - //! @brief Destroy @c Function instance. - virtual ~EFunction() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - virtual int getMaxSize() const ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Function Prototype (Calling Convention + Arguments) / Return Value] - // -------------------------------------------------------------------------- - - inline const FunctionPrototype& getPrototype() const ASMJIT_NOTHROW { return _functionPrototype; } - inline uint32_t getHint(uint32_t hint) ASMJIT_NOTHROW { return _hints[hint]; } - - void setPrototype( - uint32_t callingConvention, - const uint32_t* arguments, - uint32_t argumentsCount, - uint32_t returnValue) ASMJIT_NOTHROW; - void setHint(uint32_t hint, uint32_t value) ASMJIT_NOTHROW; - - inline EProlog* getProlog() const ASMJIT_NOTHROW { return _prolog; } - inline EEpilog* getEpilog() const ASMJIT_NOTHROW { return _epilog; } - - inline EFunctionEnd* getEnd() const ASMJIT_NOTHROW { return _end; } - - //! @brief Create variables from FunctionPrototype declaration. This is just - //! parsing what FunctionPrototype generated for current function calling - //! convention and arguments. - void _createVariables() ASMJIT_NOTHROW; - - //! @brief Prepare variables (ids, names, scope, registers). - void _prepareVariables(Emittable* first) ASMJIT_NOTHROW; - - //! @brief Allocate variables (setting correct state, changing masks, etc). - void _allocVariables(CompilerContext& cc) ASMJIT_NOTHROW; - - void _preparePrologEpilog(CompilerContext& cc) ASMJIT_NOTHROW; - void _dumpFunction(CompilerContext& cc) ASMJIT_NOTHROW; - void _emitProlog(CompilerContext& cc) ASMJIT_NOTHROW; - void _emitEpilog(CompilerContext& cc) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Function-Call] - // -------------------------------------------------------------------------- - - //! @brief Reserve stack for calling other function and mark function as - //! callee. - void reserveStackForFunctionCall(int32_t size); - - // -------------------------------------------------------------------------- - // [Labels] - // -------------------------------------------------------------------------- - - //! @brief Get function entry label. - //! - //! Entry label can be used to call this function from another code that's - //! being generated. - inline const Label& getEntryLabel() const ASMJIT_NOTHROW { return _entryLabel; } - - //! @brief Get function exit label. - //! - //! Use exit label to jump to function epilog. - inline const Label& getExitLabel() const ASMJIT_NOTHROW { return _exitLabel; } - - // -------------------------------------------------------------------------- - // [Misc] - // -------------------------------------------------------------------------- - - //! @brief Set the _isEspAdjusted member to true. - //! - //! This method is used to tell compiler that the ESP/RSP must be adjusted in - //! function prolog/epilog, because the stack is manipulated (usually caused - //! by the function call, see @c ECall). - inline void mustAdjustEsp() { _isEspAdjusted = true; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - //! @brief Function prototype. - FunctionPrototype _functionPrototype; - //! @brief Function arguments (variable IDs). - VarData** _argumentVariables; - //! @brief Function hints. - uint32_t _hints[16]; - - //! @brief Whether the function stack is aligned by 16-bytes by OS. - //! - //! This is always true for 64-bit mode and for linux. - bool _isStackAlignedByOsTo16Bytes; - - //! @brief Whether the function stack (for variables) is aligned manually - //! by function to 16-bytes. - //! - //! This makes sense only if _isStackAlignedByOsTo16Bytes is false and MOVDQA - //! instruction or other SSE/SSE2 instructions are used to work with variable - //! stored on the stack. - //! - //! Value is determined automatically by these factors, expectations are: - //! - //! 1. There is 16-byte wide variable which address was used (alloc, spill, - //! op). - //! 2. Function can't be naked. - bool _isStackAlignedByFnTo16Bytes; - - //! @brief Whether the function is using naked prolog / epilog - //! - //! Naked prolog / epilog means to omit saving and restoring EBP. - bool _isNaked; - - //! @brief Whether the ESP register is adjusted by the stack size needed - //! to save registers and function variables. - //! - //! Esp is adjusted by 'sub' instruction in prolog and by add function in - //! epilog (only if function is not naked). - bool _isEspAdjusted; - - //! @brief Whether another function is called from this function. - //! - //! If another function is called from this function, it's needed to prepare - //! stack for it. If this member is true then it's likely that true will be - //! also @c _isEspAdjusted one. - bool _isCaller; - - //! @brief Whether to emit prolog / epilog sequence using push & pop - //! instructions (the default). - bool _pePushPop; - - //! @brief Whether to emit EMMS instruction in epilog (auto-detected). - bool _emitEMMS; - - //! @brief Whether to emit SFence instruction in epilog (auto-detected). - //! - //! @note Combination of @c _emitSFence and @c _emitLFence will result in - //! emitting mfence. - bool _emitSFence; - - //! @brief Whether to emit LFence instruction in epilog (auto-detected). - //! - //! @note Combination of @c _emitSFence and @c _emitLFence will result in - //! emitting mfence. - bool _emitLFence; - - //! @brief Whether the function is finished using @c Compiler::endFunction(). - bool _finished; - - //! @brief Bitfield containing modified and preserved GP registers. - uint32_t _modifiedAndPreservedGP; - - //! @brief Bitfield containing modified and preserved MM registers. - uint32_t _modifiedAndPreservedMM; - - //! @brief Bitfield containing modified and preserved XMM registers. - uint32_t _modifiedAndPreservedXMM; - - //! @brief ID mov movdqa instruction (@c INST_MOVDQA or @c INST_MOVDQU). - //! - //! The value is based on stack alignment. If it's guaranteed that stack - //! is aligned to 16-bytes then @c INST_MOVDQA instruction is used, otherwise - //! the @c INST_MOVDQU instruction is used for 16-byte mov. - uint32_t _movDqaInstruction; - - //! @brief Prolog / epilog stack size for PUSH/POP sequences. - int32_t _pePushPopStackSize; - //! @brief Prolog / epilog stack size for MOV sequences. - int32_t _peMovStackSize; - //! @brief Prolog / epilog stack adjust size (to make it 16-byte aligned). - int32_t _peAdjustStackSize; - - //! @brief Memory stack size (for all variables and temporary memory). - int32_t _memStackSize; - //! @brief Like @c _memStackSize, but aligned to 16-bytes. - int32_t _memStackSize16; - - //! @brief Stack size needed to call other functions. - int32_t _functionCallStackSize; - - //! @brief Function entry label. - Label _entryLabel; - //! @brief Function exit label. - Label _exitLabel; - - //! @brief Function prolog emittable. - EProlog* _prolog; - //! @brief Function epilog emittable. - EEpilog* _epilog; - //! @brief Dummy emittable, signalizes end of function. - EFunctionEnd* _end; - -private: - friend struct CompilerContext; - friend struct CompilerCore; - friend struct EProlog; - friend struct EEpilog; -}; - -// ============================================================================ -// [AsmJit::EProlog] -// ============================================================================ - -//! @brief Prolog emittable. -struct ASMJIT_API EProlog : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref EProlog instance. - EProlog(Compiler* c, EFunction* f) ASMJIT_NOTHROW; - //! @brief Destroy the @ref EProlog instance. - virtual ~EProlog() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; - virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Methods] - // -------------------------------------------------------------------------- - - //! @brief Get function associated with this prolog. - inline EFunction* getFunction() const ASMJIT_NOTHROW { return _function; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - //! @brief Prolog owner function. - EFunction* _function; - -private: - friend struct CompilerCore; - friend struct EFunction; -}; - -// ============================================================================ -// [AsmJit::EEpilog] -// ============================================================================ - -//! @brief Epilog emittable. -struct ASMJIT_API EEpilog : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref EEpilog instance. - EEpilog(Compiler* c, EFunction* f) ASMJIT_NOTHROW; - //! @brief Destroy the @ref EProlog instance. - virtual ~EEpilog() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; - virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Methods] - // -------------------------------------------------------------------------- - - //! @brief Get function associated with this epilog. - inline EFunction* getFunction() const ASMJIT_NOTHROW { return _function; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - //! @brief Epilog owner function. - EFunction* _function; - -private: - friend struct CompilerCore; - friend struct EFunction; -}; - -// ============================================================================ -// [AsmJit::ECall] -// ============================================================================ - -//! @brief Function call. -struct ASMJIT_API ECall : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref ECall instance. - ECall(Compiler* c, EFunction* caller, const Operand* target) ASMJIT_NOTHROW; - //! @brief Destroy the @ref ECall instance. - virtual ~ECall() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; - virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - virtual int getMaxSize() const ASMJIT_NOTHROW; - virtual bool _tryUnuseVar(VarData* v) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Internal] - // -------------------------------------------------------------------------- - -protected: - - uint32_t _findTemporaryGpRegister(CompilerContext& cc) ASMJIT_NOTHROW; - uint32_t _findTemporaryXmmRegister(CompilerContext& cc) ASMJIT_NOTHROW; - - VarData* _getOverlappingVariable(CompilerContext& cc, - const FunctionPrototype::Argument& argType) const ASMJIT_NOTHROW; - - void _moveAllocatedVariableToStack(CompilerContext& cc, - VarData* vdata, const FunctionPrototype::Argument& argType) ASMJIT_NOTHROW; - - void _moveSpilledVariableToStack(CompilerContext& cc, - VarData* vdata, const FunctionPrototype::Argument& argType, - uint32_t temporaryGpReg, - uint32_t temporaryXmmReg) ASMJIT_NOTHROW; - - void _moveSrcVariableToRegister(CompilerContext& cc, - VarData* vdata, const FunctionPrototype::Argument& argType) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Function Prototype (Calling Convention + Arguments) / Return Value] - // -------------------------------------------------------------------------- - -public: - - //! @brief Get function prototype. - inline const FunctionPrototype& getPrototype() const ASMJIT_NOTHROW { return _functionPrototype; } - - //! @brief Set function prototype. - inline void setPrototype(uint32_t cconv, const FunctionDefinition& def) ASMJIT_NOTHROW - { - _setPrototype( - cconv, - def.getArguments(), - def.getArgumentsCount(), - def.getReturnValue()); - } - - //! @brief Set function prototype (internal). - void _setPrototype( - uint32_t callingConvention, - const uint32_t* arguments, - uint32_t argumentsCount, - uint32_t returnValue) ASMJIT_NOTHROW; - - //! @brief Set function argument @a i to @a var. - bool setArgument(uint32_t i, const BaseVar& var) ASMJIT_NOTHROW; - //! @brief Set function argument @a i to @a imm. - bool setArgument(uint32_t i, const Imm& imm) ASMJIT_NOTHROW; - - //! @brief Set return value to - bool setReturn(const Operand& first, const Operand& second = Operand()) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Methods] - // -------------------------------------------------------------------------- - - //! @brief Get caller. - inline EFunction* getCaller() const ASMJIT_NOTHROW { return _caller; } - - //! @brief Get operand (function address). - inline Operand& getTarget() ASMJIT_NOTHROW { return _target; } - //! @overload - inline const Operand& getTarget() const ASMJIT_NOTHROW { return _target; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - //! @brief Function prototype. - FunctionPrototype _functionPrototype; - - //! @brief Callee (the function that calls me). - EFunction* _caller; - - //! @brief Arguments (operands). - Operand* _args; - - //! @brief Operand (address of function, register, label, ...) - Operand _target; - - //! @brief Return value (operands) - Operand _ret[2]; - - //! @brief Mask of GP registers used as function arguments. - uint32_t _gpParams; - //! @brief Mask of MM registers used as function arguments. - uint32_t _mmParams; - //! @brief Mask of XMM registers used as function arguments. - uint32_t _xmmParams; - - //! @brief Variables count. - uint32_t _variablesCount; - - //! @brief Variables (extracted from operands). - VarCallRecord* _variables; - //! @brief Argument index to @c VarCallRecord. - VarCallRecord* _argumentToVarRecord[FUNC_MAX_ARGS]; - -private: - friend struct CompilerCore; -}; - -// ============================================================================ -// [AsmJit::ERet] -// ============================================================================ - -//! @brief Function return. -struct ASMJIT_API ERet : public Emittable -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref ERet instance. - ERet(Compiler* c, EFunction* function, const Operand* first, const Operand* second) ASMJIT_NOTHROW; - //! @brief Destroy the @ref ERet instance. - virtual ~ERet() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; - virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; - virtual void emit(Assembler& a) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Utilities] - // -------------------------------------------------------------------------- - - virtual int getMaxSize() const ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Methods] - // -------------------------------------------------------------------------- - - //! @Brief Get function. - inline EFunction* getFunction() ASMJIT_NOTHROW { return _function; } - - //! @brief Get operand (function address). - inline Operand& getFirst() ASMJIT_NOTHROW { return _ret[0]; } - //! @brief Get operand (function address). - inline Operand& getSecond() ASMJIT_NOTHROW { return _ret[1]; } - //! @overload - inline const Operand& getFirst() const ASMJIT_NOTHROW { return _ret[0]; } - //! @overload - inline const Operand& getSecond() const ASMJIT_NOTHROW { return _ret[1]; } - - //! @brief Get whether jump to epilog have to be emitted. - bool shouldEmitJumpToEpilog() const ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - //! @brief Function. - EFunction* _function; - //! @brief Return value (operands) - Operand _ret[2]; - -private: - friend struct CompilerCore; -}; - -// ============================================================================ -// [AsmJit::CompilerContext] -// ============================================================================ - -//! @internal -//! -//! @brief Compiler context is used by @ref Compiler. -//! -//! Compiler context is used during compilation and normally developer doesn't -//! need access to it. The context is user per function (it's reset after each -//! function is generated). -struct ASMJIT_API CompilerContext -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new @ref CompilerContext instance. - CompilerContext(Compiler* compiler) ASMJIT_NOTHROW; - //! @brief Destroy the @ref CompilerContext instance. - ~CompilerContext() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Clear] - // -------------------------------------------------------------------------- - - //! @brief Clear context, preparing it for next function generation. - void _clear() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Register Allocator] - // -------------------------------------------------------------------------- - - //! @brief Allocate variable - //! - //! Calls @c allocGPVar, @c allocMMVar or @c allocXMMVar methods. - void allocVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW; - //! @brief Save variable. - //! - //! Calls @c saveGPVar, @c saveMMVar or @c saveXMMVar methods. - void saveVar(VarData* vdata) ASMJIT_NOTHROW; - //! @brief Spill variable. - //! - //! Calls @c spillGPVar, @c spillMMVar or @c spillXMMVar methods. - void spillVar(VarData* vdata) ASMJIT_NOTHROW; - //! @brief Unuse variable (didn't spill, just forget about it). - void unuseVar(VarData* vdata, uint32_t toState) ASMJIT_NOTHROW; - - //! @brief Helper method that is called for each variable per emittable. - inline void _unuseVarOnEndOfScope(Emittable* e, VarData* v) - { - if (v->lastEmittable == e) - unuseVar(v, VARIABLE_STATE_UNUSED); - } - //! @overload - inline void _unuseVarOnEndOfScope(Emittable* e, VarAllocRecord* rec) - { - VarData* v = rec->vdata; - if (v->lastEmittable == e || (rec->vflags & VARIABLE_ALLOC_UNUSE_AFTER_USE)) - unuseVar(v, VARIABLE_STATE_UNUSED); - } - //! @overload - inline void _unuseVarOnEndOfScope(Emittable* e, VarCallRecord* rec) - { - VarData* v = rec->vdata; - if (v->lastEmittable == e || (rec->flags & VarCallRecord::FLAG_UNUSE_AFTER_USE)) - unuseVar(v, VARIABLE_STATE_UNUSED); - } - - //! @brief Allocate variable (GP). - void allocGPVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW; - //! @brief Save variable (GP). - void saveGPVar(VarData* vdata) ASMJIT_NOTHROW; - //! @brief Spill variable (GP). - void spillGPVar(VarData* vdata) ASMJIT_NOTHROW; - - //! @brief Allocate variable (MM). - void allocMMVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW; - //! @brief Save variable (MM). - void saveMMVar(VarData* vdata) ASMJIT_NOTHROW; - //! @brief Spill variable (MM). - void spillMMVar(VarData* vdata) ASMJIT_NOTHROW; - - //! @brief Allocate variable (XMM). - void allocXMMVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW; - //! @brief Save variable (XMM). - void saveXMMVar(VarData* vdata) ASMJIT_NOTHROW; - //! @brief Spill variable (XMM). - void spillXMMVar(VarData* vdata) ASMJIT_NOTHROW; - - //! @brief Emit load variable instruction(s). - void emitLoadVar(VarData* vdata, uint32_t regIndex) ASMJIT_NOTHROW; - //! @brief Emit save variable instruction(s). - void emitSaveVar(VarData* vdata, uint32_t regIndex) ASMJIT_NOTHROW; - - //! @brief Emit move variable instruction(s). - void emitMoveVar(VarData* vdata, uint32_t regIndex, uint32_t vflags) ASMJIT_NOTHROW; - //! @brief Emit exchange variable instruction(s). - void emitExchangeVar(VarData* vdata, uint32_t regIndex, uint32_t vflags, VarData* other) ASMJIT_NOTHROW; - - //! @brief Called each time a variable is alloceted. - void _postAlloc(VarData* vdata, uint32_t vflags) ASMJIT_NOTHROW; - //! @brief Marks variable home memory as used (must be called at least once - //! for each variable that uses function local memory - stack). - void _markMemoryUsed(VarData* vdata) ASMJIT_NOTHROW; - - Mem _getVarMem(VarData* vdata) ASMJIT_NOTHROW; - - VarData* _getSpillCandidateGP() ASMJIT_NOTHROW; - VarData* _getSpillCandidateMM() ASMJIT_NOTHROW; - VarData* _getSpillCandidateXMM() ASMJIT_NOTHROW; - VarData* _getSpillCandidateGeneric(VarData** varArray, uint32_t count) ASMJIT_NOTHROW; - - inline bool _isActive(VarData* vdata) ASMJIT_NOTHROW { return vdata->nextActive != NULL; } - void _addActive(VarData* vdata) ASMJIT_NOTHROW; - void _freeActive(VarData* vdata) ASMJIT_NOTHROW; - void _freeAllActive() ASMJIT_NOTHROW; - - void _allocatedVariable(VarData* vdata) ASMJIT_NOTHROW; - - inline void _allocatedGPRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedGP |= Util::maskFromIndex(index); _modifiedGPRegisters |= Util::maskFromIndex(index); } - inline void _allocatedMMRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedMM |= Util::maskFromIndex(index); _modifiedMMRegisters |= Util::maskFromIndex(index); } - inline void _allocatedXMMRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedXMM |= Util::maskFromIndex(index); _modifiedXMMRegisters |= Util::maskFromIndex(index); } - - inline void _freedGPRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedGP &= ~Util::maskFromIndex(index); } - inline void _freedMMRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedMM &= ~Util::maskFromIndex(index); } - inline void _freedXMMRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedXMM &= ~Util::maskFromIndex(index); } - - inline void _markGPRegisterModified(uint32_t index) ASMJIT_NOTHROW { _modifiedGPRegisters |= Util::maskFromIndex(index); } - inline void _markMMRegisterModified(uint32_t index) ASMJIT_NOTHROW { _modifiedMMRegisters |= Util::maskFromIndex(index); } - inline void _markXMMRegisterModified(uint32_t index) ASMJIT_NOTHROW { _modifiedXMMRegisters |= Util::maskFromIndex(index); } - - // TODO: Find code which uses this and improve. - inline void _newRegisterHomeIndex(VarData* vdata, uint32_t idx) - { - if (vdata->homeRegisterIndex == INVALID_VALUE) vdata->homeRegisterIndex = idx; - vdata->prefRegisterMask |= (1U << idx); - } - - // TODO: Find code which uses this and improve. - inline void _newRegisterHomeMask(VarData* vdata, uint32_t mask) - { - vdata->prefRegisterMask |= mask; - } - - // -------------------------------------------------------------------------- - // [Operand Patcher] - // -------------------------------------------------------------------------- - - void translateOperands(Operand* operands, uint32_t count) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- - - inline Compiler* getCompiler() const ASMJIT_NOTHROW { return _compiler; } - inline EFunction* getFunction() const ASMJIT_NOTHROW { return _function; } - - inline Emittable* getExtraBlock() const ASMJIT_NOTHROW { return _extraBlock; } - inline void setExtraBlock(Emittable* e) ASMJIT_NOTHROW { _extraBlock = e; } - - // -------------------------------------------------------------------------- - // [Backward Code] - // -------------------------------------------------------------------------- - - void addBackwardCode(EJmp* from) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Forward Jump] - // -------------------------------------------------------------------------- - - void addForwardJump(EJmp* inst) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [State] - // -------------------------------------------------------------------------- - - StateData* _saveState() ASMJIT_NOTHROW; - void _assignState(StateData* state) ASMJIT_NOTHROW; - void _restoreState(StateData* state, uint32_t targetOffset = INVALID_VALUE) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Memory Allocator] - // -------------------------------------------------------------------------- - - VarMemBlock* _allocMemBlock(uint32_t size) ASMJIT_NOTHROW; - void _freeMemBlock(VarMemBlock* mem) ASMJIT_NOTHROW; - - void _allocMemoryOperands() ASMJIT_NOTHROW; - void _patchMemoryOperands(Emittable* start, Emittable* stop) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! @brief Zone memory manager. - Zone _zone; - - //! @brief Compiler instance. - Compiler* _compiler; - //! @brief Function emittable. - EFunction* _function; - - //! @brief Current active scope start emittable. - Emittable* _start; - //! @brief Current active scope end emittable. - Emittable* _stop; - //! @brief Emittable that is used to insert some code after the function body. - Emittable* _extraBlock; - - //! @brief Current state (register allocator). - StateData _state; - //! @brief Link to circular double-linked list containing all active variables - //! (for current state). - VarData* _active; - - //! @brief Forward jumps (single linked list). - ForwardJumpData* _forwardJumps; - - //! @brief Current offset, used in prepare() stage. Each emittable should increment it. - uint32_t _currentOffset; - - //! @brief Whether current code is unreachable. - uint32_t _unreachable; - - //! @brief Global modified GP registers mask (per function). - uint32_t _modifiedGPRegisters; - //! @brief Global modified MM registers mask (per function). - uint32_t _modifiedMMRegisters; - //! @brief Global modified XMM registers mask (per function). - uint32_t _modifiedXMMRegisters; - - //! @brief Whether the EBP/RBP register can be used by register allocator. - uint32_t _allocableEBP; - - //! @brief ESP adjust constant (changed during PUSH/POP or when using - //! stack. - int _adjustESP; - - //! @brief Function arguments base pointer (register). - uint32_t _argumentsBaseReg; - //! @brief Function arguments base offset. - int32_t _argumentsBaseOffset; - //! @brief Function arguments displacement. - int32_t _argumentsActualDisp; - - //! @brief Function variables base pointer (register). - uint32_t _variablesBaseReg; - //! @brief Function variables base offset. - int32_t _variablesBaseOffset; - //! @brief Function variables displacement. - int32_t _variablesActualDisp; - - //! @brief Used memory blocks (for variables, here is each created mem block - //! that can be also in _memFree list). - VarMemBlock* _memUsed; - //! @brief Free memory blocks (freed, prepared for another allocation). - VarMemBlock* _memFree; - //! @brief Count of 4-byte memory blocks used by the function. - uint32_t _mem4BlocksCount; - //! @brief Count of 8-byte memory blocks used by the function. - uint32_t _mem8BlocksCount; - //! @brief Count of 16-byte memory blocks used by the function. - uint32_t _mem16BlocksCount; - //! @brief Count of total bytes of stack memory used by the function. - uint32_t _memBytesTotal; - - //! @brief Whether to emit comments. - bool _emitComments; - - //! @brief List of emittables which need to be translated. These emittables - //! are filled by @c addBackwardCode(). - PodVector _backCode; - //! @brief Backward code position (starts at 0). - sysuint_t _backPos; -}; - -// ============================================================================ -// [AsmJit::CompilerUtil] -// ============================================================================ - -//! @brief Static class that contains utility methods. -struct ASMJIT_API CompilerUtil -{ - static bool isStack16ByteAligned(); -}; - -// ============================================================================ -// [AsmJit::CompilerCore] -// ============================================================================ - -//! @brief Compiler core. -//! -//! @sa @c AsmJit::Compiler. -struct ASMJIT_API CompilerCore -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create new (empty) instance of @c Compiler. - CompilerCore(CodeGenerator* codeGenerator) ASMJIT_NOTHROW; - //! @brief Destroy @c Compiler instance. - virtual ~CompilerCore() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Code Generator] - // -------------------------------------------------------------------------- - - //! @brief Get code generator. - inline CodeGenerator* getCodeGenerator() const { return _codeGenerator; } - - // -------------------------------------------------------------------------- - // [Memory Management] - // -------------------------------------------------------------------------- - - //! @brief Get zone memory manager. - inline Zone& getZone() { return _zone; } - - // -------------------------------------------------------------------------- - // [Logging] - // -------------------------------------------------------------------------- - - //! @brief Get logger. - inline Logger* getLogger() const ASMJIT_NOTHROW { return _logger; } - - //! @brief Set logger to @a logger. - virtual void setLogger(Logger* logger) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Error Handling] - // -------------------------------------------------------------------------- - - //! @brief Get error code. - inline uint32_t getError() const ASMJIT_NOTHROW { return _error; } - - //! @brief Set error code. - //! - //! This method is virtual, because higher classes can use it to catch all - //! errors. - virtual void setError(uint32_t error) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Properties] - // -------------------------------------------------------------------------- - - //! @brief Get compiler property. - uint32_t getProperty(uint32_t propertyId); - //! @brief Set compiler property. - void setProperty(uint32_t propertyId, uint32_t value); - - // -------------------------------------------------------------------------- - // [Buffer] - // -------------------------------------------------------------------------- - - //! @brief Clear everything, but not deallocate buffers. - //! - //! @note This method will destroy your code. - void clear() ASMJIT_NOTHROW; - - //! @brief Free internal buffer, all emitters and NULL all pointers. - //! - //! @note This method will destroy your code. - void free() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emittables] - // -------------------------------------------------------------------------- - - //! @brief Get first emittable. - inline Emittable* getFirstEmittable() const ASMJIT_NOTHROW { return _first; } - - //! @brief Get last emittable. - inline Emittable* getLastEmittable() const ASMJIT_NOTHROW { return _last; } - - //! @brief Get current emittable. - //! - //! @note If this method return @c NULL, it means that nothing emitted yet. - inline Emittable* getCurrentEmittable() const ASMJIT_NOTHROW { return _current; } - - //! @brief Set new current emittable and return previous one. - Emittable* setCurrentEmittable(Emittable* current) ASMJIT_NOTHROW; - - //! @brief Add emittable after current and set current to @a emittable. - void addEmittable(Emittable* emittable) ASMJIT_NOTHROW; - - //! @brief Add emittable after @a ref. - void addEmittableAfter(Emittable* emittable, Emittable* ref) ASMJIT_NOTHROW; - - //! @brief Remove emittable (and if needed set current to previous). - void removeEmittable(Emittable* emittable) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Comment] - // -------------------------------------------------------------------------- - - //! @brief Emit a single comment line that will be logged. - //! - //! Emitting comments are useful to log something. Because assembler can be - //! generated from AST or other data structures, you may sometimes need to - //! log data characteristics or statistics. - //! - //! @note Emitting comment is not directly sent to logger, but instead it's - //! stored in @c AsmJit::Compiler and emitted when @c serialize() method is - //! called. Each comment keeps correct order. - void comment(const char* fmt, ...) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Function Builder] - // -------------------------------------------------------------------------- - - //! @brief Create a new function. - //! - //! @param cconv Calling convention to use (see @c CALL_CONV enum) - //! @param params Function arguments prototype. - //! - //! This method is usually used as a first step when generating functions - //! by @c Compiler. First parameter @a cconv specifies function calling - //! convention to use. Second parameter @a params specifies function - //! arguments. To create function arguments are used templates - //! @c BuildFunction0<>, @c BuildFunction1<...>, @c BuildFunction2<...>, - //! etc... - //! - //! Templates with BuildFunction prefix are used to generate argument IDs - //! based on real C++ types. See next example how to generate function with - //! two 32-bit integer arguments. - //! - //! @code - //! // Building function using AsmJit::Compiler example. - //! - //! // Compiler instance - //! Compiler c; - //! - //! // Begin of function (also emits function @c Prolog) - //! c.newFunction( - //! // Default calling convention (32-bit cdecl or 64-bit for host OS) - //! CALL_CONV_DEFAULT, - //! // Using function builder to generate arguments list - //! BuildFunction2()); - //! - //! // End of function (also emits function @c Epilog) - //! c.endFunction(); - //! @endcode - //! - //! You can see that building functions is really easy. Previous code snipped - //! will generate code for function with two 32-bit integer arguments. You - //! can access arguments by @c AsmJit::Function::argument() method. Arguments - //! are indexed from 0 (like everything in C). - //! - //! @code - //! // Accessing function arguments through AsmJit::Function example. - //! - //! // Compiler instance - //! Compiler c; - //! - //! // Begin of function (also emits function @c Prolog) - //! c.newFunction( - //! // Default calling convention (32-bit cdecl or 64-bit for host OS) - //! CALL_CONV_DEFAULT, - //! // Using function builder to generate arguments list - //! BuildFunction2()); - //! - //! // Arguments are like other variables, you need to reference them by - //! // variable operands: - //! GPVar a0 = c.argGP(0); - //! GPVar a1 = c.argGP(1); - //! - //! // Use them. - //! c.add(a0, a1); - //! - //! // End of function (emits function epilog and return) - //! c.endFunction(); - //! @endcode - //! - //! Arguments are like variables. How to manipulate with variables is - //! documented in @c AsmJit::Compiler, variables section. - //! - //! @note To get current function use @c currentFunction() method or save - //! pointer to @c AsmJit::Function returned by @c AsmJit::Compiler::newFunction<> - //! method. Recommended is to save the pointer. - //! - //! @sa @c BuildFunction0, @c BuildFunction1, @c BuildFunction2, ... - inline EFunction* newFunction(uint32_t cconv, const FunctionDefinition& def) ASMJIT_NOTHROW - { - return newFunction_( - cconv, - def.getArguments(), - def.getArgumentsCount(), - def.getReturnValue()); - } - - //! @brief Create a new function (low level version). - //! - //! @param cconv Function calling convention (see @c AsmJit::CALL_CONV). - //! @param args Function arguments (see @c AsmJit::VARIABLE_TYPE). - //! @param count Arguments count. - //! - //! This method is internally called from @c newFunction() method and - //! contains arguments thats used internally by @c AsmJit::Compiler. - //! - //! @note To get current function use @c currentFunction() method. - EFunction* newFunction_( - uint32_t cconv, - const uint32_t* arguments, - uint32_t argumentsCount, - uint32_t returnValue) ASMJIT_NOTHROW; - - //! @brief Get current function. - //! - //! This method can be called within @c newFunction() and @c endFunction() - //! block to get current function you are working with. It's recommended - //! to store @c AsmJit::Function pointer returned by @c newFunction<> method, - //! because this allows you in future implement function sections outside of - //! function itself (yeah, this is possible!). - inline EFunction* getFunction() const ASMJIT_NOTHROW { return _function; } - - //! @brief End of current function scope and all variables. - EFunction* endFunction() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Memory Management] - // -------------------------------------------------------------------------- - - inline EInstruction* newInstruction(uint32_t code, Operand* operandsData, uint32_t operandsCount) ASMJIT_NOTHROW - { - if (code >= _INST_J_BEGIN && code <= _INST_J_END) - { - void* addr = _zone.zalloc(sizeof(EJmp)); - - return new(addr) EJmp( - reinterpret_cast(this), code, operandsData, operandsCount); - } - else - { - void* addr = _zone.zalloc(sizeof(EInstruction) + operandsCount * sizeof(Operand)); - - return new(addr) EInstruction( - reinterpret_cast(this), code, operandsData, operandsCount); - } - } - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - //! @brief Emit instruction with no operand. - void _emitInstruction(uint32_t code) ASMJIT_NOTHROW; - - //! @brief Emit instruction with one operand. - void _emitInstruction(uint32_t code, const Operand* o0) ASMJIT_NOTHROW; - - //! @brief Emit instruction with two operands. - void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1) ASMJIT_NOTHROW; - - //! @brief Emit instruction with three operands. - void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2) ASMJIT_NOTHROW; - - //! @brief Emit instruction with four operands (Special instructions). - void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3) ASMJIT_NOTHROW; - - //! @brief Emit instruction with five operands (Special instructions). - void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3, const Operand* o4) ASMJIT_NOTHROW; - - //! @brief Private method for emitting jcc. - void _emitJcc(uint32_t code, const Label* label, uint32_t hint) ASMJIT_NOTHROW; - - //! @brief Private method for emitting function call. - ECall* _emitCall(const Operand* o0) ASMJIT_NOTHROW; - - //! @brief Private method for returning a value from the function. - void _emitReturn(const Operand* first, const Operand* second) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Embed] - // -------------------------------------------------------------------------- - - //! @brief Embed data into instruction stream. - void embed(const void* data, sysuint_t len) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Align] - // -------------------------------------------------------------------------- - - //! @brief Align target buffer to @a m bytes. - //! - //! Typical usage of this is to align labels at start of the inner loops. - //! - //! Inserts @c nop() instructions or CPU optimized NOPs. - void align(uint32_t m) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Label] - // -------------------------------------------------------------------------- - - //! @brief Create and return new label. - Label newLabel() ASMJIT_NOTHROW; - - //! @brief Bind label to the current offset. - //! - //! @note Label can be bound only once! - void bind(const Label& label) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Variables] - // -------------------------------------------------------------------------- - - //! @internal - //! - //! @brief Create a new variable data. - VarData* _newVarData(const char* name, uint32_t type, uint32_t size) ASMJIT_NOTHROW; - - //! @internal - //! - //! @brief Get variable data. - inline VarData* _getVarData(uint32_t id) const ASMJIT_NOTHROW - { - ASMJIT_ASSERT(id != INVALID_VALUE); - return _varData[id & OPERAND_ID_VALUE_MASK]; - } - - //! @brief Create a new general-purpose variable. - GPVar newGP(uint32_t variableType = VARIABLE_TYPE_GPN, const char* name = NULL) ASMJIT_NOTHROW; - //! @brief Get argument as general-purpose variable. - GPVar argGP(uint32_t index) ASMJIT_NOTHROW; - - //! @brief Create a new MM variable. - MMVar newMM(uint32_t variableType = VARIABLE_TYPE_MM, const char* name = NULL) ASMJIT_NOTHROW; - //! @brief Get argument as MM variable. - MMVar argMM(uint32_t index) ASMJIT_NOTHROW; - - //! @brief Create a new XMM variable. - XMMVar newXMM(uint32_t variableType = VARIABLE_TYPE_XMM, const char* name = NULL) ASMJIT_NOTHROW; - //! @brief Get argument as XMM variable. - XMMVar argXMM(uint32_t index) ASMJIT_NOTHROW; - - //! @internal - //! - //! @brief Serialize variable hint. - void _vhint(BaseVar& var, uint32_t hintId, uint32_t hintValue) ASMJIT_NOTHROW; - - //! @brief Alloc variable @a var. - void alloc(BaseVar& var) ASMJIT_NOTHROW; - //! @brief Alloc variable @a var using @a regIndex as a register index. - void alloc(BaseVar& var, uint32_t regIndex) ASMJIT_NOTHROW; - //! @brief Alloc variable @a var using @a reg as a demanded register. - void alloc(BaseVar& var, const BaseReg& reg) ASMJIT_NOTHROW; - //! @brief Spill variable @a var. - void spill(BaseVar& var) ASMJIT_NOTHROW; - //! @brief Save variable @a var if modified. - void save(BaseVar& var) ASMJIT_NOTHROW; - //! @brief Unuse variable @a var. - void unuse(BaseVar& var) ASMJIT_NOTHROW; - - //! @brief Get memory home of variable @a var. - void getMemoryHome(BaseVar& var, GPVar* home, int* displacement = NULL); - - //! @brief Set memory home of variable @a var. - //! - //! Default memory home location is on stack (ESP/RSP), but when needed the - //! bebahior can be changed by this method. - //! - //! It is an error to chaining memory home locations. For example the given - //! code is invalid: - //! - //! @code - //! Compiler c; - //! - //! ... - //! GPVar v0 = c.newGP(); - //! GPVar v1 = c.newGP(); - //! GPVar v2 = c.newGP(); - //! GPVar v3 = c.newGP(); - //! - //! c.setMemoryHome(v1, v0, 0); // Allowed, [v0] is memory home for v1. - //! c.setMemoryHome(v2, v0, 4); // Allowed, [v0+4] is memory home for v2. - //! c.setMemoryHome(v3, v2); // CHAINING, NOT ALLOWED! - //! @endcode - void setMemoryHome(BaseVar& var, const GPVar& home, int displacement = 0); - - //! @brief Get priority of variable @a var. - uint32_t getPriority(BaseVar& var) const ASMJIT_NOTHROW; - //! @brief Set priority of variable @a var to @a priority. - void setPriority(BaseVar& var, uint32_t priority) ASMJIT_NOTHROW; - - //! @brief Get save-on-unuse @a var property. - bool getSaveOnUnuse(BaseVar& var) const ASMJIT_NOTHROW; - //! @brief Set save-on-unuse @a var property to @a value. - void setSaveOnUnuse(BaseVar& var, bool value) ASMJIT_NOTHROW; - - //! @brief Rename variable @a var to @a name. - //! - //! @note Only new name will appear in the logger. - void rename(BaseVar& var, const char* name) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [State] - // -------------------------------------------------------------------------- - - //! @internal - //! - //! @brief Create a new @ref StateData instance. - StateData* _newStateData(uint32_t memVarsCount) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Make] - // -------------------------------------------------------------------------- - - //! @brief Make is convenience method to make currently serialized code and - //! return pointer to generated function. - //! - //! What you need is only to cast this pointer to your function type and call - //! it. Note that if there was an error and calling @c getError() method not - //! returns @c ERROR_NONE (zero) then this function always return @c NULL and - //! error value remains the same. - virtual void* make() ASMJIT_NOTHROW; - - //! @brief Method that will emit everything to @c Assembler instance @a a. - virtual void serialize(Assembler& a) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Data] - // -------------------------------------------------------------------------- - - //! @internal - //! - //! @brief Get target (emittable) from operand @a id (label id). - inline ETarget* _getTarget(uint32_t id) - { - ASMJIT_ASSERT((id & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_LABEL); - return _targetData[id & OPERAND_ID_VALUE_MASK]; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - - //! @brief Zone memory management. - Zone _zone; - - //! @brief Code generator. - CodeGenerator* _codeGenerator; - - //! @brief Logger. - Logger* _logger; - - //! @brief Last error code. - uint32_t _error; - - //! @brief Properties. - uint32_t _properties; - - //! @brief Contains options for next emitted instruction, clear after each emit. - uint32_t _emitOptions; - - //! @brief Whether compiler was finished the job (register allocator, etc...). - uint32_t _finished; - - //! @brief First emittable. - Emittable* _first; - //! @brief Last emittable. - Emittable* _last; - //! @brief Current emittable. - Emittable* _current; - - //! @brief Current function. - EFunction* _function; - - //! @brief Label data. - PodVector _targetData; - - //! @brief Variable data. - PodVector _varData; - - //! @brief Variable name id (used to generate unique names per function). - int _varNameId; - - //! @brief Compiler context instance, only available after prepare(). - CompilerContext* _cc; - - friend struct BaseVar; - friend struct CompilerContext; - friend struct EFunction; - friend struct EInstruction; -}; - -// ============================================================================ -// [AsmJit::CompilerIntrinsics] -// ============================================================================ - -//! @brief Implementation of @c Compiler intrinsics. -//! -//! Methods in this class are implemented here, because we wan't to hide them -//! in shared libraries. These methods should be never exported by C++ compiler. -//! -//! @sa @c AsmJit::Compiler. -struct ASMJIT_HIDDEN CompilerIntrinsics : public CompilerCore -{ - // Special X86 instructions: - // - cpuid, - // - cbw, cwde, cdqe, - // - cmpxchg - // - cmpxchg8b, cmpxchg16b, - // - daa, das, - // - imul, mul, idiv, div, - // - mov_ptr - // - lahf, sahf - // - maskmovq, maskmovdqu - // - enter, leave - // - ret - // - monitor, mwait - // - pop, popad, popfd, popfq, - // - push, pushad, pushfd, pushfq - // - rcl, rcr, rol, ror, sal, sar, shl, shr - // - shld, shrd - // - rdtsc. rdtscp - // - lodsb, lodsd, lodsq, lodsw - // - movsb, movsd, movsq, movsw - // - stosb, stosd, stosq, stosw - // - cmpsb, cmpsd, cmpsq, cmpsw - // - scasb, scasd, scasq, scasw - // - // Special X87 instructions: - // - fisttp - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create @c CompilerIntrinsics instance. Always use @c AsmJit::Compiler. - inline CompilerIntrinsics(CodeGenerator* codeGenerator) ASMJIT_NOTHROW : - CompilerCore(codeGenerator) - { - } - - // -------------------------------------------------------------------------- - // [Embed] - // -------------------------------------------------------------------------- - - //! @brief Add 8-bit integer data to the instuction stream. - inline void db(uint8_t x) ASMJIT_NOTHROW { embed(&x, 1); } - //! @brief Add 16-bit integer data to the instuction stream. - inline void dw(uint16_t x) ASMJIT_NOTHROW { embed(&x, 2); } - //! @brief Add 32-bit integer data to the instuction stream. - inline void dd(uint32_t x) ASMJIT_NOTHROW { embed(&x, 4); } - //! @brief Add 64-bit integer data to the instuction stream. - inline void dq(uint64_t x) ASMJIT_NOTHROW { embed(&x, 8); } - - //! @brief Add 8-bit integer data to the instuction stream. - inline void dint8(int8_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int8_t)); } - //! @brief Add 8-bit integer data to the instuction stream. - inline void duint8(uint8_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint8_t)); } - - //! @brief Add 16-bit integer data to the instuction stream. - inline void dint16(int16_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int16_t)); } - //! @brief Add 16-bit integer data to the instuction stream. - inline void duint16(uint16_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint16_t)); } - - //! @brief Add 32-bit integer data to the instuction stream. - inline void dint32(int32_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int32_t)); } - //! @brief Add 32-bit integer data to the instuction stream. - inline void duint32(uint32_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint32_t)); } - - //! @brief Add 64-bit integer data to the instuction stream. - inline void dint64(int64_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int64_t)); } - //! @brief Add 64-bit integer data to the instuction stream. - inline void duint64(uint64_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint64_t)); } - - //! @brief Add system-integer data to the instuction stream. - inline void dsysint(sysint_t x) ASMJIT_NOTHROW { embed(&x, sizeof(sysint_t)); } - //! @brief Add system-integer data to the instuction stream. - inline void dsysuint(sysuint_t x) ASMJIT_NOTHROW { embed(&x, sizeof(sysuint_t)); } - - //! @brief Add float data to the instuction stream. - inline void dfloat(float x) ASMJIT_NOTHROW { embed(&x, sizeof(float)); } - //! @brief Add double data to the instuction stream. - inline void ddouble(double x) ASMJIT_NOTHROW { embed(&x, sizeof(double)); } - - //! @brief Add pointer data to the instuction stream. - inline void dptr(void* x) ASMJIT_NOTHROW { embed(&x, sizeof(void*)); } - - //! @brief Add MM data to the instuction stream. - inline void dmm(const MMData& x) ASMJIT_NOTHROW { embed(&x, sizeof(MMData)); } - //! @brief Add XMM data to the instuction stream. - inline void dxmm(const XMMData& x) ASMJIT_NOTHROW { embed(&x, sizeof(XMMData)); } - - //! @brief Add data to the instuction stream. - inline void data(const void* data, sysuint_t size) ASMJIT_NOTHROW { embed(data, size); } - - //! @brief Add data in a given structure instance to the instuction stream. - template - inline void dstruct(const T& x) ASMJIT_NOTHROW { embed(&x, sizeof(T)); } - - // -------------------------------------------------------------------------- - // [Custom Instructions] - // -------------------------------------------------------------------------- - - // These emitters are used by custom compiler code (register alloc / spill, - // prolog / epilog generator, ...). - - inline void emit(uint32_t code) ASMJIT_NOTHROW - { - _emitInstruction(code); - } - - inline void emit(uint32_t code, const Operand& o0) ASMJIT_NOTHROW - { - _emitInstruction(code, &o0); - } - - inline void emit(uint32_t code, const Operand& o0, const Operand& o1) ASMJIT_NOTHROW - { - _emitInstruction(code, &o0, &o1); - } - - inline void emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) ASMJIT_NOTHROW - { - _emitInstruction(code, &o0, &o1, &o2); - } - - // -------------------------------------------------------------------------- - // [X86 Instructions] - // -------------------------------------------------------------------------- - - //! @brief Add with Carry. - inline void adc(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_ADC, &dst, &src); - } - //! @brief Add with Carry. - inline void adc(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_ADC, &dst, &src); - } - //! @brief Add with Carry. - inline void adc(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_ADC, &dst, &src); - } - //! @brief Add with Carry. - inline void adc(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_ADC, &dst, &src); - } - //! @brief Add with Carry. - inline void adc(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_ADC, &dst, &src); - } - - //! @brief Add. - inline void add(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_ADD, &dst, &src); - } - //! @brief Add. - inline void add(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_ADD, &dst, &src); - } - //! @brief Add. - inline void add(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_ADD, &dst, &src); - } - //! @brief Add. - inline void add(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_ADD, &dst, &src); - } - //! @brief Add. - inline void add(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_ADD, &dst, &src); - } - - //! @brief Logical And. - inline void and_(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_AND, &dst, &src); - } - //! @brief Logical And. - inline void and_(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_AND, &dst, &src); - } - //! @brief Logical And. - inline void and_(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_AND, &dst, &src); - } - //! @brief Logical And. - inline void and_(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_AND, &dst, &src); - } - //! @brief Logical And. - inline void and_(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_AND, &dst, &src); - } - - //! @brief Bit Scan Forward. - inline void bsf(const GPVar& dst, const GPVar& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - _emitInstruction(INST_BSF, &dst, &src); - } - //! @brief Bit Scan Forward. - inline void bsf(const GPVar& dst, const Mem& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - _emitInstruction(INST_BSF, &dst, &src); - } - - //! @brief Bit Scan Reverse. - inline void bsr(const GPVar& dst, const GPVar& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - _emitInstruction(INST_BSR, &dst, &src); - } - //! @brief Bit Scan Reverse. - inline void bsr(const GPVar& dst, const Mem& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - _emitInstruction(INST_BSR, &dst, &src); - } - - //! @brief Byte swap (32-bit or 64-bit registers only) (i486). - inline void bswap(const GPVar& dst) - { - // ASMJIT_ASSERT(dst.getRegType() == REG_GPD || dst.getRegType() == REG_GPQ); - _emitInstruction(INST_BSWAP, &dst); - } - - //! @brief Bit test. - inline void bt(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_BT, &dst, &src); - } - //! @brief Bit test. - inline void bt(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_BT, &dst, &src); - } - //! @brief Bit test. - inline void bt(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_BT, &dst, &src); - } - //! @brief Bit test. - inline void bt(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_BT, &dst, &src); - } - - //! @brief Bit test and complement. - inline void btc(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_BTC, &dst, &src); - } - //! @brief Bit test and complement. - inline void btc(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_BTC, &dst, &src); - } - //! @brief Bit test and complement. - inline void btc(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_BTC, &dst, &src); - } - //! @brief Bit test and complement. - inline void btc(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_BTC, &dst, &src); - } - - //! @brief Bit test and reset. - inline void btr(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_BTR, &dst, &src); - } - //! @brief Bit test and reset. - inline void btr(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_BTR, &dst, &src); - } - //! @brief Bit test and reset. - inline void btr(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_BTR, &dst, &src); - } - //! @brief Bit test and reset. - inline void btr(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_BTR, &dst, &src); - } - - //! @brief Bit test and set. - inline void bts(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_BTS, &dst, &src); - } - //! @brief Bit test and set. - inline void bts(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_BTS, &dst, &src); - } - //! @brief Bit test and set. - inline void bts(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_BTS, &dst, &src); - } - //! @brief Bit test and set. - inline void bts(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_BTS, &dst, &src); - } - - //! @brief Call Procedure. - inline ECall* call(const GPVar& dst) - { - return _emitCall(&dst); - } - //! @brief Call Procedure. - inline ECall* call(const Mem& dst) - { - return _emitCall(&dst); - } - //! @brief Call Procedure. - inline ECall* call(const Imm& dst) - { - return _emitCall(&dst); - } - //! @brief Call Procedure. - //! @overload - inline ECall* call(void* dst) - { - Imm imm((sysint_t)dst); - return _emitCall(&imm); - } - - //! @brief Call Procedure. - inline ECall* call(const Label& label) - { - return _emitCall(&label); - } - - //! @brief Convert Byte to Word (Sign Extend). - inline void cbw(const GPVar& dst) - { - _emitInstruction(INST_CBW, &dst); - } - - //! @brief Convert Word to DWord (Sign Extend). - inline void cwde(const GPVar& dst) - { - _emitInstruction(INST_CWDE, &dst); - } - -#if defined(ASMJIT_X64) - //! @brief Convert DWord to QWord (Sign Extend). - inline void cdqe(const GPVar& dst) - { - _emitInstruction(INST_CDQE, &dst); - } -#endif // ASMJIT_X64 - - //! @brief Clear Carry flag - //! - //! This instruction clears the CF flag in the EFLAGS register. - inline void clc() - { - _emitInstruction(INST_CLC); - } - - //! @brief Clear Direction flag - //! - //! This instruction clears the DF flag in the EFLAGS register. - inline void cld() - { - _emitInstruction(INST_CLD); - } - - //! @brief Complement Carry Flag. - //! - //! This instruction complements the CF flag in the EFLAGS register. - //! (CF = NOT CF) - inline void cmc() - { - _emitInstruction(INST_CMC); - } - - //! @brief Conditional Move. - inline void cmov(CONDITION cc, const GPVar& dst, const GPVar& src) - { - _emitInstruction(ConditionToInstruction::toCMovCC(cc), &dst, &src); - } - - //! @brief Conditional Move. - inline void cmov(CONDITION cc, const GPVar& dst, const Mem& src) - { - _emitInstruction(ConditionToInstruction::toCMovCC(cc), &dst, &src); - } - - //! @brief Conditional Move. - inline void cmova (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVA , &dst, &src); } - //! @brief Conditional Move. - inline void cmova (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVA , &dst, &src); } - //! @brief Conditional Move. - inline void cmovae (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVAE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovae (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVAE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovb (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVB , &dst, &src); } - //! @brief Conditional Move. - inline void cmovb (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVB , &dst, &src); } - //! @brief Conditional Move. - inline void cmovbe (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVBE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovbe (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVBE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovc (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVC , &dst, &src); } - //! @brief Conditional Move. - inline void cmovc (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVC , &dst, &src); } - //! @brief Conditional Move. - inline void cmove (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVE , &dst, &src); } - //! @brief Conditional Move. - inline void cmove (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovg (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVG , &dst, &src); } - //! @brief Conditional Move. - inline void cmovg (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVG , &dst, &src); } - //! @brief Conditional Move. - inline void cmovge (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVGE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovge (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVGE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovl (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVL , &dst, &src); } - //! @brief Conditional Move. - inline void cmovl (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVL , &dst, &src); } - //! @brief Conditional Move. - inline void cmovle (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVLE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovle (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVLE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovna (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNA , &dst, &src); } - //! @brief Conditional Move. - inline void cmovna (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNA , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnae(const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNAE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnae(const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNAE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnb (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNB , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnb (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNB , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnbe(const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNBE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnbe(const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNBE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnc (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNC , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnc (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNC , &dst, &src); } - //! @brief Conditional Move. - inline void cmovne (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovne (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovng (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNG , &dst, &src); } - //! @brief Conditional Move. - inline void cmovng (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNG , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnge(const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNGE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnge(const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNGE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnl (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNL , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnl (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNL , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnle(const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNLE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovnle(const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNLE, &dst, &src); } - //! @brief Conditional Move. - inline void cmovno (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovno (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnp (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNP , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnp (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNP , &dst, &src); } - //! @brief Conditional Move. - inline void cmovns (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNS , &dst, &src); } - //! @brief Conditional Move. - inline void cmovns (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNS , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnz (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNZ , &dst, &src); } - //! @brief Conditional Move. - inline void cmovnz (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNZ , &dst, &src); } - //! @brief Conditional Move. - inline void cmovo (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovo (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovp (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVP , &dst, &src); } - //! @brief Conditional Move. - inline void cmovp (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVP , &dst, &src); } - //! @brief Conditional Move. - inline void cmovpe (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVPE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovpe (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVPE , &dst, &src); } - //! @brief Conditional Move. - inline void cmovpo (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVPO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovpo (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVPO , &dst, &src); } - //! @brief Conditional Move. - inline void cmovs (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVS , &dst, &src); } - //! @brief Conditional Move. - inline void cmovs (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVS , &dst, &src); } - //! @brief Conditional Move. - inline void cmovz (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVZ , &dst, &src); } - //! @brief Conditional Move. - inline void cmovz (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVZ , &dst, &src); } - - //! @brief Compare Two Operands. - inline void cmp(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_CMP, &dst, &src); - } - //! @brief Compare Two Operands. - inline void cmp(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_CMP, &dst, &src); - } - //! @brief Compare Two Operands. - inline void cmp(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_CMP, &dst, &src); - } - //! @brief Compare Two Operands. - inline void cmp(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_CMP, &dst, &src); - } - //! @brief Compare Two Operands. - inline void cmp(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_CMP, &dst, &src); - } - - //! @brief Compare and Exchange (i486). - inline void cmpxchg(const GPVar cmp_1_eax, const GPVar& cmp_2, const GPVar& src) - { - ASMJIT_ASSERT(cmp_1_eax.getId() != src.getId()); - _emitInstruction(INST_CMPXCHG, &cmp_1_eax, &cmp_2, &src); - } - //! @brief Compare and Exchange (i486). - inline void cmpxchg(const GPVar cmp_1_eax, const Mem& cmp_2, const GPVar& src) - { - ASMJIT_ASSERT(cmp_1_eax.getId() != src.getId()); - _emitInstruction(INST_CMPXCHG, &cmp_1_eax, &cmp_2, &src); - } - - //! @brief Compares the 64-bit value in EDX:EAX with the memory operand (Pentium). - //! - //! If the values are equal, then this instruction stores the 64-bit value - //! in ECX:EBX into the memory operand and sets the zero flag. Otherwise, - //! this instruction copies the 64-bit memory operand into the EDX:EAX - //! registers and clears the zero flag. - inline void cmpxchg8b( - const GPVar& cmp_edx, const GPVar& cmp_eax, - const GPVar& cmp_ecx, const GPVar& cmp_ebx, - const Mem& dst) - { - ASMJIT_ASSERT(cmp_edx.getId() != cmp_eax.getId() && - cmp_eax.getId() != cmp_ecx.getId() && - cmp_ecx.getId() != cmp_ebx.getId()); - - _emitInstruction(INST_CMPXCHG8B, &cmp_edx, &cmp_eax, &cmp_ecx, &cmp_ebx, &dst); - } - -#if defined(ASMJIT_X64) - //! @brief Compares the 128-bit value in RDX:RAX with the memory operand (X64). - //! - //! If the values are equal, then this instruction stores the 128-bit value - //! in RCX:RBX into the memory operand and sets the zero flag. Otherwise, - //! this instruction copies the 128-bit memory operand into the RDX:RAX - //! registers and clears the zero flag. - inline void cmpxchg16b( - const GPVar& cmp_edx, const GPVar& cmp_eax, - const GPVar& cmp_ecx, const GPVar& cmp_ebx, - const Mem& dst) - { - ASMJIT_ASSERT(cmp_edx.getId() != cmp_eax.getId() && - cmp_eax.getId() != cmp_ecx.getId() && - cmp_ecx.getId() != cmp_ebx.getId()); - - _emitInstruction(INST_CMPXCHG16B, &cmp_edx, &cmp_eax, &cmp_ecx, &cmp_ebx, &dst); - } -#endif // ASMJIT_X64 - - //! @brief CPU Identification (i486). - inline void cpuid( - const GPVar& inout_eax, - const GPVar& out_ebx, - const GPVar& out_ecx, - const GPVar& out_edx) - { - // Destination variables must be different. - ASMJIT_ASSERT(inout_eax.getId() != out_ebx.getId() && - out_ebx.getId() != out_ecx.getId() && - out_ecx.getId() != out_edx.getId()); - - _emitInstruction(INST_CPUID, &inout_eax, &out_ebx, &out_ecx, &out_edx); - } - -#if defined(ASMJIT_X86) - inline void daa(const GPVar& dst) - { - _emitInstruction(INST_DAA, &dst); - } -#endif // ASMJIT_X86 - -#if defined(ASMJIT_X86) - inline void das(const GPVar& dst) - { - _emitInstruction(INST_DAS, &dst); - } -#endif // ASMJIT_X86 - - //! @brief Decrement by 1. - //! @note This instruction can be slower than sub(dst, 1) - inline void dec(const GPVar& dst) - { - _emitInstruction(INST_DEC, &dst); - } - //! @brief Decrement by 1. - //! @note This instruction can be slower than sub(dst, 1) - inline void dec(const Mem& dst) - { - _emitInstruction(INST_DEC, &dst); - } - - //! @brief Unsigned divide. - //! - //! This instruction divides (unsigned) the value in the AL, AX, or EAX - //! register by the source operand and stores the result in the AX, - //! DX:AX, or EDX:EAX registers. - inline void div(const GPVar& dst_rem, const GPVar& dst_quot, const GPVar& src) - { - // Destination variables must be different. - ASMJIT_ASSERT(dst_rem.getId() != dst_quot.getId()); - - _emitInstruction(INST_DIV, &dst_rem, &dst_quot, &src); - } - //! @brief Unsigned divide. - //! @overload - inline void div(const GPVar& dst_rem, const GPVar& dst_quot, const Mem& src) - { - // Destination variables must be different. - ASMJIT_ASSERT(dst_rem.getId() != dst_quot.getId()); - - _emitInstruction(INST_DIV, &dst_rem, &dst_quot, &src); - } - -#if ASMJIT_NOT_SUPPORTED_BY_COMPILER - //! @brief Make Stack Frame for Procedure Parameters. - inline void enter(const Imm& imm16, const Imm& imm8) - { - _emitInstruction(INST_ENTER, &imm16, &imm8); - } -#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER - - //! @brief Signed divide. - //! - //! This instruction divides (signed) the value in the AL, AX, or EAX - //! register by the source operand and stores the result in the AX, - //! DX:AX, or EDX:EAX registers. - inline void idiv(const GPVar& dst_rem, const GPVar& dst_quot, const GPVar& src) - { - // Destination variables must be different. - ASMJIT_ASSERT(dst_rem.getId() != dst_quot.getId()); - - _emitInstruction(INST_IDIV, &dst_rem, &dst_quot, &src); - } - //! @brief Signed divide. - //! @overload - inline void idiv(const GPVar& dst_rem, const GPVar& dst_quot, const Mem& src) - { - // Destination variables must be different. - ASMJIT_ASSERT(dst_rem.getId() != dst_quot.getId()); - - _emitInstruction(INST_IDIV, &dst_rem, &dst_quot, &src); - } - - //! @brief Signed multiply. - //! - //! [dst_lo:dst_hi] = dst_hi * src. - inline void imul(const GPVar& dst_hi, const GPVar& dst_lo, const GPVar& src) - { - // Destination variables must be different. - ASMJIT_ASSERT(dst_hi.getId() != dst_lo.getId()); - - _emitInstruction(INST_IMUL, &dst_hi, &dst_lo, &src); - } - //! @overload - inline void imul(const GPVar& dst_hi, const GPVar& dst_lo, const Mem& src) - { - // Destination variables must be different. - ASMJIT_ASSERT(dst_hi.getId() != dst_lo.getId()); - - _emitInstruction(INST_IMUL, &dst_hi, &dst_lo, &src); - } - - //! @brief Signed multiply. - //! - //! Destination operand (the first operand) is multiplied by the source - //! operand (second operand). The destination operand is a general-purpose - //! register and the source operand is an immediate value, a general-purpose - //! register, or a memory location. The product is then stored in the - //! destination operand location. - inline void imul(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_IMUL, &dst, &src); - } - //! @brief Signed multiply. - //! @overload - inline void imul(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_IMUL, &dst, &src); - } - //! @brief Signed multiply. - //! @overload - inline void imul(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_IMUL, &dst, &src); - } - - //! @brief Signed multiply. - //! - //! source operand (which can be a general-purpose register or a memory - //! location) is multiplied by the second source operand (an immediate - //! value). The product is then stored in the destination operand - //! (a general-purpose register). - inline void imul(const GPVar& dst, const GPVar& src, const Imm& imm) - { - _emitInstruction(INST_IMUL, &dst, &src, &imm); - } - //! @overload - inline void imul(const GPVar& dst, const Mem& src, const Imm& imm) - { - _emitInstruction(INST_IMUL, &dst, &src, &imm); - } - - //! @brief Increment by 1. - //! @note This instruction can be slower than add(dst, 1) - inline void inc(const GPVar& dst) - { - _emitInstruction(INST_INC, &dst); - } - //! @brief Increment by 1. - //! @note This instruction can be slower than add(dst, 1) - inline void inc(const Mem& dst) - { - _emitInstruction(INST_INC, &dst); - } - - //! @brief Interrupt 3 - trap to debugger. - inline void int3() - { - _emitInstruction(INST_INT3); - } - - //! @brief Jump to label @a label if condition @a cc is met. - //! - //! This instruction checks the state of one or more of the status flags in - //! the EFLAGS register (CF, OF, PF, SF, and ZF) and, if the flags are in the - //! specified state (condition), performs a jump to the target instruction - //! specified by the destination operand. A condition code (cc) is associated - //! with each instruction to indicate the condition being tested for. If the - //! condition is not satisfied, the jump is not performed and execution - //! continues with the instruction following the Jcc instruction. - inline void j(CONDITION cc, const Label& label, uint32_t hint = HINT_NONE) - { - _emitJcc(ConditionToInstruction::toJCC(cc), &label, hint); - } - - //! @brief Jump to label @a label if condition is met. - inline void ja (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JA , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jae (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JAE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jb (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JB , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jbe (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JBE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jc (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JC , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void je (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jg (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JG , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jge (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JGE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jl (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JL , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jle (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JLE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jna (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNA , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnae(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNAE, &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnb (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNB , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnbe(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNBE, &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnc (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNC , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jne (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jng (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNG , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnge(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNGE, &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnl (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNL , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnle(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNLE, &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jno (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNO , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnp (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNP , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jns (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNS , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jnz (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNZ , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jo (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JO , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jp (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JP , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jpe (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JPE , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jpo (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JPO , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void js (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JS , &label, hint); } - //! @brief Jump to label @a label if condition is met. - inline void jz (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JZ , &label, hint); } - - //! @brief Jump. - //! @overload - inline void jmp(const GPVar& dst) - { - _emitInstruction(INST_JMP, &dst); - } - //! @brief Jump. - //! @overload - inline void jmp(const Mem& dst) - { - _emitInstruction(INST_JMP, &dst); - } - //! @brief Jump. - //! @overload - inline void jmp(const Imm& dst) - { - _emitInstruction(INST_JMP, &dst); - } - - //! @brief Jump. - //! @overload - inline void jmp(void* dst) - { - Imm imm((sysint_t)dst); - _emitInstruction(INST_JMP, &imm); - } - - //! @brief Jump. - //! - //! This instruction transfers program control to a different point - //! in the instruction stream without recording return information. - //! The destination (target) operand specifies the label of the - //! instruction being jumped to. - inline void jmp(const Label& label) - { - _emitInstruction(INST_JMP, &label); - } - //! @brief Load Effective Address - //! - //! This instruction computes the effective address of the second - //! operand (the source operand) and stores it in the first operand - //! (destination operand). The source operand is a memory address - //! (offset part) specified with one of the processors addressing modes. - //! The destination operand is a general-purpose register. - inline void lea(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_LEA, &dst, &src); - } - -#if ASMJIT_NOT_SUPPORTED_BY_COMPILER - //! @brief High Level Procedure Exit. - inline void leave() - { - _emitInstruction(INST_LEAVE); - } -#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER - - //! @brief Move. - //! - //! This instruction copies the second operand (source operand) to the first - //! operand (destination operand). The source operand can be an immediate - //! value, general-purpose register, segment register, or memory location. - //! The destination register can be a general-purpose register, segment - //! register, or memory location. Both operands must be the same size, which - //! can be a byte, a word, or a DWORD. - //! - //! @note To move MMX or SSE registers to/from GP registers or memory, use - //! corresponding functions: @c movd(), @c movq(), etc. Passing MMX or SSE - //! registers to @c mov() is illegal. - inline void mov(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - //! @brief Move. - //! @overload - inline void mov(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - //! @brief Move. - //! @overload - inline void mov(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - //! @brief Move. - //! @overload - inline void mov(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - //! @brief Move. - //! @overload - inline void mov(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - - //! @brief Move from segment register. - //! @overload. - inline void mov(const GPVar& dst, const SegmentReg& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - - //! @brief Move from segment register. - //! @overload. - inline void mov(const Mem& dst, const SegmentReg& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - - //! @brief Move to segment register. - //! @overload. - inline void mov(const SegmentReg& dst, const GPVar& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - - //! @brief Move to segment register. - //! @overload. - inline void mov(const SegmentReg& dst, const Mem& src) - { - _emitInstruction(INST_MOV, &dst, &src); - } - - //! @brief Move byte, word, dword or qword from absolute address @a src to - //! AL, AX, EAX or RAX register. - inline void mov_ptr(const GPVar& dst, void* src) - { - Imm imm((sysint_t)src); - _emitInstruction(INST_MOV_PTR, &dst, &imm); - } - - //! @brief Move byte, word, dword or qword from AL, AX, EAX or RAX register - //! to absolute address @a dst. - inline void mov_ptr(void* dst, const GPVar& src) - { - Imm imm((sysint_t)dst); - _emitInstruction(INST_MOV_PTR, &imm, &src); - } - - //! @brief Move with Sign-Extension. - //! - //! This instruction copies the contents of the source operand (register - //! or memory location) to the destination operand (register) and sign - //! extends the value to 16, 32 or 64-bits. - //! - //! @sa movsxd(). - void movsx(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_MOVSX, &dst, &src); - } - //! @brief Move with Sign-Extension. - //! @overload - void movsx(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVSX, &dst, &src); - } - -#if defined(ASMJIT_X64) - //! @brief Move DWord to QWord with sign-extension. - inline void movsxd(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_MOVSXD, &dst, &src); - } - //! @brief Move DWord to QWord with sign-extension. - //! @overload - inline void movsxd(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVSXD, &dst, &src); - } -#endif // ASMJIT_X64 - - //! @brief Move with Zero-Extend. - //! - //! This instruction copies the contents of the source operand (register - //! or memory location) to the destination operand (register) and zero - //! extends the value to 16 or 32-bits. The size of the converted value - //! depends on the operand-size attribute. - inline void movzx(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_MOVZX, &dst, &src); - } - //! @brief Move with Zero-Extend. - //! @brief Overload - inline void movzx(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVZX, &dst, &src); - } - - //! @brief Unsigned multiply. - //! - //! Source operand (in a general-purpose register or memory location) - //! is multiplied by the value in the AL, AX, or EAX register (depending - //! on the operand size) and the product is stored in the AX, DX:AX, or - //! EDX:EAX registers, respectively. - inline void mul(const GPVar& dst_hi, const GPVar& dst_lo, const GPVar& src) - { - // Destination variables must be different. - ASMJIT_ASSERT(dst_hi.getId() != dst_lo.getId()); - - _emitInstruction(INST_MUL, &dst_hi, &dst_lo, &src); - } - //! @brief Unsigned multiply. - //! @overload - inline void mul(const GPVar& dst_hi, const GPVar& dst_lo, const Mem& src) - { - // Destination variables must be different. - ASMJIT_ASSERT(dst_hi.getId() != dst_lo.getId()); - - _emitInstruction(INST_MUL, &dst_hi, &dst_lo, &src); - } - - //! @brief Two's Complement Negation. - inline void neg(const GPVar& dst) - { - _emitInstruction(INST_NEG, &dst); - } - //! @brief Two's Complement Negation. - inline void neg(const Mem& dst) - { - _emitInstruction(INST_NEG, &dst); - } - - //! @brief No Operation. - //! - //! This instruction performs no operation. This instruction is a one-byte - //! instruction that takes up space in the instruction stream but does not - //! affect the machine context, except the EIP register. The NOP instruction - //! is an alias mnemonic for the XCHG (E)AX, (E)AX instruction. - inline void nop() - { - _emitInstruction(INST_NOP); - } - - //! @brief One's Complement Negation. - inline void not_(const GPVar& dst) - { - _emitInstruction(INST_NOT, &dst); - } - //! @brief One's Complement Negation. - inline void not_(const Mem& dst) - { - _emitInstruction(INST_NOT, &dst); - } - - //! @brief Logical Inclusive OR. - inline void or_(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_OR, &dst, &src); - } - //! @brief Logical Inclusive OR. - inline void or_(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_OR, &dst, &src); - } - //! @brief Logical Inclusive OR. - inline void or_(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_OR, &dst, &src); - } - //! @brief Logical Inclusive OR. - inline void or_(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_OR, &dst, &src); - } - //! @brief Logical Inclusive OR. - inline void or_(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_OR, &dst, &src); - } - - //! @brief Pop a Value from the Stack. - //! - //! This instruction loads the value from the top of the stack to the location - //! specified with the destination operand and then increments the stack pointer. - //! The destination operand can be a general purpose register, memory location, - //! or segment register. - inline void pop(const GPVar& dst) - { - _emitInstruction(INST_POP, &dst); - } - - inline void pop(const Mem& dst) - { - ASMJIT_ASSERT(dst.getSize() == 2 || dst.getSize() == sizeof(sysint_t)); - _emitInstruction(INST_POP, &dst); - } - -#if defined(ASMJIT_X86) - //! @brief Pop All General-Purpose Registers. - //! - //! Pop EDI, ESI, EBP, EBX, EDX, ECX, and EAX. - inline void popad() - { - _emitInstruction(INST_POPAD); - } -#endif // ASMJIT_X86 - - //! @brief Pop Stack into EFLAGS Register (32-bit or 64-bit). - inline void popf() - { -#if defined(ASMJIT_X86) - popfd(); -#else - popfq(); -#endif - } - -#if defined(ASMJIT_X86) - //! @brief Pop Stack into EFLAGS Register (32-bit). - inline void popfd() { _emitInstruction(INST_POPFD); } -#else - //! @brief Pop Stack into EFLAGS Register (64-bit). - inline void popfq() { _emitInstruction(INST_POPFQ); } -#endif - - //! @brief Push WORD/DWORD/QWORD Onto the Stack. - //! - //! @note 32-bit architecture pushed DWORD while 64-bit - //! pushes QWORD. 64-bit mode not provides instruction to - //! push 32-bit register/memory. - inline void push(const GPVar& src) - { - _emitInstruction(INST_PUSH, &src); - } - //! @brief Push WORD/DWORD/QWORD Onto the Stack. - inline void push(const Mem& src) - { - ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == sizeof(sysint_t)); - _emitInstruction(INST_PUSH, &src); - } - //! @brief Push WORD/DWORD/QWORD Onto the Stack. - inline void push(const Imm& src) - { - _emitInstruction(INST_PUSH, &src); - } - -#if defined(ASMJIT_X86) - //! @brief Push All General-Purpose Registers. - //! - //! Push EAX, ECX, EDX, EBX, original ESP, EBP, ESI, and EDI. - inline void pushad() - { - _emitInstruction(INST_PUSHAD); - } -#endif // ASMJIT_X86 - - //! @brief Push EFLAGS Register (32-bit or 64-bit) onto the Stack. - inline void pushf() - { -#if defined(ASMJIT_X86) - pushfd(); -#else - pushfq(); -#endif - } - -#if defined(ASMJIT_X86) - //! @brief Push EFLAGS Register (32-bit) onto the Stack. - inline void pushfd() { _emitInstruction(INST_PUSHFD); } -#else - //! @brief Push EFLAGS Register (64-bit) onto the Stack. - inline void pushfq() { _emitInstruction(INST_PUSHFQ); } -#endif // ASMJIT_X86 - - //! @brief Rotate Bits Left. - //! @note @a src register can be only @c cl. - inline void rcl(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_RCL, &dst, &src); - } - //! @brief Rotate Bits Left. - inline void rcl(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_RCL, &dst, &src); - } - //! @brief Rotate Bits Left. - //! @note @a src register can be only @c cl. - inline void rcl(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_RCL, &dst, &src); - } - //! @brief Rotate Bits Left. - inline void rcl(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_RCL, &dst, &src); - } - - //! @brief Rotate Bits Right. - //! @note @a src register can be only @c cl. - inline void rcr(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_RCR, &dst, &src); - } - //! @brief Rotate Bits Right. - inline void rcr(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_RCR, &dst, &src); - } - //! @brief Rotate Bits Right. - //! @note @a src register can be only @c cl. - inline void rcr(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_RCR, &dst, &src); - } - //! @brief Rotate Bits Right. - inline void rcr(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_RCR, &dst, &src); - } - - //! @brief Read Time-Stamp Counter (Pentium). - inline void rdtsc(const GPVar& dst_edx, const GPVar& dst_eax) - { - // Destination registers must be different. - ASMJIT_ASSERT(dst_edx.getId() != dst_eax.getId()); - - _emitInstruction(INST_RDTSC, &dst_edx, &dst_eax); - } - - //! @brief Read Time-Stamp Counter and Processor ID (New). - inline void rdtscp(const GPVar& dst_edx, const GPVar& dst_eax, const GPVar& dst_ecx) - { - // Destination registers must be different. - ASMJIT_ASSERT(dst_edx.getId() != dst_eax.getId() && - dst_eax.getId() != dst_ecx.getId()); - - _emitInstruction(INST_RDTSCP, &dst_edx, &dst_eax, &dst_ecx); - } - - //! @brief Load ECX/RCX BYTEs from DS:[ESI/RSI] to AL. - inline void rep_lodsb(const GPVar& dst_val, const GPVar& src_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_LODSB, &dst_val, &src_addr, &cnt_ecx); - } - - //! @brief Load ECX/RCX DWORDs from DS:[ESI/RSI] to EAX. - inline void rep_lodsd(const GPVar& dst_val, const GPVar& src_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_LODSD, &dst_val, &src_addr, &cnt_ecx); - } - -#if defined(ASMJIT_X64) - //! @brief Load ECX/RCX QWORDs from DS:[ESI/RSI] to RAX. - inline void rep_lodsq(const GPVar& dst_val, const GPVar& src_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_LODSQ, &dst_val, &src_addr, &cnt_ecx); - } -#endif // ASMJIT_X64 - //! @brief Load ECX/RCX WORDs from DS:[ESI/RSI] to AX. - inline void rep_lodsw(const GPVar& dst_val, const GPVar& src_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_LODSW, &dst_val, &src_addr, &cnt_ecx); - } - - //! @brief Move ECX/RCX BYTEs from DS:[ESI/RSI] to ES:[EDI/RDI]. - inline void rep_movsb(const GPVar& dst_addr, const GPVar& src_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_MOVSB, &dst_addr, &src_addr, &cnt_ecx); - } - - //! @brief Move ECX/RCX DWORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. - inline void rep_movsd(const GPVar& dst_addr, const GPVar& src_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_MOVSD, &dst_addr, &src_addr, &cnt_ecx); - } - -#if defined(ASMJIT_X64) - //! @brief Move ECX/RCX QWORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. - inline void rep_movsq(const GPVar& dst_addr, const GPVar& src_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_MOVSQ, &dst_addr, &src_addr, &cnt_ecx); - } -#endif // ASMJIT_X64 - - //! @brief Move ECX/RCX WORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. - inline void rep_movsw(const GPVar& dst_addr, const GPVar& src_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_MOVSW, &dst_addr, &src_addr, &cnt_ecx); - } - - //! @brief Fill ECX/RCX BYTEs at ES:[EDI/RDI] with AL. - inline void rep_stosb(const GPVar& dst_addr, const GPVar& src_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_STOSB, &dst_addr, &src_val, &cnt_ecx); - } - - //! @brief Fill ECX/RCX DWORDs at ES:[EDI/RDI] with EAX. - inline void rep_stosd(const GPVar& dst_addr, const GPVar& src_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_STOSD, &dst_addr, &src_val, &cnt_ecx); - } - -#if defined(ASMJIT_X64) - //! @brief Fill ECX/RCX QWORDs at ES:[EDI/RDI] with RAX. - inline void rep_stosq(const GPVar& dst_addr, const GPVar& src_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_STOSQ, &dst_addr, &src_val, &cnt_ecx); - } -#endif // ASMJIT_X64 - - //! @brief Fill ECX/RCX WORDs at ES:[EDI/RDI] with AX. - inline void rep_stosw(const GPVar& dst_addr, const GPVar& src_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. - ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REP_STOSW, &dst_addr, &src_val, &cnt_ecx); - } - - //! @brief Repeated find nonmatching BYTEs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repe_cmpsb(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPE_CMPSB, &cmp1_addr, &cmp2_addr, &cnt_ecx); - } - - //! @brief Repeated find nonmatching DWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repe_cmpsd(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPE_CMPSD, &cmp1_addr, &cmp2_addr, &cnt_ecx); - } - -#if defined(ASMJIT_X64) - //! @brief Repeated find nonmatching QWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repe_cmpsq(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPE_CMPSQ, &cmp1_addr, &cmp2_addr, &cnt_ecx); - } -#endif // ASMJIT_X64 - - //! @brief Repeated find nonmatching WORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. - inline void repe_cmpsw(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPE_CMPSW, &cmp1_addr, &cmp2_addr, &cnt_ecx); - } - - //! @brief Find non-AL BYTE starting at ES:[EDI/RDI]. - inline void repe_scasb(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AL, cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPE_SCASB, &cmp1_addr, &cmp2_val, &cnt_ecx); - } - - //! @brief Find non-EAX DWORD starting at ES:[EDI/RDI]. - inline void repe_scasd(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=EAX, cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPE_SCASD, &cmp1_addr, &cmp2_val, &cnt_ecx); - } - -#if defined(ASMJIT_X64) - //! @brief Find non-RAX QWORD starting at ES:[EDI/RDI]. - inline void repe_scasq(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=RAX, cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPE_SCASQ, &cmp1_addr, &cmp2_val, &cnt_ecx); - } -#endif // ASMJIT_X64 - - //! @brief Find non-AX WORD starting at ES:[EDI/RDI]. - inline void repe_scasw(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AX, cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPE_SCASW, &cmp1_addr, &cmp2_val, &cnt_ecx); - } - - //! @brief Find matching BYTEs in [RDI] and [RSI]. - inline void repne_cmpsb(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPNE_CMPSB, &cmp1_addr, &cmp2_addr, &cnt_ecx); - } - - //! @brief Find matching DWORDs in [RDI] and [RSI]. - inline void repne_cmpsd(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPNE_CMPSD, &cmp1_addr, &cmp2_addr, &cnt_ecx); - } - -#if defined(ASMJIT_X64) - //! @brief Find matching QWORDs in [RDI] and [RSI]. - inline void repne_cmpsq(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPNE_CMPSQ, &cmp1_addr, &cmp2_addr, &cnt_ecx); - } -#endif // ASMJIT_X64 - - //! @brief Find matching WORDs in [RDI] and [RSI]. - inline void repne_cmpsw(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPNE_CMPSW, &cmp1_addr, &cmp2_addr, &cnt_ecx); - } - - //! @brief Find AL, starting at ES:[EDI/RDI]. - inline void repne_scasb(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AL, cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPNE_SCASB, &cmp1_addr, &cmp2_val, &cnt_ecx); - } - - //! @brief Find EAX, starting at ES:[EDI/RDI]. - inline void repne_scasd(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=EAX, cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPNE_SCASD, &cmp1_addr, &cmp2_val, &cnt_ecx); - } - -#if defined(ASMJIT_X64) - //! @brief Find RAX, starting at ES:[EDI/RDI]. - inline void repne_scasq(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=RAX, cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPNE_SCASQ, &cmp1_addr, &cmp2_val, &cnt_ecx); - } -#endif // ASMJIT_X64 - - //! @brief Find AX, starting at ES:[EDI/RDI]. - inline void repne_scasw(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) - { - // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AX, cnt=ECX/RCX. - ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); - - _emitInstruction(INST_REPNE_SCASW, &cmp1_addr, &cmp2_val, &cnt_ecx); - } - - //! @brief Return from Procedure. - inline void ret() - { - _emitReturn(NULL, NULL); - } - - //! @brief Return from Procedure. - inline void ret(const GPVar& first) - { - _emitReturn(&first, NULL); - } - - //! @brief Return from Procedure. - inline void ret(const GPVar& first, const GPVar& second) - { - _emitReturn(&first, &second); - } - - //! @brief Return from Procedure. - inline void ret(const XMMVar& first) - { - _emitReturn(&first, NULL); - } - - //! @brief Return from Procedure. - inline void ret(const XMMVar& first, const XMMVar& second) - { - _emitReturn(&first, &second); - } - - //! @brief Rotate Bits Left. - //! @note @a src register can be only @c cl. - inline void rol(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_ROL, &dst, &src); - } - //! @brief Rotate Bits Left. - inline void rol(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_ROL, &dst, &src); - } - //! @brief Rotate Bits Left. - //! @note @a src register can be only @c cl. - inline void rol(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_ROL, &dst, &src); - } - //! @brief Rotate Bits Left. - inline void rol(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_ROL, &dst, &src); - } - - //! @brief Rotate Bits Right. - //! @note @a src register can be only @c cl. - inline void ror(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_ROR, &dst, &src); - } - //! @brief Rotate Bits Right. - inline void ror(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_ROR, &dst, &src); - } - //! @brief Rotate Bits Right. - //! @note @a src register can be only @c cl. - inline void ror(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_ROR, &dst, &src); - } - //! @brief Rotate Bits Right. - inline void ror(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_ROR, &dst, &src); - } - -#if defined(ASMJIT_X86) - //! @brief Store @a var (allocated to AH/AX/EAX/RAX) into Flags. - inline void sahf(const GPVar& var) - { - _emitInstruction(INST_SAHF, &var); - } -#endif // ASMJIT_X86 - - //! @brief Integer subtraction with borrow. - inline void sbb(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_SBB, &dst, &src); - } - //! @brief Integer subtraction with borrow. - inline void sbb(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_SBB, &dst, &src); - } - //! @brief Integer subtraction with borrow. - inline void sbb(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_SBB, &dst, &src); - } - //! @brief Integer subtraction with borrow. - inline void sbb(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_SBB, &dst, &src); - } - //! @brief Integer subtraction with borrow. - inline void sbb(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SBB, &dst, &src); - } - - //! @brief Shift Bits Left. - //! @note @a src register can be only @c cl. - inline void sal(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_SAL, &dst, &src); - } - //! @brief Shift Bits Left. - inline void sal(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_SAL, &dst, &src); - } - //! @brief Shift Bits Left. - //! @note @a src register can be only @c cl. - inline void sal(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_SAL, &dst, &src); - } - //! @brief Shift Bits Left. - inline void sal(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SAL, &dst, &src); - } - - //! @brief Shift Bits Right. - //! @note @a src register can be only @c cl. - inline void sar(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_SAR, &dst, &src); - } - //! @brief Shift Bits Right. - inline void sar(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_SAR, &dst, &src); - } - //! @brief Shift Bits Right. - //! @note @a src register can be only @c cl. - inline void sar(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_SAR, &dst, &src); - } - //! @brief Shift Bits Right. - inline void sar(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SAR, &dst, &src); - } - - //! @brief Set Byte on Condition. - inline void set(CONDITION cc, const GPVar& dst) - { - ASMJIT_ASSERT(dst.getSize() == 1); - _emitInstruction(ConditionToInstruction::toSetCC(cc), &dst); - } - - //! @brief Set Byte on Condition. - inline void set(CONDITION cc, const Mem& dst) - { - ASMJIT_ASSERT(dst.getSize() <= 1); - _emitInstruction(ConditionToInstruction::toSetCC(cc), &dst); - } - - //! @brief Set Byte on Condition. - inline void seta (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETA , &dst); } - //! @brief Set Byte on Condition. - inline void seta (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETA , &dst); } - //! @brief Set Byte on Condition. - inline void setae (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETAE , &dst); } - //! @brief Set Byte on Condition. - inline void setae (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETAE , &dst); } - //! @brief Set Byte on Condition. - inline void setb (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETB , &dst); } - //! @brief Set Byte on Condition. - inline void setb (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETB , &dst); } - //! @brief Set Byte on Condition. - inline void setbe (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETBE , &dst); } - //! @brief Set Byte on Condition. - inline void setbe (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETBE , &dst); } - //! @brief Set Byte on Condition. - inline void setc (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETC , &dst); } - //! @brief Set Byte on Condition. - inline void setc (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETC , &dst); } - //! @brief Set Byte on Condition. - inline void sete (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETE , &dst); } - //! @brief Set Byte on Condition. - inline void sete (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETE , &dst); } - //! @brief Set Byte on Condition. - inline void setg (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETG , &dst); } - //! @brief Set Byte on Condition. - inline void setg (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETG , &dst); } - //! @brief Set Byte on Condition. - inline void setge (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETGE , &dst); } - //! @brief Set Byte on Condition. - inline void setge (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETGE , &dst); } - //! @brief Set Byte on Condition. - inline void setl (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETL , &dst); } - //! @brief Set Byte on Condition. - inline void setl (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETL , &dst); } - //! @brief Set Byte on Condition. - inline void setle (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETLE , &dst); } - //! @brief Set Byte on Condition. - inline void setle (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETLE , &dst); } - //! @brief Set Byte on Condition. - inline void setna (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNA , &dst); } - //! @brief Set Byte on Condition. - inline void setna (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNA , &dst); } - //! @brief Set Byte on Condition. - inline void setnae(const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNAE, &dst); } - //! @brief Set Byte on Condition. - inline void setnae(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNAE, &dst); } - //! @brief Set Byte on Condition. - inline void setnb (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNB , &dst); } - //! @brief Set Byte on Condition. - inline void setnb (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNB , &dst); } - //! @brief Set Byte on Condition. - inline void setnbe(const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNBE, &dst); } - //! @brief Set Byte on Condition. - inline void setnbe(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNBE, &dst); } - //! @brief Set Byte on Condition. - inline void setnc (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNC , &dst); } - //! @brief Set Byte on Condition. - inline void setnc (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNC , &dst); } - //! @brief Set Byte on Condition. - inline void setne (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNE , &dst); } - //! @brief Set Byte on Condition. - inline void setne (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNE , &dst); } - //! @brief Set Byte on Condition. - inline void setng (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNG , &dst); } - //! @brief Set Byte on Condition. - inline void setng (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNG , &dst); } - //! @brief Set Byte on Condition. - inline void setnge(const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNGE, &dst); } - //! @brief Set Byte on Condition. - inline void setnge(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNGE, &dst); } - //! @brief Set Byte on Condition. - inline void setnl (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNL , &dst); } - //! @brief Set Byte on Condition. - inline void setnl (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNL , &dst); } - //! @brief Set Byte on Condition. - inline void setnle(const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNLE, &dst); } - //! @brief Set Byte on Condition. - inline void setnle(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNLE, &dst); } - //! @brief Set Byte on Condition. - inline void setno (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNO , &dst); } - //! @brief Set Byte on Condition. - inline void setno (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNO , &dst); } - //! @brief Set Byte on Condition. - inline void setnp (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNP , &dst); } - //! @brief Set Byte on Condition. - inline void setnp (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNP , &dst); } - //! @brief Set Byte on Condition. - inline void setns (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNS , &dst); } - //! @brief Set Byte on Condition. - inline void setns (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNS , &dst); } - //! @brief Set Byte on Condition. - inline void setnz (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNZ , &dst); } - //! @brief Set Byte on Condition. - inline void setnz (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNZ , &dst); } - //! @brief Set Byte on Condition. - inline void seto (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETO , &dst); } - //! @brief Set Byte on Condition. - inline void seto (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETO , &dst); } - //! @brief Set Byte on Condition. - inline void setp (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETP , &dst); } - //! @brief Set Byte on Condition. - inline void setp (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETP , &dst); } - //! @brief Set Byte on Condition. - inline void setpe (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETPE , &dst); } - //! @brief Set Byte on Condition. - inline void setpe (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETPE , &dst); } - //! @brief Set Byte on Condition. - inline void setpo (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETPO , &dst); } - //! @brief Set Byte on Condition. - inline void setpo (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETPO , &dst); } - //! @brief Set Byte on Condition. - inline void sets (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETS , &dst); } - //! @brief Set Byte on Condition. - inline void sets (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETS , &dst); } - //! @brief Set Byte on Condition. - inline void setz (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETZ , &dst); } - //! @brief Set Byte on Condition. - inline void setz (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETZ , &dst); } - - //! @brief Shift Bits Left. - //! @note @a src register can be only @c cl. - inline void shl(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_SHL, &dst, &src); - } - //! @brief Shift Bits Left. - inline void shl(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_SHL, &dst, &src); - } - //! @brief Shift Bits Left. - //! @note @a src register can be only @c cl. - inline void shl(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_SHL, &dst, &src); - } - //! @brief Shift Bits Left. - inline void shl(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SHL, &dst, &src); - } - - //! @brief Shift Bits Right. - //! @note @a src register can be only @c cl. - inline void shr(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_SHR, &dst, &src); - } - //! @brief Shift Bits Right. - inline void shr(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_SHR, &dst, &src); - } - //! @brief Shift Bits Right. - //! @note @a src register can be only @c cl. - inline void shr(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_SHR, &dst, &src); - } - //! @brief Shift Bits Right. - inline void shr(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SHR, &dst, &src); - } - - //! @brief Double Precision Shift Left. - //! @note src2 register can be only @c cl register. - inline void shld(const GPVar& dst, const GPVar& src1, const GPVar& src2) - { - _emitInstruction(INST_SHLD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Left. - inline void shld(const GPVar& dst, const GPVar& src1, const Imm& src2) - { - _emitInstruction(INST_SHLD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Left. - //! @note src2 register can be only @c cl register. - inline void shld(const Mem& dst, const GPVar& src1, const GPVar& src2) - { - _emitInstruction(INST_SHLD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Left. - inline void shld(const Mem& dst, const GPVar& src1, const Imm& src2) - { - _emitInstruction(INST_SHLD, &dst, &src1, &src2); - } - - //! @brief Double Precision Shift Right. - //! @note src2 register can be only @c cl register. - inline void shrd(const GPVar& dst, const GPVar& src1, const GPVar& src2) - { - _emitInstruction(INST_SHRD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Right. - inline void shrd(const GPVar& dst, const GPVar& src1, const Imm& src2) - { - _emitInstruction(INST_SHRD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Right. - //! @note src2 register can be only @c cl register. - inline void shrd(const Mem& dst, const GPVar& src1, const GPVar& src2) - { - _emitInstruction(INST_SHRD, &dst, &src1, &src2); - } - //! @brief Double Precision Shift Right. - inline void shrd(const Mem& dst, const GPVar& src1, const Imm& src2) - { - _emitInstruction(INST_SHRD, &dst, &src1, &src2); - } - - //! @brief Set Carry Flag to 1. - inline void stc() - { - _emitInstruction(INST_STC); - } - - //! @brief Set Direction Flag to 1. - inline void std() - { - _emitInstruction(INST_STD); - } - - //! @brief Subtract. - inline void sub(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_SUB, &dst, &src); - } - //! @brief Subtract. - inline void sub(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_SUB, &dst, &src); - } - //! @brief Subtract. - inline void sub(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_SUB, &dst, &src); - } - //! @brief Subtract. - inline void sub(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_SUB, &dst, &src); - } - //! @brief Subtract. - inline void sub(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_SUB, &dst, &src); - } - - //! @brief Logical Compare. - inline void test(const GPVar& op1, const GPVar& op2) - { - _emitInstruction(INST_TEST, &op1, &op2); - } - //! @brief Logical Compare. - inline void test(const GPVar& op1, const Imm& op2) - { - _emitInstruction(INST_TEST, &op1, &op2); - } - //! @brief Logical Compare. - inline void test(const Mem& op1, const GPVar& op2) - { - _emitInstruction(INST_TEST, &op1, &op2); - } - //! @brief Logical Compare. - inline void test(const Mem& op1, const Imm& op2) - { - _emitInstruction(INST_TEST, &op1, &op2); - } - - //! @brief Undefined instruction - Raise invalid opcode exception. - inline void ud2() - { - _emitInstruction(INST_UD2); - } - - //! @brief Exchange and Add. - inline void xadd(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_XADD, &dst, &src); - } - //! @brief Exchange and Add. - inline void xadd(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_XADD, &dst, &src); - } - - //! @brief Exchange Register/Memory with Register. - inline void xchg(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_XCHG, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xchg(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_XCHG, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xchg(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_XCHG, &src, &dst); - } - - //! @brief Exchange Register/Memory with Register. - inline void xor_(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_XOR, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xor_(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_XOR, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xor_(const GPVar& dst, const Imm& src) - { - _emitInstruction(INST_XOR, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xor_(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_XOR, &dst, &src); - } - //! @brief Exchange Register/Memory with Register. - inline void xor_(const Mem& dst, const Imm& src) - { - _emitInstruction(INST_XOR, &dst, &src); - } - - // -------------------------------------------------------------------------- - // [MMX] - // -------------------------------------------------------------------------- - - //! @brief Empty MMX state. - inline void emms() - { - _emitInstruction(INST_EMMS); - } - - //! @brief Move DWord (MMX). - inline void movd(const Mem& dst, const MMVar& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord (MMX). - inline void movd(const GPVar& dst, const MMVar& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord (MMX). - inline void movd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord (MMX). - inline void movd(const MMVar& dst, const GPVar& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - - //! @brief Move QWord (MMX). - inline void movq(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } - //! @brief Move QWord (MMX). - inline void movq(const Mem& dst, const MMVar& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#if defined(ASMJIT_X64) - //! @brief Move QWord (MMX). - inline void movq(const GPVar& dst, const MMVar& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#endif - //! @brief Move QWord (MMX). - inline void movq(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#if defined(ASMJIT_X64) - //! @brief Move QWord (MMX). - inline void movq(const MMVar& dst, const GPVar& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#endif - - //! @brief Pack with Signed Saturation (MMX). - inline void packsswb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PACKSSWB, &dst, &src); - } - //! @brief Pack with Signed Saturation (MMX). - inline void packsswb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PACKSSWB, &dst, &src); - } - - //! @brief Pack with Signed Saturation (MMX). - inline void packssdw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PACKSSDW, &dst, &src); - } - //! @brief Pack with Signed Saturation (MMX). - inline void packssdw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PACKSSDW, &dst, &src); - } - - //! @brief Pack with Unsigned Saturation (MMX). - inline void packuswb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PACKUSWB, &dst, &src); - } - //! @brief Pack with Unsigned Saturation (MMX). - inline void packuswb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PACKUSWB, &dst, &src); - } - - //! @brief Packed BYTE Add (MMX). - inline void paddb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PADDB, &dst, &src); - } - //! @brief Packed BYTE Add (MMX). - inline void paddb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDB, &dst, &src); - } - - //! @brief Packed WORD Add (MMX). - inline void paddw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PADDW, &dst, &src); - } - //! @brief Packed WORD Add (MMX). - inline void paddw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDW, &dst, &src); - } - - //! @brief Packed DWORD Add (MMX). - inline void paddd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PADDD, &dst, &src); - } - //! @brief Packed DWORD Add (MMX). - inline void paddd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDD, &dst, &src); - } - - //! @brief Packed Add with Saturation (MMX). - inline void paddsb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PADDSB, &dst, &src); - } - //! @brief Packed Add with Saturation (MMX). - inline void paddsb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDSB, &dst, &src); - } - - //! @brief Packed Add with Saturation (MMX). - inline void paddsw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PADDSW, &dst, &src); - } - //! @brief Packed Add with Saturation (MMX). - inline void paddsw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDSW, &dst, &src); - } - - //! @brief Packed Add Unsigned with Saturation (MMX). - inline void paddusb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PADDUSB, &dst, &src); - } - //! @brief Packed Add Unsigned with Saturation (MMX). - inline void paddusb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDUSB, &dst, &src); - } - - //! @brief Packed Add Unsigned with Saturation (MMX). - inline void paddusw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PADDUSW, &dst, &src); - } - //! @brief Packed Add Unsigned with Saturation (MMX). - inline void paddusw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDUSW, &dst, &src); - } - - //! @brief Logical AND (MMX). - inline void pand(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PAND, &dst, &src); - } - //! @brief Logical AND (MMX). - inline void pand(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PAND, &dst, &src); - } - - //! @brief Logical AND Not (MMX). - inline void pandn(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PANDN, &dst, &src); - } - //! @brief Logical AND Not (MMX). - inline void pandn(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PANDN, &dst, &src); - } - - //! @brief Packed Compare for Equal (BYTES) (MMX). - inline void pcmpeqb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PCMPEQB, &dst, &src); - } - //! @brief Packed Compare for Equal (BYTES) (MMX). - inline void pcmpeqb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQB, &dst, &src); - } - - //! @brief Packed Compare for Equal (WORDS) (MMX). - inline void pcmpeqw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PCMPEQW, &dst, &src); - } - //! @brief Packed Compare for Equal (WORDS) (MMX). - inline void pcmpeqw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQW, &dst, &src); - } - - //! @brief Packed Compare for Equal (DWORDS) (MMX). - inline void pcmpeqd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PCMPEQD, &dst, &src); - } - //! @brief Packed Compare for Equal (DWORDS) (MMX). - inline void pcmpeqd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQD, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (BYTES) (MMX). - inline void pcmpgtb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PCMPGTB, &dst, &src); - } - //! @brief Packed Compare for Greater Than (BYTES) (MMX). - inline void pcmpgtb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTB, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (WORDS) (MMX). - inline void pcmpgtw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PCMPGTW, &dst, &src); - } - //! @brief Packed Compare for Greater Than (WORDS) (MMX). - inline void pcmpgtw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTW, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (DWORDS) (MMX). - inline void pcmpgtd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PCMPGTD, &dst, &src); - } - //! @brief Packed Compare for Greater Than (DWORDS) (MMX). - inline void pcmpgtd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTD, &dst, &src); - } - - //! @brief Packed Multiply High (MMX). - inline void pmulhw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMULHW, &dst, &src); - } - //! @brief Packed Multiply High (MMX). - inline void pmulhw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULHW, &dst, &src); - } - - //! @brief Packed Multiply Low (MMX). - inline void pmullw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMULLW, &dst, &src); - } - //! @brief Packed Multiply Low (MMX). - inline void pmullw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULLW, &dst, &src); - } - - //! @brief Bitwise Logical OR (MMX). - inline void por(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_POR, &dst, &src); - } - //! @brief Bitwise Logical OR (MMX). - inline void por(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_POR, &dst, &src); - } - - //! @brief Packed Multiply and Add (MMX). - inline void pmaddwd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMADDWD, &dst, &src); - } - //! @brief Packed Multiply and Add (MMX). - inline void pmaddwd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMADDWD, &dst, &src); - } - - //! @brief Packed Shift Left Logical (MMX). - inline void pslld(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void pslld(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void pslld(const MMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - - //! @brief Packed Shift Left Logical (MMX). - inline void psllq(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void psllq(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void psllq(const MMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - - //! @brief Packed Shift Left Logical (MMX). - inline void psllw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void psllw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - //! @brief Packed Shift Left Logical (MMX). - inline void psllw(const MMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psrad(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psrad(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psrad(const MMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psraw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psraw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (MMX). - inline void psraw(const MMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - - //! @brief Packed Shift Right Logical (MMX). - inline void psrld(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrld(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrld(const MMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - - //! @brief Packed Shift Right Logical (MMX). - inline void psrlq(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrlq(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrlq(const MMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - - //! @brief Packed Shift Right Logical (MMX). - inline void psrlw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrlw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - //! @brief Packed Shift Right Logical (MMX). - inline void psrlw(const MMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - - //! @brief Packed Subtract (MMX). - inline void psubb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSUBB, &dst, &src); - } - //! @brief Packed Subtract (MMX). - inline void psubb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBB, &dst, &src); - } - - //! @brief Packed Subtract (MMX). - inline void psubw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSUBW, &dst, &src); - } - //! @brief Packed Subtract (MMX). - inline void psubw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBW, &dst, &src); - } - - //! @brief Packed Subtract (MMX). - inline void psubd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSUBD, &dst, &src); - } - //! @brief Packed Subtract (MMX). - inline void psubd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBD, &dst, &src); - } - - //! @brief Packed Subtract with Saturation (MMX). - inline void psubsb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSUBSB, &dst, &src); - } - //! @brief Packed Subtract with Saturation (MMX). - inline void psubsb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBSB, &dst, &src); - } - - //! @brief Packed Subtract with Saturation (MMX). - inline void psubsw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSUBSW, &dst, &src); - } - //! @brief Packed Subtract with Saturation (MMX). - inline void psubsw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBSW, &dst, &src); - } - - //! @brief Packed Subtract with Unsigned Saturation (MMX). - inline void psubusb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSUBUSB, &dst, &src); - } - //! @brief Packed Subtract with Unsigned Saturation (MMX). - inline void psubusb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBUSB, &dst, &src); - } - - //! @brief Packed Subtract with Unsigned Saturation (MMX). - inline void psubusw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSUBUSW, &dst, &src); - } - //! @brief Packed Subtract with Unsigned Saturation (MMX). - inline void psubusw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBUSW, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpckhbw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PUNPCKHBW, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpckhbw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHBW, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpckhwd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PUNPCKHWD, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpckhwd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHWD, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpckhdq(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PUNPCKHDQ, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpckhdq(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHDQ, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpcklbw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PUNPCKLBW, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpcklbw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLBW, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpcklwd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PUNPCKLWD, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpcklwd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLWD, &dst, &src); - } - - //! @brief Unpack High Packed Data (MMX). - inline void punpckldq(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PUNPCKLDQ, &dst, &src); - } - //! @brief Unpack High Packed Data (MMX). - inline void punpckldq(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLDQ, &dst, &src); - } - - //! @brief Bitwise Exclusive OR (MMX). - inline void pxor(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PXOR, &dst, &src); - } - //! @brief Bitwise Exclusive OR (MMX). - inline void pxor(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PXOR, &dst, &src); - } - - // -------------------------------------------------------------------------- - // [3dNow] - // -------------------------------------------------------------------------- - - //! @brief Faster EMMS (3dNow!). - //! - //! @note Use only for early AMD processors where is only 3dNow! or SSE. If - //! CPU contains SSE2, it's better to use @c emms() ( @c femms() is mapped - //! to @c emms() ). - inline void femms() - { - _emitInstruction(INST_FEMMS); - } - - //! @brief Packed SP-FP to Integer Convert (3dNow!). - inline void pf2id(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PF2ID, &dst, &src); - } - //! @brief Packed SP-FP to Integer Convert (3dNow!). - inline void pf2id(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PF2ID, &dst, &src); - } - - //! @brief Packed SP-FP to Integer Word Convert (3dNow!). - inline void pf2iw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PF2IW, &dst, &src); - } - //! @brief Packed SP-FP to Integer Word Convert (3dNow!). - inline void pf2iw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PF2IW, &dst, &src); - } - - //! @brief Packed SP-FP Accumulate (3dNow!). - inline void pfacc(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFACC, &dst, &src); - } - //! @brief Packed SP-FP Accumulate (3dNow!). - inline void pfacc(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFACC, &dst, &src); - } - - //! @brief Packed SP-FP Addition (3dNow!). - inline void pfadd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFADD, &dst, &src); - } - //! @brief Packed SP-FP Addition (3dNow!). - inline void pfadd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFADD, &dst, &src); - } - - //! @brief Packed SP-FP Compare - dst == src (3dNow!). - inline void pfcmpeq(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFCMPEQ, &dst, &src); - } - //! @brief Packed SP-FP Compare - dst == src (3dNow!). - inline void pfcmpeq(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFCMPEQ, &dst, &src); - } - - //! @brief Packed SP-FP Compare - dst >= src (3dNow!). - inline void pfcmpge(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFCMPGE, &dst, &src); - } - //! @brief Packed SP-FP Compare - dst >= src (3dNow!). - inline void pfcmpge(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFCMPGE, &dst, &src); - } - - //! @brief Packed SP-FP Compare - dst > src (3dNow!). - inline void pfcmpgt(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFCMPGT, &dst, &src); - } - //! @brief Packed SP-FP Compare - dst > src (3dNow!). - inline void pfcmpgt(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFCMPGT, &dst, &src); - } - - //! @brief Packed SP-FP Maximum (3dNow!). - inline void pfmax(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFMAX, &dst, &src); - } - //! @brief Packed SP-FP Maximum (3dNow!). - inline void pfmax(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFMAX, &dst, &src); - } - - //! @brief Packed SP-FP Minimum (3dNow!). - inline void pfmin(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFMIN, &dst, &src); - } - //! @brief Packed SP-FP Minimum (3dNow!). - inline void pfmin(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFMIN, &dst, &src); - } - - //! @brief Packed SP-FP Multiply (3dNow!). - inline void pfmul(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFMUL, &dst, &src); - } - //! @brief Packed SP-FP Multiply (3dNow!). - inline void pfmul(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFMUL, &dst, &src); - } - - //! @brief Packed SP-FP Negative Accumulate (3dNow!). - inline void pfnacc(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFNACC, &dst, &src); - } - //! @brief Packed SP-FP Negative Accumulate (3dNow!). - inline void pfnacc(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFNACC, &dst, &src); - } - - //! @brief Packed SP-FP Mixed Accumulate (3dNow!). - inline void pfpnaxx(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFPNACC, &dst, &src); - } - //! @brief Packed SP-FP Mixed Accumulate (3dNow!). - inline void pfpnacc(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFPNACC, &dst, &src); - } - - //! @brief Packed SP-FP Reciprocal Approximation (3dNow!). - inline void pfrcp(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFRCP, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal Approximation (3dNow!). - inline void pfrcp(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFRCP, &dst, &src); - } - - //! @brief Packed SP-FP Reciprocal, First Iteration Step (3dNow!). - inline void pfrcpit1(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFRCPIT1, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal, First Iteration Step (3dNow!). - inline void pfrcpit1(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFRCPIT1, &dst, &src); - } - - //! @brief Packed SP-FP Reciprocal, Second Iteration Step (3dNow!). - inline void pfrcpit2(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFRCPIT2, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal, Second Iteration Step (3dNow!). - inline void pfrcpit2(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFRCPIT2, &dst, &src); - } - - //! @brief Packed SP-FP Reciprocal Square Root, First Iteration Step (3dNow!). - inline void pfrsqit1(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFRSQIT1, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal Square Root, First Iteration Step (3dNow!). - inline void pfrsqit1(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFRSQIT1, &dst, &src); - } - - //! @brief Packed SP-FP Reciprocal Square Root Approximation (3dNow!). - inline void pfrsqrt(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFRSQRT, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal Square Root Approximation (3dNow!). - inline void pfrsqrt(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFRSQRT, &dst, &src); - } - - //! @brief Packed SP-FP Subtract (3dNow!). - inline void pfsub(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFSUB, &dst, &src); - } - //! @brief Packed SP-FP Subtract (3dNow!). - inline void pfsub(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFSUB, &dst, &src); - } - - //! @brief Packed SP-FP Reverse Subtract (3dNow!). - inline void pfsubr(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PFSUBR, &dst, &src); - } - //! @brief Packed SP-FP Reverse Subtract (3dNow!). - inline void pfsubr(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PFSUBR, &dst, &src); - } - - //! @brief Packed DWords to SP-FP (3dNow!). - inline void pi2fd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PI2FD, &dst, &src); - } - //! @brief Packed DWords to SP-FP (3dNow!). - inline void pi2fd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PI2FD, &dst, &src); - } - - //! @brief Packed Words to SP-FP (3dNow!). - inline void pi2fw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PI2FW, &dst, &src); - } - //! @brief Packed Words to SP-FP (3dNow!). - inline void pi2fw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PI2FW, &dst, &src); - } - - //! @brief Packed swap DWord (3dNow!) - inline void pswapd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSWAPD, &dst, &src); - } - //! @brief Packed swap DWord (3dNow!) - inline void pswapd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSWAPD, &dst, &src); - } - - // -------------------------------------------------------------------------- - // [SSE] - // -------------------------------------------------------------------------- - - //! @brief Packed SP-FP Add (SSE). - inline void addps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ADDPS, &dst, &src); - } - //! @brief Packed SP-FP Add (SSE). - inline void addps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ADDPS, &dst, &src); - } - - //! @brief Scalar SP-FP Add (SSE). - inline void addss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ADDSS, &dst, &src); - } - //! @brief Scalar SP-FP Add (SSE). - inline void addss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ADDSS, &dst, &src); - } - - //! @brief Bit-wise Logical And Not For SP-FP (SSE). - inline void andnps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ANDNPS, &dst, &src); - } - //! @brief Bit-wise Logical And Not For SP-FP (SSE). - inline void andnps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ANDNPS, &dst, &src); - } - - //! @brief Bit-wise Logical And For SP-FP (SSE). - inline void andps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ANDPS, &dst, &src); - } - //! @brief Bit-wise Logical And For SP-FP (SSE). - inline void andps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ANDPS, &dst, &src); - } - - //! @brief Packed SP-FP Compare (SSE). - inline void cmpps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_CMPPS, &dst, &src, &imm8); - } - //! @brief Packed SP-FP Compare (SSE). - inline void cmpps(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_CMPPS, &dst, &src, &imm8); - } - - //! @brief Compare Scalar SP-FP Values (SSE). - inline void cmpss(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_CMPSS, &dst, &src, &imm8); - } - //! @brief Compare Scalar SP-FP Values (SSE). - inline void cmpss(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_CMPSS, &dst, &src, &imm8); - } - - //! @brief Scalar Ordered SP-FP Compare and Set EFLAGS (SSE). - inline void comiss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_COMISS, &dst, &src); - } - //! @brief Scalar Ordered SP-FP Compare and Set EFLAGS (SSE). - inline void comiss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_COMISS, &dst, &src); - } - - //! @brief Packed Signed INT32 to Packed SP-FP Conversion (SSE). - inline void cvtpi2ps(const XMMVar& dst, const MMVar& src) - { - _emitInstruction(INST_CVTPI2PS, &dst, &src); - } - //! @brief Packed Signed INT32 to Packed SP-FP Conversion (SSE). - inline void cvtpi2ps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTPI2PS, &dst, &src); - } - - //! @brief Packed SP-FP to Packed INT32 Conversion (SSE). - inline void cvtps2pi(const MMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTPS2PI, &dst, &src); - } - //! @brief Packed SP-FP to Packed INT32 Conversion (SSE). - inline void cvtps2pi(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTPS2PI, &dst, &src); - } - - //! @brief Scalar Signed INT32 to SP-FP Conversion (SSE). - inline void cvtsi2ss(const XMMVar& dst, const GPVar& src) - { - _emitInstruction(INST_CVTSI2SS, &dst, &src); - } - //! @brief Scalar Signed INT32 to SP-FP Conversion (SSE). - inline void cvtsi2ss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTSI2SS, &dst, &src); - } - - //! @brief Scalar SP-FP to Signed INT32 Conversion (SSE). - inline void cvtss2si(const GPVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTSS2SI, &dst, &src); - } - //! @brief Scalar SP-FP to Signed INT32 Conversion (SSE). - inline void cvtss2si(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTSS2SI, &dst, &src); - } - - //! @brief Packed SP-FP to Packed INT32 Conversion (truncate) (SSE). - inline void cvttps2pi(const MMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTTPS2PI, &dst, &src); - } - //! @brief Packed SP-FP to Packed INT32 Conversion (truncate) (SSE). - inline void cvttps2pi(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTTPS2PI, &dst, &src); - } - - //! @brief Scalar SP-FP to Signed INT32 Conversion (truncate) (SSE). - inline void cvttss2si(const GPVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTTSS2SI, &dst, &src); - } - //! @brief Scalar SP-FP to Signed INT32 Conversion (truncate) (SSE). - inline void cvttss2si(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTTSS2SI, &dst, &src); - } - - //! @brief Packed SP-FP Divide (SSE). - inline void divps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_DIVPS, &dst, &src); - } - //! @brief Packed SP-FP Divide (SSE). - inline void divps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_DIVPS, &dst, &src); - } - - //! @brief Scalar SP-FP Divide (SSE). - inline void divss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_DIVSS, &dst, &src); - } - //! @brief Scalar SP-FP Divide (SSE). - inline void divss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_DIVSS, &dst, &src); - } - - //! @brief Load Streaming SIMD Extension Control/Status (SSE). - inline void ldmxcsr(const Mem& src) - { - _emitInstruction(INST_LDMXCSR, &src); - } - - //! @brief Byte Mask Write (SSE). - //! - //! @note The default memory location is specified by DS:EDI. - inline void maskmovq(const GPVar& dst_ptr, const MMVar& data, const MMVar& mask) - { - _emitInstruction(INST_MASKMOVQ, &dst_ptr, &data, &mask); - } - - //! @brief Packed SP-FP Maximum (SSE). - inline void maxps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MAXPS, &dst, &src); - } - //! @brief Packed SP-FP Maximum (SSE). - inline void maxps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MAXPS, &dst, &src); - } - - //! @brief Scalar SP-FP Maximum (SSE). - inline void maxss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MAXSS, &dst, &src); - } - //! @brief Scalar SP-FP Maximum (SSE). - inline void maxss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MAXSS, &dst, &src); - } - - //! @brief Packed SP-FP Minimum (SSE). - inline void minps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MINPS, &dst, &src); - } - //! @brief Packed SP-FP Minimum (SSE). - inline void minps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MINPS, &dst, &src); - } - - //! @brief Scalar SP-FP Minimum (SSE). - inline void minss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MINSS, &dst, &src); - } - //! @brief Scalar SP-FP Minimum (SSE). - inline void minss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MINSS, &dst, &src); - } - - //! @brief Move Aligned Packed SP-FP Values (SSE). - inline void movaps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVAPS, &dst, &src); - } - //! @brief Move Aligned Packed SP-FP Values (SSE). - inline void movaps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVAPS, &dst, &src); - } - - //! @brief Move Aligned Packed SP-FP Values (SSE). - inline void movaps(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVAPS, &dst, &src); - } - - //! @brief Move DWord. - inline void movd(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord. - inline void movd(const GPVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord. - inline void movd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - //! @brief Move DWord. - inline void movd(const XMMVar& dst, const GPVar& src) - { - _emitInstruction(INST_MOVD, &dst, &src); - } - - //! @brief Move QWord (SSE). - inline void movq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } - //! @brief Move QWord (SSE). - inline void movq(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#if defined(ASMJIT_X64) - //! @brief Move QWord (SSE). - inline void movq(const GPVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#endif // ASMJIT_X64 - //! @brief Move QWord (SSE). - inline void movq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#if defined(ASMJIT_X64) - //! @brief Move QWord (SSE). - inline void movq(const XMMVar& dst, const GPVar& src) - { - _emitInstruction(INST_MOVQ, &dst, &src); - } -#endif // ASMJIT_X64 - - //! @brief Move 64 Bits Non Temporal (SSE). - inline void movntq(const Mem& dst, const MMVar& src) - { - _emitInstruction(INST_MOVNTQ, &dst, &src); - } - - //! @brief High to Low Packed SP-FP (SSE). - inline void movhlps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVHLPS, &dst, &src); - } - - //! @brief Move High Packed SP-FP (SSE). - inline void movhps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVHPS, &dst, &src); - } - - //! @brief Move High Packed SP-FP (SSE). - inline void movhps(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVHPS, &dst, &src); - } - - //! @brief Move Low to High Packed SP-FP (SSE). - inline void movlhps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVLHPS, &dst, &src); - } - - //! @brief Move Low Packed SP-FP (SSE). - inline void movlps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVLPS, &dst, &src); - } - - //! @brief Move Low Packed SP-FP (SSE). - inline void movlps(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVLPS, &dst, &src); - } - - //! @brief Move Aligned Four Packed SP-FP Non Temporal (SSE). - inline void movntps(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVNTPS, &dst, &src); - } - - //! @brief Move Scalar SP-FP (SSE). - inline void movss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVSS, &dst, &src); - } - - //! @brief Move Scalar SP-FP (SSE). - inline void movss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVSS, &dst, &src); - } - - //! @brief Move Scalar SP-FP (SSE). - inline void movss(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVSS, &dst, &src); - } - - //! @brief Move Unaligned Packed SP-FP Values (SSE). - inline void movups(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVUPS, &dst, &src); - } - //! @brief Move Unaligned Packed SP-FP Values (SSE). - inline void movups(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVUPS, &dst, &src); - } - - //! @brief Move Unaligned Packed SP-FP Values (SSE). - inline void movups(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVUPS, &dst, &src); - } - - //! @brief Packed SP-FP Multiply (SSE). - inline void mulps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MULPS, &dst, &src); - } - //! @brief Packed SP-FP Multiply (SSE). - inline void mulps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MULPS, &dst, &src); - } - - //! @brief Scalar SP-FP Multiply (SSE). - inline void mulss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MULSS, &dst, &src); - } - //! @brief Scalar SP-FP Multiply (SSE). - inline void mulss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MULSS, &dst, &src); - } - - //! @brief Bit-wise Logical OR for SP-FP Data (SSE). - inline void orps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ORPS, &dst, &src); - } - //! @brief Bit-wise Logical OR for SP-FP Data (SSE). - inline void orps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ORPS, &dst, &src); - } - - //! @brief Packed Average (SSE). - inline void pavgb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PAVGB, &dst, &src); - } - //! @brief Packed Average (SSE). - inline void pavgb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PAVGB, &dst, &src); - } - - //! @brief Packed Average (SSE). - inline void pavgw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PAVGW, &dst, &src); - } - //! @brief Packed Average (SSE). - inline void pavgw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PAVGW, &dst, &src); - } - - //! @brief Extract Word (SSE). - inline void pextrw(const GPVar& dst, const MMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRW, &dst, &src, &imm8); - } - - //! @brief Insert Word (SSE). - inline void pinsrw(const MMVar& dst, const GPVar& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRW, &dst, &src, &imm8); - } - //! @brief Insert Word (SSE). - inline void pinsrw(const MMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRW, &dst, &src, &imm8); - } - - //! @brief Packed Signed Integer Word Maximum (SSE). - inline void pmaxsw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMAXSW, &dst, &src); - } - //! @brief Packed Signed Integer Word Maximum (SSE). - inline void pmaxsw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMAXSW, &dst, &src); - } - - //! @brief Packed Unsigned Integer Byte Maximum (SSE). - inline void pmaxub(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMAXUB, &dst, &src); - } - //! @brief Packed Unsigned Integer Byte Maximum (SSE). - inline void pmaxub(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMAXUB, &dst, &src); - } - - //! @brief Packed Signed Integer Word Minimum (SSE). - inline void pminsw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMINSW, &dst, &src); - } - //! @brief Packed Signed Integer Word Minimum (SSE). - inline void pminsw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMINSW, &dst, &src); - } - - //! @brief Packed Unsigned Integer Byte Minimum (SSE). - inline void pminub(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMINUB, &dst, &src); - } - //! @brief Packed Unsigned Integer Byte Minimum (SSE). - inline void pminub(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMINUB, &dst, &src); - } - - //! @brief Move Byte Mask To Integer (SSE). - inline void pmovmskb(const GPVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMOVMSKB, &dst, &src); - } - - //! @brief Packed Multiply High Unsigned (SSE). - inline void pmulhuw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMULHUW, &dst, &src); - } - //! @brief Packed Multiply High Unsigned (SSE). - inline void pmulhuw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULHUW, &dst, &src); - } - - //! @brief Packed Sum of Absolute Differences (SSE). - inline void psadbw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSADBW, &dst, &src); - } - //! @brief Packed Sum of Absolute Differences (SSE). - inline void psadbw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSADBW, &dst, &src); - } - - //! @brief Packed Shuffle word (SSE). - inline void pshufw(const MMVar& dst, const MMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFW, &dst, &src, &imm8); - } - //! @brief Packed Shuffle word (SSE). - inline void pshufw(const MMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFW, &dst, &src, &imm8); - } - - //! @brief Packed SP-FP Reciprocal (SSE). - inline void rcpps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_RCPPS, &dst, &src); - } - //! @brief Packed SP-FP Reciprocal (SSE). - inline void rcpps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_RCPPS, &dst, &src); - } - - //! @brief Scalar SP-FP Reciprocal (SSE). - inline void rcpss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_RCPSS, &dst, &src); - } - //! @brief Scalar SP-FP Reciprocal (SSE). - inline void rcpss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_RCPSS, &dst, &src); - } - - //! @brief Prefetch (SSE). - inline void prefetch(const Mem& mem, const Imm& hint) - { - _emitInstruction(INST_PREFETCH, &mem, &hint); - } - - //! @brief Compute Sum of Absolute Differences (SSE). - inline void psadbw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSADBW, &dst, &src); - } - //! @brief Compute Sum of Absolute Differences (SSE). - inline void psadbw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSADBW, &dst, &src); - } - - //! @brief Packed SP-FP Square Root Reciprocal (SSE). - inline void rsqrtps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_RSQRTPS, &dst, &src); - } - //! @brief Packed SP-FP Square Root Reciprocal (SSE). - inline void rsqrtps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_RSQRTPS, &dst, &src); - } - - //! @brief Scalar SP-FP Square Root Reciprocal (SSE). - inline void rsqrtss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_RSQRTSS, &dst, &src); - } - //! @brief Scalar SP-FP Square Root Reciprocal (SSE). - inline void rsqrtss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_RSQRTSS, &dst, &src); - } - - //! @brief Store fence (SSE). - inline void sfence() - { - _emitInstruction(INST_SFENCE); - } - - //! @brief Shuffle SP-FP (SSE). - inline void shufps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_SHUFPS, &dst, &src, &imm8); - } - //! @brief Shuffle SP-FP (SSE). - inline void shufps(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_SHUFPS, &dst, &src, &imm8); - } - - //! @brief Packed SP-FP Square Root (SSE). - inline void sqrtps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_SQRTPS, &dst, &src); - } - //! @brief Packed SP-FP Square Root (SSE). - inline void sqrtps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_SQRTPS, &dst, &src); - } - - //! @brief Scalar SP-FP Square Root (SSE). - inline void sqrtss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_SQRTSS, &dst, &src); - } - //! @brief Scalar SP-FP Square Root (SSE). - inline void sqrtss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_SQRTSS, &dst, &src); - } - - //! @brief Store Streaming SIMD Extension Control/Status (SSE). - inline void stmxcsr(const Mem& dst) - { - _emitInstruction(INST_STMXCSR, &dst); - } - - //! @brief Packed SP-FP Subtract (SSE). - inline void subps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_SUBPS, &dst, &src); - } - //! @brief Packed SP-FP Subtract (SSE). - inline void subps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_SUBPS, &dst, &src); - } - - //! @brief Scalar SP-FP Subtract (SSE). - inline void subss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_SUBSS, &dst, &src); - } - //! @brief Scalar SP-FP Subtract (SSE). - inline void subss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_SUBSS, &dst, &src); - } - - //! @brief Unordered Scalar SP-FP compare and set EFLAGS (SSE). - inline void ucomiss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_UCOMISS, &dst, &src); - } - //! @brief Unordered Scalar SP-FP compare and set EFLAGS (SSE). - inline void ucomiss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_UCOMISS, &dst, &src); - } - - //! @brief Unpack High Packed SP-FP Data (SSE). - inline void unpckhps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_UNPCKHPS, &dst, &src); - } - //! @brief Unpack High Packed SP-FP Data (SSE). - inline void unpckhps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_UNPCKHPS, &dst, &src); - } - - //! @brief Unpack Low Packed SP-FP Data (SSE). - inline void unpcklps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_UNPCKLPS, &dst, &src); - } - //! @brief Unpack Low Packed SP-FP Data (SSE). - inline void unpcklps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_UNPCKLPS, &dst, &src); - } - - //! @brief Bit-wise Logical Xor for SP-FP Data (SSE). - inline void xorps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_XORPS, &dst, &src); - } - //! @brief Bit-wise Logical Xor for SP-FP Data (SSE). - inline void xorps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_XORPS, &dst, &src); - } - - // -------------------------------------------------------------------------- - // [SSE2] - // -------------------------------------------------------------------------- - - //! @brief Packed DP-FP Add (SSE2). - inline void addpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ADDPD, &dst, &src); - } - //! @brief Packed DP-FP Add (SSE2). - inline void addpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ADDPD, &dst, &src); - } - - //! @brief Scalar DP-FP Add (SSE2). - inline void addsd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ADDSD, &dst, &src); - } - //! @brief Scalar DP-FP Add (SSE2). - inline void addsd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ADDSD, &dst, &src); - } - - //! @brief Bit-wise Logical And Not For DP-FP (SSE2). - inline void andnpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ANDNPD, &dst, &src); - } - //! @brief Bit-wise Logical And Not For DP-FP (SSE2). - inline void andnpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ANDNPD, &dst, &src); - } - - //! @brief Bit-wise Logical And For DP-FP (SSE2). - inline void andpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ANDPD, &dst, &src); - } - //! @brief Bit-wise Logical And For DP-FP (SSE2). - inline void andpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ANDPD, &dst, &src); - } - - //! @brief Flush Cache Line (SSE2). - inline void clflush(const Mem& mem) - { - _emitInstruction(INST_CLFLUSH, &mem); - } - - //! @brief Packed DP-FP Compare (SSE2). - inline void cmppd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_CMPPD, &dst, &src, &imm8); - } - //! @brief Packed DP-FP Compare (SSE2). - inline void cmppd(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_CMPPD, &dst, &src, &imm8); - } - - //! @brief Compare Scalar SP-FP Values (SSE2). - inline void cmpsd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_CMPSD, &dst, &src, &imm8); - } - //! @brief Compare Scalar SP-FP Values (SSE2). - inline void cmpsd(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_CMPSD, &dst, &src, &imm8); - } - - //! @brief Scalar Ordered DP-FP Compare and Set EFLAGS (SSE2). - inline void comisd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_COMISD, &dst, &src); - } - //! @brief Scalar Ordered DP-FP Compare and Set EFLAGS (SSE2). - inline void comisd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_COMISD, &dst, &src); - } - - //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). - inline void cvtdq2pd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTDQ2PD, &dst, &src); - } - //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). - inline void cvtdq2pd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTDQ2PD, &dst, &src); - } - - //! @brief Convert Packed Dword Integers to Packed SP-FP Values (SSE2). - inline void cvtdq2ps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTDQ2PS, &dst, &src); - } - //! @brief Convert Packed Dword Integers to Packed SP-FP Values (SSE2). - inline void cvtdq2ps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTDQ2PS, &dst, &src); - } - - //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvtpd2dq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTPD2DQ, &dst, &src); - } - //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvtpd2dq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTPD2DQ, &dst, &src); - } - - //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvtpd2pi(const MMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTPD2PI, &dst, &src); - } - //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvtpd2pi(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTPD2PI, &dst, &src); - } - - //! @brief Convert Packed DP-FP Values to Packed SP-FP Values (SSE2). - inline void cvtpd2ps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTPD2PS, &dst, &src); - } - //! @brief Convert Packed DP-FP Values to Packed SP-FP Values (SSE2). - inline void cvtpd2ps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTPD2PS, &dst, &src); - } - - //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). - inline void cvtpi2pd(const XMMVar& dst, const MMVar& src) - { - _emitInstruction(INST_CVTPI2PD, &dst, &src); - } - //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). - inline void cvtpi2pd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTPI2PD, &dst, &src); - } - - //! @brief Convert Packed SP-FP Values to Packed Dword Integers (SSE2). - inline void cvtps2dq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTPS2DQ, &dst, &src); - } - //! @brief Convert Packed SP-FP Values to Packed Dword Integers (SSE2). - inline void cvtps2dq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTPS2DQ, &dst, &src); - } - - //! @brief Convert Packed SP-FP Values to Packed DP-FP Values (SSE2). - inline void cvtps2pd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTPS2PD, &dst, &src); - } - //! @brief Convert Packed SP-FP Values to Packed DP-FP Values (SSE2). - inline void cvtps2pd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTPS2PD, &dst, &src); - } - - //! @brief Convert Scalar DP-FP Value to Dword Integer (SSE2). - inline void cvtsd2si(const GPVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTSD2SI, &dst, &src); - } - //! @brief Convert Scalar DP-FP Value to Dword Integer (SSE2). - inline void cvtsd2si(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTSD2SI, &dst, &src); - } - - //! @brief Convert Scalar DP-FP Value to Scalar SP-FP Value (SSE2). - inline void cvtsd2ss(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTSD2SS, &dst, &src); - } - //! @brief Convert Scalar DP-FP Value to Scalar SP-FP Value (SSE2). - inline void cvtsd2ss(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTSD2SS, &dst, &src); - } - - //! @brief Convert Dword Integer to Scalar DP-FP Value (SSE2). - inline void cvtsi2sd(const XMMVar& dst, const GPVar& src) - { - _emitInstruction(INST_CVTSI2SD, &dst, &src); - } - //! @brief Convert Dword Integer to Scalar DP-FP Value (SSE2). - inline void cvtsi2sd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTSI2SD, &dst, &src); - } - - //! @brief Convert Scalar SP-FP Value to Scalar DP-FP Value (SSE2). - inline void cvtss2sd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTSS2SD, &dst, &src); - } - //! @brief Convert Scalar SP-FP Value to Scalar DP-FP Value (SSE2). - inline void cvtss2sd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTSS2SD, &dst, &src); - } - - //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvttpd2pi(const MMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTTPD2PI, &dst, &src); - } - //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvttpd2pi(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTTPD2PI, &dst, &src); - } - - //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvttpd2dq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTTPD2DQ, &dst, &src); - } - //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). - inline void cvttpd2dq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTTPD2DQ, &dst, &src); - } - - //! @brief Convert with Truncation Packed SP-FP Values to Packed Dword Integers (SSE2). - inline void cvttps2dq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTTPS2DQ, &dst, &src); - } - //! @brief Convert with Truncation Packed SP-FP Values to Packed Dword Integers (SSE2). - inline void cvttps2dq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTTPS2DQ, &dst, &src); - } - - //! @brief Convert with Truncation Scalar DP-FP Value to Signed Dword Integer (SSE2). - inline void cvttsd2si(const GPVar& dst, const XMMVar& src) - { - _emitInstruction(INST_CVTTSD2SI, &dst, &src); - } - //! @brief Convert with Truncation Scalar DP-FP Value to Signed Dword Integer (SSE2). - inline void cvttsd2si(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_CVTTSD2SI, &dst, &src); - } - - //! @brief Packed DP-FP Divide (SSE2). - inline void divpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_DIVPD, &dst, &src); - } - //! @brief Packed DP-FP Divide (SSE2). - inline void divpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_DIVPD, &dst, &src); - } - - //! @brief Scalar DP-FP Divide (SSE2). - inline void divsd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_DIVSD, &dst, &src); - } - //! @brief Scalar DP-FP Divide (SSE2). - inline void divsd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_DIVSD, &dst, &src); - } - - //! @brief Load Fence (SSE2). - inline void lfence() - { - _emitInstruction(INST_LFENCE); - } - - //! @brief Store Selected Bytes of Double Quadword (SSE2). - //! - //! @note Target is DS:EDI. - inline void maskmovdqu(const GPVar& dst_ptr, const XMMVar& src, const XMMVar& mask) - { - _emitInstruction(INST_MASKMOVDQU, &dst_ptr, &src, &mask); - } - - //! @brief Return Maximum Packed Double-Precision FP Values (SSE2). - inline void maxpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MAXPD, &dst, &src); - } - //! @brief Return Maximum Packed Double-Precision FP Values (SSE2). - inline void maxpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MAXPD, &dst, &src); - } - - //! @brief Return Maximum Scalar Double-Precision FP Value (SSE2). - inline void maxsd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MAXSD, &dst, &src); - } - //! @brief Return Maximum Scalar Double-Precision FP Value (SSE2). - inline void maxsd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MAXSD, &dst, &src); - } - - //! @brief Memory Fence (SSE2). - inline void mfence() - { - _emitInstruction(INST_MFENCE); - } - - //! @brief Return Minimum Packed DP-FP Values (SSE2). - inline void minpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MINPD, &dst, &src); - } - //! @brief Return Minimum Packed DP-FP Values (SSE2). - inline void minpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MINPD, &dst, &src); - } - - //! @brief Return Minimum Scalar DP-FP Value (SSE2). - inline void minsd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MINSD, &dst, &src); - } - //! @brief Return Minimum Scalar DP-FP Value (SSE2). - inline void minsd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MINSD, &dst, &src); - } - - //! @brief Move Aligned DQWord (SSE2). - inline void movdqa(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVDQA, &dst, &src); - } - //! @brief Move Aligned DQWord (SSE2). - inline void movdqa(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVDQA, &dst, &src); - } - - //! @brief Move Aligned DQWord (SSE2). - inline void movdqa(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVDQA, &dst, &src); - } - - //! @brief Move Unaligned Double Quadword (SSE2). - inline void movdqu(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVDQU, &dst, &src); - } - //! @brief Move Unaligned Double Quadword (SSE2). - inline void movdqu(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVDQU, &dst, &src); - } - - //! @brief Move Unaligned Double Quadword (SSE2). - inline void movdqu(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVDQU, &dst, &src); - } - - //! @brief Extract Packed SP-FP Sign Mask (SSE2). - inline void movmskps(const GPVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVMSKPS, &dst, &src); - } - - //! @brief Extract Packed DP-FP Sign Mask (SSE2). - inline void movmskpd(const GPVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVMSKPD, &dst, &src); - } - - //! @brief Move Scalar Double-Precision FP Value (SSE2). - inline void movsd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVSD, &dst, &src); - } - //! @brief Move Scalar Double-Precision FP Value (SSE2). - inline void movsd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVSD, &dst, &src); - } - - //! @brief Move Scalar Double-Precision FP Value (SSE2). - inline void movsd(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVSD, &dst, &src); - } - - //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). - inline void movapd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVAPD, &dst, &src); - } - - //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). - inline void movapd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVAPD, &dst, &src); - } - - //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). - inline void movapd(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVAPD, &dst, &src); - } - - //! @brief Move Quadword from XMM to MMX Technology Register (SSE2). - inline void movdq2q(const MMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVDQ2Q, &dst, &src); - } - - //! @brief Move Quadword from MMX Technology to XMM Register (SSE2). - inline void movq2dq(const XMMVar& dst, const MMVar& src) - { - _emitInstruction(INST_MOVQ2DQ, &dst, &src); - } - - //! @brief Move High Packed Double-Precision FP Value (SSE2). - inline void movhpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVHPD, &dst, &src); - } - - //! @brief Move High Packed Double-Precision FP Value (SSE2). - inline void movhpd(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVHPD, &dst, &src); - } - - //! @brief Move Low Packed Double-Precision FP Value (SSE2). - inline void movlpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVLPD, &dst, &src); - } - - //! @brief Move Low Packed Double-Precision FP Value (SSE2). - inline void movlpd(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVLPD, &dst, &src); - } - - //! @brief Store Double Quadword Using Non-Temporal Hint (SSE2). - inline void movntdq(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVNTDQ, &dst, &src); - } - - //! @brief Store Store DWORD Using Non-Temporal Hint (SSE2). - inline void movnti(const Mem& dst, const GPVar& src) - { - _emitInstruction(INST_MOVNTI, &dst, &src); - } - - //! @brief Store Packed Double-Precision FP Values Using Non-Temporal Hint (SSE2). - inline void movntpd(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVNTPD, &dst, &src); - } - - //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). - inline void movupd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVUPD, &dst, &src); - } - - //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). - inline void movupd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVUPD, &dst, &src); - } - - //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). - inline void movupd(const Mem& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVUPD, &dst, &src); - } - - //! @brief Packed DP-FP Multiply (SSE2). - inline void mulpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MULPD, &dst, &src); - } - //! @brief Packed DP-FP Multiply (SSE2). - inline void mulpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MULPD, &dst, &src); - } - - //! @brief Scalar DP-FP Multiply (SSE2). - inline void mulsd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MULSD, &dst, &src); - } - //! @brief Scalar DP-FP Multiply (SSE2). - inline void mulsd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MULSD, &dst, &src); - } - - //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). - inline void orpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ORPD, &dst, &src); - } - //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). - inline void orpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ORPD, &dst, &src); - } - - //! @brief Pack with Signed Saturation (SSE2). - inline void packsswb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PACKSSWB, &dst, &src); - } - //! @brief Pack with Signed Saturation (SSE2). - inline void packsswb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PACKSSWB, &dst, &src); - } - - //! @brief Pack with Signed Saturation (SSE2). - inline void packssdw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PACKSSDW, &dst, &src); - } - //! @brief Pack with Signed Saturation (SSE2). - inline void packssdw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PACKSSDW, &dst, &src); - } - - //! @brief Pack with Unsigned Saturation (SSE2). - inline void packuswb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PACKUSWB, &dst, &src); - } - //! @brief Pack with Unsigned Saturation (SSE2). - inline void packuswb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PACKUSWB, &dst, &src); - } - - //! @brief Packed BYTE Add (SSE2). - inline void paddb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PADDB, &dst, &src); - } - //! @brief Packed BYTE Add (SSE2). - inline void paddb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDB, &dst, &src); - } - - //! @brief Packed WORD Add (SSE2). - inline void paddw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PADDW, &dst, &src); - } - //! @brief Packed WORD Add (SSE2). - inline void paddw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDW, &dst, &src); - } - - //! @brief Packed DWORD Add (SSE2). - inline void paddd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PADDD, &dst, &src); - } - //! @brief Packed DWORD Add (SSE2). - inline void paddd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDD, &dst, &src); - } - - //! @brief Packed QWORD Add (SSE2). - inline void paddq(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PADDQ, &dst, &src); - } - //! @brief Packed QWORD Add (SSE2). - inline void paddq(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDQ, &dst, &src); - } - - //! @brief Packed QWORD Add (SSE2). - inline void paddq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PADDQ, &dst, &src); - } - //! @brief Packed QWORD Add (SSE2). - inline void paddq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDQ, &dst, &src); - } - - //! @brief Packed Add with Saturation (SSE2). - inline void paddsb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PADDSB, &dst, &src); - } - //! @brief Packed Add with Saturation (SSE2). - inline void paddsb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDSB, &dst, &src); - } - - //! @brief Packed Add with Saturation (SSE2). - inline void paddsw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PADDSW, &dst, &src); - } - //! @brief Packed Add with Saturation (SSE2). - inline void paddsw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDSW, &dst, &src); - } - - //! @brief Packed Add Unsigned with Saturation (SSE2). - inline void paddusb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PADDUSB, &dst, &src); - } - //! @brief Packed Add Unsigned with Saturation (SSE2). - inline void paddusb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDUSB, &dst, &src); - } - - //! @brief Packed Add Unsigned with Saturation (SSE2). - inline void paddusw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PADDUSW, &dst, &src); - } - //! @brief Packed Add Unsigned with Saturation (SSE2). - inline void paddusw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PADDUSW, &dst, &src); - } - - //! @brief Logical AND (SSE2). - inline void pand(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PAND, &dst, &src); - } - //! @brief Logical AND (SSE2). - inline void pand(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PAND, &dst, &src); - } - - //! @brief Logical AND Not (SSE2). - inline void pandn(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PANDN, &dst, &src); - } - //! @brief Logical AND Not (SSE2). - inline void pandn(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PANDN, &dst, &src); - } - - //! @brief Spin Loop Hint (SSE2). - inline void pause() - { - _emitInstruction(INST_PAUSE); - } - - //! @brief Packed Average (SSE2). - inline void pavgb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PAVGB, &dst, &src); - } - //! @brief Packed Average (SSE2). - inline void pavgb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PAVGB, &dst, &src); - } - - //! @brief Packed Average (SSE2). - inline void pavgw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PAVGW, &dst, &src); - } - //! @brief Packed Average (SSE2). - inline void pavgw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PAVGW, &dst, &src); - } - - //! @brief Packed Compare for Equal (BYTES) (SSE2). - inline void pcmpeqb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PCMPEQB, &dst, &src); - } - //! @brief Packed Compare for Equal (BYTES) (SSE2). - inline void pcmpeqb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQB, &dst, &src); - } - - //! @brief Packed Compare for Equal (WORDS) (SSE2). - inline void pcmpeqw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PCMPEQW, &dst, &src); - } - //! @brief Packed Compare for Equal (WORDS) (SSE2). - inline void pcmpeqw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQW, &dst, &src); - } - - //! @brief Packed Compare for Equal (DWORDS) (SSE2). - inline void pcmpeqd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PCMPEQD, &dst, &src); - } - //! @brief Packed Compare for Equal (DWORDS) (SSE2). - inline void pcmpeqd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQD, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (BYTES) (SSE2). - inline void pcmpgtb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PCMPGTB, &dst, &src); - } - //! @brief Packed Compare for Greater Than (BYTES) (SSE2). - inline void pcmpgtb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTB, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (WORDS) (SSE2). - inline void pcmpgtw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PCMPGTW, &dst, &src); - } - //! @brief Packed Compare for Greater Than (WORDS) (SSE2). - inline void pcmpgtw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTW, &dst, &src); - } - - //! @brief Packed Compare for Greater Than (DWORDS) (SSE2). - inline void pcmpgtd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PCMPGTD, &dst, &src); - } - //! @brief Packed Compare for Greater Than (DWORDS) (SSE2). - inline void pcmpgtd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTD, &dst, &src); - } - - //! @brief Extract Word (SSE2). - inline void pextrw(const GPVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRW, &dst, &src, &imm8); - } - //! @brief Extract Word (SSE2). - inline void pextrw(const Mem& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRW, &dst, &src, &imm8); - } - - //! @brief Packed Signed Integer Word Maximum (SSE2). - inline void pmaxsw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMAXSW, &dst, &src); - } - //! @brief Packed Signed Integer Word Maximum (SSE2). - inline void pmaxsw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMAXSW, &dst, &src); - } - - //! @brief Packed Unsigned Integer Byte Maximum (SSE2). - inline void pmaxub(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMAXUB, &dst, &src); - } - //! @brief Packed Unsigned Integer Byte Maximum (SSE2). - inline void pmaxub(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMAXUB, &dst, &src); - } - - //! @brief Packed Signed Integer Word Minimum (SSE2). - inline void pminsw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMINSW, &dst, &src); - } - //! @brief Packed Signed Integer Word Minimum (SSE2). - inline void pminsw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMINSW, &dst, &src); - } - - //! @brief Packed Unsigned Integer Byte Minimum (SSE2). - inline void pminub(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMINUB, &dst, &src); - } - //! @brief Packed Unsigned Integer Byte Minimum (SSE2). - inline void pminub(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMINUB, &dst, &src); - } - - //! @brief Move Byte Mask (SSE2). - inline void pmovmskb(const GPVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVMSKB, &dst, &src); - } - - //! @brief Packed Multiply High (SSE2). - inline void pmulhw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMULHW, &dst, &src); - } - //! @brief Packed Multiply High (SSE2). - inline void pmulhw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULHW, &dst, &src); - } - - //! @brief Packed Multiply High Unsigned (SSE2). - inline void pmulhuw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMULHUW, &dst, &src); - } - //! @brief Packed Multiply High Unsigned (SSE2). - inline void pmulhuw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULHUW, &dst, &src); - } - - //! @brief Packed Multiply Low (SSE2). - inline void pmullw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMULLW, &dst, &src); - } - //! @brief Packed Multiply Low (SSE2). - inline void pmullw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULLW, &dst, &src); - } - - //! @brief Packed Multiply to QWORD (SSE2). - inline void pmuludq(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMULUDQ, &dst, &src); - } - //! @brief Packed Multiply to QWORD (SSE2). - inline void pmuludq(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULUDQ, &dst, &src); - } - - //! @brief Packed Multiply to QWORD (SSE2). - inline void pmuludq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMULUDQ, &dst, &src); - } - //! @brief Packed Multiply to QWORD (SSE2). - inline void pmuludq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULUDQ, &dst, &src); - } - - //! @brief Bitwise Logical OR (SSE2). - inline void por(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_POR, &dst, &src); - } - //! @brief Bitwise Logical OR (SSE2). - inline void por(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_POR, &dst, &src); - } - - //! @brief Packed Shift Left Logical (SSE2). - inline void pslld(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void pslld(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void pslld(const XMMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSLLD, &dst, &src); - } - - //! @brief Packed Shift Left Logical (SSE2). - inline void psllq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void psllq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void psllq(const XMMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSLLQ, &dst, &src); - } - - //! @brief Packed Shift Left Logical (SSE2). - inline void psllw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void psllw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - //! @brief Packed Shift Left Logical (SSE2). - inline void psllw(const XMMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSLLW, &dst, &src); - } - - //! @brief Packed Shift Left Logical (SSE2). - inline void pslldq(const XMMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSLLDQ, &dst, &src); - } - - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psrad(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psrad(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psrad(const XMMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSRAD, &dst, &src); - } - - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psraw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psraw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - //! @brief Packed Shift Right Arithmetic (SSE2). - inline void psraw(const XMMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSRAW, &dst, &src); - } - - //! @brief Packed Subtract (SSE2). - inline void psubb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSUBB, &dst, &src); - } - //! @brief Packed Subtract (SSE2). - inline void psubb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBB, &dst, &src); - } - - //! @brief Packed Subtract (SSE2). - inline void psubw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSUBW, &dst, &src); - } - //! @brief Packed Subtract (SSE2). - inline void psubw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBW, &dst, &src); - } - - //! @brief Packed Subtract (SSE2). - inline void psubd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSUBD, &dst, &src); - } - //! @brief Packed Subtract (SSE2). - inline void psubd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBD, &dst, &src); - } - - //! @brief Packed Subtract (SSE2). - inline void psubq(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSUBQ, &dst, &src); - } - //! @brief Packed Subtract (SSE2). - inline void psubq(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBQ, &dst, &src); - } - - //! @brief Packed Subtract (SSE2). - inline void psubq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSUBQ, &dst, &src); - } - //! @brief Packed Subtract (SSE2). - inline void psubq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBQ, &dst, &src); - } - - //! @brief Packed Multiply and Add (SSE2). - inline void pmaddwd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMADDWD, &dst, &src); - } - //! @brief Packed Multiply and Add (SSE2). - inline void pmaddwd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMADDWD, &dst, &src); - } - - //! @brief Shuffle Packed DWORDs (SSE2). - inline void pshufd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFD, &dst, &src, &imm8); - } - //! @brief Shuffle Packed DWORDs (SSE2). - inline void pshufd(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFD, &dst, &src, &imm8); - } - - //! @brief Shuffle Packed High Words (SSE2). - inline void pshufhw(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFHW, &dst, &src, &imm8); - } - //! @brief Shuffle Packed High Words (SSE2). - inline void pshufhw(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFHW, &dst, &src, &imm8); - } - - //! @brief Shuffle Packed Low Words (SSE2). - inline void pshuflw(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFLW, &dst, &src, &imm8); - } - //! @brief Shuffle Packed Low Words (SSE2). - inline void pshuflw(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PSHUFLW, &dst, &src, &imm8); - } - - //! @brief Packed Shift Right Logical (SSE2). - inline void psrld(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrld(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrld(const XMMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSRLD, &dst, &src); - } - - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlq(const XMMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSRLQ, &dst, &src); - } - - //! @brief DQWord Shift Right Logical (MMX). - inline void psrldq(const XMMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSRLDQ, &dst, &src); - } - - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - //! @brief Packed Shift Right Logical (SSE2). - inline void psrlw(const XMMVar& dst, const Imm& src) - { - _emitInstruction(INST_PSRLW, &dst, &src); - } - - //! @brief Packed Subtract with Saturation (SSE2). - inline void psubsb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSUBSB, &dst, &src); - } - //! @brief Packed Subtract with Saturation (SSE2). - inline void psubsb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBSB, &dst, &src); - } - - //! @brief Packed Subtract with Saturation (SSE2). - inline void psubsw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSUBSW, &dst, &src); - } - //! @brief Packed Subtract with Saturation (SSE2). - inline void psubsw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBSW, &dst, &src); - } - - //! @brief Packed Subtract with Unsigned Saturation (SSE2). - inline void psubusb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSUBUSB, &dst, &src); - } - //! @brief Packed Subtract with Unsigned Saturation (SSE2). - inline void psubusb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBUSB, &dst, &src); - } - - //! @brief Packed Subtract with Unsigned Saturation (SSE2). - inline void psubusw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSUBUSW, &dst, &src); - } - //! @brief Packed Subtract with Unsigned Saturation (SSE2). - inline void psubusw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSUBUSW, &dst, &src); - } - - //! @brief Unpack High Data (SSE2). - inline void punpckhbw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PUNPCKHBW, &dst, &src); - } - //! @brief Unpack High Data (SSE2). - inline void punpckhbw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHBW, &dst, &src); - } - - //! @brief Unpack High Data (SSE2). - inline void punpckhwd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PUNPCKHWD, &dst, &src); - } - //! @brief Unpack High Data (SSE2). - inline void punpckhwd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHWD, &dst, &src); - } - - //! @brief Unpack High Data (SSE2). - inline void punpckhdq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PUNPCKHDQ, &dst, &src); - } - //! @brief Unpack High Data (SSE2). - inline void punpckhdq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHDQ, &dst, &src); - } - - //! @brief Unpack High Data (SSE2). - inline void punpckhqdq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PUNPCKHQDQ, &dst, &src); - } - //! @brief Unpack High Data (SSE2). - inline void punpckhqdq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKHQDQ, &dst, &src); - } - - //! @brief Unpack Low Data (SSE2). - inline void punpcklbw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PUNPCKLBW, &dst, &src); - } - //! @brief Unpack Low Data (SSE2). - inline void punpcklbw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLBW, &dst, &src); - } - - //! @brief Unpack Low Data (SSE2). - inline void punpcklwd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PUNPCKLWD, &dst, &src); - } - //! @brief Unpack Low Data (SSE2). - inline void punpcklwd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLWD, &dst, &src); - } - - //! @brief Unpack Low Data (SSE2). - inline void punpckldq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PUNPCKLDQ, &dst, &src); - } - //! @brief Unpack Low Data (SSE2). - inline void punpckldq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLDQ, &dst, &src); - } - - //! @brief Unpack Low Data (SSE2). - inline void punpcklqdq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PUNPCKLQDQ, &dst, &src); - } - //! @brief Unpack Low Data (SSE2). - inline void punpcklqdq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PUNPCKLQDQ, &dst, &src); - } - - //! @brief Bitwise Exclusive OR (SSE2). - inline void pxor(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PXOR, &dst, &src); - } - //! @brief Bitwise Exclusive OR (SSE2). - inline void pxor(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PXOR, &dst, &src); - } - - //! @brief Shuffle DP-FP (SSE2). - inline void shufpd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_SHUFPD, &dst, &src, &imm8); - } - //! @brief Shuffle DP-FP (SSE2). - inline void shufpd(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_SHUFPD, &dst, &src, &imm8); - } - - //! @brief Compute Square Roots of Packed DP-FP Values (SSE2). - inline void sqrtpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_SQRTPD, &dst, &src); - } - //! @brief Compute Square Roots of Packed DP-FP Values (SSE2). - inline void sqrtpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_SQRTPD, &dst, &src); - } - - //! @brief Compute Square Root of Scalar DP-FP Value (SSE2). - inline void sqrtsd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_SQRTSD, &dst, &src); - } - //! @brief Compute Square Root of Scalar DP-FP Value (SSE2). - inline void sqrtsd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_SQRTSD, &dst, &src); - } - - //! @brief Packed DP-FP Subtract (SSE2). - inline void subpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_SUBPD, &dst, &src); - } - //! @brief Packed DP-FP Subtract (SSE2). - inline void subpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_SUBPD, &dst, &src); - } - - //! @brief Scalar DP-FP Subtract (SSE2). - inline void subsd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_SUBSD, &dst, &src); - } - //! @brief Scalar DP-FP Subtract (SSE2). - inline void subsd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_SUBSD, &dst, &src); - } - - //! @brief Scalar Unordered DP-FP Compare and Set EFLAGS (SSE2). - inline void ucomisd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_UCOMISD, &dst, &src); - } - //! @brief Scalar Unordered DP-FP Compare and Set EFLAGS (SSE2). - inline void ucomisd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_UCOMISD, &dst, &src); - } - - //! @brief Unpack and Interleave High Packed Double-Precision FP Values (SSE2). - inline void unpckhpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_UNPCKHPD, &dst, &src); - } - //! @brief Unpack and Interleave High Packed Double-Precision FP Values (SSE2). - inline void unpckhpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_UNPCKHPD, &dst, &src); - } - - //! @brief Unpack and Interleave Low Packed Double-Precision FP Values (SSE2). - inline void unpcklpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_UNPCKLPD, &dst, &src); - } - //! @brief Unpack and Interleave Low Packed Double-Precision FP Values (SSE2). - inline void unpcklpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_UNPCKLPD, &dst, &src); - } - - //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). - inline void xorpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_XORPD, &dst, &src); - } - //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). - inline void xorpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_XORPD, &dst, &src); - } - - // -------------------------------------------------------------------------- - // [SSE3] - // -------------------------------------------------------------------------- - - //! @brief Packed DP-FP Add/Subtract (SSE3). - inline void addsubpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ADDSUBPD, &dst, &src); - } - //! @brief Packed DP-FP Add/Subtract (SSE3). - inline void addsubpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ADDSUBPD, &dst, &src); - } - - //! @brief Packed SP-FP Add/Subtract (SSE3). - inline void addsubps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_ADDSUBPS, &dst, &src); - } - //! @brief Packed SP-FP Add/Subtract (SSE3). - inline void addsubps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_ADDSUBPS, &dst, &src); - } - -#if ASMJIT_NOT_SUPPORTED_BY_COMPILER - // TODO: NOT IMPLEMENTED BY THE COMPILER. - //! @brief Store Integer with Truncation (SSE3). - inline void fisttp(const Mem& dst) - { - _emitInstruction(INST_FISTTP, &dst); - } -#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER - - //! @brief Packed DP-FP Horizontal Add (SSE3). - inline void haddpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_HADDPD, &dst, &src); - } - //! @brief Packed DP-FP Horizontal Add (SSE3). - inline void haddpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_HADDPD, &dst, &src); - } - - //! @brief Packed SP-FP Horizontal Add (SSE3). - inline void haddps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_HADDPS, &dst, &src); - } - //! @brief Packed SP-FP Horizontal Add (SSE3). - inline void haddps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_HADDPS, &dst, &src); - } - - //! @brief Packed DP-FP Horizontal Subtract (SSE3). - inline void hsubpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_HSUBPD, &dst, &src); - } - //! @brief Packed DP-FP Horizontal Subtract (SSE3). - inline void hsubpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_HSUBPD, &dst, &src); - } - - //! @brief Packed SP-FP Horizontal Subtract (SSE3). - inline void hsubps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_HSUBPS, &dst, &src); - } - //! @brief Packed SP-FP Horizontal Subtract (SSE3). - inline void hsubps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_HSUBPS, &dst, &src); - } - - //! @brief Load Unaligned Integer 128 Bits (SSE3). - inline void lddqu(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_LDDQU, &dst, &src); - } - -#if ASMJIT_NOT_SUPPORTED_BY_COMPILER - //! @brief Set Up Monitor Address (SSE3). - inline void monitor() - { - _emitInstruction(INST_MONITOR); - } -#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER - - //! @brief Move One DP-FP and Duplicate (SSE3). - inline void movddup(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVDDUP, &dst, &src); - } - //! @brief Move One DP-FP and Duplicate (SSE3). - inline void movddup(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVDDUP, &dst, &src); - } - - //! @brief Move Packed SP-FP High and Duplicate (SSE3). - inline void movshdup(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVSHDUP, &dst, &src); - } - //! @brief Move Packed SP-FP High and Duplicate (SSE3). - inline void movshdup(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVSHDUP, &dst, &src); - } - - //! @brief Move Packed SP-FP Low and Duplicate (SSE3). - inline void movsldup(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_MOVSLDUP, &dst, &src); - } - //! @brief Move Packed SP-FP Low and Duplicate (SSE3). - inline void movsldup(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVSLDUP, &dst, &src); - } - -#if ASMJIT_NOT_SUPPORTED_BY_COMPILER - //! @brief Monitor Wait (SSE3). - inline void mwait() - { - _emitInstruction(INST_MWAIT); - } -#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER - - // -------------------------------------------------------------------------- - // [SSSE3] - // -------------------------------------------------------------------------- - - //! @brief Packed SIGN (SSSE3). - inline void psignb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSIGNB, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSIGNB, &dst, &src); - } - - //! @brief Packed SIGN (SSSE3). - inline void psignb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSIGNB, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSIGNB, &dst, &src); - } - - //! @brief Packed SIGN (SSSE3). - inline void psignw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSIGNW, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSIGNW, &dst, &src); - } - - //! @brief Packed SIGN (SSSE3). - inline void psignw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSIGNW, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSIGNW, &dst, &src); - } - - //! @brief Packed SIGN (SSSE3). - inline void psignd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSIGND, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSIGND, &dst, &src); - } - - //! @brief Packed SIGN (SSSE3). - inline void psignd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSIGND, &dst, &src); - } - //! @brief Packed SIGN (SSSE3). - inline void psignd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSIGND, &dst, &src); - } - - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PHADDW, &dst, &src); - } - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHADDW, &dst, &src); - } - - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PHADDW, &dst, &src); - } - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHADDW, &dst, &src); - } - - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PHADDD, &dst, &src); - } - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHADDD, &dst, &src); - } - - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PHADDD, &dst, &src); - } - //! @brief Packed Horizontal Add (SSSE3). - inline void phaddd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHADDD, &dst, &src); - } - - //! @brief Packed Horizontal Add and Saturate (SSSE3). - inline void phaddsw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PHADDSW, &dst, &src); - } - //! @brief Packed Horizontal Add and Saturate (SSSE3). - inline void phaddsw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHADDSW, &dst, &src); - } - - //! @brief Packed Horizontal Add and Saturate (SSSE3). - inline void phaddsw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PHADDSW, &dst, &src); - } - //! @brief Packed Horizontal Add and Saturate (SSSE3). - inline void phaddsw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHADDSW, &dst, &src); - } - - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PHSUBW, &dst, &src); - } - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBW, &dst, &src); - } - - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PHSUBW, &dst, &src); - } - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBW, &dst, &src); - } - - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PHSUBD, &dst, &src); - } - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBD, &dst, &src); - } - - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PHSUBD, &dst, &src); - } - //! @brief Packed Horizontal Subtract (SSSE3). - inline void phsubd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBD, &dst, &src); - } - - //! @brief Packed Horizontal Subtract and Saturate (SSSE3). - inline void phsubsw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PHSUBSW, &dst, &src); - } - //! @brief Packed Horizontal Subtract and Saturate (SSSE3). - inline void phsubsw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBSW, &dst, &src); - } - - //! @brief Packed Horizontal Subtract and Saturate (SSSE3). - inline void phsubsw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PHSUBSW, &dst, &src); - } - //! @brief Packed Horizontal Subtract and Saturate (SSSE3). - inline void phsubsw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHSUBSW, &dst, &src); - } - - //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). - inline void pmaddubsw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMADDUBSW, &dst, &src); - } - //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). - inline void pmaddubsw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMADDUBSW, &dst, &src); - } - - //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). - inline void pmaddubsw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMADDUBSW, &dst, &src); - } - //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). - inline void pmaddubsw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMADDUBSW, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PABSB, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PABSB, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PABSB, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PABSB, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PABSW, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PABSW, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PABSW, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PABSW, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsd(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PABSD, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsd(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PABSD, &dst, &src); - } - - //! @brief Packed Absolute Value (SSSE3). - inline void pabsd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PABSD, &dst, &src); - } - //! @brief Packed Absolute Value (SSSE3). - inline void pabsd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PABSD, &dst, &src); - } - - //! @brief Packed Multiply High with Round and Scale (SSSE3). - inline void pmulhrsw(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PMULHRSW, &dst, &src); - } - //! @brief Packed Multiply High with Round and Scale (SSSE3). - inline void pmulhrsw(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULHRSW, &dst, &src); - } - - //! @brief Packed Multiply High with Round and Scale (SSSE3). - inline void pmulhrsw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMULHRSW, &dst, &src); - } - //! @brief Packed Multiply High with Round and Scale (SSSE3). - inline void pmulhrsw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULHRSW, &dst, &src); - } - - //! @brief Packed Shuffle Bytes (SSSE3). - inline void pshufb(const MMVar& dst, const MMVar& src) - { - _emitInstruction(INST_PSHUFB, &dst, &src); - } - //! @brief Packed Shuffle Bytes (SSSE3). - inline void pshufb(const MMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSHUFB, &dst, &src); - } - - //! @brief Packed Shuffle Bytes (SSSE3). - inline void pshufb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PSHUFB, &dst, &src); - } - //! @brief Packed Shuffle Bytes (SSSE3). - inline void pshufb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PSHUFB, &dst, &src); - } - - //! @brief Packed Shuffle Bytes (SSSE3). - inline void palignr(const MMVar& dst, const MMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); - } - //! @brief Packed Shuffle Bytes (SSSE3). - inline void palignr(const MMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); - } - - //! @brief Packed Shuffle Bytes (SSSE3). - inline void palignr(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); - } - //! @brief Packed Shuffle Bytes (SSSE3). - inline void palignr(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); - } - - // -------------------------------------------------------------------------- - // [SSE4.1] - // -------------------------------------------------------------------------- - - //! @brief Blend Packed DP-FP Values (SSE4.1). - inline void blendpd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_BLENDPD, &dst, &src, &imm8); - } - //! @brief Blend Packed DP-FP Values (SSE4.1). - inline void blendpd(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_BLENDPD, &dst, &src, &imm8); - } - - //! @brief Blend Packed SP-FP Values (SSE4.1). - inline void blendps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_BLENDPS, &dst, &src, &imm8); - } - //! @brief Blend Packed SP-FP Values (SSE4.1). - inline void blendps(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_BLENDPS, &dst, &src, &imm8); - } - - //! @brief Variable Blend Packed DP-FP Values (SSE4.1). - inline void blendvpd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_BLENDVPD, &dst, &src); - } - //! @brief Variable Blend Packed DP-FP Values (SSE4.1). - inline void blendvpd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_BLENDVPD, &dst, &src); - } - - //! @brief Variable Blend Packed SP-FP Values (SSE4.1). - inline void blendvps(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_BLENDVPS, &dst, &src); - } - //! @brief Variable Blend Packed SP-FP Values (SSE4.1). - inline void blendvps(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_BLENDVPS, &dst, &src); - } - - //! @brief Dot Product of Packed DP-FP Values (SSE4.1). - inline void dppd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_DPPD, &dst, &src, &imm8); - } - //! @brief Dot Product of Packed DP-FP Values (SSE4.1). - inline void dppd(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_DPPD, &dst, &src, &imm8); - } - - //! @brief Dot Product of Packed SP-FP Values (SSE4.1). - inline void dpps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_DPPS, &dst, &src, &imm8); - } - //! @brief Dot Product of Packed SP-FP Values (SSE4.1). - inline void dpps(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_DPPS, &dst, &src, &imm8); - } - - //! @brief Extract Packed SP-FP Value (SSE4.1). - inline void extractps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_EXTRACTPS, &dst, &src, &imm8); - } - //! @brief Extract Packed SP-FP Value (SSE4.1). - inline void extractps(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_EXTRACTPS, &dst, &src, &imm8); - } - - //! @brief Load Double Quadword Non-Temporal Aligned Hint (SSE4.1). - inline void movntdqa(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_MOVNTDQA, &dst, &src); - } - - //! @brief Compute Multiple Packed Sums of Absolute Difference (SSE4.1). - inline void mpsadbw(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_MPSADBW, &dst, &src, &imm8); - } - //! @brief Compute Multiple Packed Sums of Absolute Difference (SSE4.1). - inline void mpsadbw(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_MPSADBW, &dst, &src, &imm8); - } - - //! @brief Pack with Unsigned Saturation (SSE4.1). - inline void packusdw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PACKUSDW, &dst, &src); - } - //! @brief Pack with Unsigned Saturation (SSE4.1). - inline void packusdw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PACKUSDW, &dst, &src); - } - - //! @brief Variable Blend Packed Bytes (SSE4.1). - inline void pblendvb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PBLENDVB, &dst, &src); - } - //! @brief Variable Blend Packed Bytes (SSE4.1). - inline void pblendvb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PBLENDVB, &dst, &src); - } - - //! @brief Blend Packed Words (SSE4.1). - inline void pblendw(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PBLENDW, &dst, &src, &imm8); - } - //! @brief Blend Packed Words (SSE4.1). - inline void pblendw(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PBLENDW, &dst, &src, &imm8); - } - - //! @brief Compare Packed Qword Data for Equal (SSE4.1). - inline void pcmpeqq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PCMPEQQ, &dst, &src); - } - //! @brief Compare Packed Qword Data for Equal (SSE4.1). - inline void pcmpeqq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPEQQ, &dst, &src); - } - - //! @brief Extract Byte (SSE4.1). - inline void pextrb(const GPVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRB, &dst, &src, &imm8); - } - //! @brief Extract Byte (SSE4.1). - inline void pextrb(const Mem& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRB, &dst, &src, &imm8); - } - - //! @brief Extract Dword (SSE4.1). - inline void pextrd(const GPVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRD, &dst, &src, &imm8); - } - //! @brief Extract Dword (SSE4.1). - inline void pextrd(const Mem& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRD, &dst, &src, &imm8); - } - - //! @brief Extract Dword (SSE4.1). - inline void pextrq(const GPVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRQ, &dst, &src, &imm8); - } - //! @brief Extract Dword (SSE4.1). - inline void pextrq(const Mem& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PEXTRQ, &dst, &src, &imm8); - } - - //! @brief Packed Horizontal Word Minimum (SSE4.1). - inline void phminposuw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PHMINPOSUW, &dst, &src); - } - //! @brief Packed Horizontal Word Minimum (SSE4.1). - inline void phminposuw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PHMINPOSUW, &dst, &src); - } - - //! @brief Insert Byte (SSE4.1). - inline void pinsrb(const XMMVar& dst, const GPVar& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRB, &dst, &src, &imm8); - } - //! @brief Insert Byte (SSE4.1). - inline void pinsrb(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRB, &dst, &src, &imm8); - } - - //! @brief Insert Dword (SSE4.1). - inline void pinsrd(const XMMVar& dst, const GPVar& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRD, &dst, &src, &imm8); - } - //! @brief Insert Dword (SSE4.1). - inline void pinsrd(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRD, &dst, &src, &imm8); - } - - //! @brief Insert Dword (SSE4.1). - inline void pinsrq(const XMMVar& dst, const GPVar& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRQ, &dst, &src, &imm8); - } - //! @brief Insert Dword (SSE4.1). - inline void pinsrq(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRQ, &dst, &src, &imm8); - } - - //! @brief Insert Word (SSE2). - inline void pinsrw(const XMMVar& dst, const GPVar& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRW, &dst, &src, &imm8); - } - //! @brief Insert Word (SSE2). - inline void pinsrw(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PINSRW, &dst, &src, &imm8); - } - - //! @brief Maximum of Packed Word Integers (SSE4.1). - inline void pmaxuw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMAXUW, &dst, &src); - } - //! @brief Maximum of Packed Word Integers (SSE4.1). - inline void pmaxuw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMAXUW, &dst, &src); - } - - //! @brief Maximum of Packed Signed Byte Integers (SSE4.1). - inline void pmaxsb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMAXSB, &dst, &src); - } - //! @brief Maximum of Packed Signed Byte Integers (SSE4.1). - inline void pmaxsb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMAXSB, &dst, &src); - } - - //! @brief Maximum of Packed Signed Dword Integers (SSE4.1). - inline void pmaxsd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMAXSD, &dst, &src); - } - //! @brief Maximum of Packed Signed Dword Integers (SSE4.1). - inline void pmaxsd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMAXSD, &dst, &src); - } - - //! @brief Maximum of Packed Unsigned Dword Integers (SSE4.1). - inline void pmaxud(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMAXUD, &dst, &src); - } - //! @brief Maximum of Packed Unsigned Dword Integers (SSE4.1). - inline void pmaxud(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMAXUD, &dst, &src); - } - - //! @brief Minimum of Packed Signed Byte Integers (SSE4.1). - inline void pminsb(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMINSB, &dst, &src); - } - //! @brief Minimum of Packed Signed Byte Integers (SSE4.1). - inline void pminsb(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMINSB, &dst, &src); - } - - //! @brief Minimum of Packed Word Integers (SSE4.1). - inline void pminuw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMINUW, &dst, &src); - } - //! @brief Minimum of Packed Word Integers (SSE4.1). - inline void pminuw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMINUW, &dst, &src); - } - - //! @brief Minimum of Packed Dword Integers (SSE4.1). - inline void pminud(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMINUD, &dst, &src); - } - //! @brief Minimum of Packed Dword Integers (SSE4.1). - inline void pminud(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMINUD, &dst, &src); - } - - //! @brief Minimum of Packed Dword Integers (SSE4.1). - inline void pminsd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMINSD, &dst, &src); - } - //! @brief Minimum of Packed Dword Integers (SSE4.1). - inline void pminsd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMINSD, &dst, &src); - } - - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVSXBW, &dst, &src); - } - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXBW, &dst, &src); - } - - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVSXBD, &dst, &src); - } - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXBD, &dst, &src); - } - - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVSXBQ, &dst, &src); - } - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxbq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXBQ, &dst, &src); - } - - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxwd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVSXWD, &dst, &src); - } - //! @brief Packed Move with Sign Extend (SSE4.1). - inline void pmovsxwd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXWD, &dst, &src); - } - - //! @brief (SSE4.1). - inline void pmovsxwq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVSXWQ, &dst, &src); - } - //! @brief (SSE4.1). - inline void pmovsxwq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXWQ, &dst, &src); - } - - //! @brief (SSE4.1). - inline void pmovsxdq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVSXDQ, &dst, &src); - } - //! @brief (SSE4.1). - inline void pmovsxdq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVSXDQ, &dst, &src); - } - - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbw(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVZXBW, &dst, &src); - } - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbw(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXBW, &dst, &src); - } - - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVZXBD, &dst, &src); - } - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXBD, &dst, &src); - } - - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVZXBQ, &dst, &src); - } - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxbq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXBQ, &dst, &src); - } - - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxwd(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVZXWD, &dst, &src); - } - //! @brief Packed Move with Zero Extend (SSE4.1). - inline void pmovzxwd(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXWD, &dst, &src); - } - - //! @brief (SSE4.1). - inline void pmovzxwq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVZXWQ, &dst, &src); - } - //! @brief (SSE4.1). - inline void pmovzxwq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXWQ, &dst, &src); - } - - //! @brief (SSE4.1). - inline void pmovzxdq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMOVZXDQ, &dst, &src); - } - //! @brief (SSE4.1). - inline void pmovzxdq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMOVZXDQ, &dst, &src); - } - - //! @brief Multiply Packed Signed Dword Integers (SSE4.1). - inline void pmuldq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMULDQ, &dst, &src); - } - //! @brief Multiply Packed Signed Dword Integers (SSE4.1). - inline void pmuldq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULDQ, &dst, &src); - } - - //! @brief Multiply Packed Signed Integers and Store Low Result (SSE4.1). - inline void pmulld(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PMULLD, &dst, &src); - } - //! @brief Multiply Packed Signed Integers and Store Low Result (SSE4.1). - inline void pmulld(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PMULLD, &dst, &src); - } - - //! @brief Logical Compare (SSE4.1). - inline void ptest(const XMMVar& op1, const XMMVar& op2) - { - _emitInstruction(INST_PTEST, &op1, &op2); - } - //! @brief Logical Compare (SSE4.1). - inline void ptest(const XMMVar& op1, const Mem& op2) - { - _emitInstruction(INST_PTEST, &op1, &op2); - } - - //! Round Packed SP-FP Values @brief (SSE4.1). - inline void roundps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDPS, &dst, &src, &imm8); - } - //! Round Packed SP-FP Values @brief (SSE4.1). - inline void roundps(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDPS, &dst, &src, &imm8); - } - - //! @brief Round Scalar SP-FP Values (SSE4.1). - inline void roundss(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDSS, &dst, &src, &imm8); - } - //! @brief Round Scalar SP-FP Values (SSE4.1). - inline void roundss(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDSS, &dst, &src, &imm8); - } - - //! @brief Round Packed DP-FP Values (SSE4.1). - inline void roundpd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDPD, &dst, &src, &imm8); - } - //! @brief Round Packed DP-FP Values (SSE4.1). - inline void roundpd(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDPD, &dst, &src, &imm8); - } - - //! @brief Round Scalar DP-FP Values (SSE4.1). - inline void roundsd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDSD, &dst, &src, &imm8); - } - //! @brief Round Scalar DP-FP Values (SSE4.1). - inline void roundsd(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_ROUNDSD, &dst, &src, &imm8); - } - - // -------------------------------------------------------------------------- - // [SSE4.2] - // -------------------------------------------------------------------------- - - //! @brief Accumulate CRC32 Value (polynomial 0x11EDC6F41) (SSE4.2). - inline void crc32(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_CRC32, &dst, &src); - } - //! @brief Accumulate CRC32 Value (polynomial 0x11EDC6F41) (SSE4.2). - inline void crc32(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_CRC32, &dst, &src); - } - - //! @brief Packed Compare Explicit Length Strings, Return Index (SSE4.2). - inline void pcmpestri(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPESTRI, &dst, &src, &imm8); - } - //! @brief Packed Compare Explicit Length Strings, Return Index (SSE4.2). - inline void pcmpestri(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPESTRI, &dst, &src, &imm8); - } - - //! @brief Packed Compare Explicit Length Strings, Return Mask (SSE4.2). - inline void pcmpestrm(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPESTRM, &dst, &src, &imm8); - } - //! @brief Packed Compare Explicit Length Strings, Return Mask (SSE4.2). - inline void pcmpestrm(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPESTRM, &dst, &src, &imm8); - } - - //! @brief Packed Compare Implicit Length Strings, Return Index (SSE4.2). - inline void pcmpistri(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPISTRI, &dst, &src, &imm8); - } - //! @brief Packed Compare Implicit Length Strings, Return Index (SSE4.2). - inline void pcmpistri(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPISTRI, &dst, &src, &imm8); - } - - //! @brief Packed Compare Implicit Length Strings, Return Mask (SSE4.2). - inline void pcmpistrm(const XMMVar& dst, const XMMVar& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPISTRM, &dst, &src, &imm8); - } - //! @brief Packed Compare Implicit Length Strings, Return Mask (SSE4.2). - inline void pcmpistrm(const XMMVar& dst, const Mem& src, const Imm& imm8) - { - _emitInstruction(INST_PCMPISTRM, &dst, &src, &imm8); - } - - //! @brief Compare Packed Data for Greater Than (SSE4.2). - inline void pcmpgtq(const XMMVar& dst, const XMMVar& src) - { - _emitInstruction(INST_PCMPGTQ, &dst, &src); - } - //! @brief Compare Packed Data for Greater Than (SSE4.2). - inline void pcmpgtq(const XMMVar& dst, const Mem& src) - { - _emitInstruction(INST_PCMPGTQ, &dst, &src); - } - - //! @brief Return the Count of Number of Bits Set to 1 (SSE4.2). - inline void popcnt(const GPVar& dst, const GPVar& src) - { - _emitInstruction(INST_POPCNT, &dst, &src); - } - //! @brief Return the Count of Number of Bits Set to 1 (SSE4.2). - inline void popcnt(const GPVar& dst, const Mem& src) - { - _emitInstruction(INST_POPCNT, &dst, &src); - } - - // -------------------------------------------------------------------------- - // [AMD only] - // -------------------------------------------------------------------------- - - //! @brief Prefetch (3dNow - Amd). - //! - //! Loads the entire 64-byte aligned memory sequence containing the - //! specified memory address into the L1 data cache. The position of - //! the specified memory address within the 64-byte cache line is - //! irrelevant. If a cache hit occurs, or if a memory fault is detected, - //! no bus cycle is initiated and the instruction is treated as a NOP. - inline void amd_prefetch(const Mem& mem) - { - _emitInstruction(INST_AMD_PREFETCH, &mem); - } - - //! @brief Prefetch and set cache to modified (3dNow - Amd). - //! - //! The PREFETCHW instruction loads the prefetched line and sets the - //! cache-line state to Modified, in anticipation of subsequent data - //! writes to the line. The PREFETCH instruction, by contrast, typically - //! sets the cache-line state to Exclusive (depending on the hardware - //! implementation). - inline void amd_prefetchw(const Mem& mem) - { - _emitInstruction(INST_AMD_PREFETCHW, &mem); - } - - // -------------------------------------------------------------------------- - // [Intel only] - // -------------------------------------------------------------------------- - - //! @brief Move Data After Swapping Bytes (SSE3 - Intel Atom). - inline void movbe(const GPVar& dst, const Mem& src) - { - ASMJIT_ASSERT(!dst.isGPB()); - _emitInstruction(INST_MOVBE, &dst, &src); - } - - //! @brief Move Data After Swapping Bytes (SSE3 - Intel Atom). - inline void movbe(const Mem& dst, const GPVar& src) - { - ASMJIT_ASSERT(!src.isGPB()); - _emitInstruction(INST_MOVBE, &dst, &src); - } - - // ------------------------------------------------------------------------- - // [Emit Options] - // ------------------------------------------------------------------------- - - //! @brief Assert LOCK# Signal Prefix. - //! - //! This instruction causes the processor's LOCK# signal to be asserted - //! during execution of the accompanying instruction (turns the - //! instruction into an atomic instruction). In a multiprocessor environment, - //! the LOCK# signal insures that the processor has exclusive use of any shared - //! memory while the signal is asserted. - //! - //! The LOCK prefix can be prepended only to the following instructions and - //! to those forms of the instructions that use a memory operand: ADD, ADC, - //! AND, BTC, BTR, BTS, CMPXCHG, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, - //! and XCHG. An undefined opcode exception will be generated if the LOCK - //! prefix is used with any other instruction. The XCHG instruction always - //! asserts the LOCK# signal regardless of the presence or absence of the LOCK - //! prefix. - inline void lock() - { - _emitOptions |= EMIT_OPTION_LOCK_PREFIX; - } - - //! @brief Force REX prefix to be emitted. - //! - //! This option should be used carefully, because there are unencodable - //! combinations. If you want to access ah, bh, ch or dh registers then you - //! can't emit REX prefix and it will cause an illegal instruction error. - //! - //! @note REX prefix is only valid for X64/AMD64 platform. - //! - //! @sa @c EMIT_OPTION_REX_PREFIX. - inline void rex() - { - _emitOptions |= EMIT_OPTION_REX_PREFIX; - } -}; - -// ============================================================================ -// [AsmJit::Compiler] -// ============================================================================ - -//! @brief Compiler - high level code generation. -//! -//! This class is used to store instruction stream and allows to modify -//! it on the fly. It uses different concept than @c AsmJit::Assembler class -//! and in fact @c AsmJit::Assembler is only used as a backend. Compiler never -//! emits machine code and each instruction you use is stored to instruction -//! array instead. This allows to modify instruction stream later and for -//! example to reorder instructions to make better performance. -//! -//! Using @c AsmJit::Compiler moves code generation to higher level. Higher -//! level constructs allows to write more abstract and extensible code that -//! is not possible with pure @c AsmJit::Assembler class. Because -//! @c AsmJit::Compiler needs to create many objects and lifetime of these -//! objects is small (same as @c AsmJit::Compiler lifetime itself) it uses -//! very fast memory management model. This model allows to create object -//! instances in nearly zero time (compared to @c malloc() or @c new() -//! operators) so overhead by creating machine code by @c AsmJit::Compiler -//! is minimized. -//! -//! @section AsmJit_Compiler_TheStory The Story -//! -//! Before telling you how Compiler works I'd like to write a story. I'd like -//! to cover reasons why this class was created and why I'm recommending to use -//! it. When I released the first version of AsmJit (0.1) it was a toy. The -//! first function I wrote was function which is still available as testjit and -//! which simply returns 1024. The reason why function works for both 32-bit/ -//! 64-bit mode and for Windows/Unix specific calling conventions is luck, no -//! arguments usage and no registers usage except returning value in EAX/RAX. -//! -//! Then I started a project called BlitJit which was targetted to generating -//! JIT code for computer graphics. After writing some lines I decided that I -//! can't join pieces of code together without abstraction, should be -//! pixels source pointer in ESI/RSI or EDI/RDI or it's completelly -//! irrellevant? What about destination pointer and SSE2 register for reading -//! input pixels? The simple answer might be "just pick some one and use it". -//! -//! Another reason for abstraction is function calling-conventions. It's really -//! not easy to write assembler code for 32-bit and 64-bit platform supporting -//! three calling conventions (32-bit is similar between Windows and Unix, but -//! 64-bit calling conventions are different). -//! -//! At this time I realized that I can't write code which uses named registers, -//! I need to abstract it. In most cases you don't need specific register, you -//! need to emit instruction that does something with 'virtual' register(s), -//! memory, immediate or label. -//! -//! The first version of AsmJit with Compiler was 0.5 (or 0.6?, can't remember). -//! There was support for 32-bit and 64-bit mode, function calling conventions, -//! but when emitting instructions the developer needed to decide which -//! registers are changed, which are only read or completely overwritten. This -//! model helped a lot when generating code, especially when joining more -//! code-sections together, but there was also small possibility for mistakes. -//! Simply the first version of Compiler was great improvement over low-level -//! Assembler class, but the API design wasn't perfect. -//! -//! The second version of Compiler, completelly rewritten and based on -//! different goals, is part of AsmJit starting at version 1.0. This version -//! was designed after the first one and it contains serious improvements over -//! the old one. The first improvement is that you just use instructions with -//! virtual registers - called variables. When using compiler there is no way -//! to use native registers, there are variables instead. AsmJit is smarter -//! than before and it knows which register is needed only for read (r), -//! read/write (w) or overwrite (x). Supported are also instructions which -//! are using some registers in implicit way (these registers are not part of -//! instruction definition in string form). For example to use CPUID instruction -//! you must give it four variables which will be automatically allocated to -//! input/output registers (EAX, EBX, ECX, EDX). -//! -//! Another improvement is algorithm used by a register allocator. In first -//! version the registers were allocated when creating instruction stream. In -//! new version registers are allocated after calling @c Compiler::make(). This -//! means that register allocator has information about scope of all variables -//! and their usage statistics. The algorithm to allocate registers is very -//! simple and it's always called as a 'linear scan register allocator'. When -//! you get out of registers the all possible variables are scored and the worst -//! is spilled. Of course algorithm ignores the variables used for current -//! instruction. -//! -//! In addition, because registers are allocated after the code stream is -//! generated, the state switches between jumps are handled by Compiler too. -//! You don't need to worry about jumps, compiler always do this dirty work -//! for you. -//! -//! The nearly last thing I'd like to present is calling other functions from -//! the generated code. AsmJit uses a @c FunctionPrototype class to hold -//! the function parameters, their position in stack (or register index) and -//! function return value. This class is used internally, but it can be -//! used to create your own function calling-convention. All standard function -//! calling conventions are implemented. -//! -//! Please enjoy the new version of Compiler, it was created for writing a -//! low-level code using high-level API, leaving developer to concentrate to -//! real problems and not to solving a register puzzle. -//! -//! @section AsmJit_Compiler_CodeGeneration Code Generation -//! -//! First that is needed to know about compiler is that compiler never emits -//! machine code. It's used as a middleware between @c AsmJit::Assembler and -//! your code. There is also convenience method @c make() that allows to -//! generate machine code directly without creating @c AsmJit::Assembler -//! instance. -//! -//! Comparison of generating machine code through @c Assembler and directly -//! by @c Compiler: -//! -//! @code -//! // Assembler instance is low level code generation class that emits -//! // machine code. -//! Assembler a; -//! -//! // Compiler instance is high level code generation class that stores all -//! // instructions in internal representation. -//! Compiler c; -//! -//! // ... put your code here ... -//! -//! // Final step - generate code. AsmJit::Compiler::serialize() will serialize -//! // all instructions into Assembler and this ensures generating real machine -//! // code. -//! c.serialize(a); -//! -//! // Your function -//! void* fn = a.make(); -//! @endcode -//! -//! Example how to generate machine code using only @c Compiler (preferred): -//! -//! @code -//! // Compiler instance is enough. -//! Compiler c; -//! -//! // ... put your code here ... -//! -//! // Your function -//! void* fn = c.make(); -//! @endcode -//! -//! You can see that there is @c AsmJit::Compiler::serialize() function that -//! emits instructions into @c AsmJit::Assembler(). This layered architecture -//! means that each class is used for something different and there is no code -//! duplication. For convenience there is also @c AsmJit::Compiler::make() -//! method that can create your function using @c AsmJit::Assembler, but -//! internally (this is preffered bahavior when using @c AsmJit::Compiler). -//! -//! The @c make() method allocates memory using @c CodeGenerator instance passed -//! into the @c Compiler constructor. If code generator is used to create JIT -//! function then virtual memory allocated by @c MemoryManager is used. To get -//! global memory manager use @c MemoryManager::getGlobal(). -//! -//! @code -//! // Compiler instance is enough. -//! Compiler c; -//! -//! // ... put your code using Compiler instance ... -//! -//! // Your function -//! void* fn = c.make(); -//! -//! // Free it if you don't want it anymore -//! // (using global memory manager instance) -//! MemoryManager::getGlobal()->free(fn); -//! @endcode -//! -//! @section AsmJit_Compiler_Functions Functions -//! -//! To build functions with @c Compiler, see @c AsmJit::Compiler::newFunction() -//! method. -//! -//! @section AsmJit_Compiler_Variables Variables -//! -//! Compiler is able to manage variables and function arguments. Internally -//! there is no difference between function argument and variable declared -//! inside. To get function argument you use @c argGP() method and to declare -//! variable use @c newGP(), @c newMM() and @c newXMM() methods. The @c newXXX() -//! methods accept also parameter describing the variable type. For example -//! the @c newGP() method always creates variable which size matches the target -//! architecture size (for 32-bit target the 32-bit variable is created, for -//! 64-bit target the variable size is 64-bit). To override this behavior the -//! variable type must be specified. -//! -//! @code -//! // Compiler and function declaration - void f(int*); -//! Compiler c; -//! c.newFunction(CALL_CONV_DEFAULT, BuildFunction1()); -//! -//! // Get argument variable (it's pointer). -//! GPVar a1(c.argGP(0)); -//! -//! // Create your variables. -//! GPVar x1(c.newGP(VARIABLE_TYPE_GPD)); -//! GPVar x2(c.newGP(VARIABLE_TYPE_GPD)); -//! -//! // Init your variables. -//! c.mov(x1, 1); -//! c.mov(x2, 2); -//! -//! // ... your code ... -//! c.add(x1, x2); -//! // ... your code ... -//! -//! // Store result to a given pointer in first argument -//! c.mov(dword_ptr(a1), x1); -//! -//! // End of function body. -//! c.endFunction(); -//! -//! // Make the function. -//! typedef void (*MyFn)(int*); -//! MyFn fn = function_cast(c.make()); -//! @endcode -//! -//! This code snipped needs to be explained. You can see that there are more -//! variable types that can be used by @c Compiler. Most useful variables can -//! be allocated using general purpose registers (@c GPVar), MMX registers -//! (@c MMVar) or SSE registers (@c XMMVar). -//! -//! X86/X64 variable types: -//! -//! - @c VARIABLE_TYPE_GPD - 32-bit general purpose register (EAX, EBX, ...). -//! - @c VARIABLE_TYPE_GPQ - 64-bit general purpose register (RAX, RBX, ...). -//! - @c VARIABLE_TYPE_GPN - 32-bit or 64-bit general purpose register, depends -//! to target architecture. Mapped to @c VARIABLE_TYPE_GPD or @c VARIABLE_TYPE_GPQ. -//! -//! - @c VARIABLE_TYPE_X87 - 80-bit floating point stack register st(0 to 7). -//! - @c VARIABLE_TYPE_X87_1F - 32-bit floating point stack register st(0 to 7). -//! - @c VARIABLE_TYPE_X87_1D - 64-bit floating point stack register st(0 to 7). -//! -//! - @c VARIALBE_TYPE_MM - 64-bit MMX register. -//! -//! - @c VARIABLE_TYPE_XMM - 128-bit SSE register. -//! - @c VARIABLE_TYPE_XMM_1F - 128-bit SSE register which contains -//! scalar 32-bit single precision floating point. -//! - @c VARIABLE_TYPE_XMM_1D - 128-bit SSE register which contains -//! scalar 64-bit double precision floating point. -//! - @c VARIABLE_TYPE_XMM_4F - 128-bit SSE register which contains -//! 4 packed 32-bit single precision floating points. -//! - @c VARIABLE_TYPE_XMM_2D - 128-bit SSE register which contains -//! 2 packed 64-bit double precision floating points. -//! -//! Unified variable types: -//! -//! - @c VARIABLE_TYPE_INT32 - 32-bit general purpose register. -//! - @c VARIABLE_TYPE_INT64 - 64-bit general purpose register. -//! - @c VARIABLE_TYPE_INTPTR - 32-bit or 64-bit general purpose register / pointer. -//! -//! - @c VARIABLE_TYPE_FLOAT - 32-bit single precision floating point. -//! - @c VARIABLE_TYPE_DOUBLE - 64-bit double precision floating point. -//! -//! Variable states: -//! -//! - @c VARIABLE_STATE_UNUSED - State that is assigned to newly created -//! variables or to not used variables (dereferenced to zero). -//! - @c VARIABLE_STATE_REGISTER - State that means that variable is currently -//! allocated in register. -//! - @c VARIABLE_STATE_MEMORY - State that means that variable is currently -//! only in memory location. -//! -//! When you create new variable, initial state is always @c VARIABLE_STATE_UNUSED, -//! allocating it to register or spilling to memory changes this state to -//! @c VARIABLE_STATE_REGISTER or @c VARIABLE_STATE_MEMORY, respectively. -//! During variable lifetime it's usual that its state is changed multiple -//! times. To generate better code, you can control allocating and spilling -//! by using up to four types of methods that allows it (see next list). -//! -//! Explicit variable allocating / spilling methods: -//! -//! - @c Compiler::alloc() - Explicit method to alloc variable into -//! register. You can use this before loops or code blocks. -//! -//! - @c Compiler::spill() - Explicit method to spill variable. If variable -//! is in register and you call this method, it's moved to its home memory -//! location. If variable is not in register no operation is performed. -//! -//! - @c Compiler::unuse() - Unuse variable (you can use this to end the -//! variable scope or sub-scope). -//! -//! Please see AsmJit tutorials (testcompiler.cpp and testvariables.cpp) for -//! more complete examples. -//! -//! @section AsmJit_Compiler_MemoryManagement Memory Management -//! -//! @c Compiler Memory management follows these rules: -//! - Everything created by @c Compiler is always freed by @c Compiler. -//! - To get decent performance, compiler always uses larger memory buffer -//! for objects to allocate and when compiler instance is destroyed, this -//! buffer is freed. Destructors of active objects are called when -//! destroying compiler instance. Destructors of abadonded compiler -//! objects are called immediately after abadonding them. -//! - This type of memory management is called 'zone memory management'. -//! -//! This means that you can't use any @c Compiler object after destructing it, -//! it also means that each object like @c Label, @c Var and others are created -//! and managed by @c Compiler itself. These objects contain ID which is used -//! internally by Compiler to store additional information about these objects. -//! -//! @section AsmJit_Compiler_StateManagement Control-Flow and State Management. -//! -//! The @c Compiler automatically manages state of the variables when using -//! control flow instructions like jumps, conditional jumps and calls. There -//! is minimal heuristics for choosing the method how state is saved or restored. -//! -//! Generally the state can be changed only when using jump or conditional jump -//! instruction. When using non-conditional jump then state change is embedded -//! into the instruction stream before the jump. When using conditional jump -//! the @c Compiler decides whether to restore state before the jump or whether -//! to use another block where state is restored. The last case is that no-code -//! have to be emitted and there is no state change (this is of course ideal). -//! -//! Choosing whether to embed 'restore-state' section before conditional jump -//! is quite simple. If jump is likely to be 'taken' then code is embedded, if -//! jump is unlikely to be taken then the small code section for state-switch -//! will be generated instead. -//! -//! Next example is the situation where the extended code block is used to -//! do state-change: -//! -//! @code -//! Compiler c; -//! -//! c.newFunction(CALL_CONV_DEFAULT, FunctionBuilder0()); -//! c.getFunction()->setHint(FUNCTION_HINT_NAKED, true); -//! -//! // Labels. -//! Label L0 = c.newLabel(); -//! -//! // Variables. -//! GPVar var0 = c.newGP(); -//! GPVar var1 = c.newGP(); -//! -//! // Cleanup. After these two lines, the var0 and var1 will be always stored -//! // in registers. Our example is very small, but in larger code the var0 can -//! // be spilled by xor(var1, var1). -//! c.xor_(var0, var0); -//! c.xor_(var1, var1); -//! c.cmp(var0, var1); -//! // State: -//! // var0 - register. -//! // var1 - register. -//! -//! // We manually spill these variables. -//! c.spill(var0); -//! c.spill(var1); -//! // State: -//! // var0 - memory. -//! // var1 - memory. -//! -//! // Conditional jump to L0. It will be always taken, but compiler thinks that -//! // it is unlikely taken so it will embed state change code somewhere. -//! c.je(L0); -//! -//! // Do something. The variables var0 and var1 will be allocated again. -//! c.add(var0, 1); -//! c.add(var1, 2); -//! // State: -//! // var0 - register. -//! // var1 - register. -//! -//! // Bind label here, the state is not changed. -//! c.bind(L0); -//! // State: -//! // var0 - register. -//! // var1 - register. -//! -//! // We need to use var0 and var1, because if compiler detects that variables -//! // are out of scope then it optimizes the state-change. -//! c.sub(var0, var1); -//! // State: -//! // var0 - register. -//! // var1 - register. -//! -//! c.endFunction(); -//! @endcode -//! -//! The output: -//! -//! @verbatim -//! xor eax, eax ; xor var_0, var_0 -//! xor ecx, ecx ; xor var_1, var_1 -//! cmp eax, ecx ; cmp var_0, var_1 -//! mov [esp - 24], eax ; spill var_0 -//! mov [esp - 28], ecx ; spill var_1 -//! je L0_Switch -//! mov eax, [esp - 24] ; alloc var_0 -//! add eax, 1 ; add var_0, 1 -//! mov ecx, [esp - 28] ; alloc var_1 -//! add ecx, 2 ; add var_1, 2 -//! L0: -//! sub eax, ecx ; sub var_0, var_1 -//! ret -//! -//! ; state-switch begin -//! L0_Switch0: -//! mov eax, [esp - 24] ; alloc var_0 -//! mov ecx, [esp - 28] ; alloc var_1 -//! jmp short L0 -//! ; state-switch end -//! @endverbatim -//! -//! You can see that the state-switch section was generated (see L0_Switch0). -//! The compiler is unable to restore state immediately when emitting the -//! forward jump (the code is generated from first to last instruction and -//! the target state is simply not known at this time). -//! -//! To tell @c Compiler that you want to embed state-switch code before jump -//! it's needed to create backward jump (where also processor expects that it -//! will be taken). To demonstrate the possibility to embed state-switch before -//! jump we use slightly modified code: -//! -//! @code -//! Compiler c; -//! -//! c.newFunction(CALL_CONV_DEFAULT, FunctionBuilder0()); -//! c.getFunction()->setHint(FUNCTION_HINT_NAKED, true); -//! -//! // Labels. -//! Label L0 = c.newLabel(); -//! -//! // Variables. -//! GPVar var0 = c.newGP(); -//! GPVar var1 = c.newGP(); -//! -//! // Cleanup. After these two lines, the var0 and var1 will be always stored -//! // in registers. Our example is very small, but in larger code the var0 can -//! // be spilled by xor(var1, var1). -//! c.xor_(var0, var0); -//! c.xor_(var1, var1); -//! // State: -//! // var0 - register. -//! // var1 - register. -//! -//! // We manually spill these variables. -//! c.spill(var0); -//! c.spill(var1); -//! // State: -//! // var0 - memory. -//! // var1 - memory. -//! -//! // Bind our label here. -//! c.bind(L0); -//! -//! // Do something, the variables will be allocated again. -//! c.add(var0, 1); -//! c.add(var1, 2); -//! // State: -//! // var0 - register. -//! // var1 - register. -//! -//! // Backward conditional jump to L0. The default behavior is that it is taken -//! // so state-change code will be embedded here. -//! c.je(L0); -//! -//! c.endFunction(); -//! @endcode -//! -//! The output: -//! -//! @verbatim -//! xor ecx, ecx ; xor var_0, var_0 -//! xor edx, edx ; xor var_1, var_1 -//! mov [esp - 24], ecx ; spill var_0 -//! mov [esp - 28], edx ; spill var_1 -//! L.2: -//! mov ecx, [esp - 24] ; alloc var_0 -//! add ecx, 1 ; add var_0, 1 -//! mov edx, [esp - 28] ; alloc var_1 -//! add edx, 2 ; add var_1, 2 -//! -//! ; state-switch begin -//! mov [esp - 24], ecx ; spill var_0 -//! mov [esp - 28], edx ; spill var_1 -//! ; state-switch end -//! -//! je short L.2 -//! ret -//! @endverbatim -//! -//! Please notice where the state-switch section is located. The @c Compiler -//! decided that jump is likely to be taken so the state change is embedded -//! before the conditional jump. To change this behavior into the previous -//! case it's needed to add a hint (@c HINT_TAKEN or @c HINT_NOT_TAKEN). -//! -//! Replacing the c.je(L0) by c.je(L0, HINT_NOT_TAKEN) -//! will generate code like this: -//! -//! @verbatim -//! xor ecx, ecx ; xor var_0, var_0 -//! xor edx, edx ; xor var_1, var_1 -//! mov [esp - 24], ecx ; spill var_0 -//! mov [esp - 28], edx ; spill var_1 -//! L0: -//! mov ecx, [esp - 24] ; alloc var_0 -//! add ecx, 1 ; add var_0, a -//! mov edx, [esp - 28] ; alloc var_1 -//! add edx, 2 ; add var_1, 2 -//! je L0_Switch, 2 -//! ret -//! -//! ; state-switch begin -//! L0_Switch: -//! mov [esp - 24], ecx ; spill var_0 -//! mov [esp - 28], edx ; spill var_1 -//! jmp short L0 -//! ; state-switch end -//! @endverbatim -//! -//! This section provided information about how state-change works. The -//! behavior is deterministic and it can be overridden. -//! -//! @section AsmJit_Compiler_AdvancedCodeGeneration Advanced Code Generation -//! -//! This section describes advanced method of code generation available to -//! @c Compiler (but also to @c Assembler). When emitting code to instruction -//! stream the methods like @c mov(), @c add(), @c sub() can be called directly -//! (advantage is static-type control performed also by C++ compiler) or -//! indirectly using @c emit() method. The @c emit() method needs only -//! instruction code and operands. -//! -//! Example of code generating by standard type-safe API: -//! -//! @code -//! Compiler c; -//! GPVar var0 = c.newGP(); -//! GPVar var1 = c.newGP(); -//! -//! ... -//! -//! c.mov(var0, imm(0)); -//! c.add(var0, var1); -//! c.sub(var0, var1); -//! @endcode -//! -//! The code above can be rewritten as: -//! -//! @code -//! Compiler c; -//! GPVar var0 = c.newGP(); -//! GPVar var1 = c.newGP(); -//! -//! ... -//! -//! c.emit(INST_MOV, var0, imm(0)); -//! c.emit(INST_ADD, var0, var1); -//! c.emit(INST_SUB, var0, var1); -//! @endcode -//! -//! The advantage of first snippet is very friendly API and type-safe control -//! that is controlled by the C++ compiler. The advantage of second snippet is -//! availability to replace or generate instruction code in different places. -//! See the next example how the @c emit() method can be used to generate -//! abstract code. -//! -//! Use case: -//! -//! @code -//! bool emitArithmetic(Compiler& c, XMMVar& var0, XMMVar& var1, const char* op) -//! { -//! uint code = INVALID_VALUE; -//! -//! if (strcmp(op, "ADD") == 0) -//! code = INST_ADDSS; -//! else if (strcmp(op, "SUBTRACT") == 0) -//! code = INST_SUBSS; -//! else if (strcmp(op, "MULTIPLY") == 0) -//! code = INST_MULSS; -//! else if (strcmp(op, "DIVIDE") == 0) -//! code = INST_DIVSS; -//! else -//! // Invalid parameter? -//! return false; -//! -//! c.emit(code, var0, var1); -//! } -//! @endcode -//! -//! Other use cases are waiting for you! Be sure that instruction you are -//! emitting is correct and encodable, because if not, Assembler will set -//! error code to @c ERROR_UNKNOWN_INSTRUCTION. -//! -//! @section AsmJit_Compiler_CompilerDetails Compiler Details -//! -//! This section is here for people interested in the compiling process. There -//! are few steps that must be done for each compiled function (or your code). -//! -//! When your @c Compiler instance is ready, you can create function and add -//! emittables using intrinsics or higher level methods implemented by the -//! @c AsmJit::Compiler. When you are done (all instructions serialized) you -//! should call @c AsmJit::Compiler::make() method which will analyze your code, -//! allocate registers and memory for local variables and serialize all emittables -//! to @c AsmJit::Assembler instance. Next steps shows what's done internally -//! before code is serialized into @c AsmJit::Assembler -//! (implemented in @c AsmJit::Compiler::serialize() method). -//! -//! 1. Compiler try to match function and end-function emittables (these -//! emittables define the function-body or function block). -//! -//! 2. For all emittables inside the function-body the virtual functions -//! are called in this order: -//! - Emittable::prepare() -//! - Emittable::translate() -//! - Emittable::emit() -//! - Emittable::post() -//! -//! There is some extra work when emitting function prolog / epilog and -//! register allocator. -//! -//! 3. Emit jump tables data. -//! -//! When everything here ends, @c AsmJit::Assembler contains binary stream -//! that needs only relocation to be callable by C/C++ code. -//! -//! @section AsmJit_Compiler_Differences Summary of Differences between @c Assembler and @c Compiler -//! -//! - Instructions are not translated to machine code immediately, they are -//! stored as emmitables (see @c AsmJit::Emittable, @c AsmJit::EInstruction). -//! - Contains function builder and ability to call other functions. -//! - Contains register allocator and variable management. -//! - Contains a lot of helper methods to simplify the code generation not -//! available/possible in @c AsmJit::Assembler. -//! - Ability to pre-process or post-process the code which is being generated. -struct ASMJIT_API Compiler : public CompilerIntrinsics -{ - //! @brief Create the @c Compiler instance. - Compiler(CodeGenerator* codeGenerator = NULL) ASMJIT_NOTHROW; - //! @brief Destroy the @c Compiler instance. - virtual ~Compiler() ASMJIT_NOTHROW; -}; - -//! @} - -} // AsmJit namespace - -#undef ASMJIT_NOT_SUPPORTED_BY_COMPILER - -// [Api-End] -#include "ApiEnd.h" - -// [Guard] -#endif // _ASMJIT_COMPILERX86X64_H diff --git a/desmume/src/utils/AsmJit/Config.h b/desmume/src/utils/AsmJit/Config.h index 5987e4644..6079622b8 100644 --- a/desmume/src/utils/AsmJit/Config.h +++ b/desmume/src/utils/AsmJit/Config.h @@ -4,16 +4,16 @@ // [License] // Zlib - See COPYING file in this package. +// [Guard] +#ifndef _ASMJIT_CONFIG_H +#define _ASMJIT_CONFIG_H + // This file is designed to be modifyable. Platform specific changes should // be applied to this file so it's guaranteed that never versions of AsmJit // library will never overwrite generated config files. // // So modify this file by your build system or by hand. -// [Guard] -#ifndef _ASMJIT_CONFIG_H -#define _ASMJIT_CONFIG_H - // ============================================================================ // [AsmJit - OS] // ============================================================================ @@ -21,8 +21,8 @@ // Provides definitions about your operating system. It's detected by default, // so override it if you have problems with automatic detection. // -// #define ASMJIT_WINDOWS 1 -// #define ASMJIT_POSIX 2 +// #define ASMJIT_WINDOWS +// #define ASMJIT_POSIX // ============================================================================ // [AsmJit - Architecture] @@ -39,17 +39,8 @@ // ============================================================================ // If you are embedding AsmJit library into your project (statically), undef -// ASMJIT_API macro. ASMJIT_HIDDEN macro can contain visibility (used by GCC) -// to hide some AsmJit symbols that shouldn't be never exported. -// -// If you have problems with throw() in compilation time, undef ASMJIT_NOTHROW -// to disable this feature. ASMJIT_NOTHROW marks functions that never throws -// an exception. - -#define ASMJIT_HIDDEN +// ASMJIT_API macro. #define ASMJIT_API -// #define ASMJIT_NOTHROW - // ============================================================================ // [AsmJit - Memory Management] diff --git a/desmume/src/utils/AsmJit/CpuInfo.cpp b/desmume/src/utils/AsmJit/CpuInfo.cpp deleted file mode 100644 index 528f36cb1..000000000 --- a/desmume/src/utils/AsmJit/CpuInfo.cpp +++ /dev/null @@ -1,337 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Dependencies] -#include "CpuInfo.h" - -#if defined(ASMJIT_WINDOWS) -# include -#endif // ASMJIT_WINDOWS - -// 2009-02-05: Thanks to Mike Tajmajer for supporting VC7.1 compiler. This -// shouldn't affect x64 compilation, because x64 compiler starts with -// VS2005 (VC8.0). -#if defined(_MSC_VER) -# if _MSC_VER >= 1400 -# include -# endif // _MSC_VER >= 1400 (>= VS2005) -#endif // _MSC_VER - -#if defined(ASMJIT_POSIX) -#include -#include -#include -#include -#include -#endif // ASMJIT_POSIX - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -// helpers -static uint32_t detectNumberOfProcessors(void) -{ -#if defined(ASMJIT_WINDOWS) - SYSTEM_INFO info; - GetSystemInfo(&info); - return info.dwNumberOfProcessors; -#elif defined(ASMJIT_POSIX) && defined(_SC_NPROCESSORS_ONLN) - // It seems that sysconf returns the number of "logical" processors on both - // mac and linux. So we get the number of "online logical" processors. - long res = sysconf(_SC_NPROCESSORS_ONLN); - if (res == -1) return 1; - - return static_cast(res); -#else - return 1; -#endif -} - -// This is messy, I know. cpuid is implemented as intrinsic in VS2005, but -// we should support other compilers as well. Main problem is that MS compilers -// in 64-bit mode not allows to use inline assembler, so we need intrinsic and -// we need also asm version. - -// cpuid() and detectCpuInfo() for x86 and x64 platforms begins here. -#if defined(ASMJIT_X86) || defined(ASMJIT_X64) -void cpuid(uint32_t in, CpuId* out) ASMJIT_NOTHROW -{ -#if defined(_MSC_VER) - -// 2009-02-05: Thanks to Mike Tajmajer for supporting VC7.1 compiler. -// ASMJIT_X64 is here only for readibility, only VS2005 can compile 64-bit code. -# if _MSC_VER >= 1400 || defined(ASMJIT_X64) - // done by intrinsics - __cpuid(reinterpret_cast(out->i), in); -# else // _MSC_VER < 1400 - uint32_t cpuid_in = in; - uint32_t* cpuid_out = out->i; - - __asm - { - mov eax, cpuid_in - mov edi, cpuid_out - cpuid - mov dword ptr[edi + 0], eax - mov dword ptr[edi + 4], ebx - mov dword ptr[edi + 8], ecx - mov dword ptr[edi + 12], edx - } -# endif // _MSC_VER < 1400 - -#elif defined(__GNUC__) - -// Note, need to preserve ebx/rbx register! -# if defined(ASMJIT_X86) -# define __mycpuid(a, b, c, d, inp) \ - asm ("mov %%ebx, %%edi\n" \ - "cpuid\n" \ - "xchg %%edi, %%ebx\n" \ - : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) -# else -# define __mycpuid(a, b, c, d, inp) \ - asm ("mov %%rbx, %%rdi\n" \ - "cpuid\n" \ - "xchg %%rdi, %%rbx\n" \ - : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) -# endif - __mycpuid(out->eax, out->ebx, out->ecx, out->edx, in); - -#endif // compiler -} - -struct CpuVendorInfo -{ - uint32_t id; - char text[12]; -}; - -static const CpuVendorInfo cpuVendorInfo[] = -{ - { CPU_VENDOR_INTEL , { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' } }, - - { CPU_VENDOR_AMD , { 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' } }, - { CPU_VENDOR_AMD , { 'A', 'M', 'D', 'i', 's', 'b', 'e', 't', 't', 'e', 'r', '!' } }, - - { CPU_VENDOR_NSM , { 'G', 'e', 'o', 'd', 'e', ' ', 'b', 'y', ' ', 'N', 'S', 'C' } }, - { CPU_VENDOR_NSM , { 'C', 'y', 'r', 'i', 'x', 'I', 'n', 's', 't', 'e', 'a', 'd' } }, - - { CPU_VENDOR_TRANSMETA, { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'T', 'M', 'x', '8', '6' } }, - { CPU_VENDOR_TRANSMETA, { 'T', 'r', 'a', 'n', 's', 'm', 'e', 't', 'a', 'C', 'P', 'U' } }, - - { CPU_VENDOR_VIA , { 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 } }, - { CPU_VENDOR_VIA , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } } -}; - -static inline bool cpuVencorEq(const CpuVendorInfo& info, const char* vendorString) -{ - const uint32_t* a = reinterpret_cast(info.text); - const uint32_t* b = reinterpret_cast(vendorString); - - return (a[0] == b[0]) & - (a[1] == b[1]) & - (a[2] == b[2]) ; -} - -static inline void simplifyBrandString(char* s) -{ - // Always clear the current character in the buffer. This ensures that there - // is no garbage after the string NULL terminator. - char* d = s; - - char prev = 0; - char curr = s[0]; - s[0] = '\0'; - - for (;;) - { - if (curr == 0) break; - - if (curr == ' ') - { - if (prev == '@') goto _Skip; - if (s[1] == ' ' || s[1] == '@') goto _Skip; - } - - d[0] = curr; - d++; - prev = curr; - -_Skip: - curr = *++s; - s[0] = '\0'; - } - - d[0] = '\0'; -} - -void detectCpuInfo(CpuInfo* i) ASMJIT_NOTHROW -{ - uint32_t a; - - // First clear our struct - memset(i, 0, sizeof(CpuInfo)); - memcpy(i->vendor, "Unknown", 8); - - i->numberOfProcessors = detectNumberOfProcessors(); - -#if defined(ASMJIT_X86) || defined(ASMJIT_X64) - CpuId out; - - // Get vendor string - cpuid(0, &out); - - memcpy(i->vendor, &out.ebx, 4); - memcpy(i->vendor + 4, &out.edx, 4); - memcpy(i->vendor + 8, &out.ecx, 4); - - for (a = 0; a < 3; a++) - { - if (cpuVencorEq(cpuVendorInfo[a], i->vendor)) - { - i->vendorId = cpuVendorInfo[a].id; - break; - } - } - - // get feature flags in ecx/edx, and family/model in eax - cpuid(1, &out); - - // family and model fields - i->family = (out.eax >> 8) & 0x0F; - i->model = (out.eax >> 4) & 0x0F; - i->stepping = (out.eax ) & 0x0F; - - // use extended family and model fields - if (i->family == 0x0F) - { - i->family += ((out.eax >> 20) & 0xFF); - i->model += ((out.eax >> 16) & 0x0F) << 4; - } - - i->x86ExtendedInfo.processorType = ((out.eax >> 12) & 0x03); - i->x86ExtendedInfo.brandIndex = ((out.ebx ) & 0xFF); - i->x86ExtendedInfo.flushCacheLineSize = ((out.ebx >> 8) & 0xFF) * 8; - i->x86ExtendedInfo.maxLogicalProcessors = ((out.ebx >> 16) & 0xFF); - i->x86ExtendedInfo.apicPhysicalId = ((out.ebx >> 24) & 0xFF); - - if (out.ecx & 0x00000001U) i->features |= CPU_FEATURE_SSE3; - if (out.ecx & 0x00000002U) i->features |= CPU_FEATURE_PCLMULDQ; - if (out.ecx & 0x00000008U) i->features |= CPU_FEATURE_MONITOR_MWAIT; - if (out.ecx & 0x00000200U) i->features |= CPU_FEATURE_SSSE3; - if (out.ecx & 0x00002000U) i->features |= CPU_FEATURE_CMPXCHG16B; - if (out.ecx & 0x00080000U) i->features |= CPU_FEATURE_SSE4_1; - if (out.ecx & 0x00100000U) i->features |= CPU_FEATURE_SSE4_2; - if (out.ecx & 0x00400000U) i->features |= CPU_FEATURE_MOVBE; - if (out.ecx & 0x00800000U) i->features |= CPU_FEATURE_POPCNT; - if (out.ecx & 0x10000000U) i->features |= CPU_FEATURE_AVX; - - if (out.edx & 0x00000010U) i->features |= CPU_FEATURE_RDTSC; - if (out.edx & 0x00000100U) i->features |= CPU_FEATURE_CMPXCHG8B; - if (out.edx & 0x00008000U) i->features |= CPU_FEATURE_CMOV; - if (out.edx & 0x00800000U) i->features |= CPU_FEATURE_MMX; - if (out.edx & 0x01000000U) i->features |= CPU_FEATURE_FXSR; - if (out.edx & 0x02000000U) i->features |= CPU_FEATURE_SSE | CPU_FEATURE_MMX_EXT; - if (out.edx & 0x04000000U) i->features |= CPU_FEATURE_SSE | CPU_FEATURE_SSE2; - if (out.edx & 0x10000000U) i->features |= CPU_FEATURE_MULTI_THREADING; - - if (i->vendorId == CPU_VENDOR_AMD && (out.edx & 0x10000000U)) - { - // AMD sets Multithreading to ON if it has more cores. - if (i->numberOfProcessors == 1) i->numberOfProcessors = 2; - } - - // This comment comes from V8 and I think that its important: - // - // Opteron Rev E has a bug in which on very rare occasions a locked - // instruction doesn't act as a read-acquire barrier if followed by a - // non-locked read-modify-write instruction. Rev F has this bug in - // pre-release versions, but not in versions released to customers, - // so we test only for Rev E, which is family 15, model 32..63 inclusive. - - if (i->vendorId == CPU_VENDOR_AMD && i->family == 15 && i->model >= 32 && i->model <= 63) - { - i->bugs |= CPU_BUG_AMD_LOCK_MB; - } - - // Calling cpuid with 0x80000000 as the in argument - // gets the number of valid extended IDs. - - cpuid(0x80000000, &out); - - uint32_t exIds = out.eax; - if (exIds > 0x80000004) exIds = 0x80000004; - - uint32_t* brand = reinterpret_cast(i->brand); - - for (a = 0x80000001; a <= exIds; a++) - { - cpuid(a, &out); - - switch (a) - { - case 0x80000001: - if (out.ecx & 0x00000001U) i->features |= CPU_FEATURE_LAHF_SAHF; - if (out.ecx & 0x00000020U) i->features |= CPU_FEATURE_LZCNT; - if (out.ecx & 0x00000040U) i->features |= CPU_FEATURE_SSE4_A; - if (out.ecx & 0x00000080U) i->features |= CPU_FEATURE_MSSE; - if (out.ecx & 0x00000100U) i->features |= CPU_FEATURE_PREFETCH; - - if (out.edx & 0x00100000U) i->features |= CPU_FEATURE_EXECUTE_DISABLE_BIT; - if (out.edx & 0x00200000U) i->features |= CPU_FEATURE_FFXSR; - if (out.edx & 0x00400000U) i->features |= CPU_FEATURE_MMX_EXT; - if (out.edx & 0x08000000U) i->features |= CPU_FEATURE_RDTSCP; - if (out.edx & 0x20000000U) i->features |= CPU_FEATURE_64_BIT; - if (out.edx & 0x40000000U) i->features |= CPU_FEATURE_3DNOW_EXT | CPU_FEATURE_MMX_EXT; - if (out.edx & 0x80000000U) i->features |= CPU_FEATURE_3DNOW; - break; - - case 0x80000002: - case 0x80000003: - case 0x80000004: - *brand++ = out.eax; - *brand++ = out.ebx; - *brand++ = out.ecx; - *brand++ = out.edx; - break; - - default: - // Additional features can be detected in the future. - break; - } - } - - // Simplify the brand string (remove unnecessary spaces to make it printable). - simplifyBrandString(i->brand); - -#endif // ASMJIT_X86 || ASMJIT_X64 -} -#else -void detectCpuInfo(CpuInfo* i) ASMJIT_NOTHROW -{ - memset(i, 0, sizeof(CpuInfo)); -} -#endif - -struct ASMJIT_HIDDEN CpuInfoStatic -{ - CpuInfoStatic() ASMJIT_NOTHROW { detectCpuInfo(&i); } - - CpuInfo i; -}; - -CpuInfo* getCpuInfo() ASMJIT_NOTHROW -{ - static CpuInfoStatic i; - return &i.i; -} - -} // AsmJit - -// [Api-End] -#include "ApiEnd.h" diff --git a/desmume/src/utils/AsmJit/CpuInfo.h b/desmume/src/utils/AsmJit/CpuInfo.h deleted file mode 100644 index d276e6af3..000000000 --- a/desmume/src/utils/AsmJit/CpuInfo.h +++ /dev/null @@ -1,226 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_CPUINFO_H -#define _ASMJIT_CPUINFO_H - -// [Dependencies] -#include "Build.h" - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -//! @addtogroup AsmJit_CpuInfo -//! @{ - -// ============================================================================ -// [AsmJit::CpuId] -// ============================================================================ - -#if defined(ASMJIT_X86) || defined(ASMJIT_X64) -//! @brief Structure (union) used by cpuid() function. -union CpuId -{ - //! @brief cpuid results array(eax, ebx, ecx and edx registers). - uint32_t i[4]; - - struct - { - //! @brief cpuid result in eax register. - uint32_t eax; - //! @brief cpuid result in ebx register. - uint32_t ebx; - //! @brief cpuid result in ecx register. - uint32_t ecx; - //! @brief cpuid result in edx register. - uint32_t edx; - }; -}; - -//! @brief Calls CPUID instruction with eax == @a in and returns result to @a out. -//! -//! @c cpuid() function has one input parameter that is passed to cpuid through -//! eax register and results in four output values representing result of cpuid -//! instruction (eax, ebx, ecx and edx registers). -ASMJIT_API void cpuid(uint32_t in, CpuId* out) ASMJIT_NOTHROW; -#endif // ASMJIT_X86 || ASMJIT_X64 - -// ============================================================================ -// [AsmJit::CPU_VENDOR] -// ============================================================================ - -//! @brief Cpu vendor IDs. -//! -//! Cpu vendor IDs are specific for AsmJit library. Vendor ID is not directly -//! read from cpuid result, instead it's based on CPU vendor string. -enum CPU_VENDOR -{ - //! @brief Unknown CPU vendor. - CPU_VENDOR_UNKNOWN = 0, - - //! @brief Intel CPU vendor. - CPU_VENDOR_INTEL = 1, - //! @brief AMD CPU vendor. - CPU_VENDOR_AMD = 2, - //! @brief National Semiconductor CPU vendor (applies also to Cyrix processors). - CPU_VENDOR_NSM = 3, - //! @brief Transmeta CPU vendor. - CPU_VENDOR_TRANSMETA = 4, - //! @brief VIA CPU vendor. - CPU_VENDOR_VIA = 5 -}; - -// ============================================================================ -// [AsmJit::CPU_FEATURE] -// ============================================================================ - -//! @brief X86/X64 CPU features. -enum CPU_FEATURE -{ - //! @brief Cpu has RDTSC instruction. - CPU_FEATURE_RDTSC = 1U << 0, - //! @brief Cpu has RDTSCP instruction. - CPU_FEATURE_RDTSCP = 1U << 1, - //! @brief Cpu has CMOV instruction (conditional move) - CPU_FEATURE_CMOV = 1U << 2, - //! @brief Cpu has CMPXCHG8B instruction - CPU_FEATURE_CMPXCHG8B = 1U << 3, - //! @brief Cpu has CMPXCHG16B instruction (64-bit processors) - CPU_FEATURE_CMPXCHG16B = 1U << 4, - //! @brief Cpu has CLFUSH instruction - CPU_FEATURE_CLFLUSH = 1U << 5, - //! @brief Cpu has PREFETCH instruction - CPU_FEATURE_PREFETCH = 1U << 6, - //! @brief Cpu supports LAHF and SAHF instrictions. - CPU_FEATURE_LAHF_SAHF = 1U << 7, - //! @brief Cpu supports FXSAVE and FXRSTOR instructions. - CPU_FEATURE_FXSR = 1U << 8, - //! @brief Cpu supports FXSAVE and FXRSTOR instruction optimizations (FFXSR). - CPU_FEATURE_FFXSR = 1U << 9, - //! @brief Cpu has MMX. - CPU_FEATURE_MMX = 1U << 10, - //! @brief Cpu has extended MMX. - CPU_FEATURE_MMX_EXT = 1U << 11, - //! @brief Cpu has 3dNow! - CPU_FEATURE_3DNOW = 1U << 12, - //! @brief Cpu has enchanced 3dNow! - CPU_FEATURE_3DNOW_EXT = 1U << 13, - //! @brief Cpu has SSE. - CPU_FEATURE_SSE = 1U << 14, - //! @brief Cpu has SSE2. - CPU_FEATURE_SSE2 = 1U << 15, - //! @brief Cpu has SSE3. - CPU_FEATURE_SSE3 = 1U << 16, - //! @brief Cpu has Supplemental SSE3 (SSSE3). - CPU_FEATURE_SSSE3 = 1U << 17, - //! @brief Cpu has SSE4.A. - CPU_FEATURE_SSE4_A = 1U << 18, - //! @brief Cpu has SSE4.1. - CPU_FEATURE_SSE4_1 = 1U << 19, - //! @brief Cpu has SSE4.2. - CPU_FEATURE_SSE4_2 = 1U << 20, - //! @brief Cpu has AVX. - CPU_FEATURE_AVX = 1U << 22, - //! @brief Cpu has Misaligned SSE (MSSE). - CPU_FEATURE_MSSE = 1U << 23, - //! @brief Cpu supports MONITOR and MWAIT instructions. - CPU_FEATURE_MONITOR_MWAIT = 1U << 24, - //! @brief Cpu supports MOVBE instruction. - CPU_FEATURE_MOVBE = 1U << 25, - //! @brief Cpu supports POPCNT instruction. - CPU_FEATURE_POPCNT = 1U << 26, - //! @brief Cpu supports LZCNT instruction. - CPU_FEATURE_LZCNT = 1U << 27, - //! @brief Cpu supports PCLMULDQ set of instructions. - CPU_FEATURE_PCLMULDQ = 1U << 28, - //! @brief Cpu supports multithreading. - CPU_FEATURE_MULTI_THREADING = 1U << 29, - //! @brief Cpu supports execute disable bit (execute protection). - CPU_FEATURE_EXECUTE_DISABLE_BIT = 1U << 30, - //! @brief 64-bit CPU. - CPU_FEATURE_64_BIT = 1U << 31 -}; - -// ============================================================================ -// [AsmJit::CPU_BUG] -// ============================================================================ - -//! @brief X86/X64 CPU bugs. -enum CPU_BUG -{ - //! @brief Whether the processor contains bug seen in some - //! AMD-Opteron processors. - CPU_BUG_AMD_LOCK_MB = 1U << 0 -}; - -// ============================================================================ -// [AsmJit::CpuInfo] -// ============================================================================ - -//! @brief Informations about host cpu. -struct ASMJIT_HIDDEN CpuInfo -{ - //! @brief Cpu short vendor string. - char vendor[16]; - //! @brief Cpu long vendor string (brand). - char brand[64]; - //! @brief Cpu vendor id (see @c AsmJit::CpuInfo::VendorId enum). - uint32_t vendorId; - //! @brief Cpu family ID. - uint32_t family; - //! @brief Cpu model ID. - uint32_t model; - //! @brief Cpu stepping. - uint32_t stepping; - //! @brief Number of processors or cores. - uint32_t numberOfProcessors; - //! @brief Cpu features bitfield, see @c AsmJit::CpuInfo::Feature enum). - uint32_t features; - //! @brief Cpu bugs bitfield, see @c AsmJit::CpuInfo::Bug enum). - uint32_t bugs; - -#if defined(ASMJIT_X86) || defined(ASMJIT_X64) - //! @brief Extended information for x86/x64 compatible processors. - struct X86ExtendedInfo - { - //! @brief Processor type. - uint32_t processorType; - //! @brief Brand index. - uint32_t brandIndex; - //! @brief Flush cache line size in bytes. - uint32_t flushCacheLineSize; - //! @brief Maximum number of addressable IDs for logical processors. - uint32_t maxLogicalProcessors; - //! @brief Initial APIC ID. - uint32_t apicPhysicalId; - }; - //! @brief Extended information for x86/x64 compatible processors. - X86ExtendedInfo x86ExtendedInfo; -#endif // ASMJIT_X86 || ASMJIT_X64 -}; - -//! @brief Detect CPU features to CpuInfo structure @a i. -//! -//! @sa @c CpuInfo. -ASMJIT_API void detectCpuInfo(CpuInfo* i) ASMJIT_NOTHROW; - -//! @brief Return CpuInfo (detection is done only once). -//! -//! @sa @c CpuInfo. -ASMJIT_API CpuInfo* getCpuInfo() ASMJIT_NOTHROW; - -//! @} - -} // AsmJit namespace - -// [Api-End] -#include "ApiEnd.h" - -// [Guard] -#endif // _ASMJIT_CPUINFO_H diff --git a/desmume/src/utils/AsmJit/Defs.h b/desmume/src/utils/AsmJit/Defs.h deleted file mode 100644 index 2cf78740c..000000000 --- a/desmume/src/utils/AsmJit/Defs.h +++ /dev/null @@ -1,416 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_DEFS_H -#define _ASMJIT_DEFS_H - -// [Dependencies] -#include "Build.h" - -namespace AsmJit { - -//! @addtogroup AsmJit_Core -//! @{ - -// ============================================================================ -// [AsmJit::ENUM] -// ============================================================================ - -//! @brief Uncategorized constants. -enum -{ - //! @brief Invalid operand identifier. - INVALID_VALUE = 0xFFFFFFFF, - - //! @brief Maximum allowed arguments per function declaration / call. - FUNC_MAX_ARGS = 32 -}; - -// ============================================================================ -// [AsmJit::MEMORY_ALLOC_TYPE] -// ============================================================================ - -//! @brief Types of allocation used by @c AsmJit::MemoryManager::alloc() method. -enum MEMORY_ALLOC_TYPE -{ - //! @brief Allocate memory that can be freed by @c AsmJit::MemoryManager::free() - //! method. - MEMORY_ALLOC_FREEABLE = 0, - //! @brief Allocate permanent memory that will be never freed. - MEMORY_ALLOC_PERMANENT = 1 -}; - -// ============================================================================ -// [AsmJit::ERROR_CODE] -// ============================================================================ - -//! @brief AsmJit error codes. -enum ERROR_CODE -{ - //! @brief No error (success). - //! - //! This is default state and state you want. - ERROR_NONE = 0, - - //! @brief Memory allocation error (@c ASMJIT_MALLOC returned @c NULL). - ERROR_NO_HEAP_MEMORY = 1, - //! @brief Virtual memory allocation error (@c VirtualMemory returned @c NULL). - ERROR_NO_VIRTUAL_MEMORY = 2, - - //! @brief Unknown instruction. This happens only if instruction code is - //! out of bounds. Shouldn't happen. - ERROR_UNKNOWN_INSTRUCTION = 3, - //! @brief Illegal instruction, usually generated by AsmJit::AssemblerCore - //! class when emitting instruction opcode. If this error is generated the - //! target buffer is not affected by this invalid instruction. - //! - //! You can also get this error code if you are under x64 (64-bit x86) and - //! you tried to decode instruction using AH, BH, CH or DH register with REX - //! prefix. These registers can't be accessed if REX prefix is used and AsmJit - //! didn't check for this situation in intrinsics (@c Compiler takes care of - //! this and rearrange registers if needed). - //! - //! Examples that will raise @c ERROR_ILLEGAL_INSTRUCTION error (a is - //! @c Assembler instance): - //! - //! @code - //! a.mov(dword_ptr(eax), al); // Invalid address size. - //! a.mov(byte_ptr(r10), ah); // Undecodable instruction (AH used with r10 - //! // which can be encoded only using REX prefix) - //! @endcode - //! - //! @note In debug mode you get assertion failure instead of setting error - //! code. - ERROR_ILLEGAL_INSTRUCTION = 4, - //! @brief Illegal addressing used (unencodable). - ERROR_ILLEGAL_ADDRESING = 5, - //! @brief Short jump instruction used, but displacement is out of bounds. - ERROR_ILLEGAL_SHORT_JUMP = 6, - - //! @brief No function defined. - ERROR_NO_FUNCTION = 7, - //! @brief Function generation is not finished by using @c Compiler::endFunction() - //! or something bad happened during generation related to function. This can - //! be missing emittable, etc... - ERROR_INCOMPLETE_FUNCTION = 8, - - //! @brief Compiler can't allocate registers, because all of them are used. - //! - //! @note AsmJit is able to spill registers so this error really shouldn't - //! happen unless all registers have priority 0 (which means never spill). - ERROR_NOT_ENOUGH_REGISTERS = 9, - //! @brief Compiler can't allocate one register to multiple destinations. - //! - //! This error can only happen using special instructions like cmpxchg8b and - //! others where there are more destination operands (implicit). - ERROR_REGISTERS_OVERLAP = 10, - - //! @brief Tried to call function using incompatible argument. - ERROR_INCOMPATIBLE_ARGUMENT = 11, - //! @brief Incompatible return value. - ERROR_INCOMPATIBLE_RETURN_VALUE = 12, - - //! @brief Count of error codes by AsmJit. Can grow in future. - _ERROR_COUNT -}; - -// ============================================================================ -// [AsmJit::OPERAND_TYPE] -// ============================================================================ - -//! @brief Operand types that can be encoded in @c Op operand. -enum OPERAND_TYPE -{ - //! @brief Operand is none, used only internally (not initialized Operand). - //! - //! This operand is not valid. - OPERAND_NONE = 0x00, - - //! @brief Operand is register. - OPERAND_REG = 0x01, - //! @brief Operand is memory. - OPERAND_MEM = 0x02, - //! @brief Operand is immediate. - OPERAND_IMM = 0x04, - //! @brief Operand is label. - OPERAND_LABEL = 0x08, - //! @brief Operand is variable. - OPERAND_VAR = 0x10 -}; - -// ============================================================================ -// [AsmJit::OPERAND_MEM_TYPE] -// ============================================================================ - -//! @brief Type of memory operand. -enum OPERAND_MEM_TYPE -{ - //! @brief Operand is combination of register(s) and displacement (native). - OPERAND_MEM_NATIVE = 0, - //! @brief Operand is label. - OPERAND_MEM_LABEL = 1, - //! @brief Operand is absolute memory location (supported mainly in 32-bit - //! mode) - OPERAND_MEM_ABSOLUTE = 2, -}; - -// ============================================================================ -// [AsmJit::OPERAND_ID] -// ============================================================================ - -//! @brief Operand ID masks used to determine the operand type. -enum OPERAND_ID -{ - //! @brief Operand id value mask (part used for IDs). - OPERAND_ID_VALUE_MASK = 0x3FFFFFFF, - //! @brief Operand id type mask (part used for operand type). - OPERAND_ID_TYPE_MASK = 0xC0000000, - //! @brief Label operand mark id. - OPERAND_ID_TYPE_LABEL = 0x40000000, - //! @brief Variable operand mark id. - OPERAND_ID_TYPE_VAR = 0x80000000 -}; - -// ============================================================================ -// [AsmJit::PROPERTY] -// ============================================================================ - -//! @brief @c Assembler/Compiler properties. -enum PROPERTY -{ - //! @brief Optimize align for current processor. - //! - //! Default: @c true. - PROPERTY_OPTIMIZE_ALIGN = 0, - - //! @brief Emit hints added to jcc() instructions. - //! - //! Default: @c true. - //! - //! @note This is X86/X64 property only. - PROPERTY_JUMP_HINTS = 1 -}; - -// ============================================================================ -// [AsmJit::SIZE] -// ============================================================================ - -//! @brief Size of registers and pointers. -enum SIZE -{ - //! @brief 1 byte size. - SIZE_BYTE = 1, - //! @brief 2 bytes size. - SIZE_WORD = 2, - //! @brief 4 bytes size. - SIZE_DWORD = 4, - //! @brief 8 bytes size. - SIZE_QWORD = 8, - //! @brief 10 bytes size. - SIZE_TWORD = 10, - //! @brief 16 bytes size. - SIZE_DQWORD = 16 -}; - -// ============================================================================ -// [EMITTABLE_TYPE] -// ============================================================================ - -//! @brief Emmitable type. -//! -//! For each emittable that is used by @c Compiler must be defined it's type. -//! Compiler can optimize instruction stream by analyzing emittables and each -//! type is hint for it. The most used emittables are instructions -//! (@c EMITTABLE_INSTRUCTION). -enum EMITTABLE_TYPE -{ - //! @brief Emittable is invalid (can't be used). - EMITTABLE_NONE = 0, - //! @brief Emittable is dummy (used as a mark) (@ref EDummy). - EMITTABLE_DUMMY, - //! @brief Emittable is comment (no code) (@ref EComment). - EMITTABLE_COMMENT, - //! @brief Emittable is embedded data (@ref EData). - EMITTABLE_EMBEDDED_DATA, - //! @brief Emittable is .align directive (@ref EAlign). - EMITTABLE_ALIGN, - //! @brief Emittable is variable hint (alloc, spill, use, unuse, ...) (@ref EVariableHint). - EMITTABLE_VARIABLE_HINT, - //! @brief Emittable is single instruction (@ref EInstruction). - EMITTABLE_INSTRUCTION, - //! @brief Emittable is block of instructions. - EMITTABLE_BLOCK, - //! @brief Emittable is function declaration (@ref EFunction). - EMITTABLE_FUNCTION, - //! @brief Emittable is function prolog (@ref EProlog). - EMITTABLE_PROLOG, - //! @brief Emittable is function epilog (@ref EEpilog). - EMITTABLE_EPILOG, - //! @brief Emittable is end of function (@ref EFunctionEnd). - EMITTABLE_FUNCTION_END, - //! @brief Emittable is target (bound label). - EMITTABLE_TARGET, - //! @brief Emittable is jump table (@ref EJmp). - EMITTABLE_JUMP_TABLE, - //! @brief Emittable is function call (@ref ECall). - EMITTABLE_CALL, - //! @brief Emittable is return (@ref ERet). - EMITTABLE_RET -}; - -// ============================================================================ -// [AsmJit::VARIABLE_STATE] -// ============================================================================ - -//! @brief State of variable. -//! -//! @note State of variable is used only during make process and it's not -//! visible to the developer. -enum VARIABLE_STATE -{ - //! @brief Variable is currently not used. - VARIABLE_STATE_UNUSED = 0, - - //! @brief Variable is in register. - //! - //! Variable is currently allocated in register. - VARIABLE_STATE_REGISTER = 1, - - //! @brief Variable is in memory location or spilled. - //! - //! Variable was spilled from register to memory or variable is used for - //! memory only storage. - VARIABLE_STATE_MEMORY = 2 -}; - -// ============================================================================ -// [AsmJit::VARIABLE_ALLOC_FLAGS] -// ============================================================================ - -//! @brief Variable alloc mode. -enum VARIABLE_ALLOC -{ - //! @brief Allocating variable to read only. - //! - //! Read only variables are used to optimize variable spilling. If variable - //! is some time ago deallocated and it's not marked as changed (so it was - //! all the life time read only) then spill is simply NOP (no mov instruction - //! is generated to move it to it's home memory location). - VARIABLE_ALLOC_READ = 0x01, - - //! @brief Allocating variable to write only (overwrite). - //! - //! Overwriting means that if variable is in memory, there is no generated - //! instruction to move variable from memory to register, because that - //! register will be overwritten by next instruction. This is used as a - //! simple optimization to improve generated code by @c Compiler. - VARIABLE_ALLOC_WRITE = 0x02, - - //! @brief Allocating variable to read / write. - //! - //! Variable allocated for read / write is marked as changed. This means that - //! if variable must be later spilled into memory, mov (or similar) - //! instruction will be generated. - VARIABLE_ALLOC_READWRITE = 0x03, - - //! @brief Variable can be allocated in register. - VARIABLE_ALLOC_REGISTER = 0x04, - - //! @brief Variable can be allocated in memory. - VARIABLE_ALLOC_MEMORY = 0x08, - - //! @brief Unuse the variable after use. - VARIABLE_ALLOC_UNUSE_AFTER_USE = 0x10, - - //! @brief Variable can be allocated only to one register (special allocation). - VARIABLE_ALLOC_SPECIAL = 0x20 -}; - -// ============================================================================ -// [AsmJit::VARIABLE_ALLOC_POLICY] -// ============================================================================ - -//! @brief Variable allocation method. -//! -//! Variable allocation method is used by compiler and it means if compiler -//! should first allocate preserved registers or not. Preserved registers are -//! registers that must be saved / restored by generated function. -//! -//! This option is for people who are calling C/C++ functions from JIT code so -//! Compiler can recude generating push/pop sequences before and after call, -//! respectively. -enum VARIABLE_ALLOC_POLICY -{ - //! @brief Allocate preserved registers first. - VARIABLE_ALLOC_PRESERVED_FIRST = 0, - //! @brief Allocate preserved registers last (default). - VARIABLE_ALLOC_PRESERVED_LAST = 1 -}; - -// ============================================================================ -// [AsmJit::FUNCTION_HINT] -// ============================================================================ - -//! @brief Function hints. -enum FUNCTION_HINT -{ - //! @brief Use push/pop sequences instead of mov sequences in function prolog - //! and epilog. - FUNCTION_HINT_PUSH_POP_SEQUENCE = 0, - //! @brief Make naked function (without using ebp/erp in prolog / epilog). - FUNCTION_HINT_NAKED = 1, - //! @brief Add emms instruction to the function epilog. - FUNCTION_HINT_EMMS = 2, - //! @brief Add sfence instruction to the function epilog. - FUNCTION_HINT_SFENCE = 3, - //! @brief Add lfence instruction to the function epilog. - FUNCTION_HINT_LFENCE = 4 -}; - -// ============================================================================ -// [AsmJit::ARGUMENT_DIR] -// ============================================================================ - -//! @brief Arguments direction used by @c Function. -enum ARGUMENT_DIR -{ - //! @brief Arguments are passed left to right. - //! - //! This arguments direction is unusual to C programming, it's used by pascal - //! compilers and in some calling conventions by Borland compiler). - ARGUMENT_DIR_LEFT_TO_RIGHT = 0, - //! @brief Arguments are passer right ro left - //! - //! This is default argument direction in C programming. - ARGUMENT_DIR_RIGHT_TO_LEFT = 1 -}; - -// ============================================================================ -// [AsmJit::API] -// ============================================================================ - -//! @brief Translates error code (see @c ERROR_CODE) into text representation. -ASMJIT_API const char* getErrorString(uint32_t error) ASMJIT_NOTHROW; - -//! @} - -} // AsmJit namespace - -// ============================================================================ -// [Platform Specific] -// -// Following enums must be declared by platform specific header: -// - CALL_CONV - Calling convention. -// - VARIABLE_TYPE - Variable type. -// ============================================================================ - -#if defined(ASMJIT_X86) || defined(ASMJIT_X64) -#include "DefsX86X64.h" -#endif // ASMJIT_X86 || ASMJIT_X64 - -// [Guard] -#endif // _ASMJIT_DEFS_H diff --git a/desmume/src/utils/AsmJit/DefsX86X64.cpp b/desmume/src/utils/AsmJit/DefsX86X64.cpp deleted file mode 100644 index a94641e77..000000000 --- a/desmume/src/utils/AsmJit/DefsX86X64.cpp +++ /dev/null @@ -1,1840 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Dependencies] -#include "Defs.h" - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -// ============================================================================ -// [AsmJit::ConditionToInstruction] -// ============================================================================ - -const uint32_t ConditionToInstruction::_jcctable[16] = -{ - INST_JO, - INST_JNO, - INST_JB, - INST_JAE, - INST_JE, - INST_JNE, - INST_JBE, - INST_JA, - INST_JS, - INST_JNS, - INST_JPE, - INST_JPO, - INST_JL, - INST_JGE, - INST_JLE, - INST_JG -}; - -const uint32_t ConditionToInstruction::_cmovcctable[16] = -{ - INST_CMOVO, - INST_CMOVNO, - INST_CMOVB, - INST_CMOVAE, - INST_CMOVE, - INST_CMOVNE, - INST_CMOVBE, - INST_CMOVA, - INST_CMOVS, - INST_CMOVNS, - INST_CMOVPE, - INST_CMOVPO, - INST_CMOVL, - INST_CMOVGE, - INST_CMOVLE, - INST_CMOVG -}; - -const uint32_t ConditionToInstruction::_setcctable[16] = -{ - INST_SETO, - INST_SETNO, - INST_SETB, - INST_SETAE, - INST_SETE, - INST_SETNE, - INST_SETBE, - INST_SETA, - INST_SETS, - INST_SETNS, - INST_SETPE, - INST_SETPO, - INST_SETL, - INST_SETGE, - INST_SETLE, - INST_SETG -}; - -// ============================================================================ -// [AsmJit::Instruction Name] -// ============================================================================ - -// Following {DATA SECTION} is auto-generated using InstructionDescription data. -// -// ${INSTRUCTION_DATA_BEGIN} -const char instructionName[] = - "adc\0" - "add\0" - "addpd\0" - "addps\0" - "addsd\0" - "addss\0" - "addsubpd\0" - "addsubps\0" - "amd_prefetch\0" - "amd_prefetchw\0" - "and\0" - "andnpd\0" - "andnps\0" - "andpd\0" - "andps\0" - "blendpd\0" - "blendps\0" - "blendvpd\0" - "blendvps\0" - "bsf\0" - "bsr\0" - "bswap\0" - "bt\0" - "btc\0" - "btr\0" - "bts\0" - "call\0" - "cbw\0" - "cdqe\0" - "clc\0" - "cld\0" - "clflush\0" - "cmc\0" - "cmova\0" - "cmovae\0" - "cmovb\0" - "cmovbe\0" - "cmovc\0" - "cmove\0" - "cmovg\0" - "cmovge\0" - "cmovl\0" - "cmovle\0" - "cmovna\0" - "cmovnae\0" - "cmovnb\0" - "cmovnbe\0" - "cmovnc\0" - "cmovne\0" - "cmovng\0" - "cmovnge\0" - "cmovnl\0" - "cmovnle\0" - "cmovno\0" - "cmovnp\0" - "cmovns\0" - "cmovnz\0" - "cmovo\0" - "cmovp\0" - "cmovpe\0" - "cmovpo\0" - "cmovs\0" - "cmovz\0" - "cmp\0" - "cmppd\0" - "cmpps\0" - "cmpsd\0" - "cmpss\0" - "cmpxchg\0" - "cmpxchg16b\0" - "cmpxchg8b\0" - "comisd\0" - "comiss\0" - "cpuid\0" - "crc32\0" - "cvtdq2pd\0" - "cvtdq2ps\0" - "cvtpd2dq\0" - "cvtpd2pi\0" - "cvtpd2ps\0" - "cvtpi2pd\0" - "cvtpi2ps\0" - "cvtps2dq\0" - "cvtps2pd\0" - "cvtps2pi\0" - "cvtsd2si\0" - "cvtsd2ss\0" - "cvtsi2sd\0" - "cvtsi2ss\0" - "cvtss2sd\0" - "cvtss2si\0" - "cvttpd2dq\0" - "cvttpd2pi\0" - "cvttps2dq\0" - "cvttps2pi\0" - "cvttsd2si\0" - "cvttss2si\0" - "cwde\0" - "daa\0" - "das\0" - "dec\0" - "div\0" - "divpd\0" - "divps\0" - "divsd\0" - "divss\0" - "dppd\0" - "dpps\0" - "emms\0" - "enter\0" - "extractps\0" - "f2xm1\0" - "fabs\0" - "fadd\0" - "faddp\0" - "fbld\0" - "fbstp\0" - "fchs\0" - "fclex\0" - "fcmovb\0" - "fcmovbe\0" - "fcmove\0" - "fcmovnb\0" - "fcmovnbe\0" - "fcmovne\0" - "fcmovnu\0" - "fcmovu\0" - "fcom\0" - "fcomi\0" - "fcomip\0" - "fcomp\0" - "fcompp\0" - "fcos\0" - "fdecstp\0" - "fdiv\0" - "fdivp\0" - "fdivr\0" - "fdivrp\0" - "femms\0" - "ffree\0" - "fiadd\0" - "ficom\0" - "ficomp\0" - "fidiv\0" - "fidivr\0" - "fild\0" - "fimul\0" - "fincstp\0" - "finit\0" - "fist\0" - "fistp\0" - "fisttp\0" - "fisub\0" - "fisubr\0" - "fld\0" - "fld1\0" - "fldcw\0" - "fldenv\0" - "fldl2e\0" - "fldl2t\0" - "fldlg2\0" - "fldln2\0" - "fldpi\0" - "fldz\0" - "fmul\0" - "fmulp\0" - "fnclex\0" - "fninit\0" - "fnop\0" - "fnsave\0" - "fnstcw\0" - "fnstenv\0" - "fnstsw\0" - "fpatan\0" - "fprem\0" - "fprem1\0" - "fptan\0" - "frndint\0" - "frstor\0" - "fsave\0" - "fscale\0" - "fsin\0" - "fsincos\0" - "fsqrt\0" - "fst\0" - "fstcw\0" - "fstenv\0" - "fstp\0" - "fstsw\0" - "fsub\0" - "fsubp\0" - "fsubr\0" - "fsubrp\0" - "ftst\0" - "fucom\0" - "fucomi\0" - "fucomip\0" - "fucomp\0" - "fucompp\0" - "fwait\0" - "fxam\0" - "fxch\0" - "fxrstor\0" - "fxsave\0" - "fxtract\0" - "fyl2x\0" - "fyl2xp1\0" - "haddpd\0" - "haddps\0" - "hsubpd\0" - "hsubps\0" - "idiv\0" - "imul\0" - "inc\0" - "int3\0" - "ja\0" - "jae\0" - "jb\0" - "jbe\0" - "jc\0" - "je\0" - "jg\0" - "jge\0" - "jl\0" - "jle\0" - "jna\0" - "jnae\0" - "jnb\0" - "jnbe\0" - "jnc\0" - "jne\0" - "jng\0" - "jnge\0" - "jnl\0" - "jnle\0" - "jno\0" - "jnp\0" - "jns\0" - "jnz\0" - "jo\0" - "jp\0" - "jpe\0" - "jpo\0" - "js\0" - "jz\0" - "jmp\0" - "lddqu\0" - "ldmxcsr\0" - "lahf\0" - "lea\0" - "leave\0" - "lfence\0" - "maskmovdqu\0" - "maskmovq\0" - "maxpd\0" - "maxps\0" - "maxsd\0" - "maxss\0" - "mfence\0" - "minpd\0" - "minps\0" - "minsd\0" - "minss\0" - "monitor\0" - "mov\0" - "movapd\0" - "movaps\0" - "movbe\0" - "movd\0" - "movddup\0" - "movdq2q\0" - "movdqa\0" - "movdqu\0" - "movhlps\0" - "movhpd\0" - "movhps\0" - "movlhps\0" - "movlpd\0" - "movlps\0" - "movmskpd\0" - "movmskps\0" - "movntdq\0" - "movntdqa\0" - "movnti\0" - "movntpd\0" - "movntps\0" - "movntq\0" - "movq\0" - "movq2dq\0" - "movsd\0" - "movshdup\0" - "movsldup\0" - "movss\0" - "movsx\0" - "movsxd\0" - "movupd\0" - "movups\0" - "movzx\0" - "mov_ptr\0" - "mpsadbw\0" - "mul\0" - "mulpd\0" - "mulps\0" - "mulsd\0" - "mulss\0" - "mwait\0" - "neg\0" - "nop\0" - "not\0" - "or\0" - "orpd\0" - "orps\0" - "pabsb\0" - "pabsd\0" - "pabsw\0" - "packssdw\0" - "packsswb\0" - "packusdw\0" - "packuswb\0" - "paddb\0" - "paddd\0" - "paddq\0" - "paddsb\0" - "paddsw\0" - "paddusb\0" - "paddusw\0" - "paddw\0" - "palignr\0" - "pand\0" - "pandn\0" - "pause\0" - "pavgb\0" - "pavgw\0" - "pblendvb\0" - "pblendw\0" - "pcmpeqb\0" - "pcmpeqd\0" - "pcmpeqq\0" - "pcmpeqw\0" - "pcmpestri\0" - "pcmpestrm\0" - "pcmpgtb\0" - "pcmpgtd\0" - "pcmpgtq\0" - "pcmpgtw\0" - "pcmpistri\0" - "pcmpistrm\0" - "pextrb\0" - "pextrd\0" - "pextrq\0" - "pextrw\0" - "pf2id\0" - "pf2iw\0" - "pfacc\0" - "pfadd\0" - "pfcmpeq\0" - "pfcmpge\0" - "pfcmpgt\0" - "pfmax\0" - "pfmin\0" - "pfmul\0" - "pfnacc\0" - "pfpnacc\0" - "pfrcp\0" - "pfrcpit1\0" - "pfrcpit2\0" - "pfrsqit1\0" - "pfrsqrt\0" - "pfsub\0" - "pfsubr\0" - "phaddd\0" - "phaddsw\0" - "phaddw\0" - "phminposuw\0" - "phsubd\0" - "phsubsw\0" - "phsubw\0" - "pi2fd\0" - "pi2fw\0" - "pinsrb\0" - "pinsrd\0" - "pinsrq\0" - "pinsrw\0" - "pmaddubsw\0" - "pmaddwd\0" - "pmaxsb\0" - "pmaxsd\0" - "pmaxsw\0" - "pmaxub\0" - "pmaxud\0" - "pmaxuw\0" - "pminsb\0" - "pminsd\0" - "pminsw\0" - "pminub\0" - "pminud\0" - "pminuw\0" - "pmovmskb\0" - "pmovsxbd\0" - "pmovsxbq\0" - "pmovsxbw\0" - "pmovsxdq\0" - "pmovsxwd\0" - "pmovsxwq\0" - "pmovzxbd\0" - "pmovzxbq\0" - "pmovzxbw\0" - "pmovzxdq\0" - "pmovzxwd\0" - "pmovzxwq\0" - "pmuldq\0" - "pmulhrsw\0" - "pmulhuw\0" - "pmulhw\0" - "pmulld\0" - "pmullw\0" - "pmuludq\0" - "pop\0" - "popad\0" - "popcnt\0" - "popfd\0" - "popfq\0" - "por\0" - "prefetch\0" - "psadbw\0" - "pshufb\0" - "pshufd\0" - "pshufw\0" - "pshufhw\0" - "pshuflw\0" - "psignb\0" - "psignd\0" - "psignw\0" - "pslld\0" - "pslldq\0" - "psllq\0" - "psllw\0" - "psrad\0" - "psraw\0" - "psrld\0" - "psrldq\0" - "psrlq\0" - "psrlw\0" - "psubb\0" - "psubd\0" - "psubq\0" - "psubsb\0" - "psubsw\0" - "psubusb\0" - "psubusw\0" - "psubw\0" - "pswapd\0" - "ptest\0" - "punpckhbw\0" - "punpckhdq\0" - "punpckhqdq\0" - "punpckhwd\0" - "punpcklbw\0" - "punpckldq\0" - "punpcklqdq\0" - "punpcklwd\0" - "push\0" - "pushad\0" - "pushfd\0" - "pushfq\0" - "pxor\0" - "rcl\0" - "rcpps\0" - "rcpss\0" - "rcr\0" - "rdtsc\0" - "rdtscp\0" - "rep lodsb\0" - "rep lodsd\0" - "rep lodsq\0" - "rep lodsw\0" - "rep movsb\0" - "rep movsd\0" - "rep movsq\0" - "rep movsw\0" - "rep stosb\0" - "rep stosd\0" - "rep stosq\0" - "rep stosw\0" - "repe cmpsb\0" - "repe cmpsd\0" - "repe cmpsq\0" - "repe cmpsw\0" - "repe scasb\0" - "repe scasd\0" - "repe scasq\0" - "repe scasw\0" - "repne cmpsb\0" - "repne cmpsd\0" - "repne cmpsq\0" - "repne cmpsw\0" - "repne scasb\0" - "repne scasd\0" - "repne scasq\0" - "repne scasw\0" - "ret\0" - "rol\0" - "ror\0" - "roundpd\0" - "roundps\0" - "roundsd\0" - "roundss\0" - "rsqrtps\0" - "rsqrtss\0" - "sahf\0" - "sal\0" - "sar\0" - "sbb\0" - "seta\0" - "setae\0" - "setb\0" - "setbe\0" - "setc\0" - "sete\0" - "setg\0" - "setge\0" - "setl\0" - "setle\0" - "setna\0" - "setnae\0" - "setnb\0" - "setnbe\0" - "setnc\0" - "setne\0" - "setng\0" - "setnge\0" - "setnl\0" - "setnle\0" - "setno\0" - "setnp\0" - "setns\0" - "setnz\0" - "seto\0" - "setp\0" - "setpe\0" - "setpo\0" - "sets\0" - "setz\0" - "sfence\0" - "shl\0" - "shld\0" - "shr\0" - "shrd\0" - "shufpd\0" - "shufps\0" - "sqrtpd\0" - "sqrtps\0" - "sqrtsd\0" - "sqrtss\0" - "stc\0" - "std\0" - "stmxcsr\0" - "sub\0" - "subpd\0" - "subps\0" - "subsd\0" - "subss\0" - "test\0" - "ucomisd\0" - "ucomiss\0" - "ud2\0" - "unpckhpd\0" - "unpckhps\0" - "unpcklpd\0" - "unpcklps\0" - "xadd\0" - "xchg\0" - "xor\0" - "xorpd\0" - "xorps\0" - ; - -#define INST_ADC_INDEX 0 -#define INST_ADD_INDEX 4 -#define INST_ADDPD_INDEX 8 -#define INST_ADDPS_INDEX 14 -#define INST_ADDSD_INDEX 20 -#define INST_ADDSS_INDEX 26 -#define INST_ADDSUBPD_INDEX 32 -#define INST_ADDSUBPS_INDEX 41 -#define INST_AMD_PREFETCH_INDEX 50 -#define INST_AMD_PREFETCHW_INDEX 63 -#define INST_AND_INDEX 77 -#define INST_ANDNPD_INDEX 81 -#define INST_ANDNPS_INDEX 88 -#define INST_ANDPD_INDEX 95 -#define INST_ANDPS_INDEX 101 -#define INST_BLENDPD_INDEX 107 -#define INST_BLENDPS_INDEX 115 -#define INST_BLENDVPD_INDEX 123 -#define INST_BLENDVPS_INDEX 132 -#define INST_BSF_INDEX 141 -#define INST_BSR_INDEX 145 -#define INST_BSWAP_INDEX 149 -#define INST_BT_INDEX 155 -#define INST_BTC_INDEX 158 -#define INST_BTR_INDEX 162 -#define INST_BTS_INDEX 166 -#define INST_CALL_INDEX 170 -#define INST_CBW_INDEX 175 -#define INST_CDQE_INDEX 179 -#define INST_CLC_INDEX 184 -#define INST_CLD_INDEX 188 -#define INST_CLFLUSH_INDEX 192 -#define INST_CMC_INDEX 200 -#define INST_CMOVA_INDEX 204 -#define INST_CMOVAE_INDEX 210 -#define INST_CMOVB_INDEX 217 -#define INST_CMOVBE_INDEX 223 -#define INST_CMOVC_INDEX 230 -#define INST_CMOVE_INDEX 236 -#define INST_CMOVG_INDEX 242 -#define INST_CMOVGE_INDEX 248 -#define INST_CMOVL_INDEX 255 -#define INST_CMOVLE_INDEX 261 -#define INST_CMOVNA_INDEX 268 -#define INST_CMOVNAE_INDEX 275 -#define INST_CMOVNB_INDEX 283 -#define INST_CMOVNBE_INDEX 290 -#define INST_CMOVNC_INDEX 298 -#define INST_CMOVNE_INDEX 305 -#define INST_CMOVNG_INDEX 312 -#define INST_CMOVNGE_INDEX 319 -#define INST_CMOVNL_INDEX 327 -#define INST_CMOVNLE_INDEX 334 -#define INST_CMOVNO_INDEX 342 -#define INST_CMOVNP_INDEX 349 -#define INST_CMOVNS_INDEX 356 -#define INST_CMOVNZ_INDEX 363 -#define INST_CMOVO_INDEX 370 -#define INST_CMOVP_INDEX 376 -#define INST_CMOVPE_INDEX 382 -#define INST_CMOVPO_INDEX 389 -#define INST_CMOVS_INDEX 396 -#define INST_CMOVZ_INDEX 402 -#define INST_CMP_INDEX 408 -#define INST_CMPPD_INDEX 412 -#define INST_CMPPS_INDEX 418 -#define INST_CMPSD_INDEX 424 -#define INST_CMPSS_INDEX 430 -#define INST_CMPXCHG_INDEX 436 -#define INST_CMPXCHG16B_INDEX 444 -#define INST_CMPXCHG8B_INDEX 455 -#define INST_COMISD_INDEX 465 -#define INST_COMISS_INDEX 472 -#define INST_CPUID_INDEX 479 -#define INST_CRC32_INDEX 485 -#define INST_CVTDQ2PD_INDEX 491 -#define INST_CVTDQ2PS_INDEX 500 -#define INST_CVTPD2DQ_INDEX 509 -#define INST_CVTPD2PI_INDEX 518 -#define INST_CVTPD2PS_INDEX 527 -#define INST_CVTPI2PD_INDEX 536 -#define INST_CVTPI2PS_INDEX 545 -#define INST_CVTPS2DQ_INDEX 554 -#define INST_CVTPS2PD_INDEX 563 -#define INST_CVTPS2PI_INDEX 572 -#define INST_CVTSD2SI_INDEX 581 -#define INST_CVTSD2SS_INDEX 590 -#define INST_CVTSI2SD_INDEX 599 -#define INST_CVTSI2SS_INDEX 608 -#define INST_CVTSS2SD_INDEX 617 -#define INST_CVTSS2SI_INDEX 626 -#define INST_CVTTPD2DQ_INDEX 635 -#define INST_CVTTPD2PI_INDEX 645 -#define INST_CVTTPS2DQ_INDEX 655 -#define INST_CVTTPS2PI_INDEX 665 -#define INST_CVTTSD2SI_INDEX 675 -#define INST_CVTTSS2SI_INDEX 685 -#define INST_CWDE_INDEX 695 -#define INST_DAA_INDEX 700 -#define INST_DAS_INDEX 704 -#define INST_DEC_INDEX 708 -#define INST_DIV_INDEX 712 -#define INST_DIVPD_INDEX 716 -#define INST_DIVPS_INDEX 722 -#define INST_DIVSD_INDEX 728 -#define INST_DIVSS_INDEX 734 -#define INST_DPPD_INDEX 740 -#define INST_DPPS_INDEX 745 -#define INST_EMMS_INDEX 750 -#define INST_ENTER_INDEX 755 -#define INST_EXTRACTPS_INDEX 761 -#define INST_F2XM1_INDEX 771 -#define INST_FABS_INDEX 777 -#define INST_FADD_INDEX 782 -#define INST_FADDP_INDEX 787 -#define INST_FBLD_INDEX 793 -#define INST_FBSTP_INDEX 798 -#define INST_FCHS_INDEX 804 -#define INST_FCLEX_INDEX 809 -#define INST_FCMOVB_INDEX 815 -#define INST_FCMOVBE_INDEX 822 -#define INST_FCMOVE_INDEX 830 -#define INST_FCMOVNB_INDEX 837 -#define INST_FCMOVNBE_INDEX 845 -#define INST_FCMOVNE_INDEX 854 -#define INST_FCMOVNU_INDEX 862 -#define INST_FCMOVU_INDEX 870 -#define INST_FCOM_INDEX 877 -#define INST_FCOMI_INDEX 882 -#define INST_FCOMIP_INDEX 888 -#define INST_FCOMP_INDEX 895 -#define INST_FCOMPP_INDEX 901 -#define INST_FCOS_INDEX 908 -#define INST_FDECSTP_INDEX 913 -#define INST_FDIV_INDEX 921 -#define INST_FDIVP_INDEX 926 -#define INST_FDIVR_INDEX 932 -#define INST_FDIVRP_INDEX 938 -#define INST_FEMMS_INDEX 945 -#define INST_FFREE_INDEX 951 -#define INST_FIADD_INDEX 957 -#define INST_FICOM_INDEX 963 -#define INST_FICOMP_INDEX 969 -#define INST_FIDIV_INDEX 976 -#define INST_FIDIVR_INDEX 982 -#define INST_FILD_INDEX 989 -#define INST_FIMUL_INDEX 994 -#define INST_FINCSTP_INDEX 1000 -#define INST_FINIT_INDEX 1008 -#define INST_FIST_INDEX 1014 -#define INST_FISTP_INDEX 1019 -#define INST_FISTTP_INDEX 1025 -#define INST_FISUB_INDEX 1032 -#define INST_FISUBR_INDEX 1038 -#define INST_FLD_INDEX 1045 -#define INST_FLD1_INDEX 1049 -#define INST_FLDCW_INDEX 1054 -#define INST_FLDENV_INDEX 1060 -#define INST_FLDL2E_INDEX 1067 -#define INST_FLDL2T_INDEX 1074 -#define INST_FLDLG2_INDEX 1081 -#define INST_FLDLN2_INDEX 1088 -#define INST_FLDPI_INDEX 1095 -#define INST_FLDZ_INDEX 1101 -#define INST_FMUL_INDEX 1106 -#define INST_FMULP_INDEX 1111 -#define INST_FNCLEX_INDEX 1117 -#define INST_FNINIT_INDEX 1124 -#define INST_FNOP_INDEX 1131 -#define INST_FNSAVE_INDEX 1136 -#define INST_FNSTCW_INDEX 1143 -#define INST_FNSTENV_INDEX 1150 -#define INST_FNSTSW_INDEX 1158 -#define INST_FPATAN_INDEX 1165 -#define INST_FPREM_INDEX 1172 -#define INST_FPREM1_INDEX 1178 -#define INST_FPTAN_INDEX 1185 -#define INST_FRNDINT_INDEX 1191 -#define INST_FRSTOR_INDEX 1199 -#define INST_FSAVE_INDEX 1206 -#define INST_FSCALE_INDEX 1212 -#define INST_FSIN_INDEX 1219 -#define INST_FSINCOS_INDEX 1224 -#define INST_FSQRT_INDEX 1232 -#define INST_FST_INDEX 1238 -#define INST_FSTCW_INDEX 1242 -#define INST_FSTENV_INDEX 1248 -#define INST_FSTP_INDEX 1255 -#define INST_FSTSW_INDEX 1260 -#define INST_FSUB_INDEX 1266 -#define INST_FSUBP_INDEX 1271 -#define INST_FSUBR_INDEX 1277 -#define INST_FSUBRP_INDEX 1283 -#define INST_FTST_INDEX 1290 -#define INST_FUCOM_INDEX 1295 -#define INST_FUCOMI_INDEX 1301 -#define INST_FUCOMIP_INDEX 1308 -#define INST_FUCOMP_INDEX 1316 -#define INST_FUCOMPP_INDEX 1323 -#define INST_FWAIT_INDEX 1331 -#define INST_FXAM_INDEX 1337 -#define INST_FXCH_INDEX 1342 -#define INST_FXRSTOR_INDEX 1347 -#define INST_FXSAVE_INDEX 1355 -#define INST_FXTRACT_INDEX 1362 -#define INST_FYL2X_INDEX 1370 -#define INST_FYL2XP1_INDEX 1376 -#define INST_HADDPD_INDEX 1384 -#define INST_HADDPS_INDEX 1391 -#define INST_HSUBPD_INDEX 1398 -#define INST_HSUBPS_INDEX 1405 -#define INST_IDIV_INDEX 1412 -#define INST_IMUL_INDEX 1417 -#define INST_INC_INDEX 1422 -#define INST_INT3_INDEX 1426 -#define INST_JA_INDEX 1431 -#define INST_JAE_INDEX 1434 -#define INST_JB_INDEX 1438 -#define INST_JBE_INDEX 1441 -#define INST_JC_INDEX 1445 -#define INST_JE_INDEX 1448 -#define INST_JG_INDEX 1451 -#define INST_JGE_INDEX 1454 -#define INST_JL_INDEX 1458 -#define INST_JLE_INDEX 1461 -#define INST_JNA_INDEX 1465 -#define INST_JNAE_INDEX 1469 -#define INST_JNB_INDEX 1474 -#define INST_JNBE_INDEX 1478 -#define INST_JNC_INDEX 1483 -#define INST_JNE_INDEX 1487 -#define INST_JNG_INDEX 1491 -#define INST_JNGE_INDEX 1495 -#define INST_JNL_INDEX 1500 -#define INST_JNLE_INDEX 1504 -#define INST_JNO_INDEX 1509 -#define INST_JNP_INDEX 1513 -#define INST_JNS_INDEX 1517 -#define INST_JNZ_INDEX 1521 -#define INST_JO_INDEX 1525 -#define INST_JP_INDEX 1528 -#define INST_JPE_INDEX 1531 -#define INST_JPO_INDEX 1535 -#define INST_JS_INDEX 1539 -#define INST_JZ_INDEX 1542 -#define INST_JMP_INDEX 1545 -#define INST_LDDQU_INDEX 1549 -#define INST_LDMXCSR_INDEX 1555 -#define INST_LAHF_INDEX 1563 -#define INST_LEA_INDEX 1568 -#define INST_LEAVE_INDEX 1572 -#define INST_LFENCE_INDEX 1578 -#define INST_MASKMOVDQU_INDEX 1585 -#define INST_MASKMOVQ_INDEX 1596 -#define INST_MAXPD_INDEX 1605 -#define INST_MAXPS_INDEX 1611 -#define INST_MAXSD_INDEX 1617 -#define INST_MAXSS_INDEX 1623 -#define INST_MFENCE_INDEX 1629 -#define INST_MINPD_INDEX 1636 -#define INST_MINPS_INDEX 1642 -#define INST_MINSD_INDEX 1648 -#define INST_MINSS_INDEX 1654 -#define INST_MONITOR_INDEX 1660 -#define INST_MOV_INDEX 1668 -#define INST_MOVAPD_INDEX 1672 -#define INST_MOVAPS_INDEX 1679 -#define INST_MOVBE_INDEX 1686 -#define INST_MOVD_INDEX 1692 -#define INST_MOVDDUP_INDEX 1697 -#define INST_MOVDQ2Q_INDEX 1705 -#define INST_MOVDQA_INDEX 1713 -#define INST_MOVDQU_INDEX 1720 -#define INST_MOVHLPS_INDEX 1727 -#define INST_MOVHPD_INDEX 1735 -#define INST_MOVHPS_INDEX 1742 -#define INST_MOVLHPS_INDEX 1749 -#define INST_MOVLPD_INDEX 1757 -#define INST_MOVLPS_INDEX 1764 -#define INST_MOVMSKPD_INDEX 1771 -#define INST_MOVMSKPS_INDEX 1780 -#define INST_MOVNTDQ_INDEX 1789 -#define INST_MOVNTDQA_INDEX 1797 -#define INST_MOVNTI_INDEX 1806 -#define INST_MOVNTPD_INDEX 1813 -#define INST_MOVNTPS_INDEX 1821 -#define INST_MOVNTQ_INDEX 1829 -#define INST_MOVQ_INDEX 1836 -#define INST_MOVQ2DQ_INDEX 1841 -#define INST_MOVSD_INDEX 1849 -#define INST_MOVSHDUP_INDEX 1855 -#define INST_MOVSLDUP_INDEX 1864 -#define INST_MOVSS_INDEX 1873 -#define INST_MOVSX_INDEX 1879 -#define INST_MOVSXD_INDEX 1885 -#define INST_MOVUPD_INDEX 1892 -#define INST_MOVUPS_INDEX 1899 -#define INST_MOVZX_INDEX 1906 -#define INST_MOV_PTR_INDEX 1912 -#define INST_MPSADBW_INDEX 1920 -#define INST_MUL_INDEX 1928 -#define INST_MULPD_INDEX 1932 -#define INST_MULPS_INDEX 1938 -#define INST_MULSD_INDEX 1944 -#define INST_MULSS_INDEX 1950 -#define INST_MWAIT_INDEX 1956 -#define INST_NEG_INDEX 1962 -#define INST_NOP_INDEX 1966 -#define INST_NOT_INDEX 1970 -#define INST_OR_INDEX 1974 -#define INST_ORPD_INDEX 1977 -#define INST_ORPS_INDEX 1982 -#define INST_PABSB_INDEX 1987 -#define INST_PABSD_INDEX 1993 -#define INST_PABSW_INDEX 1999 -#define INST_PACKSSDW_INDEX 2005 -#define INST_PACKSSWB_INDEX 2014 -#define INST_PACKUSDW_INDEX 2023 -#define INST_PACKUSWB_INDEX 2032 -#define INST_PADDB_INDEX 2041 -#define INST_PADDD_INDEX 2047 -#define INST_PADDQ_INDEX 2053 -#define INST_PADDSB_INDEX 2059 -#define INST_PADDSW_INDEX 2066 -#define INST_PADDUSB_INDEX 2073 -#define INST_PADDUSW_INDEX 2081 -#define INST_PADDW_INDEX 2089 -#define INST_PALIGNR_INDEX 2095 -#define INST_PAND_INDEX 2103 -#define INST_PANDN_INDEX 2108 -#define INST_PAUSE_INDEX 2114 -#define INST_PAVGB_INDEX 2120 -#define INST_PAVGW_INDEX 2126 -#define INST_PBLENDVB_INDEX 2132 -#define INST_PBLENDW_INDEX 2141 -#define INST_PCMPEQB_INDEX 2149 -#define INST_PCMPEQD_INDEX 2157 -#define INST_PCMPEQQ_INDEX 2165 -#define INST_PCMPEQW_INDEX 2173 -#define INST_PCMPESTRI_INDEX 2181 -#define INST_PCMPESTRM_INDEX 2191 -#define INST_PCMPGTB_INDEX 2201 -#define INST_PCMPGTD_INDEX 2209 -#define INST_PCMPGTQ_INDEX 2217 -#define INST_PCMPGTW_INDEX 2225 -#define INST_PCMPISTRI_INDEX 2233 -#define INST_PCMPISTRM_INDEX 2243 -#define INST_PEXTRB_INDEX 2253 -#define INST_PEXTRD_INDEX 2260 -#define INST_PEXTRQ_INDEX 2267 -#define INST_PEXTRW_INDEX 2274 -#define INST_PF2ID_INDEX 2281 -#define INST_PF2IW_INDEX 2287 -#define INST_PFACC_INDEX 2293 -#define INST_PFADD_INDEX 2299 -#define INST_PFCMPEQ_INDEX 2305 -#define INST_PFCMPGE_INDEX 2313 -#define INST_PFCMPGT_INDEX 2321 -#define INST_PFMAX_INDEX 2329 -#define INST_PFMIN_INDEX 2335 -#define INST_PFMUL_INDEX 2341 -#define INST_PFNACC_INDEX 2347 -#define INST_PFPNACC_INDEX 2354 -#define INST_PFRCP_INDEX 2362 -#define INST_PFRCPIT1_INDEX 2368 -#define INST_PFRCPIT2_INDEX 2377 -#define INST_PFRSQIT1_INDEX 2386 -#define INST_PFRSQRT_INDEX 2395 -#define INST_PFSUB_INDEX 2403 -#define INST_PFSUBR_INDEX 2409 -#define INST_PHADDD_INDEX 2416 -#define INST_PHADDSW_INDEX 2423 -#define INST_PHADDW_INDEX 2431 -#define INST_PHMINPOSUW_INDEX 2438 -#define INST_PHSUBD_INDEX 2449 -#define INST_PHSUBSW_INDEX 2456 -#define INST_PHSUBW_INDEX 2464 -#define INST_PI2FD_INDEX 2471 -#define INST_PI2FW_INDEX 2477 -#define INST_PINSRB_INDEX 2483 -#define INST_PINSRD_INDEX 2490 -#define INST_PINSRQ_INDEX 2497 -#define INST_PINSRW_INDEX 2504 -#define INST_PMADDUBSW_INDEX 2511 -#define INST_PMADDWD_INDEX 2521 -#define INST_PMAXSB_INDEX 2529 -#define INST_PMAXSD_INDEX 2536 -#define INST_PMAXSW_INDEX 2543 -#define INST_PMAXUB_INDEX 2550 -#define INST_PMAXUD_INDEX 2557 -#define INST_PMAXUW_INDEX 2564 -#define INST_PMINSB_INDEX 2571 -#define INST_PMINSD_INDEX 2578 -#define INST_PMINSW_INDEX 2585 -#define INST_PMINUB_INDEX 2592 -#define INST_PMINUD_INDEX 2599 -#define INST_PMINUW_INDEX 2606 -#define INST_PMOVMSKB_INDEX 2613 -#define INST_PMOVSXBD_INDEX 2622 -#define INST_PMOVSXBQ_INDEX 2631 -#define INST_PMOVSXBW_INDEX 2640 -#define INST_PMOVSXDQ_INDEX 2649 -#define INST_PMOVSXWD_INDEX 2658 -#define INST_PMOVSXWQ_INDEX 2667 -#define INST_PMOVZXBD_INDEX 2676 -#define INST_PMOVZXBQ_INDEX 2685 -#define INST_PMOVZXBW_INDEX 2694 -#define INST_PMOVZXDQ_INDEX 2703 -#define INST_PMOVZXWD_INDEX 2712 -#define INST_PMOVZXWQ_INDEX 2721 -#define INST_PMULDQ_INDEX 2730 -#define INST_PMULHRSW_INDEX 2737 -#define INST_PMULHUW_INDEX 2746 -#define INST_PMULHW_INDEX 2754 -#define INST_PMULLD_INDEX 2761 -#define INST_PMULLW_INDEX 2768 -#define INST_PMULUDQ_INDEX 2775 -#define INST_POP_INDEX 2783 -#define INST_POPAD_INDEX 2787 -#define INST_POPCNT_INDEX 2793 -#define INST_POPFD_INDEX 2800 -#define INST_POPFQ_INDEX 2806 -#define INST_POR_INDEX 2812 -#define INST_PREFETCH_INDEX 2816 -#define INST_PSADBW_INDEX 2825 -#define INST_PSHUFB_INDEX 2832 -#define INST_PSHUFD_INDEX 2839 -#define INST_PSHUFW_INDEX 2846 -#define INST_PSHUFHW_INDEX 2853 -#define INST_PSHUFLW_INDEX 2861 -#define INST_PSIGNB_INDEX 2869 -#define INST_PSIGND_INDEX 2876 -#define INST_PSIGNW_INDEX 2883 -#define INST_PSLLD_INDEX 2890 -#define INST_PSLLDQ_INDEX 2896 -#define INST_PSLLQ_INDEX 2903 -#define INST_PSLLW_INDEX 2909 -#define INST_PSRAD_INDEX 2915 -#define INST_PSRAW_INDEX 2921 -#define INST_PSRLD_INDEX 2927 -#define INST_PSRLDQ_INDEX 2933 -#define INST_PSRLQ_INDEX 2940 -#define INST_PSRLW_INDEX 2946 -#define INST_PSUBB_INDEX 2952 -#define INST_PSUBD_INDEX 2958 -#define INST_PSUBQ_INDEX 2964 -#define INST_PSUBSB_INDEX 2970 -#define INST_PSUBSW_INDEX 2977 -#define INST_PSUBUSB_INDEX 2984 -#define INST_PSUBUSW_INDEX 2992 -#define INST_PSUBW_INDEX 3000 -#define INST_PSWAPD_INDEX 3006 -#define INST_PTEST_INDEX 3013 -#define INST_PUNPCKHBW_INDEX 3019 -#define INST_PUNPCKHDQ_INDEX 3029 -#define INST_PUNPCKHQDQ_INDEX 3039 -#define INST_PUNPCKHWD_INDEX 3050 -#define INST_PUNPCKLBW_INDEX 3060 -#define INST_PUNPCKLDQ_INDEX 3070 -#define INST_PUNPCKLQDQ_INDEX 3080 -#define INST_PUNPCKLWD_INDEX 3091 -#define INST_PUSH_INDEX 3101 -#define INST_PUSHAD_INDEX 3106 -#define INST_PUSHFD_INDEX 3113 -#define INST_PUSHFQ_INDEX 3120 -#define INST_PXOR_INDEX 3127 -#define INST_RCL_INDEX 3132 -#define INST_RCPPS_INDEX 3136 -#define INST_RCPSS_INDEX 3142 -#define INST_RCR_INDEX 3148 -#define INST_RDTSC_INDEX 3152 -#define INST_RDTSCP_INDEX 3158 -#define INST_REP_LODSB_INDEX 3165 -#define INST_REP_LODSD_INDEX 3175 -#define INST_REP_LODSQ_INDEX 3185 -#define INST_REP_LODSW_INDEX 3195 -#define INST_REP_MOVSB_INDEX 3205 -#define INST_REP_MOVSD_INDEX 3215 -#define INST_REP_MOVSQ_INDEX 3225 -#define INST_REP_MOVSW_INDEX 3235 -#define INST_REP_STOSB_INDEX 3245 -#define INST_REP_STOSD_INDEX 3255 -#define INST_REP_STOSQ_INDEX 3265 -#define INST_REP_STOSW_INDEX 3275 -#define INST_REPE_CMPSB_INDEX 3285 -#define INST_REPE_CMPSD_INDEX 3296 -#define INST_REPE_CMPSQ_INDEX 3307 -#define INST_REPE_CMPSW_INDEX 3318 -#define INST_REPE_SCASB_INDEX 3329 -#define INST_REPE_SCASD_INDEX 3340 -#define INST_REPE_SCASQ_INDEX 3351 -#define INST_REPE_SCASW_INDEX 3362 -#define INST_REPNE_CMPSB_INDEX 3373 -#define INST_REPNE_CMPSD_INDEX 3385 -#define INST_REPNE_CMPSQ_INDEX 3397 -#define INST_REPNE_CMPSW_INDEX 3409 -#define INST_REPNE_SCASB_INDEX 3421 -#define INST_REPNE_SCASD_INDEX 3433 -#define INST_REPNE_SCASQ_INDEX 3445 -#define INST_REPNE_SCASW_INDEX 3457 -#define INST_RET_INDEX 3469 -#define INST_ROL_INDEX 3473 -#define INST_ROR_INDEX 3477 -#define INST_ROUNDPD_INDEX 3481 -#define INST_ROUNDPS_INDEX 3489 -#define INST_ROUNDSD_INDEX 3497 -#define INST_ROUNDSS_INDEX 3505 -#define INST_RSQRTPS_INDEX 3513 -#define INST_RSQRTSS_INDEX 3521 -#define INST_SAHF_INDEX 3529 -#define INST_SAL_INDEX 3534 -#define INST_SAR_INDEX 3538 -#define INST_SBB_INDEX 3542 -#define INST_SETA_INDEX 3546 -#define INST_SETAE_INDEX 3551 -#define INST_SETB_INDEX 3557 -#define INST_SETBE_INDEX 3562 -#define INST_SETC_INDEX 3568 -#define INST_SETE_INDEX 3573 -#define INST_SETG_INDEX 3578 -#define INST_SETGE_INDEX 3583 -#define INST_SETL_INDEX 3589 -#define INST_SETLE_INDEX 3594 -#define INST_SETNA_INDEX 3600 -#define INST_SETNAE_INDEX 3606 -#define INST_SETNB_INDEX 3613 -#define INST_SETNBE_INDEX 3619 -#define INST_SETNC_INDEX 3626 -#define INST_SETNE_INDEX 3632 -#define INST_SETNG_INDEX 3638 -#define INST_SETNGE_INDEX 3644 -#define INST_SETNL_INDEX 3651 -#define INST_SETNLE_INDEX 3657 -#define INST_SETNO_INDEX 3664 -#define INST_SETNP_INDEX 3670 -#define INST_SETNS_INDEX 3676 -#define INST_SETNZ_INDEX 3682 -#define INST_SETO_INDEX 3688 -#define INST_SETP_INDEX 3693 -#define INST_SETPE_INDEX 3698 -#define INST_SETPO_INDEX 3704 -#define INST_SETS_INDEX 3710 -#define INST_SETZ_INDEX 3715 -#define INST_SFENCE_INDEX 3720 -#define INST_SHL_INDEX 3727 -#define INST_SHLD_INDEX 3731 -#define INST_SHR_INDEX 3736 -#define INST_SHRD_INDEX 3740 -#define INST_SHUFPD_INDEX 3745 -#define INST_SHUFPS_INDEX 3752 -#define INST_SQRTPD_INDEX 3759 -#define INST_SQRTPS_INDEX 3766 -#define INST_SQRTSD_INDEX 3773 -#define INST_SQRTSS_INDEX 3780 -#define INST_STC_INDEX 3787 -#define INST_STD_INDEX 3791 -#define INST_STMXCSR_INDEX 3795 -#define INST_SUB_INDEX 3803 -#define INST_SUBPD_INDEX 3807 -#define INST_SUBPS_INDEX 3813 -#define INST_SUBSD_INDEX 3819 -#define INST_SUBSS_INDEX 3825 -#define INST_TEST_INDEX 3831 -#define INST_UCOMISD_INDEX 3836 -#define INST_UCOMISS_INDEX 3844 -#define INST_UD2_INDEX 3852 -#define INST_UNPCKHPD_INDEX 3856 -#define INST_UNPCKHPS_INDEX 3865 -#define INST_UNPCKLPD_INDEX 3874 -#define INST_UNPCKLPS_INDEX 3883 -#define INST_XADD_INDEX 3892 -#define INST_XCHG_INDEX 3897 -#define INST_XOR_INDEX 3902 -#define INST_XORPD_INDEX 3906 -#define INST_XORPS_INDEX 3912 -// ${INSTRUCTION_DATA_END} - -// ============================================================================ -// [AsmJit::Instruction Description] -// ============================================================================ - -#define MAKE_INST(code, name, group, flags, oflags0, oflags1, opReg, opCode0, opCode1) \ - { code, code##_INDEX, group, flags, { oflags0, oflags1 }, opReg, { opCode0, opCode1 } } - -#define G(g) InstructionDescription::G_##g -#define F(f) InstructionDescription::F_##f -#define O(o) InstructionDescription::O_##o - -const InstructionDescription instructionDescription[] = -{ - // Instruction code (enum) | instruction name | instruction group| instruction flags| oflags[0] | oflags[1] | r| opCode[0] | opcode[1] - MAKE_INST(INST_ADC , "adc" , G(ALU) , F(LOCKABLE) , O(GQDWB_MEM) , O(GQDWB_MEM)|O(IMM) , 2, 0x00000010, 0x00000080), - MAKE_INST(INST_ADD , "add" , G(ALU) , F(LOCKABLE) , O(GQDWB_MEM) , O(GQDWB_MEM)|O(IMM) , 0, 0x00000000, 0x00000080), - MAKE_INST(INST_ADDPD , "addpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F58, 0), - MAKE_INST(INST_ADDPS , "addps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F58, 0), - MAKE_INST(INST_ADDSD , "addsd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F58, 0), - MAKE_INST(INST_ADDSS , "addss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F58, 0), - MAKE_INST(INST_ADDSUBPD , "addsubpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000FD0, 0), - MAKE_INST(INST_ADDSUBPS , "addsubps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000FD0, 0), - MAKE_INST(INST_AMD_PREFETCH , "amd_prefetch" , G(M) , F(NONE) , O(MEM) , 0 , 0, 0x00000F0D, 0), - MAKE_INST(INST_AMD_PREFETCHW , "amd_prefetchw" , G(M) , F(NONE) , O(MEM) , 0 , 1, 0x00000F0D, 0), - MAKE_INST(INST_AND , "and" , G(ALU) , F(LOCKABLE) , O(GQDWB_MEM) , O(GQDWB_MEM)|O(IMM) , 4, 0x00000020, 0x00000080), - MAKE_INST(INST_ANDNPD , "andnpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F55, 0), - MAKE_INST(INST_ANDNPS , "andnps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F55, 0), - MAKE_INST(INST_ANDPD , "andpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F54, 0), - MAKE_INST(INST_ANDPS , "andps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F54, 0), - MAKE_INST(INST_BLENDPD , "blendpd" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A0D, 0), - MAKE_INST(INST_BLENDPS , "blendps" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A0C, 0), - MAKE_INST(INST_BLENDVPD , "blendvpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3815, 0), - MAKE_INST(INST_BLENDVPS , "blendvps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3814, 0), - MAKE_INST(INST_BSF , "bsf" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000FBC, 0), - MAKE_INST(INST_BSR , "bsr" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000FBD, 0), - MAKE_INST(INST_BSWAP , "bswap" , G(BSWAP) , F(NONE) , O(GQD) , 0 , 0, 0 , 0), - MAKE_INST(INST_BT , "bt" , G(BT) , F(NONE) , O(GQDW)|O(MEM) , O(GQDW)|O(IMM) , 4, 0x00000FA3, 0x00000FBA), - MAKE_INST(INST_BTC , "btc" , G(BT) , F(LOCKABLE) , O(GQDW)|O(MEM) , O(GQDW)|O(IMM) , 7, 0x00000FBB, 0x00000FBA), - MAKE_INST(INST_BTR , "btr" , G(BT) , F(LOCKABLE) , O(GQDW)|O(MEM) , O(GQDW)|O(IMM) , 6, 0x00000FB3, 0x00000FBA), - MAKE_INST(INST_BTS , "bts" , G(BT) , F(LOCKABLE) , O(GQDW)|O(MEM) , O(GQDW)|O(IMM) , 5, 0x00000FAB, 0x00000FBA), - MAKE_INST(INST_CALL , "call" , G(CALL) , F(JUMP) , O(GQD)|O(MEM) , 0 , 0, 0 , 0), - MAKE_INST(INST_CBW , "cbw" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x66000099, 0), - MAKE_INST(INST_CDQE , "cdqe" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x48000099, 0), - MAKE_INST(INST_CLC , "clc" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x000000F8, 0), - MAKE_INST(INST_CLD , "cld" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x000000FC, 0), - MAKE_INST(INST_CLFLUSH , "clflush" , G(M) , F(NONE) , O(MEM) , 0 , 7, 0x00000FAE, 0), - MAKE_INST(INST_CMC , "cmc" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x000000F5, 0), - MAKE_INST(INST_CMOVA , "cmova" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F47, 0), - MAKE_INST(INST_CMOVAE , "cmovae" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F43, 0), - MAKE_INST(INST_CMOVB , "cmovb" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F42, 0), - MAKE_INST(INST_CMOVBE , "cmovbe" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F46, 0), - MAKE_INST(INST_CMOVC , "cmovc" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F42, 0), - MAKE_INST(INST_CMOVE , "cmove" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F44, 0), - MAKE_INST(INST_CMOVG , "cmovg" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4F, 0), - MAKE_INST(INST_CMOVGE , "cmovge" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4D, 0), - MAKE_INST(INST_CMOVL , "cmovl" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4C, 0), - MAKE_INST(INST_CMOVLE , "cmovle" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4E, 0), - MAKE_INST(INST_CMOVNA , "cmovna" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F46, 0), - MAKE_INST(INST_CMOVNAE , "cmovnae" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F42, 0), - MAKE_INST(INST_CMOVNB , "cmovnb" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F43, 0), - MAKE_INST(INST_CMOVNBE , "cmovnbe" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F47, 0), - MAKE_INST(INST_CMOVNC , "cmovnc" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F43, 0), - MAKE_INST(INST_CMOVNE , "cmovne" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F45, 0), - MAKE_INST(INST_CMOVNG , "cmovng" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4E, 0), - MAKE_INST(INST_CMOVNGE , "cmovnge" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4C, 0), - MAKE_INST(INST_CMOVNL , "cmovnl" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4D, 0), - MAKE_INST(INST_CMOVNLE , "cmovnle" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4F, 0), - MAKE_INST(INST_CMOVNO , "cmovno" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F41, 0), - MAKE_INST(INST_CMOVNP , "cmovnp" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4B, 0), - MAKE_INST(INST_CMOVNS , "cmovns" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F49, 0), - MAKE_INST(INST_CMOVNZ , "cmovnz" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F45, 0), - MAKE_INST(INST_CMOVO , "cmovo" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F40, 0), - MAKE_INST(INST_CMOVP , "cmovp" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4A, 0), - MAKE_INST(INST_CMOVPE , "cmovpe" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4A, 0), - MAKE_INST(INST_CMOVPO , "cmovpo" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F4B, 0), - MAKE_INST(INST_CMOVS , "cmovs" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F48, 0), - MAKE_INST(INST_CMOVZ , "cmovz" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0x00000F44, 0), - MAKE_INST(INST_CMP , "cmp" , G(ALU) , F(NONE) , O(GQDWB_MEM) , O(GQDWB_MEM)|O(IMM) , 7, 0x00000038, 0x00000080), - MAKE_INST(INST_CMPPD , "cmppd" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000FC2, 0), - MAKE_INST(INST_CMPPS , "cmpps" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000FC2, 0), - MAKE_INST(INST_CMPSD , "cmpsd" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000FC2, 0), - MAKE_INST(INST_CMPSS , "cmpss" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF3000FC2, 0), - MAKE_INST(INST_CMPXCHG , "cmpxchg" , G(RM_R) , F(SPECIAL)|F(LOCKABLE), 0 , 0 , 0, 0x00000FB0, 0), - MAKE_INST(INST_CMPXCHG16B , "cmpxchg16b" , G(M) , F(SPECIAL) , O(MEM) , 0 , 1, 0x00000FC7, 1 /* RexW */), - MAKE_INST(INST_CMPXCHG8B , "cmpxchg8b" , G(M) , F(SPECIAL) , O(MEM) , 0 , 1, 0x00000FC7, 0), - MAKE_INST(INST_COMISD , "comisd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F2F, 0), - MAKE_INST(INST_COMISS , "comiss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F2F, 0), - MAKE_INST(INST_CPUID , "cpuid" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x00000FA2, 0), - MAKE_INST(INST_CRC32 , "crc32" , G(CRC32) , F(NONE) , O(GQD) , O(GQDWB_MEM) , 0, 0xF20F38F0, 0), - MAKE_INST(INST_CVTDQ2PD , "cvtdq2pd" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0xF3000FE6, 0), - MAKE_INST(INST_CVTDQ2PS , "cvtdq2ps" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x00000F5B, 0), - MAKE_INST(INST_CVTPD2DQ , "cvtpd2dq" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0xF2000FE6, 0), - MAKE_INST(INST_CVTPD2PI , "cvtpd2pi" , G(MMU_RMI) , F(MOV) , O(MM) , O(XMM_MEM) , 0, 0x66000F2D, 0), - MAKE_INST(INST_CVTPD2PS , "cvtpd2ps" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x66000F5A, 0), - MAKE_INST(INST_CVTPI2PD , "cvtpi2pd" , G(MMU_RMI) , F(MOV) , O(XMM) , O(MM_MEM) , 0, 0x66000F2A, 0), - MAKE_INST(INST_CVTPI2PS , "cvtpi2ps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(MM_MEM) , 0, 0x00000F2A, 0), - MAKE_INST(INST_CVTPS2DQ , "cvtps2dq" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x66000F5B, 0), - MAKE_INST(INST_CVTPS2PD , "cvtps2pd" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x00000F5A, 0), - MAKE_INST(INST_CVTPS2PI , "cvtps2pi" , G(MMU_RMI) , F(MOV) , O(MM) , O(XMM_MEM) , 0, 0x00000F2D, 0), - MAKE_INST(INST_CVTSD2SI , "cvtsd2si" , G(MMU_RMI) , F(MOV) , O(GQD) , O(XMM_MEM) , 0, 0xF2000F2D, 0), - MAKE_INST(INST_CVTSD2SS , "cvtsd2ss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F5A, 0), - MAKE_INST(INST_CVTSI2SD , "cvtsi2sd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(GQD)|O(MEM) , 0, 0xF2000F2A, 0), - MAKE_INST(INST_CVTSI2SS , "cvtsi2ss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(GQD)|O(MEM) , 0, 0xF3000F2A, 0), - MAKE_INST(INST_CVTSS2SD , "cvtss2sd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F5A, 0), - MAKE_INST(INST_CVTSS2SI , "cvtss2si" , G(MMU_RMI) , F(NONE) , O(GQD) , O(XMM_MEM) , 0, 0xF3000F2D, 0), - MAKE_INST(INST_CVTTPD2DQ , "cvttpd2dq" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x66000FE6, 0), - MAKE_INST(INST_CVTTPD2PI , "cvttpd2pi" , G(MMU_RMI) , F(MOV) , O(MM) , O(XMM_MEM) , 0, 0x66000F2C, 0), - MAKE_INST(INST_CVTTPS2DQ , "cvttps2dq" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F5B, 0), - MAKE_INST(INST_CVTTPS2PI , "cvttps2pi" , G(MMU_RMI) , F(MOV) , O(MM) , O(XMM_MEM) , 0, 0x00000F2C, 0), - MAKE_INST(INST_CVTTSD2SI , "cvttsd2si" , G(MMU_RMI) , F(NONE) , O(GQD) , O(XMM_MEM) , 0, 0xF2000F2C, 0), - MAKE_INST(INST_CVTTSS2SI , "cvttss2si" , G(MMU_RMI) , F(NONE) , O(GQD) , O(XMM_MEM) , 0, 0xF3000F2C, 0), - MAKE_INST(INST_CWDE , "cwde" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x00000099, 0), - MAKE_INST(INST_DAA , "daa" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x00000027, 0), - MAKE_INST(INST_DAS , "das" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x0000002F, 0), - MAKE_INST(INST_DEC , "dec" , G(INC_DEC) , F(LOCKABLE) , O(GQDWB_MEM) , 0 , 1, 0x00000048, 0x000000FE), - MAKE_INST(INST_DIV , "div" , G(RM) , F(SPECIAL) , 0 , 0 , 6, 0x000000F6, 0), - MAKE_INST(INST_DIVPD , "divpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F5E, 0), - MAKE_INST(INST_DIVPS , "divps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F5E, 0), - MAKE_INST(INST_DIVSD , "divsd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F5E, 0), - MAKE_INST(INST_DIVSS , "divss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F5E, 0), - MAKE_INST(INST_DPPD , "dppd" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A41, 0), - MAKE_INST(INST_DPPS , "dpps" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A40, 0), - MAKE_INST(INST_EMMS , "emms" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x00000F77, 0), - MAKE_INST(INST_ENTER , "enter" , G(ENTER) , F(SPECIAL) , 0 , 0 , 0, 0x000000C8, 0), - MAKE_INST(INST_EXTRACTPS , "extractps" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A17, 0), - MAKE_INST(INST_F2XM1 , "f2xm1" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9F0, 0), - MAKE_INST(INST_FABS , "fabs" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9E1, 0), - MAKE_INST(INST_FADD , "fadd" , G(X87_FPU) , F(FPU) , 0 , 0 , 0, 0xD8DCC0C0, 0), - MAKE_INST(INST_FADDP , "faddp" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DEC0, 0), - MAKE_INST(INST_FBLD , "fbld" , G(M) , F(FPU) , O(MEM) , 0 , 4, 0x000000DF, 0), - MAKE_INST(INST_FBSTP , "fbstp" , G(M) , F(FPU) , O(MEM) , 0 , 6, 0x000000DF, 0), - MAKE_INST(INST_FCHS , "fchs" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9E0, 0), - MAKE_INST(INST_FCLEX , "fclex" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x9B00DBE2, 0), - MAKE_INST(INST_FCMOVB , "fcmovb" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DAC0, 0), - MAKE_INST(INST_FCMOVBE , "fcmovbe" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DAD0, 0), - MAKE_INST(INST_FCMOVE , "fcmove" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DAC8, 0), - MAKE_INST(INST_FCMOVNB , "fcmovnb" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DBC0, 0), - MAKE_INST(INST_FCMOVNBE , "fcmovnbe" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DBD0, 0), - MAKE_INST(INST_FCMOVNE , "fcmovne" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DBC8, 0), - MAKE_INST(INST_FCMOVNU , "fcmovnu" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DBD8, 0), - MAKE_INST(INST_FCMOVU , "fcmovu" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DAD8, 0), - MAKE_INST(INST_FCOM , "fcom" , G(X87_FPU) , F(FPU) , 0 , 0 , 2, 0xD8DCD0D0, 0), - MAKE_INST(INST_FCOMI , "fcomi" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DBF0, 0), - MAKE_INST(INST_FCOMIP , "fcomip" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DFF0, 0), - MAKE_INST(INST_FCOMP , "fcomp" , G(X87_FPU) , F(FPU) , 0 , 0 , 3, 0xD8DCD8D8, 0), - MAKE_INST(INST_FCOMPP , "fcompp" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000DED9, 0), - MAKE_INST(INST_FCOS , "fcos" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9FF, 0), - MAKE_INST(INST_FDECSTP , "fdecstp" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9F6, 0), - MAKE_INST(INST_FDIV , "fdiv" , G(X87_FPU) , F(FPU) , 0 , 0 , 6, 0xD8DCF0F8, 0), - MAKE_INST(INST_FDIVP , "fdivp" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DEF8, 0), - MAKE_INST(INST_FDIVR , "fdivr" , G(X87_FPU) , F(FPU) , 0 , 0 , 7, 0xD8DCF8F0, 0), - MAKE_INST(INST_FDIVRP , "fdivrp" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DEF0, 0), - MAKE_INST(INST_FEMMS , "femms" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x00000F0E, 0), - MAKE_INST(INST_FFREE , "ffree" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DDC0, 0), - MAKE_INST(INST_FIADD , "fiadd" , G(X87_MEM) , F(FPU) , O(FM_2_4) , 0 , 0, 0xDEDA0000, 0), - MAKE_INST(INST_FICOM , "ficom" , G(X87_MEM) , F(FPU) , O(FM_2_4) , 0 , 2, 0xDEDA0000, 0), - MAKE_INST(INST_FICOMP , "ficomp" , G(X87_MEM) , F(FPU) , O(FM_2_4) , 0 , 3, 0xDEDA0000, 0), - MAKE_INST(INST_FIDIV , "fidiv" , G(X87_MEM) , F(FPU) , O(FM_2_4) , 0 , 6, 0xDEDA0000, 0), - MAKE_INST(INST_FIDIVR , "fidivr" , G(X87_MEM) , F(FPU) , O(FM_2_4) , 0 , 7, 0xDEDA0000, 0), - MAKE_INST(INST_FILD , "fild" , G(X87_MEM) , F(FPU) , O(FM_2_4_8) , 0 , 0, 0xDFDBDF05, 0), - MAKE_INST(INST_FIMUL , "fimul" , G(X87_MEM) , F(FPU) , O(FM_2_4) , 0 , 1, 0xDEDA0000, 0), - MAKE_INST(INST_FINCSTP , "fincstp" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9F7, 0), - MAKE_INST(INST_FINIT , "finit" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x9B00DBE3, 0), - MAKE_INST(INST_FIST , "fist" , G(X87_MEM) , F(FPU) , O(FM_2_4) , 0 , 2, 0xDFDB0000, 0), - MAKE_INST(INST_FISTP , "fistp" , G(X87_MEM) , F(FPU) , O(FM_2_4_8) , 0 , 3, 0xDFDBDF07, 0), - MAKE_INST(INST_FISTTP , "fisttp" , G(X87_MEM) , F(FPU) , O(FM_2_4_8) , 0 , 1, 0xDFDBDD01, 0), - MAKE_INST(INST_FISUB , "fisub" , G(X87_MEM) , F(FPU) , O(FM_2_4) , 0 , 4, 0xDEDA0000, 0), - MAKE_INST(INST_FISUBR , "fisubr" , G(X87_MEM) , F(FPU) , O(FM_2_4) , 0 , 5, 0xDEDA0000, 0), - MAKE_INST(INST_FLD , "fld" , G(X87_MEM_STI) , F(FPU) , O(FM_4_8_10) , 0 , 0, 0x00D9DD00, 0xD9C0DB05), - MAKE_INST(INST_FLD1 , "fld1" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9E8, 0), - MAKE_INST(INST_FLDCW , "fldcw" , G(M) , F(FPU) , O(MEM) , 0 , 5, 0x000000D9, 0), - MAKE_INST(INST_FLDENV , "fldenv" , G(M) , F(FPU) , O(MEM) , 0 , 4, 0x000000D9, 0), - MAKE_INST(INST_FLDL2E , "fldl2e" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9EA, 0), - MAKE_INST(INST_FLDL2T , "fldl2t" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9E9, 0), - MAKE_INST(INST_FLDLG2 , "fldlg2" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9EC, 0), - MAKE_INST(INST_FLDLN2 , "fldln2" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9ED, 0), - MAKE_INST(INST_FLDPI , "fldpi" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9EB, 0), - MAKE_INST(INST_FLDZ , "fldz" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9EE, 0), - MAKE_INST(INST_FMUL , "fmul" , G(X87_FPU) , F(FPU) , 0 , 0 , 1, 0xD8DCC8C8, 0), - MAKE_INST(INST_FMULP , "fmulp" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DEC8, 0), - MAKE_INST(INST_FNCLEX , "fnclex" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000DBE2, 0), - MAKE_INST(INST_FNINIT , "fninit" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000DBE3, 0), - MAKE_INST(INST_FNOP , "fnop" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9D0, 0), - MAKE_INST(INST_FNSAVE , "fnsave" , G(M) , F(FPU) , O(MEM) , 0 , 6, 0x000000DD, 0), - MAKE_INST(INST_FNSTCW , "fnstcw" , G(M) , F(FPU) , O(MEM) , 0 , 7, 0x000000D9, 0), - MAKE_INST(INST_FNSTENV , "fnstenv" , G(M) , F(FPU) , O(MEM) , 0 , 6, 0x000000D9, 0), - MAKE_INST(INST_FNSTSW , "fnstsw" , G(X87_FSTSW) , F(FPU) , O(MEM) , 0 , 7, 0x000000DD, 0x0000DFE0), - MAKE_INST(INST_FPATAN , "fpatan" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9F3, 0), - MAKE_INST(INST_FPREM , "fprem" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9F8, 0), - MAKE_INST(INST_FPREM1 , "fprem1" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9F5, 0), - MAKE_INST(INST_FPTAN , "fptan" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9F2, 0), - MAKE_INST(INST_FRNDINT , "frndint" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9FC, 0), - MAKE_INST(INST_FRSTOR , "frstor" , G(M) , F(FPU) , O(MEM) , 0 , 4, 0x000000DD, 0), - MAKE_INST(INST_FSAVE , "fsave" , G(M) , F(FPU) , O(MEM) , 0 , 6, 0x9B0000DD, 0), - MAKE_INST(INST_FSCALE , "fscale" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9FD, 0), - MAKE_INST(INST_FSIN , "fsin" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9FE, 0), - MAKE_INST(INST_FSINCOS , "fsincos" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9FB, 0), - MAKE_INST(INST_FSQRT , "fsqrt" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9FA, 0), - MAKE_INST(INST_FST , "fst" , G(X87_MEM_STI) , F(FPU) , O(FM_4_8) , 0 , 2, 0x00D9DD02, 0xDDD00000), - MAKE_INST(INST_FSTCW , "fstcw" , G(M) , F(FPU) , O(MEM) , 0 , 7, 0x9B0000D9, 0), - MAKE_INST(INST_FSTENV , "fstenv" , G(M) , F(FPU) , O(MEM) , 0 , 6, 0x9B0000D9, 0), - MAKE_INST(INST_FSTP , "fstp" , G(X87_MEM_STI) , F(FPU) , O(FM_4_8_10) , 0 , 3, 0x00D9DD03, 0xDDD8DB07), - MAKE_INST(INST_FSTSW , "fstsw" , G(X87_FSTSW) , F(FPU) , O(MEM) , 0 , 7, 0x9B0000DD, 0x9B00DFE0), - MAKE_INST(INST_FSUB , "fsub" , G(X87_FPU) , F(FPU) , 0 , 0 , 4, 0xD8DCE0E8, 0), - MAKE_INST(INST_FSUBP , "fsubp" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DEE8, 0), - MAKE_INST(INST_FSUBR , "fsubr" , G(X87_FPU) , F(FPU) , 0 , 0 , 5, 0xD8DCE8E0, 0), - MAKE_INST(INST_FSUBRP , "fsubrp" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DEE0, 0), - MAKE_INST(INST_FTST , "ftst" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9E4, 0), - MAKE_INST(INST_FUCOM , "fucom" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DDE0, 0), - MAKE_INST(INST_FUCOMI , "fucomi" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DBE8, 0), - MAKE_INST(INST_FUCOMIP , "fucomip" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DFE8, 0), - MAKE_INST(INST_FUCOMP , "fucomp" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000DDE8, 0), - MAKE_INST(INST_FUCOMPP , "fucompp" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000DAE9, 0), - MAKE_INST(INST_FWAIT , "fwait" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x000000DB, 0), - MAKE_INST(INST_FXAM , "fxam" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9E5, 0), - MAKE_INST(INST_FXCH , "fxch" , G(X87_STI) , F(FPU) , 0 , 0 , 0, 0x0000D9C8, 0), - MAKE_INST(INST_FXRSTOR , "fxrstor" , G(M) , F(FPU) , 0 , 0 , 1, 0x00000FAE, 0), - MAKE_INST(INST_FXSAVE , "fxsave" , G(M) , F(FPU) , 0 , 0 , 0, 0x00000FAE, 0), - MAKE_INST(INST_FXTRACT , "fxtract" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9F4, 0), - MAKE_INST(INST_FYL2X , "fyl2x" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9F1, 0), - MAKE_INST(INST_FYL2XP1 , "fyl2xp1" , G(EMIT) , F(FPU) , 0 , 0 , 0, 0x0000D9F9, 0), - MAKE_INST(INST_HADDPD , "haddpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F7C, 0), - MAKE_INST(INST_HADDPS , "haddps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F7C, 0), - MAKE_INST(INST_HSUBPD , "hsubpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F7D, 0), - MAKE_INST(INST_HSUBPS , "hsubps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F7D, 0), - MAKE_INST(INST_IDIV , "idiv" , G(RM) , F(SPECIAL) , 0 , 0 , 7, 0x000000F6, 0), - MAKE_INST(INST_IMUL , "imul" , G(IMUL) , F(SPECIAL) , 0 , 0 , 0, 0 , 0), - MAKE_INST(INST_INC , "inc" , G(INC_DEC) , F(LOCKABLE) , O(GQDWB_MEM) , 0 , 0, 0x00000040, 0x000000FE), - MAKE_INST(INST_INT3 , "int3" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x000000CC, 0), - MAKE_INST(INST_JA , "ja" , G(J) , F(JUMP) , 0 , 0 , 0, 0x7 , 0), - MAKE_INST(INST_JAE , "jae" , G(J) , F(JUMP) , 0 , 0 , 0, 0x3 , 0), - MAKE_INST(INST_JB , "jb" , G(J) , F(JUMP) , 0 , 0 , 0, 0x2 , 0), - MAKE_INST(INST_JBE , "jbe" , G(J) , F(JUMP) , 0 , 0 , 0, 0x6 , 0), - MAKE_INST(INST_JC , "jc" , G(J) , F(JUMP) , 0 , 0 , 0, 0x2 , 0), - MAKE_INST(INST_JE , "je" , G(J) , F(JUMP) , 0 , 0 , 0, 0x4 , 0), - MAKE_INST(INST_JG , "jg" , G(J) , F(JUMP) , 0 , 0 , 0, 0xF , 0), - MAKE_INST(INST_JGE , "jge" , G(J) , F(JUMP) , 0 , 0 , 0, 0xD , 0), - MAKE_INST(INST_JL , "jl" , G(J) , F(JUMP) , 0 , 0 , 0, 0xC , 0), - MAKE_INST(INST_JLE , "jle" , G(J) , F(JUMP) , 0 , 0 , 0, 0xE , 0), - MAKE_INST(INST_JNA , "jna" , G(J) , F(JUMP) , 0 , 0 , 0, 0x6 , 0), - MAKE_INST(INST_JNAE , "jnae" , G(J) , F(JUMP) , 0 , 0 , 0, 0x2 , 0), - MAKE_INST(INST_JNB , "jnb" , G(J) , F(JUMP) , 0 , 0 , 0, 0x3 , 0), - MAKE_INST(INST_JNBE , "jnbe" , G(J) , F(JUMP) , 0 , 0 , 0, 0x7 , 0), - MAKE_INST(INST_JNC , "jnc" , G(J) , F(JUMP) , 0 , 0 , 0, 0x3 , 0), - MAKE_INST(INST_JNE , "jne" , G(J) , F(JUMP) , 0 , 0 , 0, 0x5 , 0), - MAKE_INST(INST_JNG , "jng" , G(J) , F(JUMP) , 0 , 0 , 0, 0xE , 0), - MAKE_INST(INST_JNGE , "jnge" , G(J) , F(JUMP) , 0 , 0 , 0, 0xC , 0), - MAKE_INST(INST_JNL , "jnl" , G(J) , F(JUMP) , 0 , 0 , 0, 0xD , 0), - MAKE_INST(INST_JNLE , "jnle" , G(J) , F(JUMP) , 0 , 0 , 0, 0xF , 0), - MAKE_INST(INST_JNO , "jno" , G(J) , F(JUMP) , 0 , 0 , 0, 0x1 , 0), - MAKE_INST(INST_JNP , "jnp" , G(J) , F(JUMP) , 0 , 0 , 0, 0xB , 0), - MAKE_INST(INST_JNS , "jns" , G(J) , F(JUMP) , 0 , 0 , 0, 0x9 , 0), - MAKE_INST(INST_JNZ , "jnz" , G(J) , F(JUMP) , 0 , 0 , 0, 0x5 , 0), - MAKE_INST(INST_JO , "jo" , G(J) , F(JUMP) , 0 , 0 , 0, 0x0 , 0), - MAKE_INST(INST_JP , "jp" , G(J) , F(JUMP) , 0 , 0 , 0, 0xA , 0), - MAKE_INST(INST_JPE , "jpe" , G(J) , F(JUMP) , 0 , 0 , 0, 0xA , 0), - MAKE_INST(INST_JPO , "jpo" , G(J) , F(JUMP) , 0 , 0 , 0, 0xB , 0), - MAKE_INST(INST_JS , "js" , G(J) , F(JUMP) , 0 , 0 , 0, 0x8 , 0), - MAKE_INST(INST_JZ , "jz" , G(J) , F(JUMP) , 0 , 0 , 0, 0x4 , 0), - MAKE_INST(INST_JMP , "jmp" , G(JMP) , F(JUMP) , 0 , 0 , 0, 0 , 0), - MAKE_INST(INST_LDDQU , "lddqu" , G(MMU_RMI) , F(NONE) , O(XMM) , O(MEM) , 0, 0xF2000FF0, 0), - MAKE_INST(INST_LDMXCSR , "ldmxcsr" , G(M) , F(NONE) , O(MEM) , 0 , 2, 0x00000FAE, 0), - MAKE_INST(INST_LAHF , "lahf" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x0000009F, 0), - MAKE_INST(INST_LEA , "lea" , G(LEA) , F(NONE) , O(GQD) , O(MEM) , 0, 0 , 0), - MAKE_INST(INST_LEAVE , "leave" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x000000C9, 0), - MAKE_INST(INST_LFENCE , "lfence" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x000FAEE8, 0), - MAKE_INST(INST_MASKMOVDQU , "maskmovdqu" , G(MMU_RMI) , F(SPECIAL) , O(XMM) , O(XMM) , 0, 0x66000F57, 0), - MAKE_INST(INST_MASKMOVQ , "maskmovq" , G(MMU_RMI) , F(SPECIAL) , O(MM) , O(MM) , 0, 0x00000FF7, 0), - MAKE_INST(INST_MAXPD , "maxpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F5F, 0), - MAKE_INST(INST_MAXPS , "maxps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F5F, 0), - MAKE_INST(INST_MAXSD , "maxsd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F5F, 0), - MAKE_INST(INST_MAXSS , "maxss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F5F, 0), - MAKE_INST(INST_MFENCE , "mfence" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x000FAEF0, 0), - MAKE_INST(INST_MINPD , "minpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F5D, 0), - MAKE_INST(INST_MINPS , "minps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F5D, 0), - MAKE_INST(INST_MINSD , "minsd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F5D, 0), - MAKE_INST(INST_MINSS , "minss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F5D, 0), - MAKE_INST(INST_MONITOR , "monitor" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x000F01C8, 0), - MAKE_INST(INST_MOV , "mov" , G(MOV) , F(MOV) , O(GQDWB_MEM) , O(GQDWB_MEM)|O(IMM) , 0, 0 , 0), - MAKE_INST(INST_MOVAPD , "movapd" , G(MMU_MOV) , F(MOV) , O(XMM_MEM) , O(XMM_MEM) , 0, 0x66000F28, 0x66000F29), - MAKE_INST(INST_MOVAPS , "movaps" , G(MMU_MOV) , F(MOV) , O(XMM_MEM) , O(XMM_MEM) , 0, 0x00000F28, 0x00000F29), - MAKE_INST(INST_MOVBE , "movbe" , G(MOVBE) , F(MOV) , O(GQDW)|O(MEM) , O(GQDW)|O(MEM) , 0, 0x000F38F0, 0x000F38F1), - MAKE_INST(INST_MOVD , "movd" , G(MMU_MOVD) , F(MOV) , O(GD)|O(MM_XMM_MEM) , O(GD)|O(MM_XMM_MEM) , 0, 0 , 0), - MAKE_INST(INST_MOVDDUP , "movddup" , G(MMU_MOV) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F12, 0), - MAKE_INST(INST_MOVDQ2Q , "movdq2q" , G(MMU_MOV) , F(MOV) , O(MM) , O(XMM) , 0, 0xF2000FD6, 0), - MAKE_INST(INST_MOVDQA , "movdqa" , G(MMU_MOV) , F(MOV) , O(XMM_MEM) , O(XMM_MEM) , 0, 0x66000F6F, 0x66000F7F), - MAKE_INST(INST_MOVDQU , "movdqu" , G(MMU_MOV) , F(MOV) , O(XMM_MEM) , O(XMM_MEM) , 0, 0xF3000F6F, 0xF3000F7F), - MAKE_INST(INST_MOVHLPS , "movhlps" , G(MMU_MOV) , F(NONE) , O(XMM) , O(XMM) , 0, 0x00000F12, 0), - MAKE_INST(INST_MOVHPD , "movhpd" , G(MMU_MOV) , F(NONE) , O(XMM_MEM) , O(XMM_MEM) , 0, 0x66000F16, 0x66000F17), - MAKE_INST(INST_MOVHPS , "movhps" , G(MMU_MOV) , F(NONE) , O(XMM_MEM) , O(XMM_MEM) , 0, 0x00000F16, 0x00000F17), - MAKE_INST(INST_MOVLHPS , "movlhps" , G(MMU_MOV) , F(NONE) , O(XMM) , O(XMM) , 0, 0x00000F16, 0), - MAKE_INST(INST_MOVLPD , "movlpd" , G(MMU_MOV) , F(NONE) , O(XMM_MEM) , O(XMM_MEM) , 0, 0x66000F12, 0x66000F13), - MAKE_INST(INST_MOVLPS , "movlps" , G(MMU_MOV) , F(NONE) , O(XMM_MEM) , O(XMM_MEM) , 0, 0x00000F12, 0x00000F13), - MAKE_INST(INST_MOVMSKPD , "movmskpd" , G(MMU_MOV) , F(MOV) , O(GQD)|O(NOREX) , O(XMM) , 0, 0x66000F50, 0), - MAKE_INST(INST_MOVMSKPS , "movmskps" , G(MMU_MOV) , F(MOV) , O(GQD)|O(NOREX) , O(XMM) , 0, 0x00000F50, 0), - MAKE_INST(INST_MOVNTDQ , "movntdq" , G(MMU_MOV) , F(NONE) , O(MEM) , O(XMM) , 0, 0 , 0x66000FE7), - MAKE_INST(INST_MOVNTDQA , "movntdqa" , G(MMU_MOV) , F(MOV) , O(XMM) , O(MEM) , 0, 0x660F382A, 0), - MAKE_INST(INST_MOVNTI , "movnti" , G(MMU_MOV) , F(MOV) , O(MEM) , O(GQD) , 0, 0 , 0x00000FC3), - MAKE_INST(INST_MOVNTPD , "movntpd" , G(MMU_MOV) , F(NONE) , O(MEM) , O(XMM) , 0, 0 , 0x66000F2B), - MAKE_INST(INST_MOVNTPS , "movntps" , G(MMU_MOV) , F(NONE) , O(MEM) , O(XMM) , 0, 0 , 0x00000F2B), - MAKE_INST(INST_MOVNTQ , "movntq" , G(MMU_MOV) , F(NONE) , O(MEM) , O(MM) , 0, 0 , 0x00000FE7), - MAKE_INST(INST_MOVQ , "movq" , G(MMU_MOVQ) , F(MOV) , O(GQ)|O(MM_XMM_MEM) , O(GQ)|O(MM_XMM_MEM) , 0, 0 , 0), - MAKE_INST(INST_MOVQ2DQ , "movq2dq" , G(MMU_RMI) , F(MOV) , O(XMM) , O(MM) , 0, 0xF3000FD6, 0), - MAKE_INST(INST_MOVSD , "movsd" , G(MMU_MOV) , F(NONE) , O(XMM_MEM) , O(XMM_MEM) , 0, 0xF2000F10, 0xF2000F11), - MAKE_INST(INST_MOVSHDUP , "movshdup" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F16, 0), - MAKE_INST(INST_MOVSLDUP , "movsldup" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F12, 0), - MAKE_INST(INST_MOVSS , "movss" , G(MMU_MOV) , F(NONE) , O(XMM_MEM) , O(XMM_MEM) , 0, 0xF3000F10, 0xF3000F11), - MAKE_INST(INST_MOVSX , "movsx" , G(MOVSX_MOVZX) , F(NONE) , O(GQDW) , O(GWB_MEM) , 0, 0x00000FBE, 0), - MAKE_INST(INST_MOVSXD , "movsxd" , G(MOVSXD) , F(NONE) , O(GQ) , O(GD_MEM) , 0, 0 , 0), - MAKE_INST(INST_MOVUPD , "movupd" , G(MMU_MOV) , F(MOV) , O(XMM_MEM) , O(XMM_MEM) , 0, 0x66000F10, 0x66000F11), - MAKE_INST(INST_MOVUPS , "movups" , G(MMU_MOV) , F(MOV) , O(XMM_MEM) , O(XMM_MEM) , 0, 0x00000F10, 0x00000F11), - MAKE_INST(INST_MOVZX , "movzx" , G(MOVSX_MOVZX) , F(MOV) , O(GQDW) , O(GWB_MEM) , 0, 0x00000FB6, 0), - MAKE_INST(INST_MOV_PTR , "mov_ptr" , G(MOV_PTR) , F(MOV)|F(SPECIAL), O(GQDWB) , O(IMM) , 0, 0 , 0), - MAKE_INST(INST_MPSADBW , "mpsadbw" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A42, 0), - MAKE_INST(INST_MUL , "mul" , G(RM) , F(SPECIAL) , 0 , 0 , 4, 0x000000F6, 0), - MAKE_INST(INST_MULPD , "mulpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F59, 0), - MAKE_INST(INST_MULPS , "mulps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F59, 0), - MAKE_INST(INST_MULSD , "mulsd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F59, 0), - MAKE_INST(INST_MULSS , "mulss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F59, 0), - MAKE_INST(INST_MWAIT , "mwait" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x000F01C9, 0), - MAKE_INST(INST_NEG , "neg" , G(RM) , F(LOCKABLE) , O(GQDWB_MEM) , 0 , 3, 0x000000F6, 0), - MAKE_INST(INST_NOP , "nop" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x00000090, 0), - MAKE_INST(INST_NOT , "not" , G(RM) , F(LOCKABLE) , O(GQDWB_MEM) , 0 , 2, 0x000000F6, 0), - MAKE_INST(INST_OR , "or" , G(ALU) , F(LOCKABLE) , O(GQDWB_MEM) , O(GQDWB_MEM)|O(IMM) , 1, 0x00000008, 0x00000080), - MAKE_INST(INST_ORPD , "orpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F56, 0), - MAKE_INST(INST_ORPS , "orps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F56, 0), - MAKE_INST(INST_PABSB , "pabsb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F381C, 0), - MAKE_INST(INST_PABSD , "pabsd" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F381E, 0), - MAKE_INST(INST_PABSW , "pabsw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F381D, 0), - MAKE_INST(INST_PACKSSDW , "packssdw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F6B, 0), - MAKE_INST(INST_PACKSSWB , "packsswb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F63, 0), - MAKE_INST(INST_PACKUSDW , "packusdw" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F382B, 0), - MAKE_INST(INST_PACKUSWB , "packuswb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F67, 0), - MAKE_INST(INST_PADDB , "paddb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FFC, 0), - MAKE_INST(INST_PADDD , "paddd" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FFE, 0), - MAKE_INST(INST_PADDQ , "paddq" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FD4, 0), - MAKE_INST(INST_PADDSB , "paddsb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FEC, 0), - MAKE_INST(INST_PADDSW , "paddsw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FED, 0), - MAKE_INST(INST_PADDUSB , "paddusb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FDC, 0), - MAKE_INST(INST_PADDUSW , "paddusw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FDD, 0), - MAKE_INST(INST_PADDW , "paddw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FFD, 0), - MAKE_INST(INST_PALIGNR , "palignr" , G(MMU_RM_IMM8) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F3A0F, 0), - MAKE_INST(INST_PAND , "pand" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FDB, 0), - MAKE_INST(INST_PANDN , "pandn" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FDF, 0), - MAKE_INST(INST_PAUSE , "pause" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0xF3000090, 0), - MAKE_INST(INST_PAVGB , "pavgb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FE0, 0), - MAKE_INST(INST_PAVGW , "pavgw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FE3, 0), - MAKE_INST(INST_PBLENDVB , "pblendvb" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3810, 0), - MAKE_INST(INST_PBLENDW , "pblendw" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A0E, 0), - MAKE_INST(INST_PCMPEQB , "pcmpeqb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F74, 0), - MAKE_INST(INST_PCMPEQD , "pcmpeqd" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F76, 0), - MAKE_INST(INST_PCMPEQQ , "pcmpeqq" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3829, 0), - MAKE_INST(INST_PCMPEQW , "pcmpeqw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F75, 0), - MAKE_INST(INST_PCMPESTRI , "pcmpestri" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A61, 0), - MAKE_INST(INST_PCMPESTRM , "pcmpestrm" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A60, 0), - MAKE_INST(INST_PCMPGTB , "pcmpgtb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F64, 0), - MAKE_INST(INST_PCMPGTD , "pcmpgtd" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F66, 0), - MAKE_INST(INST_PCMPGTQ , "pcmpgtq" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3837, 0), - MAKE_INST(INST_PCMPGTW , "pcmpgtw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F65, 0), - MAKE_INST(INST_PCMPISTRI , "pcmpistri" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A63, 0), - MAKE_INST(INST_PCMPISTRM , "pcmpistrm" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A62, 0), - MAKE_INST(INST_PEXTRB , "pextrb" , G(MMU_PEXTR) , F(NONE) , O(GD)|O(GB)|O(MEM) , O(XMM) , 0, 0x000F3A14, 0), - MAKE_INST(INST_PEXTRD , "pextrd" , G(MMU_PEXTR) , F(NONE) , O(GD) |O(MEM) , O(XMM) , 0, 0x000F3A16, 0), - MAKE_INST(INST_PEXTRQ , "pextrq" , G(MMU_PEXTR) , F(NONE) , O(GQD) |O(MEM) , O(XMM) , 1, 0x000F3A16, 0), - MAKE_INST(INST_PEXTRW , "pextrw" , G(MMU_PEXTR) , F(NONE) , O(GD) |O(MEM) , O(XMM) | O(MM) , 0, 0x000F3A15, 0), - MAKE_INST(INST_PF2ID , "pf2id" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x1D), - MAKE_INST(INST_PF2IW , "pf2iw" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x1C), - MAKE_INST(INST_PFACC , "pfacc" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0xAE), - MAKE_INST(INST_PFADD , "pfadd" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x9E), - MAKE_INST(INST_PFCMPEQ , "pfcmpeq" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0xB0), - MAKE_INST(INST_PFCMPGE , "pfcmpge" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x90), - MAKE_INST(INST_PFCMPGT , "pfcmpgt" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0xA0), - MAKE_INST(INST_PFMAX , "pfmax" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0xA4), - MAKE_INST(INST_PFMIN , "pfmin" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x94), - MAKE_INST(INST_PFMUL , "pfmul" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0xB4), - MAKE_INST(INST_PFNACC , "pfnacc" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x8A), - MAKE_INST(INST_PFPNACC , "pfpnacc" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x8E), - MAKE_INST(INST_PFRCP , "pfrcp" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x96), - MAKE_INST(INST_PFRCPIT1 , "pfrcpit1" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0xA6), - MAKE_INST(INST_PFRCPIT2 , "pfrcpit2" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0xB6), - MAKE_INST(INST_PFRSQIT1 , "pfrsqit1" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0xA7), - MAKE_INST(INST_PFRSQRT , "pfrsqrt" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x97), - MAKE_INST(INST_PFSUB , "pfsub" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x9A), - MAKE_INST(INST_PFSUBR , "pfsubr" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0xAA), - MAKE_INST(INST_PHADDD , "phaddd" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F3802, 0), - MAKE_INST(INST_PHADDSW , "phaddsw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F3803, 0), - MAKE_INST(INST_PHADDW , "phaddw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F3801, 0), - MAKE_INST(INST_PHMINPOSUW , "phminposuw" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3841, 0), - MAKE_INST(INST_PHSUBD , "phsubd" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F3806, 0), - MAKE_INST(INST_PHSUBSW , "phsubsw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F3807, 0), - MAKE_INST(INST_PHSUBW , "phsubw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F3805, 0), - MAKE_INST(INST_PI2FD , "pi2fd" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x0D), - MAKE_INST(INST_PI2FW , "pi2fw" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0x0C), - MAKE_INST(INST_PINSRB , "pinsrb" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(GD) | O(MEM) , 0, 0x660F3A20, 0), - MAKE_INST(INST_PINSRD , "pinsrd" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(GD) | O(MEM) , 0, 0x660F3A22, 0), - MAKE_INST(INST_PINSRQ , "pinsrq" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(GQ) | O(MEM) , 0, 0x660F3A22, 0), - MAKE_INST(INST_PINSRW , "pinsrw" , G(MMU_RM_IMM8) , F(NONE) , O(MM_XMM) , O(GD) | O(MEM) , 0, 0x00000FC4, 0), - MAKE_INST(INST_PMADDUBSW , "pmaddubsw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F3804, 0), - MAKE_INST(INST_PMADDWD , "pmaddwd" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FF5, 0), - MAKE_INST(INST_PMAXSB , "pmaxsb" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F383C, 0), - MAKE_INST(INST_PMAXSD , "pmaxsd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F383D, 0), - MAKE_INST(INST_PMAXSW , "pmaxsw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FEE, 0), - MAKE_INST(INST_PMAXUB , "pmaxub" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FDE, 0), - MAKE_INST(INST_PMAXUD , "pmaxud" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F383F, 0), - MAKE_INST(INST_PMAXUW , "pmaxuw" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F383E, 0), - MAKE_INST(INST_PMINSB , "pminsb" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3838, 0), - MAKE_INST(INST_PMINSD , "pminsd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3839, 0), - MAKE_INST(INST_PMINSW , "pminsw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FEA, 0), - MAKE_INST(INST_PMINUB , "pminub" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FDA, 0), - MAKE_INST(INST_PMINUD , "pminud" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F383B, 0), - MAKE_INST(INST_PMINUW , "pminuw" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F383A, 0), - MAKE_INST(INST_PMOVMSKB , "pmovmskb" , G(MMU_RMI) , F(MOV) , O(GQD) , O(MM_XMM) , 0, 0x00000FD7, 0), - MAKE_INST(INST_PMOVSXBD , "pmovsxbd" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3821, 0), - MAKE_INST(INST_PMOVSXBQ , "pmovsxbq" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3822, 0), - MAKE_INST(INST_PMOVSXBW , "pmovsxbw" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3820, 0), - MAKE_INST(INST_PMOVSXDQ , "pmovsxdq" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3825, 0), - MAKE_INST(INST_PMOVSXWD , "pmovsxwd" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3823, 0), - MAKE_INST(INST_PMOVSXWQ , "pmovsxwq" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3824, 0), - MAKE_INST(INST_PMOVZXBD , "pmovzxbd" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3831, 0), - MAKE_INST(INST_PMOVZXBQ , "pmovzxbq" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3832, 0), - MAKE_INST(INST_PMOVZXBW , "pmovzxbw" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3830, 0), - MAKE_INST(INST_PMOVZXDQ , "pmovzxdq" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3835, 0), - MAKE_INST(INST_PMOVZXWD , "pmovzxwd" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3833, 0), - MAKE_INST(INST_PMOVZXWQ , "pmovzxwq" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3834, 0), - MAKE_INST(INST_PMULDQ , "pmuldq" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3828, 0), - MAKE_INST(INST_PMULHRSW , "pmulhrsw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F380B, 0), - MAKE_INST(INST_PMULHUW , "pmulhuw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FE4, 0), - MAKE_INST(INST_PMULHW , "pmulhw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FE5, 0), - MAKE_INST(INST_PMULLD , "pmulld" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3840, 0), - MAKE_INST(INST_PMULLW , "pmullw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FD5, 0), - MAKE_INST(INST_PMULUDQ , "pmuludq" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FF4, 0), - MAKE_INST(INST_POP , "pop" , G(POP) , F(SPECIAL) , 0 , 0 , 0, 0x00000058, 0x0000008F), - MAKE_INST(INST_POPAD , "popad" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x00000061, 0), - MAKE_INST(INST_POPCNT , "popcnt" , G(R_RM) , F(NONE) , O(GQDW) , O(GQDW_MEM) , 0, 0xF3000FB8, 0), - MAKE_INST(INST_POPFD , "popfd" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x0000009D, 0), - MAKE_INST(INST_POPFQ , "popfq" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x0000009D, 0), - MAKE_INST(INST_POR , "por" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FEB, 0), - MAKE_INST(INST_PREFETCH , "prefetch" , G(MMU_PREFETCH) , F(NONE) , O(MEM) , O(IMM) , 0, 0 , 0), - MAKE_INST(INST_PSADBW , "psadbw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FF6, 0), - MAKE_INST(INST_PSHUFB , "pshufb" , G(MMU_RMI) , F(MOV) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F3800, 0), - MAKE_INST(INST_PSHUFD , "pshufd" , G(MMU_RM_IMM8) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x66000F70, 0), - MAKE_INST(INST_PSHUFW , "pshufw" , G(MMU_RM_IMM8) , F(MOV) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F70, 0), - MAKE_INST(INST_PSHUFHW , "pshufhw" , G(MMU_RM_IMM8) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F70, 0), - MAKE_INST(INST_PSHUFLW , "pshuflw" , G(MMU_RM_IMM8) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F70, 0), - MAKE_INST(INST_PSIGNB , "psignb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F3808, 0), - MAKE_INST(INST_PSIGND , "psignd" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F380A, 0), - MAKE_INST(INST_PSIGNW , "psignw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x000F3809, 0), - MAKE_INST(INST_PSLLD , "pslld" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM)|O(IMM), 6, 0x00000FF2, 0x00000F72), - MAKE_INST(INST_PSLLDQ , "pslldq" , G(MMU_RMI) , F(NONE) , O(XMM) , O(IMM) , 7, 0 , 0x66000F73), - MAKE_INST(INST_PSLLQ , "psllq" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM)|O(IMM), 6, 0x00000FF3, 0x00000F73), - MAKE_INST(INST_PSLLW , "psllw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM)|O(IMM), 6, 0x00000FF1, 0x00000F71), - MAKE_INST(INST_PSRAD , "psrad" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM)|O(IMM), 4, 0x00000FE2, 0x00000F72), - MAKE_INST(INST_PSRAW , "psraw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM)|O(IMM), 4, 0x00000FE1, 0x00000F71), - MAKE_INST(INST_PSRLD , "psrld" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM)|O(IMM), 2, 0x00000FD2, 0x00000F72), - MAKE_INST(INST_PSRLDQ , "psrldq" , G(MMU_RMI) , F(NONE) , O(XMM) , O(IMM) , 3, 0 , 0x66000F73), - MAKE_INST(INST_PSRLQ , "psrlq" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM)|O(IMM), 2, 0x00000FD3, 0x00000F73), - MAKE_INST(INST_PSRLW , "psrlw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM)|O(IMM), 2, 0x00000FD1, 0x00000F71), - MAKE_INST(INST_PSUBB , "psubb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FF8, 0), - MAKE_INST(INST_PSUBD , "psubd" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FFA, 0), - MAKE_INST(INST_PSUBQ , "psubq" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FFB, 0), - MAKE_INST(INST_PSUBSB , "psubsb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FE8, 0), - MAKE_INST(INST_PSUBSW , "psubsw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FE9, 0), - MAKE_INST(INST_PSUBUSB , "psubusb" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FD8, 0), - MAKE_INST(INST_PSUBUSW , "psubusw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FD9, 0), - MAKE_INST(INST_PSUBW , "psubw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FF9, 0), - MAKE_INST(INST_PSWAPD , "pswapd" , G(MMU_RM_3DNOW) , F(NONE) , O(MM) , O(MM_MEM) , 0, 0x00000F0F, 0xBB), - MAKE_INST(INST_PTEST , "ptest" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3817, 0), - MAKE_INST(INST_PUNPCKHBW , "punpckhbw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F68, 0), - MAKE_INST(INST_PUNPCKHDQ , "punpckhdq" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F6A, 0), - MAKE_INST(INST_PUNPCKHQDQ , "punpckhqdq" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F6D, 0), - MAKE_INST(INST_PUNPCKHWD , "punpckhwd" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F69, 0), - MAKE_INST(INST_PUNPCKLBW , "punpcklbw" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F60, 0), - MAKE_INST(INST_PUNPCKLDQ , "punpckldq" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F62, 0), - MAKE_INST(INST_PUNPCKLQDQ , "punpcklqdq" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F6C, 0), - MAKE_INST(INST_PUNPCKLWD , "punpcklwd" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000F61, 0), - MAKE_INST(INST_PUSH , "push" , G(PUSH) , F(SPECIAL) , 0 , 0 , 6, 0x00000050, 0x000000FF), - MAKE_INST(INST_PUSHAD , "pushad" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x00000060, 0), - MAKE_INST(INST_PUSHFD , "pushfd" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x0000009C, 0), - MAKE_INST(INST_PUSHFQ , "pushfq" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x0000009C, 0), - MAKE_INST(INST_PXOR , "pxor" , G(MMU_RMI) , F(NONE) , O(MM_XMM) , O(MM_XMM_MEM) , 0, 0x00000FEF, 0), - MAKE_INST(INST_RCL , "rcl" , G(ROT) , F(SPECIAL) , O(GQDWB_MEM) , O(GB)|O(IMM) , 2, 0 , 0), - MAKE_INST(INST_RCPPS , "rcpps" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x00000F53, 0), - MAKE_INST(INST_RCPSS , "rcpss" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F53, 0), - MAKE_INST(INST_RCR , "rcr" , G(ROT) , F(SPECIAL) , O(GQDWB_MEM) , O(GB)|O(IMM) , 3, 0 , 0), - MAKE_INST(INST_RDTSC , "rdtsc" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x00000F31, 0), - MAKE_INST(INST_RDTSCP , "rdtscp" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x000F01F9, 0), - MAKE_INST(INST_REP_LODSB , "rep lodsb" , G(REP) , F(SPECIAL) , O(MEM) , 0 , 0, 0xF30000AC, 1 /* Size of mem */), - MAKE_INST(INST_REP_LODSD , "rep lodsd" , G(REP) , F(SPECIAL) , O(MEM) , 0 , 0, 0xF30000AC, 4 /* Size of mem */), - MAKE_INST(INST_REP_LODSQ , "rep lodsq" , G(REP) , F(SPECIAL) , O(MEM) , 0 , 0, 0xF30000AC, 8 /* Size of mem */), - MAKE_INST(INST_REP_LODSW , "rep lodsw" , G(REP) , F(SPECIAL) , O(MEM) , 0 , 0, 0xF30000AC, 2 /* Size of mem */), - MAKE_INST(INST_REP_MOVSB , "rep movsb" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000A4, 1 /* Size of mem */), - MAKE_INST(INST_REP_MOVSD , "rep movsd" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000A4, 4 /* Size of mem */), - MAKE_INST(INST_REP_MOVSQ , "rep movsq" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000A4, 8 /* Size of mem */), - MAKE_INST(INST_REP_MOVSW , "rep movsw" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000A4, 2 /* Size of mem */), - MAKE_INST(INST_REP_STOSB , "rep stosb" , G(REP) , F(SPECIAL) , O(MEM) , 0 , 0, 0xF30000AA, 1 /* Size of mem */), - MAKE_INST(INST_REP_STOSD , "rep stosd" , G(REP) , F(SPECIAL) , O(MEM) , 0 , 0, 0xF30000AA, 4 /* Size of mem */), - MAKE_INST(INST_REP_STOSQ , "rep stosq" , G(REP) , F(SPECIAL) , O(MEM) , 0 , 0, 0xF30000AA, 8 /* Size of mem */), - MAKE_INST(INST_REP_STOSW , "rep stosw" , G(REP) , F(SPECIAL) , O(MEM) , 0 , 0, 0xF30000AA, 2 /* Size of mem */), - MAKE_INST(INST_REPE_CMPSB , "repe cmpsb" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000A6, 1 /* Size of mem */), - MAKE_INST(INST_REPE_CMPSD , "repe cmpsd" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000A6, 4 /* Size of mem */), - MAKE_INST(INST_REPE_CMPSQ , "repe cmpsq" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000A6, 8 /* Size of mem */), - MAKE_INST(INST_REPE_CMPSW , "repe cmpsw" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000A6, 2 /* Size of mem */), - MAKE_INST(INST_REPE_SCASB , "repe scasb" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000AE, 1 /* Size of mem */), - MAKE_INST(INST_REPE_SCASD , "repe scasd" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000AE, 4 /* Size of mem */), - MAKE_INST(INST_REPE_SCASQ , "repe scasq" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000AE, 8 /* Size of mem */), - MAKE_INST(INST_REPE_SCASW , "repe scasw" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF30000AE, 2 /* Size of mem */), - MAKE_INST(INST_REPNE_CMPSB , "repne cmpsb" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF20000A6, 1 /* Size of mem */), - MAKE_INST(INST_REPNE_CMPSD , "repne cmpsd" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF20000A6, 4 /* Size of mem */), - MAKE_INST(INST_REPNE_CMPSQ , "repne cmpsq" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF20000A6, 8 /* Size of mem */), - MAKE_INST(INST_REPNE_CMPSW , "repne cmpsw" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF20000A6, 2 /* Size of mem */), - MAKE_INST(INST_REPNE_SCASB , "repne scasb" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF20000AE, 1 /* Size of mem */), - MAKE_INST(INST_REPNE_SCASD , "repne scasd" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF20000AE, 4 /* Size of mem */), - MAKE_INST(INST_REPNE_SCASQ , "repne scasq" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF20000AE, 8 /* Size of mem */), - MAKE_INST(INST_REPNE_SCASW , "repne scasw" , G(REP) , F(SPECIAL) , O(MEM) , O(MEM) , 0, 0xF20000AE, 2 /* Size of mem */), - MAKE_INST(INST_RET , "ret" , G(RET) , F(SPECIAL) , 0 , 0 , 0, 0 , 0), - MAKE_INST(INST_ROL , "rol" , G(ROT) , F(SPECIAL) , O(GQDWB_MEM) , O(GB)|O(IMM) , 0, 0 , 0), - MAKE_INST(INST_ROR , "ror" , G(ROT) , F(SPECIAL) , O(GQDWB_MEM) , O(GB)|O(IMM) , 1, 0 , 0), - MAKE_INST(INST_ROUNDPD , "roundpd" , G(MMU_RM_IMM8) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A09, 0), - MAKE_INST(INST_ROUNDPS , "roundps" , G(MMU_RM_IMM8) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A08, 0), - MAKE_INST(INST_ROUNDSD , "roundsd" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A0B, 0), - MAKE_INST(INST_ROUNDSS , "roundss" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x660F3A0A, 0), - MAKE_INST(INST_RSQRTPS , "rsqrtps" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x00000F52, 0), - MAKE_INST(INST_RSQRTSS , "rsqrtss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F52, 0), - MAKE_INST(INST_SAHF , "sahf" , G(EMIT) , F(SPECIAL) , 0 , 0 , 0, 0x0000009E, 0), - MAKE_INST(INST_SAL , "sal" , G(ROT) , F(SPECIAL) , O(GQDWB_MEM) , O(GB)|O(IMM) , 4, 0 , 0), - MAKE_INST(INST_SAR , "sar" , G(ROT) , F(SPECIAL) , O(GQDWB_MEM) , O(GB)|O(IMM) , 7, 0 , 0), - MAKE_INST(INST_SBB , "sbb" , G(ALU) , F(LOCKABLE) , O(GQDWB_MEM) , O(GQDWB_MEM)|O(IMM) , 3, 0x00000018, 0x00000080), - MAKE_INST(INST_SETA , "seta" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F97, 0), - MAKE_INST(INST_SETAE , "setae" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F93, 0), - MAKE_INST(INST_SETB , "setb" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F92, 0), - MAKE_INST(INST_SETBE , "setbe" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F96, 0), - MAKE_INST(INST_SETC , "setc" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F92, 0), - MAKE_INST(INST_SETE , "sete" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F94, 0), - MAKE_INST(INST_SETG , "setg" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9F, 0), - MAKE_INST(INST_SETGE , "setge" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9D, 0), - MAKE_INST(INST_SETL , "setl" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9C, 0), - MAKE_INST(INST_SETLE , "setle" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9E, 0), - MAKE_INST(INST_SETNA , "setna" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F96, 0), - MAKE_INST(INST_SETNAE , "setnae" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F92, 0), - MAKE_INST(INST_SETNB , "setnb" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F93, 0), - MAKE_INST(INST_SETNBE , "setnbe" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F97, 0), - MAKE_INST(INST_SETNC , "setnc" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F93, 0), - MAKE_INST(INST_SETNE , "setne" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F95, 0), - MAKE_INST(INST_SETNG , "setng" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9E, 0), - MAKE_INST(INST_SETNGE , "setnge" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9C, 0), - MAKE_INST(INST_SETNL , "setnl" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9D, 0), - MAKE_INST(INST_SETNLE , "setnle" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9F, 0), - MAKE_INST(INST_SETNO , "setno" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F91, 0), - MAKE_INST(INST_SETNP , "setnp" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9B, 0), - MAKE_INST(INST_SETNS , "setns" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F99, 0), - MAKE_INST(INST_SETNZ , "setnz" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F95, 0), - MAKE_INST(INST_SETO , "seto" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F90, 0), - MAKE_INST(INST_SETP , "setp" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9A, 0), - MAKE_INST(INST_SETPE , "setpe" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9A, 0), - MAKE_INST(INST_SETPO , "setpo" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F9B, 0), - MAKE_INST(INST_SETS , "sets" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F98, 0), - MAKE_INST(INST_SETZ , "setz" , G(RM_B) , F(NONE) , O(GB_MEM) , 0 , 0, 0x00000F94, 0), - MAKE_INST(INST_SFENCE , "sfence" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x000FAEF8, 0), - MAKE_INST(INST_SHL , "shl" , G(ROT) , F(SPECIAL) , O(GQDWB_MEM) , O(GB)|O(IMM) , 4, 0 , 0), - MAKE_INST(INST_SHLD , "shld" , G(SHLD_SHRD) , F(SPECIAL) , O(GQDWB_MEM) , O(GB) , 0, 0x00000FA4, 0), - MAKE_INST(INST_SHR , "shr" , G(ROT) , F(SPECIAL) , O(GQDWB_MEM) , O(GB)|O(IMM) , 5, 0 , 0), - MAKE_INST(INST_SHRD , "shrd" , G(SHLD_SHRD) , F(SPECIAL) , O(GQDWB_MEM) , O(GQDWB) , 0, 0x00000FAC, 0), - MAKE_INST(INST_SHUFPD , "shufpd" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000FC6, 0), - MAKE_INST(INST_SHUFPS , "shufps" , G(MMU_RM_IMM8) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000FC6, 0), - MAKE_INST(INST_SQRTPD , "sqrtpd" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x66000F51, 0), - MAKE_INST(INST_SQRTPS , "sqrtps" , G(MMU_RMI) , F(MOV) , O(XMM) , O(XMM_MEM) , 0, 0x00000F51, 0), - MAKE_INST(INST_SQRTSD , "sqrtsd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F51, 0), - MAKE_INST(INST_SQRTSS , "sqrtss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F51, 0), - MAKE_INST(INST_STC , "stc" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x000000F9, 0), - MAKE_INST(INST_STD , "std" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x000000FD, 0), - MAKE_INST(INST_STMXCSR , "stmxcsr" , G(M) , F(NONE) , O(MEM) , 0 , 3, 0x00000FAE, 0), - MAKE_INST(INST_SUB , "sub" , G(ALU) , F(LOCKABLE) , O(GQDWB_MEM) , O(GQDWB_MEM)|O(IMM) , 5, 0x00000028, 0x00000080), - MAKE_INST(INST_SUBPD , "subpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F5C, 0), - MAKE_INST(INST_SUBPS , "subps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F5C, 0), - MAKE_INST(INST_SUBSD , "subsd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF2000F5C, 0), - MAKE_INST(INST_SUBSS , "subss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0xF3000F5C, 0), - MAKE_INST(INST_TEST , "test" , G(TEST) , F(NONE) , O(GQDWB_MEM) , O(GQDWB)|O(IMM) , 0, 0 , 0), - MAKE_INST(INST_UCOMISD , "ucomisd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F2E, 0), - MAKE_INST(INST_UCOMISS , "ucomiss" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F2E, 0), - MAKE_INST(INST_UD2 , "ud2" , G(EMIT) , F(NONE) , 0 , 0 , 0, 0x00000F0B, 0), - MAKE_INST(INST_UNPCKHPD , "unpckhpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F15, 0), - MAKE_INST(INST_UNPCKHPS , "unpckhps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F15, 0), - MAKE_INST(INST_UNPCKLPD , "unpcklpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F14, 0), - MAKE_INST(INST_UNPCKLPS , "unpcklps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F14, 0), - MAKE_INST(INST_XADD , "xadd" , G(RM_R) , F(LOCKABLE) , O(GQDWB_MEM) , O(GQDWB) , 0, 0x00000FC0, 0), - MAKE_INST(INST_XCHG , "xchg" , G(XCHG) , F(LOCKABLE) , O(GQDWB_MEM) , O(GQDWB) , 0, 0 , 0), - MAKE_INST(INST_XOR , "xor" , G(ALU) , F(LOCKABLE) , O(GQDWB_MEM) , O(GQDWB_MEM)|O(IMM) , 6, 0x00000030, 0x00000080), - MAKE_INST(INST_XORPD , "xorpd" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x66000F57, 0), - MAKE_INST(INST_XORPS , "xorps" , G(MMU_RMI) , F(NONE) , O(XMM) , O(XMM_MEM) , 0, 0x00000F57, 0) -}; - -#undef G -#undef F -#undef O - -#undef MAKE_INST - -} // AsmJit namespace - -#include "ApiEnd.h" diff --git a/desmume/src/utils/AsmJit/DefsX86X64.h b/desmume/src/utils/AsmJit/DefsX86X64.h deleted file mode 100644 index fd744a49a..000000000 --- a/desmume/src/utils/AsmJit/DefsX86X64.h +++ /dev/null @@ -1,1987 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_DEFSX86X64_H -#define _ASMJIT_DEFSX86X64_H - -#if !defined(_ASMJIT_DEFS_H) -#warning "AsmJit/DefsX86X64.h can be only included by AsmJit/Defs.h" -#endif // _ASMJIT_DEFS_H - -// [Dependencies] -#include "Build.h" -#include "Util.h" - -#include -#include - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -//! @addtogroup AsmJit_Core -//! @{ - -// ============================================================================ -// [AsmJit::REG_NUM] -// ============================================================================ - -//! @var REG_NUM -//! @brief Count of General purpose registers and XMM registers. -//! -//! Count of general purpose registers and XMM registers depends on current -//! bit-mode. If application is compiled for 32-bit platform then this number -//! is 8, 64-bit platforms have 8 extra general purpose and xmm registers (16 -//! total). - -//! @brief Count of registers. -enum REG_NUM -{ - //! @var REG_NUM_BASE - //! - //! Count of general purpose registers and XMM registers depends on current - //! bit-mode. If application is compiled for 32-bit platform then this number - //! is 8, 64-bit platforms have 8 extra general purpose and XMM registers (16 - //! total). -#if defined(ASMJIT_X86) - REG_NUM_BASE = 8, -#else - REG_NUM_BASE = 16, -#endif // ASMJIT - - //! @brief Count of general purpose registers. - //! - //! 8 in 32-bit mode and 16 in 64-bit mode. - REG_NUM_GP = REG_NUM_BASE, - - //! @brief Count of MM registers (always 8). - REG_NUM_MM = 8, - - //! @brief Count of FPU stack registers (always 8). - REG_NUM_FPU = 8, - - //! @brief Count of XMM registers. - //! - //! 8 in 32-bit mode and 16 in 64-bit mode. - REG_NUM_XMM = REG_NUM_BASE, - - //! @brief Count of segment registers, including no segment (AsmJit specific). - //! - //! @note There are 6 segment registers, but AsmJit uses 0 as no segment, and - //! 1...6 as segment registers, this means that there are 7 segment registers - //! in AsmJit API, but only 6 can be used through @c Assembler or @c Compiler - //! API. - REG_NUM_SEGMENT = 7 -}; - -// ============================================================================ -// [AsmJit::REG_INDEX] -// ============================================================================ - -//! @brief Valid X86 register indexes. -//! -//! These codes are real, don't miss with @c REG enum! and don't use these -//! values if you are not writing AsmJit code. -enum REG_INDEX -{ - //! @brief Mask for register code (index). - REG_INDEX_MASK = 0x00FF, - - //! @brief ID for AX/EAX/RAX registers. - REG_INDEX_EAX = 0, - //! @brief ID for CX/ECX/RCX registers. - REG_INDEX_ECX = 1, - //! @brief ID for DX/EDX/RDX registers. - REG_INDEX_EDX = 2, - //! @brief ID for BX/EBX/RBX registers. - REG_INDEX_EBX = 3, - //! @brief ID for SP/ESP/RSP registers. - REG_INDEX_ESP = 4, - //! @brief ID for BP/EBP/RBP registers. - REG_INDEX_EBP = 5, - //! @brief ID for SI/ESI/RSI registers. - REG_INDEX_ESI = 6, - //! @brief ID for DI/EDI/RDI registers. - REG_INDEX_EDI = 7, - -#if defined(ASMJIT_X64) - //! @brief ID for AX/EAX/RAX registers. - REG_INDEX_RAX = 0, - //! @brief ID for CX/ECX/RCX registers. - REG_INDEX_RCX = 1, - //! @brief ID for DX/EDX/RDX registers. - REG_INDEX_RDX = 2, - //! @brief ID for BX/EBX/RBX registers. - REG_INDEX_RBX = 3, - //! @brief ID for SP/ESP/RSP registers. - REG_INDEX_RSP = 4, - //! @brief ID for BP/EBP/RBP registers. - REG_INDEX_RBP = 5, - //! @brief ID for SI/ESI/RSI registers. - REG_INDEX_RSI = 6, - //! @brief ID for DI/EDI/RDI registers. - REG_INDEX_RDI = 7, - - //! @brief ID for r8 register (additional register introduced by 64-bit architecture). - REG_INDEX_R8 = 8, - //! @brief ID for R9 register (additional register introduced by 64-bit architecture). - REG_INDEX_R9 = 9, - //! @brief ID for R10 register (additional register introduced by 64-bit architecture). - REG_INDEX_R10 = 10, - //! @brief ID for R11 register (additional register introduced by 64-bit architecture). - REG_INDEX_R11 = 11, - //! @brief ID for R12 register (additional register introduced by 64-bit architecture). - REG_INDEX_R12 = 12, - //! @brief ID for R13 register (additional register introduced by 64-bit architecture). - REG_INDEX_R13 = 13, - //! @brief ID for R14 register (additional register introduced by 64-bit architecture). - REG_INDEX_R14 = 14, - //! @brief ID for R15 register (additional register introduced by 64-bit architecture). - REG_INDEX_R15 = 15, -#endif // ASMJIT_X64 - - //! @brief ID for mm0 register. - REG_INDEX_MM0 = 0, - //! @brief ID for mm1 register. - REG_INDEX_MM1 = 1, - //! @brief ID for mm2 register. - REG_INDEX_MM2 = 2, - //! @brief ID for mm3 register. - REG_INDEX_MM3 = 3, - //! @brief ID for mm4 register. - REG_INDEX_MM4 = 4, - //! @brief ID for mm5 register. - REG_INDEX_MM5 = 5, - //! @brief ID for mm6 register. - REG_INDEX_MM6 = 6, - //! @brief ID for mm7 register. - REG_INDEX_MM7 = 7, - - //! @brief ID for xmm0 register. - REG_INDEX_XMM0 = 0, - //! @brief ID for xmm1 register. - REG_INDEX_XMM1 = 1, - //! @brief ID for xmm2 register. - REG_INDEX_XMM2 = 2, - //! @brief ID for xmm3 register. - REG_INDEX_XMM3 = 3, - //! @brief ID for xmm4 register. - REG_INDEX_XMM4 = 4, - //! @brief ID for xmm5 register. - REG_INDEX_XMM5 = 5, - //! @brief ID for xmm6 register. - REG_INDEX_XMM6 = 6, - //! @brief ID for xmm7 register. - REG_INDEX_XMM7 = 7, - -#if defined(ASMJIT_X64) - //! @brief ID for xmm8 register (additional register introduced by 64-bit architecture). - REG_INDEX_XMM8 = 8, - //! @brief ID for xmm9 register (additional register introduced by 64-bit architecture). - REG_INDEX_XMM9 = 9, - //! @brief ID for xmm10 register (additional register introduced by 64-bit architecture). - REG_INDEX_XMM10 = 10, - //! @brief ID for xmm11 register (additional register introduced by 64-bit architecture). - REG_INDEX_XMM11 = 11, - //! @brief ID for xmm12 register (additional register introduced by 64-bit architecture). - REG_INDEX_XMM12 = 12, - //! @brief ID for xmm13 register (additional register introduced by 64-bit architecture). - REG_INDEX_XMM13 = 13, - //! @brief ID for xmm14 register (additional register introduced by 64-bit architecture). - REG_INDEX_XMM14 = 14, - //! @brief ID for xmm15 register (additional register introduced by 64-bit architecture). - REG_INDEX_XMM15 = 15, -#endif // ASMJIT_X64 - - //! @brief ID for ES segment register. - REG_INDEX_ES = 0, - //! @brief ID for CS segment register. - REG_INDEX_CS = 1, - //! @brief ID for SS segment register. - REG_INDEX_SS = 2, - //! @brief ID for DS segment register. - REG_INDEX_DS = 3, - //! @brief ID for FS segment register. - REG_INDEX_FS = 4, - //! @brief ID for GS segment register. - REG_INDEX_GS = 5 -}; - -// ============================================================================ -// [AsmJit::REG_TYPE] -// ============================================================================ - -//! @brief Pseudo (not real X86) register types. -enum REG_TYPE -{ - //! @brief Mask for register type. - REG_TYPE_MASK = 0xFF00, - - // First byte contains register type (mask 0xFF00), Second byte contains - // register index code. - - // -------------------------------------------------------------------------- - // [GP Register Types] - // -------------------------------------------------------------------------- - - //! @brief 8-bit general purpose register type (LO). - REG_TYPE_GPB_LO = 0x0100, - //! @brief 8-bit general purpose register type (HI, only AH, BH, CH, DH). - REG_TYPE_GPB_HI = 0x0200, - //! @brief 16-bit general purpose register type. - REG_TYPE_GPW = 0x1000, - //! @brief 32-bit general purpose register type. - REG_TYPE_GPD = 0x2000, - //! @brief 64-bit general purpose register type. - REG_TYPE_GPQ = 0x3000, - - //! @var REG_GPN - //! @brief 32-bit or 64-bit general purpose register type. - - // native 32-bit or 64-bit register type (depends on x86 or x64 mode). -#if defined(ASMJIT_X86) - REG_TYPE_GPN = REG_TYPE_GPD, -#else - REG_TYPE_GPN = REG_TYPE_GPQ, -#endif - - // -------------------------------------------------------------------------- - // [X87 (FPU) Register Type] - // -------------------------------------------------------------------------- - - //! @brief X87 (FPU) register type. - REG_TYPE_X87 = 0x5000, - - // -------------------------------------------------------------------------- - // [MM Register Type] - // -------------------------------------------------------------------------- - - //! @brief 64-bit MM register type. - REG_TYPE_MM = 0x6000, - - // -------------------------------------------------------------------------- - // [XMM Register Type] - // -------------------------------------------------------------------------- - - //! @brief 128-bit XMM register type. - REG_TYPE_XMM = 0x7000, - - // -------------------------------------------------------------------------- - // [YMM Register Type] - // -------------------------------------------------------------------------- - - //! @brief 256-bit YMM register type. - REG_TYPE_YMM = 0x8000, - - // -------------------------------------------------------------------------- - // [Other] - // -------------------------------------------------------------------------- - - //! @brief 16-bit segment register type. - REG_TYPE_SEGMENT = 0xD000 -}; - -// ============================================================================ -// [AsmJit::REG_CODE] -// ============================================================================ - -//! @brief Pseudo (not real X86) register codes used for generating opcodes. -//! -//! From this register code can be generated real x86 register ID, type of -//! register and size of register. -enum REG_CODE -{ - // -------------------------------------------------------------------------- - // [8-bit Registers] - // -------------------------------------------------------------------------- - - REG_AL = REG_TYPE_GPB_LO, - REG_CL, - REG_DL, - REG_BL, -#if defined(ASMJIT_X64) - REG_SPL, - REG_BPL, - REG_SIL, - REG_DIL, -#endif // ASMJIT_X64 - -#if defined(ASMJIT_X64) - REG_R8B, - REG_R9B, - REG_R10B, - REG_R11B, - REG_R12B, - REG_R13B, - REG_R14B, - REG_R15B, -#endif // ASMJIT_X64 - - REG_AH = REG_TYPE_GPB_HI, - REG_CH, - REG_DH, - REG_BH, - - // -------------------------------------------------------------------------- - // [16-bit Registers] - // -------------------------------------------------------------------------- - - REG_AX = REG_TYPE_GPW, - REG_CX, - REG_DX, - REG_BX, - REG_SP, - REG_BP, - REG_SI, - REG_DI, -#if defined(ASMJIT_X64) - REG_R8W, - REG_R9W, - REG_R10W, - REG_R11W, - REG_R12W, - REG_R13W, - REG_R14W, - REG_R15W, -#endif // ASMJIT_X64 - - // -------------------------------------------------------------------------- - // [32-bit Registers] - // -------------------------------------------------------------------------- - - REG_EAX = REG_TYPE_GPD, - REG_ECX, - REG_EDX, - REG_EBX, - REG_ESP, - REG_EBP, - REG_ESI, - REG_EDI, -#if defined(ASMJIT_X64) - REG_R8D, - REG_R9D, - REG_R10D, - REG_R11D, - REG_R12D, - REG_R13D, - REG_R14D, - REG_R15D, -#endif // ASMJIT_X64 - - // -------------------------------------------------------------------------- - // [64-bit Registers] - // -------------------------------------------------------------------------- - -#if defined(ASMJIT_X64) - REG_RAX = REG_TYPE_GPQ, - REG_RCX, - REG_RDX, - REG_RBX, - REG_RSP, - REG_RBP, - REG_RSI, - REG_RDI, - REG_R8, - REG_R9, - REG_R10, - REG_R11, - REG_R12, - REG_R13, - REG_R14, - REG_R15, -#endif // ASMJIT_X64 - - // -------------------------------------------------------------------------- - // [MM Registers] - // -------------------------------------------------------------------------- - - REG_MM0 = REG_TYPE_MM, - REG_MM1, - REG_MM2, - REG_MM3, - REG_MM4, - REG_MM5, - REG_MM6, - REG_MM7, - - // -------------------------------------------------------------------------- - // [XMM Registers] - // -------------------------------------------------------------------------- - - REG_XMM0 = REG_TYPE_XMM, - REG_XMM1, - REG_XMM2, - REG_XMM3, - REG_XMM4, - REG_XMM5, - REG_XMM6, - REG_XMM7, -#if defined(ASMJIT_X64) - REG_XMM8, - REG_XMM9, - REG_XMM10, - REG_XMM11, - REG_XMM12, - REG_XMM13, - REG_XMM14, - REG_XMM15, -#endif // ASMJIT_X64 - - // -------------------------------------------------------------------------- - // [Native registers (depends on 32-bit or 64-bit mode)] - // -------------------------------------------------------------------------- - - REG_NAX = REG_TYPE_GPN, - REG_NCX, - REG_NDX, - REG_NBX, - REG_NSP, - REG_NBP, - REG_NSI, - REG_NDI, - - // -------------------------------------------------------------------------- - // [Segment registers] - // -------------------------------------------------------------------------- - - //! @brief ES segment register. - REG_ES = REG_TYPE_SEGMENT, - //! @brief CS segment register. - REG_CS, - //! @brief SS segment register. - REG_SS, - //! @brief DS segment register. - REG_DS, - //! @brief FS segment register. - REG_FS, - //! @brief GS segment register. - REG_GS -}; - -// ============================================================================ -// [AsmJit::SEGMENT_PREFIX] -// ============================================================================ - -//! @brief Segment override prefixes. -enum SEGMENT_PREFIX -{ - // DO NOT MODIFY INDEX CODES - They are used by _emitSegmentPrefix() and - // by logger in the following order: - - //! @brief Use 'es' segment override prefix. - SEGMENT_ES = 0, - //! @brief Use 'cs' segment override prefix. - SEGMENT_CS = 1, - //! @brief Use 'ss' segment override prefix. - SEGMENT_SS = 2, - //! @brief Use 'ds' segment override prefix. - SEGMENT_DS = 3, - //! @brief Use 'fs' segment override prefix. - SEGMENT_FS = 4, - //! @brief Use 'gs' segment override prefix. - SEGMENT_GS = 5, - - //! @brief No segment override prefix. - SEGMENT_NONE = 0xF, - - //! @brief End of prefix codes - _SEGMENT_COUNT = 6 -}; - -// ============================================================================ -// [AsmJit::PREFETCH_HINT] -// ============================================================================ - -//! @brief Prefetch hints. -enum PREFETCH_HINT -{ - //! @brief Prefetch to L0 cache. - PREFETCH_T0 = 1, - //! @brief Prefetch to L1 cache. - PREFETCH_T1 = 2, - //! @brief Prefetch to L2 cache. - PREFETCH_T2 = 3, - //! @brief Prefetch using NT hint. - PREFETCH_NTA = 0 -}; - -// ============================================================================ -// [AsmJit::CONDITION] -// ============================================================================ - -//! @brief Condition codes. -enum CONDITION -{ - //! @brief No condition code. - C_NO_CONDITION = -1, - - // Condition codes from processor manuals. - C_A = 0x7, - C_AE = 0x3, - C_B = 0x2, - C_BE = 0x6, - C_C = 0x2, - C_E = 0x4, - C_G = 0xF, - C_GE = 0xD, - C_L = 0xC, - C_LE = 0xE, - C_NA = 0x6, - C_NAE = 0x2, - C_NB = 0x3, - C_NBE = 0x7, - C_NC = 0x3, - C_NE = 0x5, - C_NG = 0xE, - C_NGE = 0xC, - C_NL = 0xD, - C_NLE = 0xF, - C_NO = 0x1, - C_NP = 0xB, - C_NS = 0x9, - C_NZ = 0x5, - C_O = 0x0, - C_P = 0xA, - C_PE = 0xA, - C_PO = 0xB, - C_S = 0x8, - C_Z = 0x4, - - // Simplified condition codes - C_OVERFLOW = 0x0, - C_NO_OVERFLOW = 0x1, - C_BELOW = 0x2, - C_ABOVE_EQUAL = 0x3, - C_EQUAL = 0x4, - C_NOT_EQUAL = 0x5, - C_BELOW_EQUAL = 0x6, - C_ABOVE = 0x7, - C_SIGN = 0x8, - C_NOT_SIGN = 0x9, - C_PARITY_EVEN = 0xA, - C_PARITY_ODD = 0xB, - C_LESS = 0xC, - C_GREATER_EQUAL = 0xD, - C_LESS_EQUAL = 0xE, - C_GREATER = 0xF, - - // aliases - C_ZERO = 0x4, - C_NOT_ZERO = 0x5, - C_NEGATIVE = 0x8, - C_POSITIVE = 0x9, - - // x87 floating point only - C_FP_UNORDERED = 16, - C_FP_NOT_UNORDERED = 17 -}; - -//! @brief Returns the equivalent of !cc. -//! -//! Negation of the default no_condition (-1) results in a non-default -//! no_condition value (-2). As long as tests for no_condition check -//! for condition < 0, this will work as expected. -static inline CONDITION negateCondition(CONDITION cc) -{ - return static_cast(cc ^ 1); -} - -//! @brief Corresponds to transposing the operands of a comparison. -static inline CONDITION reverseCondition(CONDITION cc) -{ - switch (cc) { - case C_BELOW: - return C_ABOVE; - case C_ABOVE: - return C_BELOW; - case C_ABOVE_EQUAL: - return C_BELOW_EQUAL; - case C_BELOW_EQUAL: - return C_ABOVE_EQUAL; - case C_LESS: - return C_GREATER; - case C_GREATER: - return C_LESS; - case C_GREATER_EQUAL: - return C_LESS_EQUAL; - case C_LESS_EQUAL: - return C_GREATER_EQUAL; - default: - return cc; - }; -} - -struct ASMJIT_API ConditionToInstruction -{ - //! @brief Used to map condition code to jcc instructions. - static const uint32_t _jcctable[16]; - //! @brief Used to map condition code to cmovcc instructions. - static const uint32_t _cmovcctable[16]; - //! @brief Used to map condition code to setcc instructions. - static const uint32_t _setcctable[16]; - - //! @brief Translate condition code @a cc to jcc instruction code. - //! @sa @c INST_CODE, @c INST_J. - static inline uint32_t toJCC(CONDITION cc) ASMJIT_NOTHROW - { - ASMJIT_ASSERT(static_cast(cc) <= 0xF); - return _jcctable[cc]; - } - - //! @brief Translate condition code @a cc to cmovcc instruction code. - //! @sa @c INST_CODE, @c INST_CMOV. - static inline uint32_t toCMovCC(CONDITION cc) ASMJIT_NOTHROW - { - ASMJIT_ASSERT(static_cast(cc) <= 0xF); - return _cmovcctable[cc]; - } - - //! @brief Translate condition code @a cc to setcc instruction code. - //! @sa @c INST_CODE, @c INST_SET. - static inline uint32_t toSetCC(CONDITION cc) ASMJIT_NOTHROW - { - ASMJIT_ASSERT(static_cast(cc) <= 0xF); - return _setcctable[cc]; - } -}; - -// ============================================================================ -// [AsmJit::SCALE] -// ============================================================================ - -//! @brief Scale, can be used for addressing. -//! -//! See @c Op and addressing methods like @c byte_ptr(), @c word_ptr(), -//! @c dword_ptr(), etc... -enum SCALE -{ - //! @brief Scale 1 times (no scale). - TIMES_1 = 0, - //! @brief Scale 2 times (same as shifting to left by 1). - TIMES_2 = 1, - //! @brief Scale 4 times (same as shifting to left by 2). - TIMES_4 = 2, - //! @brief Scale 8 times (same as shifting to left by 3). - TIMES_8 = 3 -}; - -// ============================================================================ -// [AsmJit::HINT] -// ============================================================================ - -//! @brief Condition hint, see @c AsmJit::Assembler::jz(), @c AsmJit::Compiler::jz() -//! and friends. -enum HINT -{ - //! @brief No hint. - HINT_NONE = 0x00, - //! @brief Condition will be taken (likely). - HINT_TAKEN = 0x01, - //! @brief Condition will be not taken (unlikely). - HINT_NOT_TAKEN = 0x02 -}; - -//! @brief Hint byte value is the byte that will be emitted if hint flag -//! is specified by @c HINT. -enum HINT_BYTE_VALUE -{ - //! @brief Condition will be taken (likely). - HINT_BYTE_VALUE_TAKEN = 0x3E, - //! @brief Condition will be not taken (unlikely). - HINT_BYTE_VALUE_NOT_TAKEN = 0x2E -}; - -// ============================================================================ -// [AsmJit::FP_STATUS] -// ============================================================================ - -//! @brief Floating point status. -enum FP_STATUS -{ - FP_C0 = 0x100, - FP_C1 = 0x200, - FP_C2 = 0x400, - FP_C3 = 0x4000, - FP_CC_MASK = 0x4500 -}; - -// ============================================================================ -// [AsmJit::FP_CW] -// ============================================================================ - -//! @brief Floating point control word. -enum FP_CW -{ - FP_CW_INVOPEX_MASK = 0x001, - FP_CW_DENOPEX_MASK = 0x002, - FP_CW_ZERODIV_MASK = 0x004, - FP_CW_OVFEX_MASK = 0x008, - FP_CW_UNDFEX_MASK = 0x010, - FP_CW_PRECEX_MASK = 0x020, - FP_CW_PRECC_MASK = 0x300, - FP_CW_ROUNDC_MASK = 0xC00, - - // Values for precision control. - FP_CW_PREC_SINGLE = 0x000, - FP_CW_PREC_DOUBLE = 0x200, - FP_CW_PREC_EXTENDED = 0x300, - - // Values for rounding control. - FP_CW_ROUND_NEAREST = 0x000, - FP_CW_ROUND_DOWN = 0x400, - FP_CW_ROUND_UP = 0x800, - FP_CW_ROUND_TOZERO = 0xC00 -}; - -// ============================================================================ -// [AsmJit::INST_CODE] -// ============================================================================ - -//! @brief Instruction codes. -//! -//! Note that these instruction codes are AsmJit specific. Each instruction is -//! unique ID into AsmJit instruction table. Instruction codes are used together -//! with AsmJit::Assembler and you can also use instruction codes to serialize -//! instructions by @ref AssemblerCore::_emitInstruction() or -//! @ref CompilerCore::_emitInstruction() -enum INST_CODE -{ - INST_ADC, // X86/X64 - INST_ADD, // X86/X64 - INST_ADDPD, // SSE2 - INST_ADDPS, // SSE - INST_ADDSD, // SSE2 - INST_ADDSS, // SSE - INST_ADDSUBPD, // SSE3 - INST_ADDSUBPS, // SSE3 - INST_AMD_PREFETCH, - INST_AMD_PREFETCHW, - INST_AND, // X86/X64 - INST_ANDNPD, // SSE2 - INST_ANDNPS, // SSE - INST_ANDPD, // SSE2 - INST_ANDPS, // SSE - INST_BLENDPD, // SSE4.1 - INST_BLENDPS, // SSE4.1 - INST_BLENDVPD, // SSE4.1 - INST_BLENDVPS, // SSE4.1 - INST_BSF, // X86/X64 - INST_BSR, // X86/X64 - INST_BSWAP, // X86/X64 (i486) - INST_BT, // X86/X64 - INST_BTC, // X86/X64 - INST_BTR, // X86/X64 - INST_BTS, // X86/X64 - INST_CALL, // X86/X64 - INST_CBW, // X86/X64 - INST_CDQE, // X64 only - INST_CLC, // X86/X64 - INST_CLD, // X86/X64 - INST_CLFLUSH, // SSE2 - INST_CMC, // X86/X64 - - INST_CMOV, // Begin (cmovcc) (i586) - INST_CMOVA = INST_CMOV, //X86/X64 (cmovcc) (i586) - INST_CMOVAE, // X86/X64 (cmovcc) (i586) - INST_CMOVB, // X86/X64 (cmovcc) (i586) - INST_CMOVBE, // X86/X64 (cmovcc) (i586) - INST_CMOVC, // X86/X64 (cmovcc) (i586) - INST_CMOVE, // X86/X64 (cmovcc) (i586) - INST_CMOVG, // X86/X64 (cmovcc) (i586) - INST_CMOVGE, // X86/X64 (cmovcc) (i586) - INST_CMOVL, // X86/X64 (cmovcc) (i586) - INST_CMOVLE, // X86/X64 (cmovcc) (i586) - INST_CMOVNA, // X86/X64 (cmovcc) (i586) - INST_CMOVNAE, // X86/X64 (cmovcc) (i586) - INST_CMOVNB, // X86/X64 (cmovcc) (i586) - INST_CMOVNBE, // X86/X64 (cmovcc) (i586) - INST_CMOVNC, // X86/X64 (cmovcc) (i586) - INST_CMOVNE, // X86/X64 (cmovcc) (i586) - INST_CMOVNG, // X86/X64 (cmovcc) (i586) - INST_CMOVNGE, // X86/X64 (cmovcc) (i586) - INST_CMOVNL, // X86/X64 (cmovcc) (i586) - INST_CMOVNLE, // X86/X64 (cmovcc) (i586) - INST_CMOVNO, // X86/X64 (cmovcc) (i586) - INST_CMOVNP, // X86/X64 (cmovcc) (i586) - INST_CMOVNS, // X86/X64 (cmovcc) (i586) - INST_CMOVNZ, // X86/X64 (cmovcc) (i586) - INST_CMOVO, // X86/X64 (cmovcc) (i586) - INST_CMOVP, // X86/X64 (cmovcc) (i586) - INST_CMOVPE, // X86/X64 (cmovcc) (i586) - INST_CMOVPO, // X86/X64 (cmovcc) (i586) - INST_CMOVS, // X86/X64 (cmovcc) (i586) - INST_CMOVZ, // X86/X64 (cmovcc) (i586) - - INST_CMP, // X86/X64 - INST_CMPPD, // SSE2 - INST_CMPPS, // SSE - INST_CMPSD, // SSE2 - INST_CMPSS, // SSE - INST_CMPXCHG, // X86/X64 (i486) - INST_CMPXCHG16B, // X64 only - INST_CMPXCHG8B, // X86/X64 (i586) - INST_COMISD, // SSE2 - INST_COMISS, // SSE - INST_CPUID, // X86/X64 (i486) - INST_CRC32, // SSE4.2 - INST_CVTDQ2PD, // SSE2 - INST_CVTDQ2PS, // SSE2 - INST_CVTPD2DQ, // SSE2 - INST_CVTPD2PI, // SSE2 - INST_CVTPD2PS, // SSE2 - INST_CVTPI2PD, // SSE2 - INST_CVTPI2PS, // SSE - INST_CVTPS2DQ, // SSE2 - INST_CVTPS2PD, // SSE2 - INST_CVTPS2PI, // SSE - INST_CVTSD2SI, // SSE2 - INST_CVTSD2SS, // SSE2 - INST_CVTSI2SD, // SSE2 - INST_CVTSI2SS, // SSE - INST_CVTSS2SD, // SSE2 - INST_CVTSS2SI, // SSE - INST_CVTTPD2DQ, // SSE2 - INST_CVTTPD2PI, // SSE2 - INST_CVTTPS2DQ, // SSE2 - INST_CVTTPS2PI, // SSE - INST_CVTTSD2SI, // SSE2 - INST_CVTTSS2SI, // SSE - INST_CWDE, // X86/X64 - INST_DAA, // X86 only - INST_DAS, // X86 only - INST_DEC, // X86/X64 - INST_DIV, // X86/X64 - INST_DIVPD, // SSE2 - INST_DIVPS, // SSE - INST_DIVSD, // SSE2 - INST_DIVSS, // SSE - INST_DPPD, // SSE4.1 - INST_DPPS, // SSE4.1 - INST_EMMS, // MMX - INST_ENTER, // X86/X64 - INST_EXTRACTPS, // SSE4.1 - INST_F2XM1, // X87 - INST_FABS, // X87 - INST_FADD, // X87 - INST_FADDP, // X87 - INST_FBLD, // X87 - INST_FBSTP, // X87 - INST_FCHS, // X87 - INST_FCLEX, // X87 - INST_FCMOVB, // X87 - INST_FCMOVBE, // X87 - INST_FCMOVE, // X87 - INST_FCMOVNB, // X87 - INST_FCMOVNBE, // X87 - INST_FCMOVNE, // X87 - INST_FCMOVNU, // X87 - INST_FCMOVU, // X87 - INST_FCOM, // X87 - INST_FCOMI, // X87 - INST_FCOMIP, // X87 - INST_FCOMP, // X87 - INST_FCOMPP, // X87 - INST_FCOS, // X87 - INST_FDECSTP, // X87 - INST_FDIV, // X87 - INST_FDIVP, // X87 - INST_FDIVR, // X87 - INST_FDIVRP, // X87 - INST_FEMMS, // 3dNow! - INST_FFREE, // X87 - INST_FIADD, // X87 - INST_FICOM, // X87 - INST_FICOMP, // X87 - INST_FIDIV, // X87 - INST_FIDIVR, // X87 - INST_FILD, // X87 - INST_FIMUL, // X87 - INST_FINCSTP, // X87 - INST_FINIT, // X87 - INST_FIST, // X87 - INST_FISTP, // X87 - INST_FISTTP, // SSE3 - INST_FISUB, // X87 - INST_FISUBR, // X87 - INST_FLD, // X87 - INST_FLD1, // X87 - INST_FLDCW, // X87 - INST_FLDENV, // X87 - INST_FLDL2E, // X87 - INST_FLDL2T, // X87 - INST_FLDLG2, // X87 - INST_FLDLN2, // X87 - INST_FLDPI, // X87 - INST_FLDZ, // X87 - INST_FMUL, // X87 - INST_FMULP, // X87 - INST_FNCLEX, // X87 - INST_FNINIT, // X87 - INST_FNOP, // X87 - INST_FNSAVE, // X87 - INST_FNSTCW, // X87 - INST_FNSTENV, // X87 - INST_FNSTSW, // X87 - INST_FPATAN, // X87 - INST_FPREM, // X87 - INST_FPREM1, // X87 - INST_FPTAN, // X87 - INST_FRNDINT, // X87 - INST_FRSTOR, // X87 - INST_FSAVE, // X87 - INST_FSCALE, // X87 - INST_FSIN, // X87 - INST_FSINCOS, // X87 - INST_FSQRT, // X87 - INST_FST, // X87 - INST_FSTCW, // X87 - INST_FSTENV, // X87 - INST_FSTP, // X87 - INST_FSTSW, // X87 - INST_FSUB, // X87 - INST_FSUBP, // X87 - INST_FSUBR, // X87 - INST_FSUBRP, // X87 - INST_FTST, // X87 - INST_FUCOM, // X87 - INST_FUCOMI, // X87 - INST_FUCOMIP, // X87 - INST_FUCOMP, // X87 - INST_FUCOMPP, // X87 - INST_FWAIT, // X87 - INST_FXAM, // X87 - INST_FXCH, // X87 - INST_FXRSTOR, // X87 - INST_FXSAVE, // X87 - INST_FXTRACT, // X87 - INST_FYL2X, // X87 - INST_FYL2XP1, // X87 - INST_HADDPD, // SSE3 - INST_HADDPS, // SSE3 - INST_HSUBPD, // SSE3 - INST_HSUBPS, // SSE3 - INST_IDIV, // X86/X64 - INST_IMUL, // X86/X64 - INST_INC, // X86/X64 - INST_INT3, // X86/X64 - INST_J, // Begin (jcc) - INST_JA = - INST_J, // X86/X64 (jcc) - INST_JAE, // X86/X64 (jcc) - INST_JB, // X86/X64 (jcc) - INST_JBE, // X86/X64 (jcc) - INST_JC, // X86/X64 (jcc) - INST_JE, // X86/X64 (jcc) - INST_JG, // X86/X64 (jcc) - INST_JGE, // X86/X64 (jcc) - INST_JL, // X86/X64 (jcc) - INST_JLE, // X86/X64 (jcc) - INST_JNA, // X86/X64 (jcc) - INST_JNAE, // X86/X64 (jcc) - INST_JNB, // X86/X64 (jcc) - INST_JNBE, // X86/X64 (jcc) - INST_JNC, // X86/X64 (jcc) - INST_JNE, // X86/X64 (jcc) - INST_JNG, // X86/X64 (jcc) - INST_JNGE, // X86/X64 (jcc) - INST_JNL, // X86/X64 (jcc) - INST_JNLE, // X86/X64 (jcc) - INST_JNO, // X86/X64 (jcc) - INST_JNP, // X86/X64 (jcc) - INST_JNS, // X86/X64 (jcc) - INST_JNZ, // X86/X64 (jcc) - INST_JO, // X86/X64 (jcc) - INST_JP, // X86/X64 (jcc) - INST_JPE, // X86/X64 (jcc) - INST_JPO, // X86/X64 (jcc) - INST_JS, // X86/X64 (jcc) - INST_JZ, // X86/X64 (jcc) - INST_JMP, // X86/X64 (jmp) - INST_LDDQU, // SSE3 - INST_LDMXCSR, // SSE - INST_LAHF, // X86/X64 (CPUID NEEDED) - INST_LEA, // X86/X64 - INST_LEAVE, // X86/X64 - INST_LFENCE, // SSE2 - INST_MASKMOVDQU, // SSE2 - INST_MASKMOVQ, // MMX-Ext - INST_MAXPD, // SSE2 - INST_MAXPS, // SSE - INST_MAXSD, // SSE2 - INST_MAXSS, // SSE - INST_MFENCE, // SSE2 - INST_MINPD, // SSE2 - INST_MINPS, // SSE - INST_MINSD, // SSE2 - INST_MINSS, // SSE - INST_MONITOR, // SSE3 - INST_MOV, // X86/X64 - INST_MOVAPD, // SSE2 - INST_MOVAPS, // SSE - INST_MOVBE, // SSE3 - Intel-Atom - INST_MOVD, // MMX/SSE2 - INST_MOVDDUP, // SSE3 - INST_MOVDQ2Q, // SSE2 - INST_MOVDQA, // SSE2 - INST_MOVDQU, // SSE2 - INST_MOVHLPS, // SSE - INST_MOVHPD, // SSE2 - INST_MOVHPS, // SSE - INST_MOVLHPS, // SSE - INST_MOVLPD, // SSE2 - INST_MOVLPS, // SSE - INST_MOVMSKPD, // SSE2 - INST_MOVMSKPS, // SSE2 - INST_MOVNTDQ, // SSE2 - INST_MOVNTDQA, // SSE4.1 - INST_MOVNTI, // SSE2 - INST_MOVNTPD, // SSE2 - INST_MOVNTPS, // SSE - INST_MOVNTQ, // MMX-Ext - INST_MOVQ, // MMX/SSE/SSE2 - INST_MOVQ2DQ, // SSE2 - INST_MOVSD, // SSE2 - INST_MOVSHDUP, // SSE3 - INST_MOVSLDUP, // SSE3 - INST_MOVSS, // SSE - INST_MOVSX, // X86/X64 - INST_MOVSXD, // X86/X64 - INST_MOVUPD, // SSE2 - INST_MOVUPS, // SSE - INST_MOVZX, // X86/X64 - INST_MOV_PTR, // X86/X64 - INST_MPSADBW, // SSE4.1 - INST_MUL, // X86/X64 - INST_MULPD, // SSE2 - INST_MULPS, // SSE - INST_MULSD, // SSE2 - INST_MULSS, // SSE - INST_MWAIT, // SSE3 - INST_NEG, // X86/X64 - INST_NOP, // X86/X64 - INST_NOT, // X86/X64 - INST_OR, // X86/X64 - INST_ORPD, // SSE2 - INST_ORPS, // SSE - INST_PABSB, // SSSE3 - INST_PABSD, // SSSE3 - INST_PABSW, // SSSE3 - INST_PACKSSDW, // MMX/SSE2 - INST_PACKSSWB, // MMX/SSE2 - INST_PACKUSDW, // SSE4.1 - INST_PACKUSWB, // MMX/SSE2 - INST_PADDB, // MMX/SSE2 - INST_PADDD, // MMX/SSE2 - INST_PADDQ, // SSE2 - INST_PADDSB, // MMX/SSE2 - INST_PADDSW, // MMX/SSE2 - INST_PADDUSB, // MMX/SSE2 - INST_PADDUSW, // MMX/SSE2 - INST_PADDW, // MMX/SSE2 - INST_PALIGNR, // SSSE3 - INST_PAND, // MMX/SSE2 - INST_PANDN, // MMX/SSE2 - INST_PAUSE, // SSE2. - INST_PAVGB, // MMX-Ext - INST_PAVGW, // MMX-Ext - INST_PBLENDVB, // SSE4.1 - INST_PBLENDW, // SSE4.1 - INST_PCMPEQB, // MMX/SSE2 - INST_PCMPEQD, // MMX/SSE2 - INST_PCMPEQQ, // SSE4.1 - INST_PCMPEQW, // MMX/SSE2 - INST_PCMPESTRI, // SSE4.2 - INST_PCMPESTRM, // SSE4.2 - INST_PCMPGTB, // MMX/SSE2 - INST_PCMPGTD, // MMX/SSE2 - INST_PCMPGTQ, // SSE4.2 - INST_PCMPGTW, // MMX/SSE2 - INST_PCMPISTRI, // SSE4.2 - INST_PCMPISTRM, // SSE4.2 - INST_PEXTRB, // SSE4.1 - INST_PEXTRD, // SSE4.1 - INST_PEXTRQ, // SSE4.1 - INST_PEXTRW, // MMX-Ext/SSE2 - INST_PF2ID, // 3dNow! - INST_PF2IW, // Enhanced 3dNow! - INST_PFACC, // 3dNow! - INST_PFADD, // 3dNow! - INST_PFCMPEQ, // 3dNow! - INST_PFCMPGE, // 3dNow! - INST_PFCMPGT, // 3dNow! - INST_PFMAX, // 3dNow! - INST_PFMIN, // 3dNow! - INST_PFMUL, // 3dNow! - INST_PFNACC, // Enhanced 3dNow! - INST_PFPNACC, // Enhanced 3dNow! - INST_PFRCP, // 3dNow! - INST_PFRCPIT1, // 3dNow! - INST_PFRCPIT2, // 3dNow! - INST_PFRSQIT1, // 3dNow! - INST_PFRSQRT, // 3dNow! - INST_PFSUB, // 3dNow! - INST_PFSUBR, // 3dNow! - INST_PHADDD, // SSSE3 - INST_PHADDSW, // SSSE3 - INST_PHADDW, // SSSE3 - INST_PHMINPOSUW, // SSE4.1 - INST_PHSUBD, // SSSE3 - INST_PHSUBSW, // SSSE3 - INST_PHSUBW, // SSSE3 - INST_PI2FD, // 3dNow! - INST_PI2FW, // Enhanced 3dNow! - INST_PINSRB, // SSE4.1 - INST_PINSRD, // SSE4.1 - INST_PINSRQ, // SSE4.1 - INST_PINSRW, // MMX-Ext - INST_PMADDUBSW, // SSSE3 - INST_PMADDWD, // MMX/SSE2 - INST_PMAXSB, // SSE4.1 - INST_PMAXSD, // SSE4.1 - INST_PMAXSW, // MMX-Ext - INST_PMAXUB, // MMX-Ext - INST_PMAXUD, // SSE4.1 - INST_PMAXUW, // SSE4.1 - INST_PMINSB, // SSE4.1 - INST_PMINSD, // SSE4.1 - INST_PMINSW, // MMX-Ext - INST_PMINUB, // MMX-Ext - INST_PMINUD, // SSE4.1 - INST_PMINUW, // SSE4.1 - INST_PMOVMSKB, // MMX-Ext - INST_PMOVSXBD, // SSE4.1 - INST_PMOVSXBQ, // SSE4.1 - INST_PMOVSXBW, // SSE4.1 - INST_PMOVSXDQ, // SSE4.1 - INST_PMOVSXWD, // SSE4.1 - INST_PMOVSXWQ, // SSE4.1 - INST_PMOVZXBD, // SSE4.1 - INST_PMOVZXBQ, // SSE4.1 - INST_PMOVZXBW, // SSE4.1 - INST_PMOVZXDQ, // SSE4.1 - INST_PMOVZXWD, // SSE4.1 - INST_PMOVZXWQ, // SSE4.1 - INST_PMULDQ, // SSE4.1 - INST_PMULHRSW, // SSSE3 - INST_PMULHUW, // MMX-Ext - INST_PMULHW, // MMX/SSE2 - INST_PMULLD, // SSE4.1 - INST_PMULLW, // MMX/SSE2 - INST_PMULUDQ, // SSE2 - INST_POP, // X86/X64 - INST_POPAD, // X86 only - INST_POPCNT, // SSE4.2 - INST_POPFD, // X86 only - INST_POPFQ, // X64 only - INST_POR, // MMX/SSE2 - INST_PREFETCH, // MMX-Ext - INST_PSADBW, // MMX-Ext - INST_PSHUFB, // SSSE3 - INST_PSHUFD, // SSE2 - INST_PSHUFW, // MMX-Ext - INST_PSHUFHW, // SSE2 - INST_PSHUFLW, // SSE2 - INST_PSIGNB, // SSSE3 - INST_PSIGND, // SSSE3 - INST_PSIGNW, // SSSE3 - INST_PSLLD, // MMX/SSE2 - INST_PSLLDQ, // SSE2 - INST_PSLLQ, // MMX/SSE2 - INST_PSLLW, // MMX/SSE2 - INST_PSRAD, // MMX/SSE2 - INST_PSRAW, // MMX/SSE2 - INST_PSRLD, // MMX/SSE2 - INST_PSRLDQ, // SSE2 - INST_PSRLQ, // MMX/SSE2 - INST_PSRLW, // MMX/SSE2 - INST_PSUBB, // MMX/SSE2 - INST_PSUBD, // MMX/SSE2 - INST_PSUBQ, // SSE2 - INST_PSUBSB, // MMX/SSE2 - INST_PSUBSW, // MMX/SSE2 - INST_PSUBUSB, // MMX/SSE2 - INST_PSUBUSW, // MMX/SSE2 - INST_PSUBW, // MMX/SSE2 - INST_PSWAPD, // Enhanced 3dNow! - INST_PTEST, // SSE4.1 - INST_PUNPCKHBW, // MMX/SSE2 - INST_PUNPCKHDQ, // MMX/SSE2 - INST_PUNPCKHQDQ, // SSE2 - INST_PUNPCKHWD, // MMX/SSE2 - INST_PUNPCKLBW, // MMX/SSE2 - INST_PUNPCKLDQ, // MMX/SSE2 - INST_PUNPCKLQDQ, // SSE2 - INST_PUNPCKLWD, // MMX/SSE2 - INST_PUSH, // X86/X64 - INST_PUSHAD, // X86 only - INST_PUSHFD, // X86 only - INST_PUSHFQ, // X64 only - INST_PXOR, // MMX/SSE2 - INST_RCL, // X86/X64 - INST_RCPPS, // SSE - INST_RCPSS, // SSE - INST_RCR, // X86/X64 - INST_RDTSC, // X86/X64 - INST_RDTSCP, // X86/X64 - INST_REP_LODSB, // X86/X64 (REP) - INST_REP_LODSD, // X86/X64 (REP) - INST_REP_LODSQ, // X64 only (REP) - INST_REP_LODSW, // X86/X64 (REP) - INST_REP_MOVSB, // X86/X64 (REP) - INST_REP_MOVSD, // X86/X64 (REP) - INST_REP_MOVSQ, // X64 only (REP) - INST_REP_MOVSW, // X86/X64 (REP) - INST_REP_STOSB, // X86/X64 (REP) - INST_REP_STOSD, // X86/X64 (REP) - INST_REP_STOSQ, // X64 only (REP) - INST_REP_STOSW, // X86/X64 (REP) - INST_REPE_CMPSB, // X86/X64 (REP) - INST_REPE_CMPSD, // X86/X64 (REP) - INST_REPE_CMPSQ, // X64 only (REP) - INST_REPE_CMPSW, // X86/X64 (REP) - INST_REPE_SCASB, // X86/X64 (REP) - INST_REPE_SCASD, // X86/X64 (REP) - INST_REPE_SCASQ, // X64 only (REP) - INST_REPE_SCASW, // X86/X64 (REP) - INST_REPNE_CMPSB, // X86/X64 (REP) - INST_REPNE_CMPSD, // X86/X64 (REP) - INST_REPNE_CMPSQ, // X64 only (REP) - INST_REPNE_CMPSW, // X86/X64 (REP) - INST_REPNE_SCASB, // X86/X64 (REP) - INST_REPNE_SCASD, // X86/X64 (REP) - INST_REPNE_SCASQ, // X64 only (REP) - INST_REPNE_SCASW, // X86/X64 (REP) - INST_RET, // X86/X64 - INST_ROL, // X86/X64 - INST_ROR, // X86/X64 - INST_ROUNDPD, // SSE4.1 - INST_ROUNDPS, // SSE4.1 - INST_ROUNDSD, // SSE4.1 - INST_ROUNDSS, // SSE4.1 - INST_RSQRTPS, // SSE - INST_RSQRTSS, // SSE - INST_SAHF, // X86/X64 (CPUID NEEDED) - INST_SAL, // X86/X64 - INST_SAR, // X86/X64 - INST_SBB, // X86/X64 - INST_SET, // Begin (setcc) - INST_SETA=INST_SET, // X86/X64 (setcc) - INST_SETAE, // X86/X64 (setcc) - INST_SETB, // X86/X64 (setcc) - INST_SETBE, // X86/X64 (setcc) - INST_SETC, // X86/X64 (setcc) - INST_SETE, // X86/X64 (setcc) - INST_SETG, // X86/X64 (setcc) - INST_SETGE, // X86/X64 (setcc) - INST_SETL, // X86/X64 (setcc) - INST_SETLE, // X86/X64 (setcc) - INST_SETNA, // X86/X64 (setcc) - INST_SETNAE, // X86/X64 (setcc) - INST_SETNB, // X86/X64 (setcc) - INST_SETNBE, // X86/X64 (setcc) - INST_SETNC, // X86/X64 (setcc) - INST_SETNE, // X86/X64 (setcc) - INST_SETNG, // X86/X64 (setcc) - INST_SETNGE, // X86/X64 (setcc) - INST_SETNL, // X86/X64 (setcc) - INST_SETNLE, // X86/X64 (setcc) - INST_SETNO, // X86/X64 (setcc) - INST_SETNP, // X86/X64 (setcc) - INST_SETNS, // X86/X64 (setcc) - INST_SETNZ, // X86/X64 (setcc) - INST_SETO, // X86/X64 (setcc) - INST_SETP, // X86/X64 (setcc) - INST_SETPE, // X86/X64 (setcc) - INST_SETPO, // X86/X64 (setcc) - INST_SETS, // X86/X64 (setcc) - INST_SETZ, // X86/X64 (setcc) - INST_SFENCE, // MMX-Ext/SSE - INST_SHL, // X86/X64 - INST_SHLD, // X86/X64 - INST_SHR, // X86/X64 - INST_SHRD, // X86/X64 - INST_SHUFPD, // SSE2 - INST_SHUFPS, // SSE - INST_SQRTPD, // SSE2 - INST_SQRTPS, // SSE - INST_SQRTSD, // SSE2 - INST_SQRTSS, // SSE - INST_STC, // X86/X64 - INST_STD, // X86/X64 - INST_STMXCSR, // SSE - INST_SUB, // X86/X64 - INST_SUBPD, // SSE2 - INST_SUBPS, // SSE - INST_SUBSD, // SSE2 - INST_SUBSS, // SSE - INST_TEST, // X86/X64 - INST_UCOMISD, // SSE2 - INST_UCOMISS, // SSE - INST_UD2, // X86/X64 - INST_UNPCKHPD, // SSE2 - INST_UNPCKHPS, // SSE - INST_UNPCKLPD, // SSE2 - INST_UNPCKLPS, // SSE - INST_XADD, // X86/X64 (i486) - INST_XCHG, // X86/X64 (i386) - INST_XOR, // X86/X64 - INST_XORPD, // SSE2 - INST_XORPS, // SSE - - _INST_COUNT, - - _INST_J_BEGIN = INST_J, - _INST_J_END = INST_JMP -}; - -// ============================================================================ -// [AsmJit::Instruction Name] -// ============================================================================ - -//! @internal -//! -//! @brief Instruction names. -ASMJIT_API extern const char instructionName[]; - -// ============================================================================ -// [AsmJit::Instruction Description] -// ============================================================================ - -struct InstructionDescription -{ - // -------------------------------------------------------------------------- - // [Instruction Groups] - // -------------------------------------------------------------------------- - - //! @brief Instruction groups. - //! - //! This should be only used by assembler, because it's @c AsmJit::Assembler - //! specific grouping. Each group represents one 'case' in the Assembler's - //! main emit method. - enum G - { - // Gloup categories. - G_EMIT, - - G_ALU, - G_BSWAP, - G_BT, - G_CALL, - G_CRC32, - G_ENTER, - G_IMUL, - G_INC_DEC, - G_J, - G_JMP, - G_LEA, - G_M, - G_MOV, - G_MOV_PTR, - G_MOVSX_MOVZX, - G_MOVSXD, - G_PUSH, // I_PUSH is implemented before I_POP - G_POP, - G_R_RM, - G_RM_B, - G_RM, - G_RM_R, - G_REP, - G_RET, - G_ROT, - G_SHLD_SHRD, - G_TEST, - G_XCHG, - - // Group for x87 FP instructions in format mem or st(i), st(i) (fadd, fsub, fdiv, ...) - G_X87_FPU, - // Group for x87 FP instructions in format st(i), st(i) - G_X87_STI, - // Group for fld/fst/fstp instruction, internally uses I_X87_MEM group. - G_X87_MEM_STI, - // Group for x87 FP instructions that uses Word, DWord, QWord or TWord memory pointer. - G_X87_MEM, - // Group for x87 FSTSW/FNSTSW instructions - G_X87_FSTSW, - - // Group for movbe instruction - G_MOVBE, - - // Group for MMX/SSE instructions in format (X)MM|Reg|Mem <- (X)MM|Reg|Mem, - // 0x66 prefix must be set manually in opcodes. - // - Primary opcode is used for instructions in (X)MM <- (X)MM/Mem format, - // - Secondary opcode is used for instructions in (X)MM/Mem <- (X)MM format. - G_MMU_MOV, - - // Group for movd and movq instructions. - G_MMU_MOVD, - G_MMU_MOVQ, - - // Group for pextrd, pextrq and pextrw instructions (it's special instruction - // not similar to others) - G_MMU_PEXTR, - - // Group for prefetch instruction - G_MMU_PREFETCH, - - // Group for MMX/SSE instructions in format (X)MM|Reg <- (X)MM|Reg|Mem|Imm, - // 0x66 prefix is added for MMX instructions that used by SSE2 registers. - // - Primary opcode is used for instructions in (X)MM|Reg <- (X)MM|Reg|Mem format, - // - Secondary opcode is iused for instructions in (X)MM|Reg <- Imm format. - G_MMU_RMI, - G_MMU_RM_IMM8, - - // Group for 3dNow instructions - G_MMU_RM_3DNOW - }; - - // -------------------------------------------------------------------------- - // [Instruction Core Flags] - // -------------------------------------------------------------------------- - - //! @brief Instruction core flags. - enum F - { - //! @brief No flags. - F_NONE = 0x00, - //! @brief Instruction is jump, conditional jump, call or ret. - F_JUMP = 0x01, - //! @brief Instruction will overwrite first operand - o[0]. - F_MOV = 0x02, - //! @brief Instruction is X87 FPU. - F_FPU = 0x04, - //! @brief Instruction can be prepended using LOCK prefix - //! (usable for multithreaded applications). - F_LOCKABLE = 0x08, - - //! @brief Instruction is special, this is for @c Compiler. - F_SPECIAL = 0x10, - //! @brief Instruction always performs memory access. - //! - //! This flag is always combined with @c F_SPECIAL and signalizes that - //! there is implicit address which is accessed (usually EDI/RDI or ESI/EDI). - F_SPECIAL_MEM = 0x20 - }; - - // -------------------------------------------------------------------------- - // [Instruction Operand Flags] - // -------------------------------------------------------------------------- - - //! @brief Instruction operand flags. - enum O - { - // X86, MM, XMM - O_GB = 0x0001, - O_GW = 0x0002, - O_GD = 0x0004, - O_GQ = 0x0008, - O_MM = 0x0010, - O_XMM = 0x0020, - O_MEM = 0x0040, - O_IMM = 0x0080, - - - O_GB_MEM = O_GB | O_MEM, - O_GW_MEM = O_GW | O_MEM, - O_GD_MEM = O_GD | O_MEM, - O_GQ_MEM = O_GQ | O_MEM, - - O_GQDWB = O_GQ | O_GD | O_GW | O_GB, - O_GQDW = O_GQ | O_GD | O_GW, - O_GQD = O_GQ | O_GD, - O_GWB = O_GW | O_GB, - - O_GQDWB_MEM = O_GQDWB | O_MEM, - O_GQDW_MEM = O_GQDW | O_MEM, - O_GQD_MEM = O_GQD | O_MEM, - O_GWB_MEM = O_GWB | O_MEM, - - O_MM_MEM = O_MM | O_MEM, - O_XMM_MEM = O_XMM | O_MEM, - O_MM_XMM = O_MM | O_XMM, - O_MM_XMM_MEM = O_MM | O_XMM | O_MEM, - - // X87 - O_FM_2 = O_MEM | 0x0100, - O_FM_4 = O_MEM | 0x0200, - O_FM_8 = O_MEM | 0x0400, - O_FM_10 = O_MEM | 0x0800, - - O_FM_2_4 = O_FM_2 | O_FM_4, - O_FM_2_4_8 = O_FM_2 | O_FM_4 | O_FM_8, - O_FM_4_8 = O_FM_4 | O_FM_8, - O_FM_4_8_10 = O_FM_4 | O_FM_8 | O_FM_10, - - // Don't emit REX prefix. - O_NOREX = 0x2000 - }; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! @brief Instruction code. - uint16_t code; - //! @brief Instruction name index in instructionName[] array. - uint16_t nameIndex; - //! @brief Instruction group, used also by @c Compiler. - uint8_t group; - //! @brief Instruction type flags. - uint8_t flags; - //! @brief First and second operand flags (some groups depends on these settings, used also by @c Compiler). - uint16_t oflags[2]; - //! @brief If instruction has only memory operand, this is register opcode. - uint16_t opCodeR; - //! @brief Primary and secondary opcodes. - uint32_t opCode[2]; - - //! @brief Get the instruction name (null terminated string). - inline const char* getName() const { return instructionName + nameIndex; } - - //! @brief Get whether the instruction is conditional or standard jump. - inline bool isJump() const { return (flags & F_JUMP) != 0; } - //! @brief Get whether the instruction is MOV type. - inline bool isMov() const { return (flags & F_MOV) != 0; } - //! @brief Get whether the instruction is X87 FPU type. - inline bool isFPU() const { return (flags & F_FPU) != 0; } - //! @brief Get whether the instruction can be prefixed by LOCK prefix. - inline bool isLockable() const { return (flags & F_LOCKABLE) != 0; } - - //! @brief Get whether the instruction is special type (this is used by - //! @c Compiler to manage additional variables or functionality). - inline bool isSpecial() const { return (flags & F_SPECIAL) != 0; } - //! @brief Get whether the instruction is special type and it performs - //! memory access. - inline bool isSpecialMem() const { return (flags & F_SPECIAL_MEM) != 0; } -}; - -ASMJIT_API extern const InstructionDescription instructionDescription[]; - -// ============================================================================ -// [AsmJit::EMIT_OPTIONS] -// ============================================================================ - -//! @brief Emit options, mainly for internal purposes. -enum EMIT_OPTIONS -{ - //! @brief Force REX prefix to be emitted. - //! - //! This option should be used carefully, because there are unencodable - //! combinations. If you want to access ah, bh, ch or dh registers then you - //! can't emit REX prefix and it will cause an illegal instruction error. - EMIT_OPTION_REX_PREFIX = (1 << 0), - - //! @brief Tell @c Assembler or @c Compiler to emit and validate lock prefix. - //! - //! If this option is used and instruction doesn't support LOCK prefix then - //! invalid instruction error is generated. - EMIT_OPTION_LOCK_PREFIX = (1 << 1), - - //! @brief Emit short/near jump or conditional jump instead of far one, - //! saving some bytes. - EMIT_OPTION_SHORT_JUMP = (1 << 2) -}; - -// ============================================================================ -// [AsmJit::CALL_CONV] -// ============================================================================ - -//! @brief Calling convention type. -//! -//! Calling convention is scheme how function arguments are passed into -//! function and how functions returns values. In assembler programming -//! it's needed to always comply with function calling conventions, because -//! even small inconsistency can cause undefined behavior or crash. -//! -//! List of calling conventions for 32-bit x86 mode: -//! - @c CALL_CONV_CDECL - Calling convention for C runtime. -//! - @c CALL_CONV_STDCALL - Calling convention for WinAPI functions. -//! - @c CALL_CONV_MSTHISCALL - Calling convention for C++ members under -//! Windows (produced by MSVC and all MSVC compatible compilers). -//! - @c CALL_CONV_MSFASTCALL - Fastest calling convention that can be used -//! by MSVC compiler. -//! - @c CALL_CONV_BORNANDFASTCALL - Borland fastcall convention. -//! - @c CALL_CONV_GCCFASTCALL - GCC fastcall convention (2 register arguments). -//! - @c CALL_CONV_GCCREGPARM_1 - GCC regparm(1) convention. -//! - @c CALL_CONV_GCCREGPARM_2 - GCC regparm(2) convention. -//! - @c CALL_CONV_GCCREGPARM_3 - GCC regparm(3) convention. -//! -//! List of calling conventions for 64-bit x86 mode (x64): -//! - @c CALL_CONV_X64W - Windows 64-bit calling convention (WIN64 ABI). -//! - @c CALL_CONV_X64U - Unix 64-bit calling convention (AMD64 ABI). -//! -//! There is also @c CALL_CONV_DEFAULT that is defined to fit best to your -//! compiler. -//! -//! These types are used together with @c AsmJit::Compiler::newFunction() -//! method. -enum CALL_CONV -{ - //! @brief Calling convention is invalid (can't be used). - CALL_CONV_NONE = 0, - - // [X64 Calling Conventions] - - //! @brief X64 calling convention for Windows platform (WIN64 ABI). - //! - //! For first four arguments are used these registers: - //! - 1. 32/64-bit integer or floating point argument - rcx/xmm0 - //! - 2. 32/64-bit integer or floating point argument - rdx/xmm1 - //! - 3. 32/64-bit integer or floating point argument - r8/xmm2 - //! - 4. 32/64-bit integer or floating point argument - r9/xmm3 - //! - //! Note first four arguments here means arguments at positions from 1 to 4 - //! (included). For example if second argument is not passed by register then - //! rdx/xmm1 register is unused. - //! - //! All other arguments are pushed on the stack in right-to-left direction. - //! Stack is aligned by 16 bytes. There is 32-byte shadow space on the stack - //! that can be used to save up to four 64-bit registers (probably designed to - //! be used to save first four arguments passed in registers). - //! - //! Arguments direction: - //! - Right to Left (except for first 4 parameters that's in registers) - //! - //! Stack is cleaned by: - //! - Caller. - //! - //! Return value: - //! - Integer types - RAX register. - //! - Floating points - XMM0 register. - //! - //! Stack is always aligned by 16 bytes. - //! - //! More information about this calling convention can be found on MSDN: - //! http://msdn.microsoft.com/en-us/library/9b372w95.aspx . - CALL_CONV_X64W = 1, - - //! @brief X64 calling convention for Unix platforms (AMD64 ABI). - //! - //! First six 32 or 64-bit integer arguments are passed in rdi, rsi, rdx, - //! rcx, r8, r9 registers. First eight floating point or XMM arguments - //! are passed in xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 registers. - //! This means that in registers can be transferred up to 14 arguments total. - //! - //! There is also RED ZONE below the stack pointer that can be used for - //! temporary storage. The red zone is the space from [rsp-128] to [rsp-8]. - //! - //! Arguments direction: - //! - Right to Left (Except for arguments passed in registers). - //! - //! Stack is cleaned by: - //! - Caller. - //! - //! Return value: - //! - Integer types - RAX register. - //! - Floating points - XMM0 register. - //! - //! Stack is always aligned by 16 bytes. - CALL_CONV_X64U = 2, - - // [X86 Calling Conventions] - - //! @brief Cdecl calling convention (used by C runtime). - //! - //! Compatible across MSVC and GCC. - //! - //! Arguments direction: - //! - Right to Left - //! - //! Stack is cleaned by: - //! - Caller. - CALL_CONV_CDECL = 3, - - //! @brief Stdcall calling convention (used by WinAPI). - //! - //! Compatible across MSVC and GCC. - //! - //! Arguments direction: - //! - Right to Left - //! - //! Stack is cleaned by: - //! - Callee. - //! - //! Return value: - //! - Integer types - EAX:EDX registers. - //! - Floating points - st(0) register. - CALL_CONV_STDCALL = 4, - - //! @brief MSVC specific calling convention used by MSVC/Intel compilers - //! for struct/class methods. - //! - //! This is MSVC (and Intel) only calling convention used in Windows - //! world for C++ class methods. Implicit 'this' pointer is stored in - //! ECX register instead of storing it on the stack. - //! - //! Arguments direction: - //! - Right to Left (except this pointer in ECX) - //! - //! Stack is cleaned by: - //! - Callee. - //! - //! Return value: - //! - Integer types - EAX:EDX registers. - //! - Floating points - st(0) register. - //! - //! C++ class methods that have variable count of arguments uses different - //! calling convention called cdecl. - //! - //! @note This calling convention is always used by MSVC for class methods, - //! it's implicit and there is no way how to override it. - CALL_CONV_MSTHISCALL = 5, - - //! @brief MSVC specific fastcall. - //! - //! Two first parameters (evaluated from left-to-right) are in ECX:EDX - //! registers, all others on the stack in right-to-left order. - //! - //! Arguments direction: - //! - Right to Left (except to first two integer arguments in ECX:EDX) - //! - //! Stack is cleaned by: - //! - Callee. - //! - //! Return value: - //! - Integer types - EAX:EDX registers. - //! - Floating points - st(0) register. - //! - //! @note This calling convention differs to GCC one in stack cleaning - //! mechanism. - CALL_CONV_MSFASTCALL = 6, - - //! @brief Borland specific fastcall with 2 parameters in registers. - //! - //! Two first parameters (evaluated from left-to-right) are in ECX:EDX - //! registers, all others on the stack in left-to-right order. - //! - //! Arguments direction: - //! - Left to Right (except to first two integer arguments in ECX:EDX) - //! - //! Stack is cleaned by: - //! - Callee. - //! - //! Return value: - //! - Integer types - EAX:EDX registers. - //! - Floating points - st(0) register. - //! - //! @note Arguments on the stack are in left-to-right order that differs - //! to other fastcall conventions used in different compilers. - CALL_CONV_BORLANDFASTCALL = 7, - - //! @brief GCC specific fastcall convention. - //! - //! Two first parameters (evaluated from left-to-right) are in ECX:EDX - //! registers, all others on the stack in right-to-left order. - //! - //! Arguments direction: - //! - Right to Left (except to first two integer arguments in ECX:EDX) - //! - //! Stack is cleaned by: - //! - Callee. - //! - //! Return value: - //! - Integer types - EAX:EDX registers. - //! - Floating points - st(0) register. - //! - //! @note This calling convention should be compatible to - //! @c CALL_CONV_MSFASTCALL. - CALL_CONV_GCCFASTCALL = 8, - - //! @brief GCC specific regparm(1) convention. - //! - //! The first parameter (evaluated from left-to-right) is in EAX register, - //! all others on the stack in right-to-left order. - //! - //! Arguments direction: - //! - Right to Left (except to first one integer argument in EAX) - //! - //! Stack is cleaned by: - //! - Caller. - //! - //! Return value: - //! - Integer types - EAX:EDX registers. - //! - Floating points - st(0) register. - CALL_CONV_GCCREGPARM_1 = 9, - - //! @brief GCC specific regparm(2) convention. - //! - //! Two first parameters (evaluated from left-to-right) are in EAX:EDX - //! registers, all others on the stack in right-to-left order. - //! - //! Arguments direction: - //! - Right to Left (except to first two integer arguments in EAX:EDX) - //! - //! Stack is cleaned by: - //! - Caller. - //! - //! Return value: - //! - Integer types - EAX:EDX registers. - //! - Floating points - st(0) register. - CALL_CONV_GCCREGPARM_2 = 10, - - //! @brief GCC specific fastcall with 3 parameters in registers. - //! - //! Three first parameters (evaluated from left-to-right) are in - //! EAX:EDX:ECX registers, all others on the stack in right-to-left order. - //! - //! Arguments direction: - //! - Right to Left (except to first three integer arguments in EAX:EDX:ECX) - //! - //! Stack is cleaned by: - //! - Caller. - //! - //! Return value: - //! - Integer types - EAX:EDX registers. - //! - Floating points - st(0) register. - CALL_CONV_GCCREGPARM_3 = 11, - - // [Preferred Calling Convention] - - //! @def CALL_CONV_DEFAULT - //! @brief Default calling convention for current platform / operating system. - -#if defined(ASMJIT_X86) - - CALL_CONV_DEFAULT = CALL_CONV_CDECL, - -# if defined(_MSC_VER) - CALL_CONV_COMPAT_FASTCALL = CALL_CONV_MSFASTCALL, -# elif defined(__GNUC__) - CALL_CONV_COMPAT_FASTCALL = CALL_CONV_GCCFASTCALL, -# elif defined(__BORLANDC__) - CALL_CONV_COMPAT_FASTCALL = CALL_CONV_BORLANDFASTCALL, -# else -# error "AsmJit::CALL_CONV_COMPATIBLE_FASTCALL_2 - Unsupported." -# endif - - CALL_CONV_COMPAT_STDCALL = CALL_CONV_STDCALL, - CALL_CONV_COMPAT_CDECL = CALL_CONV_CDECL - -#else - -# if defined(ASMJIT_WINDOWS) - CALL_CONV_DEFAULT = CALL_CONV_X64W, -# else - CALL_CONV_DEFAULT = CALL_CONV_X64U, -# endif - - CALL_CONV_COMPAT_FASTCALL = CALL_CONV_DEFAULT, - CALL_CONV_COMPAT_STDCALL = CALL_CONV_DEFAULT, - CALL_CONV_COMPAT_CDECL = CALL_CONV_DEFAULT - -#endif // ASMJIT_X86 -}; - -// ============================================================================ -// [AsmJit::VARIABLE_TYPE] -// ============================================================================ - -//! @brief Variable type. -enum VARIABLE_TYPE -{ - // -------------------------------------------------------------------------- - // [Platform Dependent] - // -------------------------------------------------------------------------- - - //! @brief Variable is 32-bit general purpose register. - VARIABLE_TYPE_GPD = 0, - //! @brief Variable is 64-bit general purpose register. - VARIABLE_TYPE_GPQ = 1, - - //! @var VARIABLE_TYPE_GPN - //! @brief Variable is system wide general purpose register (32-bit or 64-bit). -#if defined(ASMJIT_X86) - VARIABLE_TYPE_GPN = VARIABLE_TYPE_GPD, -#else - VARIABLE_TYPE_GPN = VARIABLE_TYPE_GPQ, -#endif - - //! @brief Variable is X87 (FPU). - VARIABLE_TYPE_X87 = 2, - - //! @brief Variable is X87 (FPU) SP-FP number (float). - VARIABLE_TYPE_X87_1F = 3, - - //! @brief Variable is X87 (FPU) DP-FP number (double). - VARIABLE_TYPE_X87_1D = 4, - - //! @brief Variable is MM register / memory location. - VARIABLE_TYPE_MM = 5, - - //! @brief Variable is XMM register / memory location. - VARIABLE_TYPE_XMM = 6, - - //! @brief Variable is SSE scalar SP-FP number. - VARIABLE_TYPE_XMM_1F = 7, - //! @brief Variable is SSE packed SP-FP number (4 floats). - VARIABLE_TYPE_XMM_4F = 8, - - //! @brief Variable is SSE2 scalar DP-FP number. - VARIABLE_TYPE_XMM_1D = 9, - //! @brief Variable is SSE2 packed DP-FP number (2 doubles). - VARIABLE_TYPE_XMM_2D = 10, - - //! @brief Count of variable types. - _VARIABLE_TYPE_COUNT = 11, - - // -------------------------------------------------------------------------- - // [Platform Independent] - // -------------------------------------------------------------------------- - - //! @brief Variable is 32-bit integer. - VARIABLE_TYPE_INT32 = VARIABLE_TYPE_GPD, - //! @brief Variable is 64-bit integer. - VARIABLE_TYPE_INT64 = VARIABLE_TYPE_GPQ, - //! @brief Variable is system dependent integer / pointer. - VARIABLE_TYPE_INTPTR = VARIABLE_TYPE_GPN, - -#if !defined(ASMJIT_NODOC) -#if defined(ASMJIT_X86) - VARIABLE_TYPE_FLOAT = VARIABLE_TYPE_X87_1F, - VARIABLE_TYPE_DOUBLE = VARIABLE_TYPE_X87_1D -#else - VARIABLE_TYPE_FLOAT = VARIABLE_TYPE_XMM_1F, - VARIABLE_TYPE_DOUBLE = VARIABLE_TYPE_XMM_1D -#endif -#else - //! @brief Variable is SP-FP (x87 or xmm). - VARIABLE_TYPE_FLOAT = XXX, - //! @brief Variable is DP-FP (x87 or xmm). - VARIABLE_TYPE_DOUBLE = XXX -#endif -}; - -// ============================================================================ -// [AsmJit::VARIABLE_HINT] -// ============================================================================ - -//! @brief Variable hint (used by @ref Compiler). -//! -//! @sa @ref Compiler. -enum VARIABLE_HINT -{ - //! @brief Alloc variable. - VARIABLE_HINT_ALLOC = 0, - //! @brief Spill variable. - VARIABLE_HINT_SPILL = 1, - //! @brief Save variable if modified. - VARIABLE_HINT_SAVE = 2, - //! @brief Save variable if modified and mark it as unused. - VARIABLE_HINT_SAVE_AND_UNUSE = 3, - //! @brief Mark variable as unused. - VARIABLE_HINT_UNUSE = 4 -}; - -//! @} - -} // AsmJit namespace - -// [Api-End] -#include "ApiEnd.h" - -// [Guard] -#endif // _ASMJIT_DEFSX86X64_H diff --git a/desmume/src/utils/AsmJit/Logger.cpp b/desmume/src/utils/AsmJit/Logger.cpp deleted file mode 100644 index 1fc8f773d..000000000 --- a/desmume/src/utils/AsmJit/Logger.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// We are using sprintf() here. -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif // _MSC_VER - -// [Dependencies] -#include "Logger.h" - -#include -#include -#include - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -// ============================================================================ -// [AsmJit::Logger] -// ============================================================================ - -Logger::Logger() ASMJIT_NOTHROW : - _enabled(true), - _used(true), - _logBinary(false) -{ -} - -Logger::~Logger() ASMJIT_NOTHROW -{ -} - -void Logger::logFormat(const char* fmt, ...) ASMJIT_NOTHROW -{ - char buf[1024]; - sysuint_t len; - - va_list ap; - va_start(ap, fmt); - len = vsnprintf(buf, 1023, fmt, ap); - va_end(ap); - - logString(buf, len); -} - -void Logger::setEnabled(bool enabled) ASMJIT_NOTHROW -{ - _enabled = enabled; - _used = enabled; -} - -// ============================================================================ -// [AsmJit::FileLogger] -// ============================================================================ - -FileLogger::FileLogger(FILE* stream) ASMJIT_NOTHROW - : _stream(NULL) -{ - setStream(stream); -} - -void FileLogger::logString(const char* buf, sysuint_t len) ASMJIT_NOTHROW -{ - if (!_used) return; - - if (len == (sysuint_t)-1) len = strlen(buf); - fwrite(buf, 1, len, _stream); -} - -void FileLogger::setEnabled(bool enabled) ASMJIT_NOTHROW -{ - _enabled = enabled; - _used = (_enabled == true) & (_stream != NULL); -} - -//! @brief Set file stream. -void FileLogger::setStream(FILE* stream) ASMJIT_NOTHROW -{ - _stream = stream; - _used = (_enabled == true) & (_stream != NULL); -} - -} // AsmJit namespace - -// [Api-End] -#include "ApiEnd.h" diff --git a/desmume/src/utils/AsmJit/Logger.h b/desmume/src/utils/AsmJit/Logger.h deleted file mode 100644 index dc8126c41..000000000 --- a/desmume/src/utils/AsmJit/Logger.h +++ /dev/null @@ -1,175 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_LOGGER_H -#define _ASMJIT_LOGGER_H - -// [Dependencies] -#include "Defs.h" - -#include -#include -#include - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -//! @addtogroup AsmJit_Logging -//! @{ - -//! @brief Abstract logging class. -//! -//! This class can be inherited and reimplemented to fit into your logging -//! subsystem. When reimplementing use @c AsmJit::Logger::log() method to -//! log into your stream. -//! -//! This class also contain @c _enabled member that can be used to enable -//! or disable logging. -struct ASMJIT_API Logger -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create logger. - Logger() ASMJIT_NOTHROW; - //! @brief Destroy logger. - virtual ~Logger() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Logging] - // -------------------------------------------------------------------------- - - //! @brief Abstract method to log output. - //! - //! Default implementation that is in @c AsmJit::Logger is to do nothing. - //! It's virtual to fit to your logging system. - virtual void logString(const char* buf, sysuint_t len = (sysuint_t)-1) ASMJIT_NOTHROW = 0; - - //! @brief Log formatter message (like sprintf) sending output to @c logString() method. - virtual void logFormat(const char* fmt, ...) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Enabled] - // -------------------------------------------------------------------------- - - //! @brief Return @c true if logging is enabled. - inline bool isEnabled() const ASMJIT_NOTHROW { return _enabled; } - - //! @brief Set logging to enabled or disabled. - virtual void setEnabled(bool enabled) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Used] - // -------------------------------------------------------------------------- - - //! @brief Get whether the logger should be used. - inline bool isUsed() const ASMJIT_NOTHROW { return _used; } - - // -------------------------------------------------------------------------- - // [LogBinary] - // -------------------------------------------------------------------------- - - //! @brief Get whether logging binary output. - inline bool getLogBinary() const { return _logBinary; } - //! @brief Get whether to log binary output. - inline void setLogBinary(bool val) { _logBinary = val; } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - - //! @brief Whether logger is enabled or disabled. - //! - //! Default @c true. - bool _enabled; - - //! @brief Whether logger is enabled and can be used. - //! - //! This value can be set by inherited classes to inform @c Logger that - //! assigned stream (or something that can log output) is invalid. If - //! @c _used is false it means that there is no logging output and AsmJit - //! shouldn't use this logger (because all messages will be lost). - //! - //! This is designed only to optimize cases that logger exists, but its - //! configured not to output messages. The API inside Logging and AsmJit - //! should only check this value when needed. The API outside AsmJit should - //! check only whether logging is @c _enabled. - //! - //! Default @c true. - bool _used; - - //! @brief Whether to log instruction in binary form. - bool _logBinary; - -private: - ASMJIT_DISABLE_COPY(Logger) -}; - -//! @brief Logger that can log to standard C @c FILE* stream. -struct ASMJIT_API FileLogger : public Logger -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create new @c FileLogger. - //! @param stream FILE stream where logging will be sent (can be @c NULL - //! to disable logging). - FileLogger(FILE* stream = NULL) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Logging] - // -------------------------------------------------------------------------- - - virtual void logString(const char* buf, sysuint_t len = (sysuint_t)-1) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Enabled] - // -------------------------------------------------------------------------- - - virtual void setEnabled(bool enabled) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Stream] - // -------------------------------------------------------------------------- - - //! @brief Get @c FILE* stream. - //! - //! @note Return value can be @c NULL. - inline FILE* getStream() const ASMJIT_NOTHROW { return _stream; } - - //! @brief Set @c FILE* stream. - //! - //! @param stream @c FILE stream where to log output (can be @c NULL to - //! disable logging). - void setStream(FILE* stream) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -protected: - //! @brief C file stream. - FILE* _stream; - - ASMJIT_DISABLE_COPY(FileLogger) -}; - -//! @} - -} // AsmJit namespace - -// [Api-End] -#include "ApiEnd.h" - -// [Guard] -#endif // _ASMJIT_LOGGER_H diff --git a/desmume/src/utils/AsmJit/Operand.h b/desmume/src/utils/AsmJit/Operand.h deleted file mode 100644 index c1d0756b0..000000000 --- a/desmume/src/utils/AsmJit/Operand.h +++ /dev/null @@ -1,34 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_OPERAND_H -#define _ASMJIT_OPERAND_H - -// [Dependencies] -#include "Build.h" - -namespace AsmJit { - -//! @addtogroup AsmJit_Core -//! @{ - -// There is currently no platform independent code. - -//! @} - -} // AsmJit namespace - -// ============================================================================ -// [Platform Specific] -// ============================================================================ - -#if defined(ASMJIT_X86) || defined(ASMJIT_X64) -#include "OperandX86X64.h" -#endif // ASMJIT_X86 || ASMJIT_X64 - -// [Guard] -#endif // _ASMJIT_OPERAND_H diff --git a/desmume/src/utils/AsmJit/OperandX86X64.cpp b/desmume/src/utils/AsmJit/OperandX86X64.cpp deleted file mode 100644 index 2901fc736..000000000 --- a/desmume/src/utils/AsmJit/OperandX86X64.cpp +++ /dev/null @@ -1,425 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Dependencies] -#include "Defs.h" -#include "Operand.h" - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -// ============================================================================ -// [AsmJit::Registers - no_reg] -// ============================================================================ - -const GPReg no_reg(_Initialize(), INVALID_VALUE); - -// ============================================================================ -// [AsmJit::Registers - 8-bit] -// ============================================================================ - -const GPReg al(_Initialize(), REG_AL); -const GPReg cl(_Initialize(), REG_CL); -const GPReg dl(_Initialize(), REG_DL); -const GPReg bl(_Initialize(), REG_BL); - -#if defined(ASMJIT_X64) -const GPReg spl(_Initialize(), REG_SPL); -const GPReg bpl(_Initialize(), REG_BPL); -const GPReg sil(_Initialize(), REG_SIL); -const GPReg dil(_Initialize(), REG_DIL); - -const GPReg r8b(_Initialize(), REG_R8B); -const GPReg r9b(_Initialize(), REG_R9B); -const GPReg r10b(_Initialize(), REG_R10B); -const GPReg r11b(_Initialize(), REG_R11B); -const GPReg r12b(_Initialize(), REG_R12B); -const GPReg r13b(_Initialize(), REG_R13B); -const GPReg r14b(_Initialize(), REG_R14B); -const GPReg r15b(_Initialize(), REG_R15B); -#endif // ASMJIT_X64 - -const GPReg ah(_Initialize(), REG_AH); -const GPReg ch(_Initialize(), REG_CH); -const GPReg dh(_Initialize(), REG_DH); -const GPReg bh(_Initialize(), REG_BH); - -// ============================================================================ -// [AsmJit::Registers - 16-bit] -// ============================================================================ - -const GPReg ax(_Initialize(), REG_AX); -const GPReg cx(_Initialize(), REG_CX); -const GPReg dx(_Initialize(), REG_DX); -const GPReg bx(_Initialize(), REG_BX); -const GPReg sp(_Initialize(), REG_SP); -const GPReg bp(_Initialize(), REG_BP); -const GPReg si(_Initialize(), REG_SI); -const GPReg di(_Initialize(), REG_DI); - -#if defined(ASMJIT_X64) -const GPReg r8w(_Initialize(), REG_R8W); -const GPReg r9w(_Initialize(), REG_R9W); -const GPReg r10w(_Initialize(), REG_R10W); -const GPReg r11w(_Initialize(), REG_R11W); -const GPReg r12w(_Initialize(), REG_R12W); -const GPReg r13w(_Initialize(), REG_R13W); -const GPReg r14w(_Initialize(), REG_R14W); -const GPReg r15w(_Initialize(), REG_R15W); -#endif // ASMJIT_X64 - -// ============================================================================ -// [AsmJit::Registers - 32-bit] -// ============================================================================ - -const GPReg eax(_Initialize(), REG_EAX); -const GPReg ecx(_Initialize(), REG_ECX); -const GPReg edx(_Initialize(), REG_EDX); -const GPReg ebx(_Initialize(), REG_EBX); -const GPReg esp(_Initialize(), REG_ESP); -const GPReg ebp(_Initialize(), REG_EBP); -const GPReg esi(_Initialize(), REG_ESI); -const GPReg edi(_Initialize(), REG_EDI); - -#if defined(ASMJIT_X64) -const GPReg r8d(_Initialize(), REG_R8D); -const GPReg r9d(_Initialize(), REG_R9D); -const GPReg r10d(_Initialize(), REG_R10D); -const GPReg r11d(_Initialize(), REG_R11D); -const GPReg r12d(_Initialize(), REG_R12D); -const GPReg r13d(_Initialize(), REG_R13D); -const GPReg r14d(_Initialize(), REG_R14D); -const GPReg r15d(_Initialize(), REG_R15D); -#endif // ASMJIT_X64 - -// ============================================================================ -// [AsmJit::Registers - 64-bit] -// ============================================================================ - -#if defined(ASMJIT_X64) -const GPReg rax(_Initialize(), REG_RAX); -const GPReg rcx(_Initialize(), REG_RCX); -const GPReg rdx(_Initialize(), REG_RDX); -const GPReg rbx(_Initialize(), REG_RBX); -const GPReg rsp(_Initialize(), REG_RSP); -const GPReg rbp(_Initialize(), REG_RBP); -const GPReg rsi(_Initialize(), REG_RSI); -const GPReg rdi(_Initialize(), REG_RDI); - -const GPReg r8(_Initialize(), REG_R8); -const GPReg r9(_Initialize(), REG_R9); -const GPReg r10(_Initialize(), REG_R10); -const GPReg r11(_Initialize(), REG_R11); -const GPReg r12(_Initialize(), REG_R12); -const GPReg r13(_Initialize(), REG_R13); -const GPReg r14(_Initialize(), REG_R14); -const GPReg r15(_Initialize(), REG_R15); -#endif // ASMJIT_X64 - -// ============================================================================ -// [AsmJit::Registers - Native (AsmJit extension)] -// ============================================================================ - -const GPReg nax(_Initialize(), REG_NAX); -const GPReg ncx(_Initialize(), REG_NCX); -const GPReg ndx(_Initialize(), REG_NDX); -const GPReg nbx(_Initialize(), REG_NBX); -const GPReg nsp(_Initialize(), REG_NSP); -const GPReg nbp(_Initialize(), REG_NBP); -const GPReg nsi(_Initialize(), REG_NSI); -const GPReg ndi(_Initialize(), REG_NDI); - -// ============================================================================ -// [AsmJit::Registers - MM] -// ============================================================================ - -const MMReg mm0(_Initialize(), REG_MM0); -const MMReg mm1(_Initialize(), REG_MM1); -const MMReg mm2(_Initialize(), REG_MM2); -const MMReg mm3(_Initialize(), REG_MM3); -const MMReg mm4(_Initialize(), REG_MM4); -const MMReg mm5(_Initialize(), REG_MM5); -const MMReg mm6(_Initialize(), REG_MM6); -const MMReg mm7(_Initialize(), REG_MM7); - -// ============================================================================ -// [AsmJit::Registers - XMM] -// ============================================================================ - -const XMMReg xmm0(_Initialize(), REG_XMM0); -const XMMReg xmm1(_Initialize(), REG_XMM1); -const XMMReg xmm2(_Initialize(), REG_XMM2); -const XMMReg xmm3(_Initialize(), REG_XMM3); -const XMMReg xmm4(_Initialize(), REG_XMM4); -const XMMReg xmm5(_Initialize(), REG_XMM5); -const XMMReg xmm6(_Initialize(), REG_XMM6); -const XMMReg xmm7(_Initialize(), REG_XMM7); - -#if defined(ASMJIT_X64) -const XMMReg xmm8(_Initialize(), REG_XMM8); -const XMMReg xmm9(_Initialize(), REG_XMM9); -const XMMReg xmm10(_Initialize(), REG_XMM10); -const XMMReg xmm11(_Initialize(), REG_XMM11); -const XMMReg xmm12(_Initialize(), REG_XMM12); -const XMMReg xmm13(_Initialize(), REG_XMM13); -const XMMReg xmm14(_Initialize(), REG_XMM14); -const XMMReg xmm15(_Initialize(), REG_XMM15); -#endif // ASMJIT_X64 - -// ============================================================================ -// [AsmJit::Registers - Segment] -// ============================================================================ - -const SegmentReg cs(_Initialize(), REG_CS); -const SegmentReg ss(_Initialize(), REG_SS); -const SegmentReg ds(_Initialize(), REG_DS); -const SegmentReg es(_Initialize(), REG_ES); -const SegmentReg fs(_Initialize(), REG_FS); -const SegmentReg gs(_Initialize(), REG_GS); - -// ============================================================================ -// [AsmJit::Immediate] -// ============================================================================ - -//! @brief Create signed immediate value operand. -Imm imm(sysint_t i) ASMJIT_NOTHROW -{ - return Imm(i, false); -} - -//! @brief Create unsigned immediate value operand. -Imm uimm(sysuint_t i) ASMJIT_NOTHROW -{ - return Imm((sysint_t)i, true); -} - -// ============================================================================ -// [AsmJit::BaseVar] -// ============================================================================ - -Mem _BaseVarMem(const BaseVar& var, uint32_t ptrSize) ASMJIT_NOTHROW -{ - Mem m; //(_DontInitialize()); - - m._mem.op = OPERAND_MEM; - m._mem.size = (ptrSize == INVALID_VALUE) ? var.getSize() : (uint8_t)ptrSize; - m._mem.type = OPERAND_MEM_NATIVE; - m._mem.segmentPrefix = SEGMENT_NONE; - m._mem.sizePrefix = 0; - m._mem.shift = 0; - - m._mem.id = var.getId(); - m._mem.base = INVALID_VALUE; - m._mem.index = INVALID_VALUE; - - m._mem.target = NULL; - m._mem.displacement = 0; - - return m; -} - - -Mem _BaseVarMem(const BaseVar& var, uint32_t ptrSize, sysint_t disp) ASMJIT_NOTHROW -{ - Mem m; //(_DontInitialize()); - - m._mem.op = OPERAND_MEM; - m._mem.size = (ptrSize == INVALID_VALUE) ? var.getSize() : (uint8_t)ptrSize; - m._mem.type = OPERAND_MEM_NATIVE; - m._mem.segmentPrefix = SEGMENT_NONE; - m._mem.sizePrefix = 0; - m._mem.shift = 0; - - m._mem.id = var.getId(); - - m._mem.base = INVALID_VALUE; - m._mem.index = INVALID_VALUE; - - m._mem.target = NULL; - m._mem.displacement = disp; - - return m; -} - -Mem _BaseVarMem(const BaseVar& var, uint32_t ptrSize, const GPVar& index, uint32_t shift, sysint_t disp) ASMJIT_NOTHROW -{ - Mem m; //(_DontInitialize()); - - m._mem.op = OPERAND_MEM; - m._mem.size = (ptrSize == INVALID_VALUE) ? var.getSize() : (uint8_t)ptrSize; - m._mem.type = OPERAND_MEM_NATIVE; - m._mem.segmentPrefix = SEGMENT_NONE; - m._mem.sizePrefix = 0; - m._mem.shift = shift; - - m._mem.id = var.getId(); - - m._mem.base = INVALID_VALUE; - m._mem.index = index.getId(); - - m._mem.target = NULL; - m._mem.displacement = disp; - - return m; -} - -// ============================================================================ -// [AsmJit::Mem - ptr[]] -// ============================================================================ - -Mem _MemPtrBuild( - const Label& label, sysint_t disp, uint32_t ptrSize) - ASMJIT_NOTHROW -{ - return Mem(label, disp, ptrSize); -} - -Mem _MemPtrBuild( - const Label& label, - const GPReg& index, uint32_t shift, sysint_t disp, uint32_t ptrSize) - ASMJIT_NOTHROW -{ - Mem m(label, disp, ptrSize); - - m._mem.index = index.getRegIndex(); - m._mem.shift = shift; - - return m; -} - -Mem _MemPtrBuild( - const Label& label, - const GPVar& index, uint32_t shift, sysint_t disp, uint32_t ptrSize) - ASMJIT_NOTHROW -{ - Mem m(label, disp, ptrSize); - - m._mem.index = index.getId(); - m._mem.shift = shift; - - return m; -} - -// ============================================================================ -// [AsmJit::Mem - ptr[] - Absolute Addressing] -// ============================================================================ - -ASMJIT_API Mem _MemPtrAbs( - void* target, sysint_t disp, - uint32_t segmentPrefix, uint32_t ptrSize) - ASMJIT_NOTHROW -{ - Mem m; - - m._mem.size = ptrSize; - m._mem.type = OPERAND_MEM_ABSOLUTE; - m._mem.segmentPrefix = segmentPrefix; - - m._mem.target = target; - m._mem.displacement = disp; - - return m; -} - -ASMJIT_API Mem _MemPtrAbs( - void* target, - const GPReg& index, uint32_t shift, sysint_t disp, - uint32_t segmentPrefix, uint32_t ptrSize) - ASMJIT_NOTHROW -{ - Mem m;// (_DontInitialize()); - - m._mem.op = OPERAND_MEM; - m._mem.size = ptrSize; - m._mem.type = OPERAND_MEM_ABSOLUTE; - m._mem.segmentPrefix = (uint8_t)segmentPrefix; - -#if defined(ASMJIT_X86) - m._mem.sizePrefix = index.getSize() != 4; -#else - m._mem.sizePrefix = index.getSize() != 8; -#endif - - m._mem.shift = shift; - - m._mem.id = INVALID_VALUE; - m._mem.base = INVALID_VALUE; - m._mem.index = index.getRegIndex(); - - m._mem.target = target; - m._mem.displacement = disp; - - return m; -} - -ASMJIT_API Mem _MemPtrAbs( - void* target, - const GPVar& index, uint32_t shift, sysint_t disp, - uint32_t segmentPrefix, uint32_t ptrSize) - ASMJIT_NOTHROW -{ - Mem m;// (_DontInitialize()); - - m._mem.op = OPERAND_MEM; - m._mem.size = ptrSize; - m._mem.type = OPERAND_MEM_ABSOLUTE; - m._mem.segmentPrefix = (uint8_t)segmentPrefix; - -#if defined(ASMJIT_X86) - m._mem.sizePrefix = index.getSize() != 4; -#else - m._mem.sizePrefix = index.getSize() != 8; -#endif - - m._mem.shift = shift; - - m._mem.id = INVALID_VALUE; - m._mem.base = INVALID_VALUE; - m._mem.index = index.getId(); - - m._mem.target = target; - m._mem.displacement = disp; - - return m; -} - -// ============================================================================ -// [AsmJit::Mem - ptr[base + displacement]] -// ============================================================================ - -Mem _MemPtrBuild( - const GPReg& base, sysint_t disp, uint32_t ptrSize) - ASMJIT_NOTHROW -{ - return Mem(base, disp, ptrSize); -} - -Mem _MemPtrBuild( - const GPReg& base, - const GPReg& index, uint32_t shift, sysint_t disp, uint32_t ptrSize) - ASMJIT_NOTHROW -{ - return Mem(base, index, shift, disp, ptrSize); -} - -Mem _MemPtrBuild( - const GPVar& base, sysint_t disp, uint32_t ptrSize) - ASMJIT_NOTHROW -{ - return Mem(base, disp, ptrSize); -} - -Mem _MemPtrBuild( - const GPVar& base, - const GPVar& index, uint32_t shift, sysint_t disp, uint32_t ptrSize) - ASMJIT_NOTHROW -{ - return Mem(base, index, shift, disp, ptrSize); -} - -} // AsmJit namespace diff --git a/desmume/src/utils/AsmJit/OperandX86X64.h b/desmume/src/utils/AsmJit/OperandX86X64.h deleted file mode 100644 index 9309a27ec..000000000 --- a/desmume/src/utils/AsmJit/OperandX86X64.h +++ /dev/null @@ -1,2383 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_OPERANDX86X64_H -#define _ASMJIT_OPERANDX86X64_H - -#if !defined(_ASMJIT_OPERAND_H) -#warning "AsmJit/OperandX86X64.h can be only included by AsmJit/Operand.h" -#endif // _ASMJIT_OPERAND_H - -// [Dependencies] -#include "Build.h" -#include "Defs.h" - -namespace AsmJit { - -// ============================================================================ -// [AsmJit::Forward Declarations] -// ============================================================================ - -struct BaseReg; -struct BaseVar; -struct Compiler; -struct GPReg; -struct GPVar; -struct Imm; -struct Label; -struct Mem; -struct MMReg; -struct MMVar; -struct Operand; -struct X87Reg; -struct X87Var; -struct XMMReg; -struct XMMVar; - -//! @addtogroup AsmJit_Core -//! @{ - -// ============================================================================ -// [AsmJit::Operand] -// ============================================================================ - -//! @brief Operand, abstract class for register, memory location and immediate -//! value operands. -struct ASMJIT_HIDDEN Operand -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create an uninitialized operand. - inline Operand() ASMJIT_NOTHROW - { - memset(this, 0, sizeof(Operand)); - _base.id = INVALID_VALUE; - } - - //! @brief Create a reference to @a other operand. - inline Operand(const Operand& other) ASMJIT_NOTHROW - { - _init(other); - } - -#if !defined(ASMJIT_NODOC) - inline Operand(const _DontInitialize&) ASMJIT_NOTHROW - { - } -#endif // ASMJIT_NODOC - - // -------------------------------------------------------------------------- - // [Init & Copy] - // -------------------------------------------------------------------------- - - //! @internal - //! - //! @brief Initialize operand to @a other (used by constructors). - inline void _init(const Operand& other) ASMJIT_NOTHROW - { - memcpy(this, &other, sizeof(Operand)); - } - - //! @internal - //! - //! @brief Initialize operand to @a other (used by assign operators). - inline void _copy(const Operand& other) ASMJIT_NOTHROW - { - memcpy(this, &other, sizeof(Operand)); - } - - // -------------------------------------------------------------------------- - // [Identification] - // -------------------------------------------------------------------------- - - //! @brief Get type of operand, see @c OPERAND_TYPE. - inline uint32_t getType() const ASMJIT_NOTHROW - { return _base.op; } - - //! @brief Get whether operand is none (@c OPERAND_NONE). - inline bool isNone() const ASMJIT_NOTHROW - { return (_base.op == OPERAND_NONE); } - - //! @brief Get whether operand is any (general purpose, mmx or sse) register (@c OPERAND_REG). - inline bool isReg() const ASMJIT_NOTHROW - { return (_base.op == OPERAND_REG); } - - //! @brief Get whether operand is memory address (@c OPERAND_MEM). - inline bool isMem() const ASMJIT_NOTHROW - { return (_base.op == OPERAND_MEM); } - - //! @brief Get whether operand is immediate (@c OPERAND_IMM). - inline bool isImm() const ASMJIT_NOTHROW - { return (_base.op == OPERAND_IMM); } - - //! @brief Get whether operand is label (@c OPERAND_LABEL). - inline bool isLabel() const ASMJIT_NOTHROW - { return (_base.op == OPERAND_LABEL); } - - //! @brief Get whether operand is variable (@c OPERAND_VAR). - inline bool isVar() const ASMJIT_NOTHROW - { return (_base.op == OPERAND_VAR); } - - //! @brief Get whether operand is variable or memory. - inline bool isVarMem() const ASMJIT_NOTHROW - { return ((_base.op & (OPERAND_VAR | OPERAND_MEM)) != 0); } - - //! @brief Get whether operand is register and type of register is @a regType. - inline bool isRegType(uint32_t regType) const ASMJIT_NOTHROW - { return (_base.op == OPERAND_REG) & ((_reg.code & REG_TYPE_MASK) == regType); } - - //! @brief Get whether operand is register and code of register is @a regCode. - inline bool isRegCode(uint32_t regCode) const ASMJIT_NOTHROW - { return (_base.op == OPERAND_REG) & (_reg.code == regCode); } - - //! @brief Get whether operand is register and index of register is @a regIndex. - inline bool isRegIndex(uint32_t regIndex) const ASMJIT_NOTHROW - { return (_base.op == OPERAND_REG) & ((_reg.code & REG_INDEX_MASK) == (regIndex & REG_INDEX_MASK)); } - - //! @brief Get whether operand is any register or memory. - inline bool isRegMem() const ASMJIT_NOTHROW - { return ((_base.op & (OPERAND_REG | OPERAND_MEM)) != 0); } - - //! @brief Get whether operand is register of @a regType type or memory. - inline bool isRegTypeMem(uint32_t regType) const ASMJIT_NOTHROW - { return ((_base.op == OPERAND_REG) & ((_reg.code & REG_TYPE_MASK) == regType)) | (_base.op == OPERAND_MEM); } - - // -------------------------------------------------------------------------- - // [Operand Size] - // -------------------------------------------------------------------------- - - //! @brief Return size of operand in bytes. - inline uint32_t getSize() const ASMJIT_NOTHROW - { return _base.size; } - - // -------------------------------------------------------------------------- - // [Operand Id] - // -------------------------------------------------------------------------- - - //! @brief Return operand Id (Operand Id's are used internally by - //! @c Assembler and @c Compiler classes). - //! - //! @note There is no way how to change or remove operand id. If you don't - //! need the operand just assign different operand to this one. - inline uint32_t getId() const ASMJIT_NOTHROW - { return _base.id; } - - // -------------------------------------------------------------------------- - // [Extensions] - // -------------------------------------------------------------------------- - - //! @brief Get whether the extended register (additional eight registers - //! introduced by 64-bit mode) is used. - inline bool isExtendedRegisterUsed() const ASMJIT_NOTHROW - { - // Hacky, but correct. - // - If operand type is register then extended register is register with - // index 8 and greater (8 to 15 inclusive). - // - If operand type is memory operand then we need to take care about - // label (in _mem.base) and INVALID_VALUE, we just decrement the value - // by 8 and check if it's at interval 0 to 7 inclusive (if it's there - // then it's extended register. - return (isReg() && (_reg.code & REG_INDEX_MASK) >= 8) || - (isMem() && ((((uint32_t)_mem.base - 8U) < 8U) || - (((uint32_t)_mem.index - 8U) < 8U) )); - } - - // -------------------------------------------------------------------------- - // [Data Structures] - // -------------------------------------------------------------------------- - - //! @internal - //! - //! @brief Base operand data shared between all operands. - struct BaseData - { - //! @brief Type of operand, see @c OPERAND_TYPE. - uint8_t op; - //! @brief Size of operand (register, address, immediate or variable). - uint8_t size; - - //! @brief Not used. - uint8_t reserved[2]; - - //! @brief Operand id (private variable for @c Assembler and @c Compiler classes). - //! - //! @note Uninitialized operands has id equal to zero. - uint32_t id; - }; - - //! @internal - //! - //! @brief Register data. - struct RegData - { - //! @brief Type of operand, see @c OPERAND_TYPE (in this case @c OPERAND_REG). - uint8_t op; - //! @brief Size of register. - uint8_t size; - - //! @brief Not used. - uint8_t reserved[2]; - - //! @brief Operand id. - uint32_t id; - - //! @brief Register code or variable, see @c REG and @c INVALID_VALUE. - uint32_t code; - }; - - //! @internal - //! - //! @brief Memory address data. - struct MemData - { - //! @brief Type of operand, see @c OPERAND_TYPE (in this case @c OPERAND_MEM). - uint8_t op; - //! @brief Size of pointer. - uint8_t size; - - //! @brief Memory operand type, see @c OPERAND_MEM_TYPE. - uint8_t type; - //! @brief Segment override prefix, see @c SEGMENT_PREFIX. - uint8_t segmentPrefix : 4; - //! @brief Emit MOV/LEA instruction using 16-bit form of base/index registers. - uint8_t sizePrefix : 1; - //! @brief Index register shift/scale (0 to 3 inclusive, see @c SCALE). - uint8_t shift : 3; - - //! @brief Operand ID. - uint32_t id; - - //! @brief Base register index, variable or label id. - uint32_t base; - //! @brief Index register index or variable id. - uint32_t index; - - //! @brief Target (for 32-bit, absolute address). - void* target; - - //! @brief Displacement. - sysint_t displacement; - }; - - //! @internal - //! - //! @brief Immediate value data. - struct ImmData - { - //! @brief Type of operand, see @c OPERAND_TYPE (in this case @c OPERAND_IMM).. - uint8_t op; - //! @brief Size of immediate (or 0 to autodetect). - uint8_t size; - - //! @brief @c true if immediate is unsigned. - uint8_t isUnsigned; - //! @brief Not used. - uint8_t reserved; - - //! @brief Operand ID. - uint32_t id; - - //! @brief Immediate value. - sysint_t value; - }; - - //! @internal - //! - //! @brief Label data. - struct LblData - { - //! @brief Type of operand, see @c OPERAND_TYPE (in this case @c OPERAND_LABEL). - uint8_t op; - //! @brief Size of label, currently not used. - uint8_t size; - - //! @brief Not used. - uint8_t reserved[2]; - - //! @brief Operand ID. - uint32_t id; - }; - - //! @internal - //! - //! @brief Variable data. - struct VarData - { - //! @brief Type of operand, see @c OPERAND_TYPE (in this case @c OPERAND_VAR). - uint8_t op; - //! @brief Size of variable (0 if don't known). - uint8_t size; - - //! @brief Not used. - uint8_t reserved[2]; - - //! @brief Operand ID. - uint32_t id; - - //! @brief Type (and later also code) of register, see @c REG_TYPE, @c REG_CODE. - //! - //! @note Register code and variable code are two different things. In most - //! cases registerCode is very related to variableType, but general purpose - //! registers are divided to 64-bit, 32-bit, 16-bit and 8-bit entities so - //! the registerCode can be used to access these, variableType remains - //! unchanged from the initialization state. Variable type describes mainly - //! variable type and home memory size. - uint32_t registerCode; - - //! @brief Type of variable. See @c VARIABLE_TYPE enum. - uint32_t variableType; - }; - - //! @brief Binary data. - struct BinData - { - //! @brief First four 32-bit integers. - uint32_t u32[4]; - //! @brief Second two 32 or 64-bit integers. - sysuint_t s[2]; - }; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - union - { - //! @brief Generic operand data. - BaseData _base; - //! @brief Register operand data. - RegData _reg; - //! @brief Memory operand data. - MemData _mem; - //! @brief Immediate operand data. - ImmData _imm; - //! @brief Label data. - LblData _lbl; - //! @brief Variable data. - VarData _var; - //! @brief - BinData _bin; - }; -}; - -// ============================================================================ -// [AsmJit::BaseReg] -// ============================================================================ - -//! @brief Base class for all registers. -struct ASMJIT_HIDDEN BaseReg : public Operand -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new base register. - inline BaseReg(uint32_t code, uint32_t size) ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - _reg.op = OPERAND_REG; - _reg.size = (uint8_t)size; - _reg.id = INVALID_VALUE; - _reg.code = code; - } - - //! @brief Create a new reference to @a other. - inline BaseReg(const BaseReg& other) ASMJIT_NOTHROW : - Operand(other) - {} - -#if !defined(ASMJIT_NODOC) - inline BaseReg(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - Operand(dontInitialize) - {} -#endif // ASMJIT_NODOC - - // -------------------------------------------------------------------------- - // [BaseReg Specific] - // -------------------------------------------------------------------------- - - //! @brief Get register code, see @c REG. - inline uint32_t getRegCode() const ASMJIT_NOTHROW - { return (uint32_t)(_reg.code); } - - //! @brief Get register type, see @c REG. - inline uint32_t getRegType() const ASMJIT_NOTHROW - { return (uint32_t)(_reg.code & REG_TYPE_MASK); } - - //! @brief Get register index (value from 0 to 7/15). - inline uint32_t getRegIndex() const ASMJIT_NOTHROW - { return (uint32_t)(_reg.code & REG_INDEX_MASK); } - - //! @brief Get whether register code is equal to @a code. - inline bool isRegCode(uint32_t code) const ASMJIT_NOTHROW - { return _reg.code == code; } - - //! @brief Get whether register code is equal to @a type. - inline bool isRegType(uint32_t type) const ASMJIT_NOTHROW - { return (uint32_t)(_reg.code & REG_TYPE_MASK) == type; } - - //! @brief Get whether register index is equal to @a index. - inline bool isRegIndex(uint32_t index) const ASMJIT_NOTHROW - { return (uint32_t)(_reg.code & REG_INDEX_MASK) == index; } - - //! @brief Set register code to @a code. - inline void setCode(uint32_t code) ASMJIT_NOTHROW - { _reg.code = code; } - - //! @brief Set register size to @a size. - inline void setSize(uint32_t size) ASMJIT_NOTHROW - { _reg.size = (uint8_t)size; } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - inline BaseReg& operator=(const BaseReg& other) ASMJIT_NOTHROW - { _copy(other); return *this; } - - inline bool operator==(const BaseReg& other) const ASMJIT_NOTHROW - { return getRegCode() == other.getRegCode(); } - - inline bool operator!=(const BaseReg& other) const ASMJIT_NOTHROW - { return getRegCode() != other.getRegCode(); } -}; - -// ============================================================================ -// [AsmJit::Reg] -// ============================================================================ - -//! @brief General purpose register. -//! -//! This class is for all general purpose registers (64, 32, 16 and 8-bit). -struct ASMJIT_HIDDEN GPReg : public BaseReg -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create non-initialized general purpose register. - inline GPReg() ASMJIT_NOTHROW : - BaseReg(INVALID_VALUE, 0) {} - - //! @brief Create a reference to @a other general purpose register. - inline GPReg(const GPReg& other) ASMJIT_NOTHROW : - BaseReg(other) {} - -#if !defined(ASMJIT_NODOC) - inline GPReg(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - BaseReg(dontInitialize) {} - - inline GPReg(const _Initialize&, uint32_t code) ASMJIT_NOTHROW : - BaseReg(code, static_cast(1U << ((code & REG_TYPE_MASK) >> 12))) {} -#endif // ASMJIT_NODOC - - // -------------------------------------------------------------------------- - // [GPReg Specific] - // -------------------------------------------------------------------------- - - //! @brief Get whether the general purpose register is BYTE (8-bit) type. - inline bool isGPB() const ASMJIT_NOTHROW { return (_reg.code & REG_TYPE_MASK) <= REG_TYPE_GPB_HI; } - //! @brief Get whether the general purpose register is LO-BYTE (8-bit) type. - inline bool isGPBLo() const ASMJIT_NOTHROW { return (_reg.code & REG_TYPE_MASK) == REG_TYPE_GPB_LO; } - //! @brief Get whether the general purpose register is HI-BYTE (8-bit) type. - inline bool isGPBHi() const ASMJIT_NOTHROW { return (_reg.code & REG_TYPE_MASK) == REG_TYPE_GPB_HI; } - - //! @brief Get whether the general purpose register is WORD (16-bit) type. - inline bool isGPW() const ASMJIT_NOTHROW { return (_reg.code & REG_TYPE_MASK) == REG_TYPE_GPW; } - //! @brief Get whether the general purpose register is DWORD (32-bit) type. - //! - //! This is default type for 32-bit platforms. - inline bool isGPD() const ASMJIT_NOTHROW { return (_reg.code & REG_TYPE_MASK) == REG_TYPE_GPD; } - //! @brief Get whether the general purpose register is QWORD (64-bit) type. - //! - //! This is default type for 64-bit platforms. - inline bool isGPQ() const ASMJIT_NOTHROW { return (_reg.code & REG_TYPE_MASK) == REG_TYPE_GPQ; } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline GPReg& operator=(const GPReg& other) ASMJIT_NOTHROW { _copy(other); return *this; } - inline bool operator==(const GPReg& other) const ASMJIT_NOTHROW { return getRegCode() == other.getRegCode(); } - inline bool operator!=(const GPReg& other) const ASMJIT_NOTHROW { return getRegCode() != other.getRegCode(); } -#endif // ASMJIT_NODOC -}; - -// ============================================================================ -// [AsmJit::X87Register] -// ============================================================================ - -//! @brief 80-bit x87 floating point register. -//! -//! To create instance of x87 register, use @c st() function. -struct ASMJIT_HIDDEN X87Reg : public BaseReg -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create non-initialized x87 register. - inline X87Reg() ASMJIT_NOTHROW : - BaseReg(INVALID_VALUE, 10) {} - - //! @brief Create a reference to @a other x87 register. - inline X87Reg(const X87Reg& other) ASMJIT_NOTHROW : - BaseReg(other) {} - -#if !defined(ASMJIT_NODOC) - inline X87Reg(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - BaseReg(dontInitialize) {} - - inline X87Reg(const _Initialize&, uint32_t code) ASMJIT_NOTHROW : - BaseReg(code | REG_TYPE_X87, 10) {} -#endif // ASMJIT_NODOC - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline X87Reg& operator=(const X87Reg& other) ASMJIT_NOTHROW { _copy(other); return *this; } - inline bool operator==(const X87Reg& other) const ASMJIT_NOTHROW { return getRegCode() == other.getRegCode(); } - inline bool operator!=(const X87Reg& other) const ASMJIT_NOTHROW { return getRegCode() != other.getRegCode(); } -#endif // ASMJIT_NODOC -}; - -// ============================================================================ -// [AsmJit::MMReg] -// ============================================================================ - -//! @brief 64-bit MMX register. -struct ASMJIT_HIDDEN MMReg : public BaseReg -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create non-initialized MM register. - inline MMReg() ASMJIT_NOTHROW : - BaseReg(INVALID_VALUE, 8) {} - - //! @brief Create a reference to @a other MM register. - inline MMReg(const MMReg& other) ASMJIT_NOTHROW : - BaseReg(other) {} - -#if !defined(ASMJIT_NODOC) - inline MMReg(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - BaseReg(dontInitialize) {} - - inline MMReg(const _Initialize&, uint32_t code) ASMJIT_NOTHROW : - BaseReg(code, 8) {} -#endif // ASMJIT_NODOC - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline MMReg& operator=(const MMReg& other) ASMJIT_NOTHROW { _copy(other); return *this; } - inline bool operator==(const MMReg& other) const ASMJIT_NOTHROW { return getRegCode() == other.getRegCode(); } - inline bool operator!=(const MMReg& other) const ASMJIT_NOTHROW { return getRegCode() != other.getRegCode(); } -#endif // ASMJIT_NODOC -}; - -// ============================================================================ -// [AsmJit::XMMReg] -// ============================================================================ - -//! @brief 128-bit SSE register. -struct ASMJIT_HIDDEN XMMReg : public BaseReg -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create non-initialized XMM register. - inline XMMReg() ASMJIT_NOTHROW : - BaseReg(INVALID_VALUE, 16) {} - - //! @brief Create a reference to @a other XMM register. - inline XMMReg(const _Initialize&, uint32_t code) ASMJIT_NOTHROW : - BaseReg(code, 16) {} - -#if !defined(ASMJIT_NODOC) - inline XMMReg(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - BaseReg(dontInitialize) {} - - inline XMMReg(const XMMReg& other) ASMJIT_NOTHROW : - BaseReg(other) {} -#endif // ASMJIT_NODOC - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline XMMReg& operator=(const XMMReg& other) ASMJIT_NOTHROW { _copy(other); return *this; } - inline bool operator==(const XMMReg& other) const ASMJIT_NOTHROW { return getRegCode() == other.getRegCode(); } - inline bool operator!=(const XMMReg& other) const ASMJIT_NOTHROW { return getRegCode() != other.getRegCode(); } -#endif // ASMJIT_NODOC -}; - -// ============================================================================ -// [AsmJit::SegmentReg] -// ============================================================================ - -//! @brief Segment register. -struct ASMJIT_HIDDEN SegmentReg : public BaseReg -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create non-initialized segment register. - inline SegmentReg() ASMJIT_NOTHROW : - BaseReg(INVALID_VALUE, 2) {} - - //! @brief Create a reference to @a other segment register. - inline SegmentReg(const _Initialize&, uint32_t code) ASMJIT_NOTHROW : - BaseReg(code, 2) {} - -#if !defined(ASMJIT_NODOC) - inline SegmentReg(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - BaseReg(dontInitialize) {} - - inline SegmentReg(const SegmentReg& other) ASMJIT_NOTHROW : - BaseReg(other) {} -#endif // ASMJIT_NODOC - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline SegmentReg& operator=(const SegmentReg& other) ASMJIT_NOTHROW { _copy(other); return *this; } - inline bool operator==(const SegmentReg& other) const ASMJIT_NOTHROW { return getRegCode() == other.getRegCode(); } - inline bool operator!=(const SegmentReg& other) const ASMJIT_NOTHROW { return getRegCode() != other.getRegCode(); } -#endif // ASMJIT_NODOC -}; - -// ============================================================================ -// [AsmJit::Registers - no_reg] -// ============================================================================ - -//! @brief No register, can be used only in @c Mem operand. -ASMJIT_VAR const GPReg no_reg; - -// ============================================================================ -// [AsmJit::Registers - 8-bit] -// ============================================================================ - -//! @brief 8-bit General purpose register. -ASMJIT_VAR const GPReg al; -//! @brief 8-bit General purpose register. -ASMJIT_VAR const GPReg cl; -//! @brief 8-bit General purpose register. -ASMJIT_VAR const GPReg dl; -//! @brief 8-bit General purpose register. -ASMJIT_VAR const GPReg bl; - -#if defined(ASMJIT_X64) -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg spl; -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg bpl; -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg sil; -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg dil; - -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r8b; -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r9b; -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r10b; -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r11b; -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r12b; -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r13b; -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r14b; -//! @brief 8-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r15b; -#endif // ASMJIT_X64 - -//! @brief 8-bit General purpose register. -ASMJIT_VAR const GPReg ah; -//! @brief 8-bit General purpose register. -ASMJIT_VAR const GPReg ch; -//! @brief 8-bit General purpose register. -ASMJIT_VAR const GPReg dh; -//! @brief 8-bit General purpose register. -ASMJIT_VAR const GPReg bh; - -// ============================================================================ -// [AsmJit::Registers - 16-bit] -// ============================================================================ - -//! @brief 16-bit General purpose register. -ASMJIT_VAR const GPReg ax; -//! @brief 16-bit General purpose register. -ASMJIT_VAR const GPReg cx; -//! @brief 16-bit General purpose register. -ASMJIT_VAR const GPReg dx; -//! @brief 16-bit General purpose register. -ASMJIT_VAR const GPReg bx; -//! @brief 16-bit General purpose register. -ASMJIT_VAR const GPReg sp; -//! @brief 16-bit General purpose register. -ASMJIT_VAR const GPReg bp; -//! @brief 16-bit General purpose register. -ASMJIT_VAR const GPReg si; -//! @brief 16-bit General purpose register. -ASMJIT_VAR const GPReg di; - -#if defined(ASMJIT_X64) -//! @brief 16-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r8w; -//! @brief 16-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r9w; -//! @brief 16-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r10w; -//! @brief 16-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r11w; -//! @brief 16-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r12w; -//! @brief 16-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r13w; -//! @brief 16-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r14w; -//! @brief 16-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r15w; -#endif // ASMJIT_X64 - -// ============================================================================ -// [AsmJit::Registers - 32-bit] -// ============================================================================ - -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg eax; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg ecx; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg edx; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg ebx; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg esp; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg ebp; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg esi; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg edi; - -#if defined(ASMJIT_X64) -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg r8d; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg r9d; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg r10d; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg r11d; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg r12d; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg r13d; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg r14d; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg r15d; -#endif // ASMJIT_X64 - -// ============================================================================ -// [AsmJit::Registers - 64-bit] -// ============================================================================ - -#if defined(ASMJIT_X64) -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg rax; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg rcx; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg rdx; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg rbx; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg rsp; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg rbp; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg rsi; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg rdi; - -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r8; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r9; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r10; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r11; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r12; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r13; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r14; -//! @brief 64-bit General purpose register (64-bit mode only). -ASMJIT_VAR const GPReg r15; -#endif // ASMJIT_X64 - -// ============================================================================ -// [AsmJit::Registers - Native (AsmJit extension)] -// ============================================================================ - -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg nax; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg ncx; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg ndx; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg nbx; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg nsp; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg nbp; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg nsi; -//! @brief 32-bit General purpose register. -ASMJIT_VAR const GPReg ndi; - -// ============================================================================ -// [AsmJit::Registers - MM] -// ============================================================================ - -//! @brief 64-bit MM register. -ASMJIT_VAR const MMReg mm0; -//! @brief 64-bit MM register. -ASMJIT_VAR const MMReg mm1; -//! @brief 64-bit MM register. -ASMJIT_VAR const MMReg mm2; -//! @brief 64-bit MM register. -ASMJIT_VAR const MMReg mm3; -//! @brief 64-bit MM register. -ASMJIT_VAR const MMReg mm4; -//! @brief 64-bit MM register. -ASMJIT_VAR const MMReg mm5; -//! @brief 64-bit MM register. -ASMJIT_VAR const MMReg mm6; -//! @brief 64-bit MM register. -ASMJIT_VAR const MMReg mm7; - -// ============================================================================ -// [AsmJit::Registers - XMM] -// ============================================================================ - -//! @brief 128-bit XMM register. -ASMJIT_VAR const XMMReg xmm0; -//! @brief 128-bit XMM register. -ASMJIT_VAR const XMMReg xmm1; -//! @brief 128-bit XMM register. -ASMJIT_VAR const XMMReg xmm2; -//! @brief 128-bit XMM register. -ASMJIT_VAR const XMMReg xmm3; -//! @brief 128-bit XMM register. -ASMJIT_VAR const XMMReg xmm4; -//! @brief 128-bit XMM register. -ASMJIT_VAR const XMMReg xmm5; -//! @brief 128-bit XMM register. -ASMJIT_VAR const XMMReg xmm6; -//! @brief 128-bit XMM register. -ASMJIT_VAR const XMMReg xmm7; - -#if defined(ASMJIT_X64) -//! @brief 128-bit XMM register (64-bit mode only). -ASMJIT_VAR const XMMReg xmm8; -//! @brief 128-bit XMM register (64-bit mode only). -ASMJIT_VAR const XMMReg xmm9; -//! @brief 128-bit XMM register (64-bit mode only). -ASMJIT_VAR const XMMReg xmm10; -//! @brief 128-bit XMM register (64-bit mode only). -ASMJIT_VAR const XMMReg xmm11; -//! @brief 128-bit XMM register (64-bit mode only). -ASMJIT_VAR const XMMReg xmm12; -//! @brief 128-bit XMM register (64-bit mode only). -ASMJIT_VAR const XMMReg xmm13; -//! @brief 128-bit XMM register (64-bit mode only). -ASMJIT_VAR const XMMReg xmm14; -//! @brief 128-bit XMM register (64-bit mode only). -ASMJIT_VAR const XMMReg xmm15; -#endif // ASMJIT_X64 - -// ============================================================================ -// [AsmJit::Registers - Segment] -// ============================================================================ - -ASMJIT_VAR const SegmentReg cs; -ASMJIT_VAR const SegmentReg ss; -ASMJIT_VAR const SegmentReg ds; -ASMJIT_VAR const SegmentReg es; -ASMJIT_VAR const SegmentReg fs; -ASMJIT_VAR const SegmentReg gs; - -// ============================================================================ -// [AsmJit::Registers - Register From Index] -// ============================================================================ - -//! @brief Get general purpose register of byte size. -static inline GPReg gpb_lo(uint32_t index) ASMJIT_NOTHROW -{ return GPReg(_Initialize(), static_cast(index | REG_TYPE_GPB_LO)); } - -//! @brief Get general purpose register of byte size. -static inline GPReg gpb_hi(uint32_t index) ASMJIT_NOTHROW -{ return GPReg(_Initialize(), static_cast(index | REG_TYPE_GPB_HI)); } - -//! @brief Get general purpose register of word size. -static inline GPReg gpw(uint32_t index) ASMJIT_NOTHROW -{ return GPReg(_Initialize(), static_cast(index | REG_TYPE_GPW)); } - -//! @brief Get general purpose register of dword size. -static inline GPReg gpd(uint32_t index) ASMJIT_NOTHROW -{ return GPReg(_Initialize(), static_cast(index | REG_TYPE_GPD)); } - -#if defined(ASMJIT_X64) -//! @brief Get general purpose register of qword size (64-bit only). -static inline GPReg gpq(uint32_t index) ASMJIT_NOTHROW -{ return GPReg(_Initialize(), static_cast(index | REG_TYPE_GPQ)); } -#endif - -//! @brief Get general purpose dword/qword register (depending to architecture). -static inline GPReg gpn(uint32_t index) ASMJIT_NOTHROW -{ return GPReg(_Initialize(), static_cast(index | REG_TYPE_GPN)); } - -//! @brief Get MMX (MM) register . -static inline MMReg mm(uint32_t index) ASMJIT_NOTHROW -{ return MMReg(_Initialize(), static_cast(index | REG_TYPE_MM)); } - -//! @brief Get SSE (XMM) register. -static inline XMMReg xmm(uint32_t index) ASMJIT_NOTHROW -{ return XMMReg(_Initialize(), static_cast(index | REG_TYPE_XMM)); } - -//! @brief Get x87 register with index @a i. -static inline X87Reg st(uint32_t i) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(i < 8); - return X87Reg(_Initialize(), static_cast(i)); -} - -// ============================================================================ -// [AsmJit::Imm] -// ============================================================================ - -//! @brief Immediate operand. -//! -//! Immediate operand is part of instruction (it's inlined after it). -//! -//! To create immediate operand, use @c imm() and @c uimm() constructors -//! or constructors provided by @c Immediate class itself. -struct ASMJIT_HIDDEN Imm : public Operand -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create a new immediate value (initial value is 0). - Imm() ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - _imm.op = OPERAND_IMM; - _imm.size = 0; - _imm.isUnsigned = false; - _imm.reserved = 0; - - _imm.id = INVALID_VALUE; - _imm.value = 0; - } - - //! @brief Create a new signed immediate value, assigning the value to @a i. - Imm(sysint_t i) ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - _imm.op = OPERAND_IMM; - _imm.size = 0; - _imm.isUnsigned = false; - _imm.reserved = 0; - - _imm.id = INVALID_VALUE; - _imm.value = i; - } - - //! @brief Create a new signed or unsigned immediate value, assigning the value to @a i. - Imm(sysint_t i, bool isUnsigned) ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - _imm.op = OPERAND_IMM; - _imm.size = 0; - _imm.isUnsigned = isUnsigned; - _imm.reserved = 0; - - _imm.id = INVALID_VALUE; - _imm.value = i; - } - - //! @brief Create a new immediate value from @a other. - inline Imm(const Imm& other) ASMJIT_NOTHROW : - Operand(other) {} - - // -------------------------------------------------------------------------- - // [Immediate Specific] - // -------------------------------------------------------------------------- - - //! @brief Get whether an immediate is unsigned value. - inline bool isUnsigned() const ASMJIT_NOTHROW { return _imm.isUnsigned != 0; } - - //! @brief Get signed immediate value. - inline sysint_t getValue() const ASMJIT_NOTHROW { return _imm.value; } - - //! @brief Get unsigned immediate value. - inline sysuint_t getUValue() const ASMJIT_NOTHROW { return (sysuint_t)_imm.value; } - - //! @brief Set immediate value as signed type to @a val. - inline void setValue(sysint_t val, bool isUnsigned = false) ASMJIT_NOTHROW - { - _imm.value = val; - _imm.isUnsigned = isUnsigned; - } - - //! @brief Set immediate value as unsigned type to @a val. - inline void setUValue(sysuint_t val) ASMJIT_NOTHROW - { - _imm.value = (sysint_t)val; - _imm.isUnsigned = true; - } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - //! @brief Assign a signed value @a val to the immediate operand. - inline Imm& operator=(sysint_t val) ASMJIT_NOTHROW - { setValue(val); return *this; } - - //! @brief Assign @a other to the immediate operand. - inline Imm& operator=(const Imm& other) ASMJIT_NOTHROW - { _copy(other); return *this; } -}; - -//! @brief Create signed immediate value operand. -ASMJIT_API Imm imm(sysint_t i) ASMJIT_NOTHROW; - -//! @brief Create unsigned immediate value operand. -ASMJIT_API Imm uimm(sysuint_t i) ASMJIT_NOTHROW; - -// ============================================================================ -// [AsmJit::Label] -// ============================================================================ - -//! @brief Label (jump target or data location). -//! -//! Label represents locations typically used as jump targets, but may be also -//! used as position where are stored constants or static variables. If you -//! want to use @c Label you need first to associate it with @c Assembler or -//! @c Compiler instance. To create new label use @c Assembler::newLabel() or -//! @c Compiler::newLabel(). -//! -//! Example of using labels: -//! -//! @code -//! // Create Assembler or Compiler instance. -//! Assembler a; -//! -//! // Create Label instance. -//! Label L_1(a); -//! -//! // ... your code ... -//! -//! // Using label, see @c AsmJit::Assembler or @c AsmJit::Compiler. -//! a.jump(L_1); -//! -//! // ... your code ... -//! -//! // Bind label to current position, see @c AsmJit::Assembler::bind() or -//! // @c AsmJit::Compiler::bind(). -//! a.bind(L_1); -//! @endcode -struct ASMJIT_HIDDEN Label : public Operand -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create new, unassociated label. - inline Label() ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - _lbl.op = OPERAND_LABEL; - _lbl.size = 0; - _lbl.id = INVALID_VALUE; - } - - //! @brief Create reference to another label. - inline Label(const Label& other) ASMJIT_NOTHROW : - Operand(other) - { - } - - //! @brief Destroy the label. - inline ~Label() ASMJIT_NOTHROW - { - } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline Label& operator=(const Label& other) - { _copy(other); return *this; } - - inline bool operator==(const Label& other) const ASMJIT_NOTHROW { return _base.id == other._base.id; } - inline bool operator!=(const Label& other) const ASMJIT_NOTHROW { return _base.id != other._base.id; } -#endif // ASMJIT_NODOC -}; - -// ============================================================================ -// [AsmJit::Mem] -// ============================================================================ - -//! @brief Memory operand. -struct ASMJIT_HIDDEN Mem : public Operand -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - inline Mem() ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - _mem.op = OPERAND_MEM; - _mem.size = 0; - _mem.type = OPERAND_MEM_NATIVE; - _mem.segmentPrefix = SEGMENT_NONE; - _mem.sizePrefix = 0; - _mem.shift = 0; - - _mem.id = INVALID_VALUE; - _mem.base = INVALID_VALUE; - _mem.index = INVALID_VALUE; - - _mem.target = NULL; - _mem.displacement = 0; - } - - inline Mem(const Label& label, sysint_t displacement, uint32_t size = 0) ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - _mem.op = OPERAND_MEM; - _mem.size = (uint8_t)size; - _mem.type = OPERAND_MEM_LABEL; - _mem.segmentPrefix = SEGMENT_NONE; - _mem.sizePrefix = 0; - _mem.shift = 0; - - _mem.id = INVALID_VALUE; - _mem.base = reinterpret_cast(label)._base.id; - _mem.index = INVALID_VALUE; - - _mem.target = NULL; - _mem.displacement = displacement; - } - - inline Mem(const GPReg& base, sysint_t displacement, uint32_t size = 0) ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - _mem.op = OPERAND_MEM; - _mem.size = (uint8_t)size; - _mem.type = OPERAND_MEM_NATIVE; - _mem.segmentPrefix = SEGMENT_NONE; - -#if defined(ASMJIT_X86) - _mem.sizePrefix = base.getSize() != 4; -#else - _mem.sizePrefix = base.getSize() != 8; -#endif - - _mem.shift = 0; - - _mem.id = INVALID_VALUE; - _mem.base = base.getRegCode() & REG_INDEX_MASK; - _mem.index = INVALID_VALUE; - - _mem.target = NULL; - _mem.displacement = displacement; - } - - inline Mem(const GPVar& base, sysint_t displacement, uint32_t size = 0) ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - _mem.op = OPERAND_MEM; - _mem.size = (uint8_t)size; - _mem.type = OPERAND_MEM_NATIVE; - _mem.segmentPrefix = SEGMENT_NONE; - -#if defined(ASMJIT_X86) - _mem.sizePrefix = (reinterpret_cast(base)._var.size) != 4; -#else - _mem.sizePrefix = (reinterpret_cast(base)._var.size) != 8; -#endif - - _mem.shift = 0; - - _mem.id = INVALID_VALUE; - _mem.base = reinterpret_cast(base).getId(); - _mem.index = INVALID_VALUE; - - _mem.target = NULL; - _mem.displacement = displacement; - } - - inline Mem(const GPReg& base, const GPReg& index, uint32_t shift, sysint_t displacement, uint32_t size = 0) ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - ASMJIT_ASSERT(shift <= 3); - - _mem.op = OPERAND_MEM; - _mem.size = (uint8_t)size; - _mem.type = OPERAND_MEM_NATIVE; - _mem.segmentPrefix = SEGMENT_NONE; - -#if defined(ASMJIT_X86) - _mem.sizePrefix = (base.getSize() | index.getSize()) != 4; -#else - _mem.sizePrefix = (base.getSize() | index.getSize()) != 8; -#endif - - _mem.shift = (uint8_t)shift; - - _mem.id = INVALID_VALUE; - _mem.base = base.getRegIndex(); - _mem.index = index.getRegIndex(); - - _mem.target = NULL; - _mem.displacement = displacement; - } - - inline Mem(const GPVar& base, const GPVar& index, uint32_t shift, sysint_t displacement, uint32_t size = 0) ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - ASMJIT_ASSERT(shift <= 3); - - _mem.op = OPERAND_MEM; - _mem.size = (uint8_t)size; - _mem.type = OPERAND_MEM_NATIVE; - _mem.segmentPrefix = SEGMENT_NONE; - -#if defined(ASMJIT_X86) - _mem.sizePrefix = (reinterpret_cast(base )._var.size | - reinterpret_cast(index)._var.size ) != 4; -#else - _mem.sizePrefix = (reinterpret_cast(base )._var.size | - reinterpret_cast(index)._var.size ) != 8; -#endif - - _mem.shift = (uint8_t)shift; - - _mem.id = INVALID_VALUE; - _mem.base = reinterpret_cast(base).getId(); - _mem.index = reinterpret_cast(index).getId(); - - _mem.target = NULL; - _mem.displacement = displacement; - } - - inline Mem(const Mem& other) ASMJIT_NOTHROW : - Operand(other) - { - } - - inline Mem(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - Operand(dontInitialize) - { - } - - // -------------------------------------------------------------------------- - // [Mem Specific] - // -------------------------------------------------------------------------- - - //! @brief Get type of memory operand, see @c OPERAND_MEM_TYPE enum. - inline uint32_t getMemType() const ASMJIT_NOTHROW - { return _mem.type; } - - //! @brief Get memory operand segment prefix, see @c SEGMENT_PREFIX enum. - inline uint32_t getSegmentPrefix() const ASMJIT_NOTHROW - { return _mem.segmentPrefix; } - - //! @brief Get whether the memory operand has base register. - inline bool hasBase() const ASMJIT_NOTHROW - { return _mem.base != INVALID_VALUE; } - - //! @brief Get whether the memory operand has index. - inline bool hasIndex() const ASMJIT_NOTHROW - { return _mem.index != INVALID_VALUE; } - - //! @brief Get whether the memory operand has shift used. - inline bool hasShift() const ASMJIT_NOTHROW - { return _mem.shift != 0; } - - //! @brief Get memory operand base register or @c INVALID_VALUE. - inline uint32_t getBase() const ASMJIT_NOTHROW - { return _mem.base; } - - //! @brief Get memory operand index register or @c INVALID_VALUE. - inline uint32_t getIndex() const ASMJIT_NOTHROW - { return _mem.index; } - - //! @brief Get memory operand index scale (0, 1, 2 or 3). - inline uint32_t getShift() const ASMJIT_NOTHROW - { return _mem.shift; } - - //! @brief Get whether to use size-override prefix. - //! - //! @note This is useful only for MOV and LEA type of instructions. - inline bool getSizePrefix() const ASMJIT_NOTHROW - { return _mem.sizePrefix; } - - //! @brief Set whether to use size-override prefix. - inline void setSizePrefix(bool b) ASMJIT_NOTHROW - { _mem.sizePrefix = b; } - - //! @brief Get absolute target address. - //! - //! @note You should always check if operand contains address by @c getMemType(). - inline void* getTarget() const ASMJIT_NOTHROW - { return _mem.target; } - - //! @brief Set memory operand size. - inline void setSize(uint32_t size) ASMJIT_NOTHROW - { _mem.size = size; } - - //! @brief Set absolute target address. - inline void setTarget(void* target) ASMJIT_NOTHROW - { _mem.target = target; } - - //! @brief Get memory operand relative displacement. - inline sysint_t getDisplacement() const ASMJIT_NOTHROW - { return _mem.displacement; } - - //! @brief Set memory operand relative displacement. - inline void setDisplacement(sysint_t displacement) ASMJIT_NOTHROW - { _mem.displacement = displacement; } - - //! @brief Adjust memory operand relative displacement by @a displacement. - inline void adjust(sysint_t displacement) ASMJIT_NOTHROW - { - _mem.displacement += displacement; - } - - //! @brief Get new memory operand adjusted by @a displacement. - inline Mem adjusted(sysint_t displacement) const ASMJIT_NOTHROW - { - Mem result(*this); - result.adjust(displacement); - return result; - } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline Mem& operator=(const Mem& other) ASMJIT_NOTHROW - { - _copy(other); - return *this; - } - - inline bool operator==(const Mem& other) const ASMJIT_NOTHROW - { - return _bin.u32[0] == other._bin.u32[0] && - _bin.u32[1] == other._bin.u32[1] && - _bin.u32[2] == other._bin.u32[2] && - _bin.u32[3] == other._bin.u32[3] && - _bin.s[0] == other._bin.s[0] && - _bin.s[1] == other._bin.s[1]; - } - - inline bool operator!=(const Mem& other) const ASMJIT_NOTHROW - { - return !(*this == other); - } -#endif // ASMJIT_NODOC -}; - -// ============================================================================ -// [AsmJit::BaseVar] -// ============================================================================ - -ASMJIT_API Mem _BaseVarMem(const BaseVar& var, uint32_t ptrSize) ASMJIT_NOTHROW; -ASMJIT_API Mem _BaseVarMem(const BaseVar& var, uint32_t ptrSize, sysint_t disp) ASMJIT_NOTHROW; -ASMJIT_API Mem _BaseVarMem(const BaseVar& var, uint32_t ptrSize, const GPVar& index, uint32_t shift, sysint_t disp) ASMJIT_NOTHROW; - -//! @brief Base class for all variables. -struct ASMJIT_HIDDEN BaseVar : public Operand -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline BaseVar(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - Operand(dontInitialize) - { - } -#endif // ASMJIT_NODOC - - inline BaseVar() ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - _var.op = OPERAND_VAR; - _var.size = 0; - _var.registerCode = INVALID_VALUE; - _var.variableType = INVALID_VALUE; - _var.id = INVALID_VALUE; - } - - inline BaseVar(const BaseVar& other) ASMJIT_NOTHROW : - Operand(other) - { - } - - // -------------------------------------------------------------------------- - // [Type] - // -------------------------------------------------------------------------- - - inline uint32_t getVariableType() const ASMJIT_NOTHROW - { return _var.variableType; } - - inline bool isGPVar() const ASMJIT_NOTHROW - { return _var.variableType <= VARIABLE_TYPE_GPQ; } - - inline bool isX87Var() const ASMJIT_NOTHROW - { return _var.variableType >= VARIABLE_TYPE_X87 && _var.variableType <= VARIABLE_TYPE_X87_1D; } - - inline bool isMMVar() const ASMJIT_NOTHROW - { return _var.variableType == VARIABLE_TYPE_MM; } - - inline bool isXMMVar() const ASMJIT_NOTHROW - { return _var.variableType >= VARIABLE_TYPE_XMM && _var.variableType <= VARIABLE_TYPE_XMM_2D; } - - // -------------------------------------------------------------------------- - // [Memory Cast] - // -------------------------------------------------------------------------- - - //! @brief Cast this variable to memory operand. - //! - //! @note Size of operand depends on native variable type, you can use other - //! variants if you want specific one. - inline Mem m() const ASMJIT_NOTHROW - { return _BaseVarMem(*this, INVALID_VALUE); } - - //! @overload. - inline Mem m(sysint_t disp) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, INVALID_VALUE, disp); } - - //! @overload. - inline Mem m(const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, INVALID_VALUE, index, shift, disp); } - - //! @brief Cast this variable to 8-bit memory operand. - inline Mem m8() const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 1); } - - //! @overload. - inline Mem m8(sysint_t disp) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 1, disp); } - - //! @overload. - inline Mem m8(const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 1, index, shift, disp); } - - //! @brief Cast this variable to 16-bit memory operand. - inline Mem m16() const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 2); } - - //! @overload. - inline Mem m16(sysint_t disp) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 2, disp); } - - //! @overload. - inline Mem m16(const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 2, index, shift, disp); } - - //! @brief Cast this variable to 32-bit memory operand. - inline Mem m32() const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 4); } - - //! @overload. - inline Mem m32(sysint_t disp) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 4, disp); } - - //! @overload. - inline Mem m32(const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 4, index, shift, disp); } - - //! @brief Cast this variable to 64-bit memory operand. - inline Mem m64() const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 8); } - - //! @overload. - inline Mem m64(sysint_t disp) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 8, disp); } - - //! @overload. - inline Mem m64(const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 8, index, shift, disp); } - - //! @brief Cast this variable to 80-bit memory operand (long double). - inline Mem m80() const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 10); } - - //! @overload. - inline Mem m80(sysint_t disp) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 10, disp); } - - //! @overload. - inline Mem m80(const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 10, index, shift, disp); } - - //! @brief Cast this variable to 128-bit memory operand. - inline Mem m128() const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 16); } - - //! @overload. - inline Mem m128(sysint_t disp) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 16, disp); } - - //! @overload. - inline Mem m128(const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) const ASMJIT_NOTHROW - { return _BaseVarMem(*this, 16, index, shift, disp); } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline BaseVar& operator=(const BaseVar& other) ASMJIT_NOTHROW - { _copy(other); return *this; } - - inline bool operator==(const BaseVar& other) const ASMJIT_NOTHROW { return _base.id == other._base.id && _var.registerCode == other._var.registerCode; } - inline bool operator!=(const BaseVar& other) const ASMJIT_NOTHROW { return _base.id != other._base.id || _var.registerCode != other._var.registerCode; } -#endif // ASMJIT_NODOC - - // -------------------------------------------------------------------------- - // [Private] - // -------------------------------------------------------------------------- - -protected: - inline BaseVar(const BaseVar& other, uint32_t registerCode, uint32_t size) ASMJIT_NOTHROW : - Operand(_DontInitialize()) - { - _var.op = OPERAND_VAR; - _var.size = (uint8_t)size; - _var.id = other._base.id; - _var.registerCode = registerCode; - _var.variableType = other._var.variableType; - } -}; - -// ============================================================================ -// [AsmJit::X87Var] -// ============================================================================ - -//! @brief X87 Variable operand. -struct ASMJIT_HIDDEN X87Var : public BaseVar -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - inline X87Var(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - BaseVar(dontInitialize) - { - } - - inline X87Var() ASMJIT_NOTHROW : - BaseVar(_DontInitialize()) - { - _var.op = OPERAND_VAR; - _var.size = 12; - _var.id = INVALID_VALUE; - - _var.registerCode = REG_TYPE_X87; - _var.variableType = VARIABLE_TYPE_X87; - } - - inline X87Var(const X87Var& other) ASMJIT_NOTHROW : - BaseVar(other) {} - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline X87Var& operator=(const X87Var& other) ASMJIT_NOTHROW - { _copy(other); return *this; } - - inline bool operator==(const X87Var& other) const ASMJIT_NOTHROW { return _base.id == other._base.id; } - inline bool operator!=(const X87Var& other) const ASMJIT_NOTHROW { return _base.id != other._base.id; } -#endif // ASMJIT_NODOC -}; - -// ============================================================================ -// [AsmJit::GPVar] -// ============================================================================ - -//! @brief GP variable operand. -struct ASMJIT_HIDDEN GPVar : public BaseVar -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create new uninitialized @c GPVar instance (internal constructor). - inline GPVar(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - BaseVar(dontInitialize) - { - } - - //! @brief Create new uninitialized @c GPVar instance. - inline GPVar() ASMJIT_NOTHROW : - BaseVar(_DontInitialize()) - { - _var.op = OPERAND_VAR; - _var.size = sizeof(sysint_t); - _var.id = INVALID_VALUE; - - _var.registerCode = REG_TYPE_GPN; - _var.variableType = VARIABLE_TYPE_GPN; - } - - //! @brief Create new @c GPVar instance using @a other. - //! - //! Note this will not create a different variable, use @c Compiler::newGP() - //! if you want to do so. This is only copy-constructor that allows to store - //! the same variable in different places. - inline GPVar(const GPVar& other) ASMJIT_NOTHROW : - BaseVar(other) {} - - // -------------------------------------------------------------------------- - // [GPVar Specific] - // -------------------------------------------------------------------------- - - //! @brief Get whether this variable is general purpose BYTE register. - inline bool isGPB() const ASMJIT_NOTHROW { return (_var.registerCode & REG_TYPE_MASK) <= REG_TYPE_GPB_HI; } - //! @brief Get whether this variable is general purpose BYTE.LO register. - inline bool isGPBLo() const ASMJIT_NOTHROW { return (_var.registerCode & REG_TYPE_MASK) == REG_TYPE_GPB_LO; } - //! @brief Get whether this variable is general purpose BYTE.HI register. - inline bool isGPBHi() const ASMJIT_NOTHROW { return (_var.registerCode & REG_TYPE_MASK) == REG_TYPE_GPB_HI; } - - //! @brief Get whether this variable is general purpose WORD register. - inline bool isGPW() const ASMJIT_NOTHROW { return (_var.registerCode & REG_TYPE_MASK) == REG_TYPE_GPW; } - //! @brief Get whether this variable is general purpose DWORD register. - inline bool isGPD() const ASMJIT_NOTHROW { return (_var.registerCode & REG_TYPE_MASK) == REG_TYPE_GPD; } - //! @brief Get whether this variable is general purpose QWORD (only 64-bit) register. - inline bool isGPQ() const ASMJIT_NOTHROW { return (_var.registerCode & REG_TYPE_MASK) == REG_TYPE_GPQ; } - - // -------------------------------------------------------------------------- - // [GPVar Cast] - // -------------------------------------------------------------------------- - - //! @brief Cast this variable to 8-bit (LO) part of variable - inline GPVar r8() const ASMJIT_NOTHROW { return GPVar(*this, REG_TYPE_GPB_LO, 1); } - //! @brief Cast this variable to 8-bit (LO) part of variable - inline GPVar r8Lo() const ASMJIT_NOTHROW { return GPVar(*this, REG_TYPE_GPB_LO, 1); } - //! @brief Cast this variable to 8-bit (HI) part of variable - inline GPVar r8Hi() const ASMJIT_NOTHROW { return GPVar(*this, REG_TYPE_GPB_HI, 1); } - - //! @brief Cast this variable to 16-bit part of variable - inline GPVar r16() const ASMJIT_NOTHROW { return GPVar(*this, REG_TYPE_GPW, 2); } - //! @brief Cast this variable to 32-bit part of variable - inline GPVar r32() const ASMJIT_NOTHROW { return GPVar(*this, REG_TYPE_GPD, 4); } -#if defined(ASMJIT_X64) - //! @brief Cast this variable to 64-bit part of variable - inline GPVar r64() const ASMJIT_NOTHROW { return GPVar(*this, REG_TYPE_GPQ, 8); } -#endif // ASMJIT_X64 - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline GPVar& operator=(const GPVar& other) ASMJIT_NOTHROW - { _copy(other); return *this; } - - inline bool operator==(const GPVar& other) const ASMJIT_NOTHROW { return _base.id == other._base.id && _var.registerCode == other._var.registerCode; } - inline bool operator!=(const GPVar& other) const ASMJIT_NOTHROW { return _base.id != other._base.id || _var.registerCode != other._var.registerCode; } -#endif // ASMJIT_NODOC - - // -------------------------------------------------------------------------- - // [Private] - // -------------------------------------------------------------------------- - -protected: - inline GPVar(const GPVar& other, uint32_t registerCode, uint32_t size) ASMJIT_NOTHROW : - BaseVar(other, registerCode, size) - { - } -}; - -// ============================================================================ -// [AsmJit::MMVar] -// ============================================================================ - -//! @brief MM variable operand. -struct ASMJIT_HIDDEN MMVar : public BaseVar -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create new uninitialized @c MMVar instance (internal constructor). - inline MMVar(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - BaseVar(dontInitialize) - { - } - - //! @brief Create new uninitialized @c MMVar instance. - inline MMVar() ASMJIT_NOTHROW : - BaseVar(_DontInitialize()) - { - _var.op = OPERAND_VAR; - _var.size = 8; - _var.id = INVALID_VALUE; - - _var.registerCode = REG_TYPE_MM; - _var.variableType = VARIABLE_TYPE_MM; - } - - //! @brief Create new @c MMVar instance using @a other. - //! - //! Note this will not create a different variable, use @c Compiler::newMM() - //! if you want to do so. This is only copy-constructor that allows to store - //! the same variable in different places. - inline MMVar(const MMVar& other) ASMJIT_NOTHROW : - BaseVar(other) {} - - // -------------------------------------------------------------------------- - // [MMVar Cast] - // -------------------------------------------------------------------------- - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline MMVar& operator=(const MMVar& other) ASMJIT_NOTHROW - { _copy(other); return *this; } - - inline bool operator==(const MMVar& other) const ASMJIT_NOTHROW { return _base.id == other._base.id; } - inline bool operator!=(const MMVar& other) const ASMJIT_NOTHROW { return _base.id != other._base.id; } -#endif // ASMJIT_NODOC -}; - -// ============================================================================ -// [AsmJit::XMMVar] -// ============================================================================ - -//! @brief XMM Variable operand. -struct ASMJIT_HIDDEN XMMVar : public BaseVar -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - inline XMMVar(const _DontInitialize& dontInitialize) ASMJIT_NOTHROW : - BaseVar(dontInitialize) - { - } - - inline XMMVar() ASMJIT_NOTHROW : - BaseVar(_DontInitialize()) - { - _var.op = OPERAND_VAR; - _var.size = 16; - _var.id = INVALID_VALUE; - - _var.registerCode = REG_TYPE_XMM; - _var.variableType = VARIABLE_TYPE_XMM; - } - - inline XMMVar(const XMMVar& other) ASMJIT_NOTHROW : - BaseVar(other) {} - - // -------------------------------------------------------------------------- - // [XMMVar Access] - // -------------------------------------------------------------------------- - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - -#if !defined(ASMJIT_NODOC) - inline XMMVar& operator=(const XMMVar& other) ASMJIT_NOTHROW - { _copy(other); return *this; } - - inline bool operator==(const XMMVar& other) const ASMJIT_NOTHROW { return _base.id == other._base.id; } - inline bool operator!=(const XMMVar& other) const ASMJIT_NOTHROW { return _base.id != other._base.id; } -#endif // ASMJIT_NODOC -}; - -// ============================================================================ -// [AsmJit::Mem - ptr[displacement]] -// ============================================================================ - -//! @internal -ASMJIT_API Mem _MemPtrBuild(const Label& label, sysint_t disp, uint32_t ptrSize) ASMJIT_NOTHROW; - -//! @internal -ASMJIT_API Mem _MemPtrBuild(const Label& label, const GPReg& index, uint32_t shift, sysint_t disp, uint32_t ptrSize) ASMJIT_NOTHROW; - -//! @internal -ASMJIT_API Mem _MemPtrBuild(const Label& label, const GPVar& index, uint32_t shift, sysint_t disp, uint32_t ptrSize) ASMJIT_NOTHROW; - - - -//! @brief Create pointer operand with not specified size. -static inline Mem ptr(const Label& label, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, disp, 0); } - -//! @brief Create byte pointer operand. -static inline Mem byte_ptr(const Label& label, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, disp, SIZE_BYTE); } - -//! @brief Create word (2 Bytes) pointer operand. -static inline Mem word_ptr(const Label& label, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, disp, SIZE_WORD); } - -//! @brief Create dword (4 Bytes) pointer operand. -static inline Mem dword_ptr(const Label& label, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, disp, SIZE_DWORD); } - -//! @brief Create qword (8 Bytes) pointer operand. -static inline Mem qword_ptr(const Label& label, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, disp, SIZE_QWORD); } - -//! @brief Create tword (10 Bytes) pointer operand (used for 80-bit floating points). -static inline Mem tword_ptr(const Label& label, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, disp, SIZE_TWORD); } - -//! @brief Create dqword (16 Bytes) pointer operand. -static inline Mem dqword_ptr(const Label& label, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, disp, SIZE_DQWORD); } - -//! @brief Create mmword (8 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for mmx programming. -static inline Mem mmword_ptr(const Label& label, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, disp, SIZE_QWORD); } - -//! @brief Create xmmword (16 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for sse programming. -static inline Mem xmmword_ptr(const Label& label, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, disp, SIZE_DQWORD); } - -//! @brief Create system dependent pointer operand (32-bit or 64-bit). -static inline Mem sysint_ptr(const Label& label, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, disp, sizeof(sysint_t)); } - - - -//! @brief Create pointer operand with not specified size. -static inline Mem ptr(const Label& label, const GPReg& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, 0); } - -//! @brief Create byte pointer operand. -static inline Mem byte_ptr(const Label& label, const GPReg& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_BYTE); } - -//! @brief Create word (2 Bytes) pointer operand. -static inline Mem word_ptr(const Label& label, const GPReg& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_WORD); } - -//! @brief Create dword (4 Bytes) pointer operand. -static inline Mem dword_ptr(const Label& label, const GPReg& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_DWORD); } - -//! @brief Create qword (8 Bytes) pointer operand. -static inline Mem qword_ptr(const Label& label, const GPReg& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_QWORD); } - -//! @brief Create tword (10 Bytes) pointer operand (used for 80-bit floating points). -static inline Mem tword_ptr(const Label& label, const GPReg& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_TWORD); } - -//! @brief Create dqword (16 Bytes) pointer operand. -static inline Mem dqword_ptr(const Label& label, const GPReg& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_DQWORD); } - -//! @brief Create mmword (8 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for mmx programming. -static inline Mem mmword_ptr(const Label& label, const GPReg& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_QWORD); } - -//! @brief Create xmmword (16 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for sse programming. -static inline Mem xmmword_ptr(const Label& label, const GPReg& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_DQWORD); } - -//! @brief Create system dependent pointer operand (32-bit or 64-bit). -static inline Mem sysint_ptr(const Label& label, const GPReg& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, sizeof(sysint_t)); } - - - -//! @brief Create pointer operand with not specified size. -static inline Mem ptr(const Label& label, const GPVar& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, 0); } - -//! @brief Create byte pointer operand. -static inline Mem byte_ptr(const Label& label, const GPVar& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_BYTE); } - -//! @brief Create word (2 Bytes) pointer operand. -static inline Mem word_ptr(const Label& label, const GPVar& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_WORD); } - -//! @brief Create dword (4 Bytes) pointer operand. -static inline Mem dword_ptr(const Label& label, const GPVar& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_DWORD); } - -//! @brief Create qword (8 Bytes) pointer operand. -static inline Mem qword_ptr(const Label& label, const GPVar& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_QWORD); } - -//! @brief Create tword (10 Bytes) pointer operand (used for 80-bit floating points). -static inline Mem tword_ptr(const Label& label, const GPVar& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_TWORD); } - -//! @brief Create dqword (16 Bytes) pointer operand. -static inline Mem dqword_ptr(const Label& label, const GPVar& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_DQWORD); } - -//! @brief Create mmword (8 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for mmx programming. -static inline Mem mmword_ptr(const Label& label, const GPVar& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_QWORD); } - -//! @brief Create xmmword (16 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for sse programming. -static inline Mem xmmword_ptr(const Label& label, const GPVar& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, SIZE_DQWORD); } - -//! @brief Create system dependent pointer operand (32-bit or 64-bit). -static inline Mem sysint_ptr(const Label& label, const GPVar& index, uint32_t shift, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(label, index, shift, disp, sizeof(sysint_t)); } - -// ============================================================================ -// [AsmJit::Mem - Absolute Addressing] -// ============================================================================ - -//! @internal -ASMJIT_API Mem _MemPtrAbs( - void* target, - sysint_t disp, - uint32_t segmentPrefix, uint32_t ptrSize) ASMJIT_NOTHROW; - -//! @internal -ASMJIT_API Mem _MemPtrAbs( - void* target, - const GPReg& index, uint32_t shift, sysint_t disp, - uint32_t segmentPrefix, uint32_t ptrSize) ASMJIT_NOTHROW; - -//! @internal -ASMJIT_API Mem _MemPtrAbs( - void* target, - const GPVar& index, uint32_t shift, sysint_t disp, - uint32_t segmentPrefix, uint32_t ptrSize) ASMJIT_NOTHROW; - - - -//! @brief Create pointer operand with not specified size. -static inline Mem ptr_abs(void* target, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, disp, segmentPrefix, 0); } - -//! @brief Create byte pointer operand. -static inline Mem byte_ptr_abs(void* target, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, disp, segmentPrefix, SIZE_BYTE); } - -//! @brief Create word (2 Bytes) pointer operand. -static inline Mem word_ptr_abs(void* target, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, disp, segmentPrefix, SIZE_WORD); } - -//! @brief Create dword (4 Bytes) pointer operand. -static inline Mem dword_ptr_abs(void* target, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, disp, segmentPrefix, SIZE_DWORD); } - -//! @brief Create qword (8 Bytes) pointer operand. -static inline Mem qword_ptr_abs(void* target, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, disp, segmentPrefix, SIZE_QWORD); } - -//! @brief Create tword (10 Bytes) pointer operand (used for 80-bit floating points). -static inline Mem tword_ptr_abs(void* target, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, disp, segmentPrefix, SIZE_TWORD); } - -//! @brief Create dqword (16 Bytes) pointer operand. -static inline Mem dqword_ptr_abs(void* target, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, disp, segmentPrefix, SIZE_DQWORD); } - -//! @brief Create mmword (8 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for mmx programming. -static inline Mem mmword_ptr_abs(void* target, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, disp, segmentPrefix, SIZE_QWORD); } - -//! @brief Create xmmword (16 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for sse programming. -static inline Mem xmmword_ptr_abs(void* target, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, disp, segmentPrefix, SIZE_DQWORD); } - -//! @brief Create system dependent pointer operand (32-bit or 64-bit). -static inline Mem sysint_ptr_abs(void* target, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, disp, segmentPrefix, sizeof(sysint_t)); } - - - -//! @brief Create pointer operand with not specified size. -static inline Mem ptr_abs(void* target, const GPReg& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, 0); } - -//! @brief Create byte pointer operand. -static inline Mem byte_ptr_abs(void* target, const GPReg& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_BYTE); } - -//! @brief Create word (2 Bytes) pointer operand. -static inline Mem word_ptr_abs(void* target, const GPReg& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_WORD); } - -//! @brief Create dword (4 Bytes) pointer operand. -static inline Mem dword_ptr_abs(void* target, const GPReg& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_DWORD); } - -//! @brief Create qword (8 Bytes) pointer operand. -static inline Mem qword_ptr_abs(void* target, const GPReg& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_QWORD); } - -//! @brief Create tword (10 Bytes) pointer operand (used for 80-bit floating points). -static inline Mem tword_ptr_abs(void* target, const GPReg& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_TWORD); } - -//! @brief Create dqword (16 Bytes) pointer operand. -static inline Mem dqword_ptr_abs(void* target, const GPReg& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_DQWORD); } - -//! @brief Create mmword (8 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for mmx programming. -static inline Mem mmword_ptr_abs(void* target, const GPReg& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_QWORD); } - -//! @brief Create xmmword (16 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for sse programming. -static inline Mem xmmword_ptr_abs(void* target, const GPReg& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_DQWORD); } - -//! @brief Create system dependent pointer operand (32-bit or 64-bit). -static inline Mem sysint_ptr_abs(void* target, const GPReg& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, sizeof(sysint_t)); } - - - -//! @brief Create pointer operand with not specified size. -static inline Mem ptr_abs(void* target, const GPVar& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, 0); } - -//! @brief Create byte pointer operand. -static inline Mem byte_ptr_abs(void* target, const GPVar& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_BYTE); } - -//! @brief Create word (2 Bytes) pointer operand. -static inline Mem word_ptr_abs(void* target, const GPVar& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_WORD); } - -//! @brief Create dword (4 Bytes) pointer operand. -static inline Mem dword_ptr_abs(void* target, const GPVar& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_DWORD); } - -//! @brief Create qword (8 Bytes) pointer operand. -static inline Mem qword_ptr_abs(void* target, const GPVar& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_QWORD); } - -//! @brief Create tword (10 Bytes) pointer operand (used for 80-bit floating points). -static inline Mem tword_ptr_abs(void* target, const GPVar& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_TWORD); } - -//! @brief Create dqword (16 Bytes) pointer operand. -static inline Mem dqword_ptr_abs(void* target, const GPVar& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_DQWORD); } - -//! @brief Create mmword (8 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for mmx programming. -static inline Mem mmword_ptr_abs(void* target, const GPVar& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_QWORD); } - -//! @brief Create xmmword (16 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for sse programming. -static inline Mem xmmword_ptr_abs(void* target, const GPVar& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, SIZE_DQWORD); } - -//! @brief Create system dependent pointer operand (32-bit or 64-bit). -static inline Mem sysint_ptr_abs(void* target, const GPVar& index, uint32_t shift, sysint_t disp = 0, uint32_t segmentPrefix = SEGMENT_NONE) ASMJIT_NOTHROW -{ return _MemPtrAbs(target, index, shift, disp, segmentPrefix, sizeof(sysint_t)); } - -// ============================================================================ -// [AsmJit::Mem - ptr[base + displacement]] -// ============================================================================ - -//! @internal -ASMJIT_API Mem _MemPtrBuild(const GPReg& base, sysint_t disp, uint32_t ptrSize) ASMJIT_NOTHROW; - -//! @internal -ASMJIT_API Mem _MemPtrBuild(const GPVar& base, sysint_t disp, uint32_t ptrSize) ASMJIT_NOTHROW; - - - -//! @brief Create pointer operand with not specified size. -static inline Mem ptr(const GPReg& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, 0); } - -//! @brief Create byte pointer operand. -static inline Mem byte_ptr(const GPReg& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_BYTE); } - -//! @brief Create word (2 Bytes) pointer operand. -static inline Mem word_ptr(const GPReg& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_WORD); } - -//! @brief Create dword (4 Bytes) pointer operand. -static inline Mem dword_ptr(const GPReg& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_DWORD); } - -//! @brief Create qword (8 Bytes) pointer operand. -static inline Mem qword_ptr(const GPReg& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_QWORD); } - -//! @brief Create tword (10 Bytes) pointer operand (used for 80-bit floating points). -static inline Mem tword_ptr(const GPReg& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_TWORD); } - -//! @brief Create dqword (16 Bytes) pointer operand. -static inline Mem dqword_ptr(const GPReg& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_DQWORD); } - -//! @brief Create mmword (8 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for mmx programming. -static inline Mem mmword_ptr(const GPReg& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_QWORD); } - -//! @brief Create xmmword (16 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for sse programming. -static inline Mem xmmword_ptr(const GPReg& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_DQWORD); } - -//! @brief Create system dependent pointer operand (32-bit or 64-bit). -static inline Mem sysint_ptr(const GPReg& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, sizeof(sysint_t)); } - - - -//! @brief Create pointer operand with not specified size. -static inline Mem ptr(const GPVar& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, 0); } - -//! @brief Create byte pointer operand. -static inline Mem byte_ptr(const GPVar& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_BYTE); } - -//! @brief Create word (2 Bytes) pointer operand. -static inline Mem word_ptr(const GPVar& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_WORD); } - -//! @brief Create dword (4 Bytes) pointer operand. -static inline Mem dword_ptr(const GPVar& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_DWORD); } - -//! @brief Create qword (8 Bytes) pointer operand. -static inline Mem qword_ptr(const GPVar& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_QWORD); } - -//! @brief Create tword (10 Bytes) pointer operand (used for 80-bit floating points). -static inline Mem tword_ptr(const GPVar& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_TWORD); } - -//! @brief Create dqword (16 Bytes) pointer operand. -static inline Mem dqword_ptr(const GPVar& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_DQWORD); } - -//! @brief Create mmword (8 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for mmx programming. -static inline Mem mmword_ptr(const GPVar& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_QWORD); } - -//! @brief Create xmmword (16 bytes) pointer operand -//! -//! @note This constructor is provided only for convenience for sse programming. -static inline Mem xmmword_ptr(const GPVar& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, SIZE_DQWORD); } - -//! @brief Create system dependent pointer operand (32-bit or 64-bit). -static inline Mem sysint_ptr(const GPVar& base, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, disp, sizeof(sysint_t)); } - -// ============================================================================ -// [AsmJit::Mem - ptr[base + (index << shift) + displacement]] -// ============================================================================ - -//! @internal -ASMJIT_API Mem _MemPtrBuild(const GPReg& base, const GPReg& index, uint32_t shift, sysint_t disp, uint32_t ptrSize) ASMJIT_NOTHROW; - -//! @internal -ASMJIT_API Mem _MemPtrBuild(const GPVar& base, const GPVar& index, uint32_t shift, sysint_t disp, uint32_t ptrSize) ASMJIT_NOTHROW; - - - -//! @brief Create pointer operand with not specified size. -static inline Mem ptr(const GPReg& base, const GPReg& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, 0); } - -//! @brief Create byte pointer operand. -static inline Mem byte_ptr(const GPReg& base, const GPReg& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_BYTE); } - -//! @brief Create word (2 Bytes) pointer operand. -static inline Mem word_ptr(const GPReg& base, const GPReg& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_WORD); } - -//! @brief Create dword (4 Bytes) pointer operand. -static inline Mem dword_ptr(const GPReg& base, const GPReg& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_DWORD); } - -//! @brief Create qword (8 Bytes) pointer operand. -static inline Mem qword_ptr(const GPReg& base, const GPReg& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_QWORD); } - -//! @brief Create tword (10 Bytes) pointer operand (used for 80-bit floating points). -static inline Mem tword_ptr(const GPReg& base, const GPReg& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_TWORD); } - -//! @brief Create dqword (16 Bytes) pointer operand. -static inline Mem dqword_ptr(const GPReg& base, const GPReg& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_DQWORD); } - -//! @brief Create mmword (8 Bytes) pointer operand). -//! -//! @note This constructor is provided only for convenience for mmx programming. -static inline Mem mmword_ptr(const GPReg& base, const GPReg& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_QWORD); } - -//! @brief Create xmmword (16 Bytes) pointer operand. -//! -//! @note This constructor is provided only for convenience for sse programming. -static inline Mem xmmword_ptr(const GPReg& base, const GPReg& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_DQWORD); } - -//! @brief Create system dependent pointer operand (32-bit or 64-bit). -static inline Mem sysint_ptr(const GPReg& base, const GPReg& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, sizeof(sysint_t)); } - - - -//! @brief Create pointer operand with not specified size. -static inline Mem ptr(const GPVar& base, const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, 0); } - -//! @brief Create byte pointer operand. -static inline Mem byte_ptr(const GPVar& base, const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_BYTE); } - -//! @brief Create word (2 Bytes) pointer operand. -static inline Mem word_ptr(const GPVar& base, const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_WORD); } - -//! @brief Create dword (4 Bytes) pointer operand. -static inline Mem dword_ptr(const GPVar& base, const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_DWORD); } - -//! @brief Create qword (8 Bytes) pointer operand. -static inline Mem qword_ptr(const GPVar& base, const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_QWORD); } - -//! @brief Create tword (10 Bytes) pointer operand (used for 80-bit floating points). -static inline Mem tword_ptr(const GPVar& base, const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_TWORD); } - -//! @brief Create dqword (16 Bytes) pointer operand. -static inline Mem dqword_ptr(const GPVar& base, const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_DQWORD); } - -//! @brief Create mmword (8 Bytes) pointer operand). -//! -//! @note This constructor is provided only for convenience for mmx programming. -static inline Mem mmword_ptr(const GPVar& base, const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_QWORD); } - -//! @brief Create xmmword (16 Bytes) pointer operand. -//! -//! @note This constructor is provided only for convenience for sse programming. -static inline Mem xmmword_ptr(const GPVar& base, const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, SIZE_DQWORD); } - -//! @brief Create system dependent pointer operand (32-bit or 64-bit). -static inline Mem sysint_ptr(const GPVar& base, const GPVar& index, uint32_t shift = 0, sysint_t disp = 0) ASMJIT_NOTHROW -{ return _MemPtrBuild(base, index, shift, disp, sizeof(sysint_t)); } - -// ============================================================================ -// [AsmJit::Macros] -// ============================================================================ - -//! @brief Create Shuffle Constant for MMX/SSE shuffle instrutions. -//! @param z First component position, number at interval [0, 3] inclusive. -//! @param x Second component position, number at interval [0, 3] inclusive. -//! @param y Third component position, number at interval [0, 3] inclusive. -//! @param w Fourth component position, number at interval [0, 3] inclusive. -//! -//! Shuffle constants can be used to make immediate value for these intrinsics: -//! - @c AsmJit::AssemblerIntrinsics::pshufw() -//! - @c AsmJit::AssemblerIntrinsics::pshufd() -//! - @c AsmJit::AssemblerIntrinsics::pshufhw() -//! - @c AsmJit::AssemblerIntrinsics::pshuflw() -//! - @c AsmJit::AssemblerIntrinsics::shufps() -static inline uint8_t mm_shuffle(uint8_t z, uint8_t y, uint8_t x, uint8_t w) ASMJIT_NOTHROW -{ return (z << 6) | (y << 4) | (x << 2) | w; } - -//! @} - -} // AsmJit namespace - -// [Guard] -#endif // _ASMJIT_OPERANDX86X64_H diff --git a/desmume/src/utils/AsmJit/Platform.cpp b/desmume/src/utils/AsmJit/Platform.cpp deleted file mode 100644 index fe15179ff..000000000 --- a/desmume/src/utils/AsmJit/Platform.cpp +++ /dev/null @@ -1,222 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Dependencies] -#include - -#include "Platform.h" - -// [Api-Begin] -#include "ApiBegin.h" - -// helpers -namespace AsmJit { - -// ============================================================================ -// [AsmJit::Assert] -// ============================================================================ - -void assertionFailure(const char* file, int line, const char* exp) -{ - fprintf(stderr, - "*** ASSERTION FAILURE at %s (line %d)\n" - "*** %s\n", file, line, exp); - - exit(1); -} - -// ============================================================================ -// [AsmJit::Helpers] -// ============================================================================ - -static bool isAligned(sysuint_t base, sysuint_t alignment) -{ - return base % alignment == 0; -} - -static sysuint_t roundUp(sysuint_t base, sysuint_t pageSize) -{ - sysuint_t over = base % pageSize; - return base + (over > 0 ? pageSize - over : 0); -} - -// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr., -// figure 3-3, page 48, where the function is called clp2. -static sysuint_t roundUpToPowerOf2(sysuint_t base) -{ - base -= 1; - - base = base | (base >> 1); - base = base | (base >> 2); - base = base | (base >> 4); - base = base | (base >> 8); - base = base | (base >> 16); - - // I'm trying to make this portable and MSVC strikes me the warning C4293: - // "Shift count negative or too big, undefined behavior" - // Fixing... -#if _MSC_VER -# pragma warning(disable: 4293) -#endif // _MSC_VER - - if (sizeof(sysuint_t) >= 8) - base = base | (base >> 32); - - return base + 1; -} - -} // AsmJit namespace - -// ============================================================================ -// [AsmJit::VirtualMemory::Windows] -// ============================================================================ - -#if defined(ASMJIT_WINDOWS) - -#include - -namespace AsmJit { - -struct ASMJIT_HIDDEN VirtualMemoryLocal -{ - VirtualMemoryLocal() ASMJIT_NOTHROW - { - SYSTEM_INFO info; - GetSystemInfo(&info); - - alignment = info.dwAllocationGranularity; - pageSize = roundUpToPowerOf2(info.dwPageSize); - } - - sysuint_t alignment; - sysuint_t pageSize; -}; - -static VirtualMemoryLocal& vm() ASMJIT_NOTHROW -{ - static VirtualMemoryLocal vm; - return vm; -}; - -void* VirtualMemory::alloc(sysuint_t length, sysuint_t* allocated, bool canExecute) - ASMJIT_NOTHROW -{ - return allocProcessMemory(GetCurrentProcess(), length, allocated, canExecute); -} - -void VirtualMemory::free(void* addr, sysuint_t length) - ASMJIT_NOTHROW -{ - return freeProcessMemory(GetCurrentProcess(), addr, length); -} - -void* VirtualMemory::allocProcessMemory(HANDLE hProcess, sysuint_t length, sysuint_t* allocated, bool canExecute) ASMJIT_NOTHROW -{ - // VirtualAlloc rounds allocated size to page size automatically. - sysuint_t msize = roundUp(length, vm().pageSize); - - // Windows XP SP2 / Vista allow Data Excution Prevention (DEP). - WORD protect = canExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; - LPVOID mbase = VirtualAllocEx(hProcess, NULL, msize, MEM_COMMIT | MEM_RESERVE, protect); - if (mbase == NULL) return NULL; - - ASMJIT_ASSERT(isAligned(reinterpret_cast(mbase), vm().alignment)); - - if (allocated) *allocated = msize; - return mbase; -} - -void VirtualMemory::freeProcessMemory(HANDLE hProcess, void* addr, sysuint_t /* length */) ASMJIT_NOTHROW -{ - VirtualFreeEx(hProcess, addr, 0, MEM_RELEASE); -} - -sysuint_t VirtualMemory::getAlignment() - ASMJIT_NOTHROW -{ - return vm().alignment; -} - -sysuint_t VirtualMemory::getPageSize() - ASMJIT_NOTHROW -{ - return vm().pageSize; -} - -} // AsmJit - -#endif // ASMJIT_WINDOWS - -// ============================================================================ -// [AsmJit::VirtualMemory::Posix] -// ============================================================================ - -#if defined(ASMJIT_POSIX) - -#include -#include -#include - -// MacOS uses MAP_ANON instead of MAP_ANONYMOUS -#ifndef MAP_ANONYMOUS -# define MAP_ANONYMOUS MAP_ANON -#endif - -namespace AsmJit { - -struct ASMJIT_HIDDEN VirtualMemoryLocal -{ - VirtualMemoryLocal() ASMJIT_NOTHROW - { - alignment = pageSize = getpagesize(); - } - - sysuint_t alignment; - sysuint_t pageSize; -}; - -static VirtualMemoryLocal& vm() - ASMJIT_NOTHROW -{ - static VirtualMemoryLocal vm; - return vm; -} - -void* VirtualMemory::alloc(sysuint_t length, sysuint_t* allocated, bool canExecute) - ASMJIT_NOTHROW -{ - sysuint_t msize = roundUp(length, vm().pageSize); - int protection = PROT_READ | PROT_WRITE | (canExecute ? PROT_EXEC : 0); - void* mbase = mmap(NULL, msize, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (mbase == MAP_FAILED) return NULL; - if (allocated) *allocated = msize; - return mbase; -} - -void VirtualMemory::free(void* addr, sysuint_t length) - ASMJIT_NOTHROW -{ - munmap(addr, length); -} - -sysuint_t VirtualMemory::getAlignment() - ASMJIT_NOTHROW -{ - return vm().alignment; -} - -sysuint_t VirtualMemory::getPageSize() - ASMJIT_NOTHROW -{ - return vm().pageSize; -} - -} // AsmJit - -#endif // ASMJIT_POSIX - -// [Api-End] -#include "ApiEnd.h" diff --git a/desmume/src/utils/AsmJit/Platform.h b/desmume/src/utils/AsmJit/Platform.h deleted file mode 100644 index b35ad44b8..000000000 --- a/desmume/src/utils/AsmJit/Platform.h +++ /dev/null @@ -1,208 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_PLATFORM_H -#define _ASMJIT_PLATFORM_H - -// [Dependencies] -#include "Build.h" - -#if defined(ASMJIT_WINDOWS) -#include -#endif // ASMJIT_WINDOWS - -#if defined(ASMJIT_POSIX) -#include -#endif // ASMJIT_POSIX - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -//! @addtogroup AsmJit_Util -//! @{ - -// ============================================================================ -// [AsmJit::Assert] -// ============================================================================ - -//! @brief Called in debug build on assertion failure. -//! @param file Source file name where it happened. -//! @param line Line in the source file. -//! @param exp Expression what failed. -//! -//! If you have problems with assertions simply put a breakpoint into -//! AsmJit::assertionFailure() method (see AsmJit/Platform.cpp file) and see -//! call stack. -ASMJIT_API void assertionFailure(const char* file, int line, const char* exp); - -// ============================================================================ -// [AsmJit::Lock] -// ============================================================================ - -//! @brief Lock - used in thread-safe code for locking. -struct ASMJIT_HIDDEN Lock -{ -#if defined(ASMJIT_WINDOWS) - typedef CRITICAL_SECTION Handle; -#endif // ASMJIT_WINDOWS -#if defined(ASMJIT_POSIX) - typedef pthread_mutex_t Handle; -#endif // ASMJIT_POSIX - - //! @brief Create a new @ref Lock instance. - inline Lock() ASMJIT_NOTHROW - { -#if defined(ASMJIT_WINDOWS) - InitializeCriticalSection(&_handle); - // InitializeLockAndSpinCount(&_handle, 2000); -#endif // ASMJIT_WINDOWS -#if defined(ASMJIT_POSIX) - pthread_mutex_init(&_handle, NULL); -#endif // ASMJIT_POSIX - } - - //! @brief Destroy the @ref Lock instance. - inline ~Lock() ASMJIT_NOTHROW - { -#if defined(ASMJIT_WINDOWS) - DeleteCriticalSection(&_handle); -#endif // ASMJIT_WINDOWS -#if defined(ASMJIT_POSIX) - pthread_mutex_destroy(&_handle); -#endif // ASMJIT_POSIX - } - - //! @brief Get handle. - inline Handle& getHandle() ASMJIT_NOTHROW - { - return _handle; - } - - //! @overload - inline const Handle& getHandle() const ASMJIT_NOTHROW - { - return _handle; - } - - //! @brief Lock. - inline void lock() ASMJIT_NOTHROW - { -#if defined(ASMJIT_WINDOWS) - EnterCriticalSection(&_handle); -#endif // ASMJIT_WINDOWS -#if defined(ASMJIT_POSIX) - pthread_mutex_lock(&_handle); -#endif // ASMJIT_POSIX - } - - //! @brief Unlock. - inline void unlock() ASMJIT_NOTHROW - { -#if defined(ASMJIT_WINDOWS) - LeaveCriticalSection(&_handle); -#endif // ASMJIT_WINDOWS -#if defined(ASMJIT_POSIX) - pthread_mutex_unlock(&_handle); -#endif // ASMJIT_POSIX - } - -private: - //! @brief Handle. - Handle _handle; - - // Disable copy. - ASMJIT_DISABLE_COPY(Lock) -}; - -// ============================================================================ -// [AsmJit::AutoLock] -// ============================================================================ - -//! @brief Scope auto locker. -struct ASMJIT_HIDDEN AutoLock -{ - //! @brief Locks @a target. - inline AutoLock(Lock& target) ASMJIT_NOTHROW : _target(target) - { - _target.lock(); - } - - //! @brief Unlocks target. - inline ~AutoLock() ASMJIT_NOTHROW - { - _target.unlock(); - } - -private: - //! @brief Pointer to target (lock). - Lock& _target; - - // Disable copy. - ASMJIT_DISABLE_COPY(AutoLock) -}; - -// ============================================================================ -// [AsmJit::VirtualMemory] -// ============================================================================ - -//! @brief Class that helps with allocating memory for executing code -//! generated by JIT compiler. -//! -//! There are defined functions that provides facility to allocate and free -//! memory where can be executed code. If processor and operating system -//! supports execution protection then you can't run code from normally -//! malloc()'ed memory. -//! -//! Functions are internally implemented by operating system dependent way. -//! VirtualAlloc() function is used for Windows operating system and mmap() -//! for posix ones. If you want to study or create your own functions, look -//! at VirtualAlloc() or mmap() documentation (depends on you target OS). -//! -//! Under posix operating systems is also useable mprotect() function, that -//! can enable execution protection to malloc()'ed memory block. -struct ASMJIT_API VirtualMemory -{ - //! @brief Allocate virtual memory. - //! - //! Pages are readable/writeable, but they are not guaranteed to be - //! executable unless 'canExecute' is true. Returns the address of - //! allocated memory, or NULL if failed. - static void* alloc(sysuint_t length, sysuint_t* allocated, bool canExecute) ASMJIT_NOTHROW; - - //! @brief Free memory allocated by @c alloc() - static void free(void* addr, sysuint_t length) ASMJIT_NOTHROW; - -#if defined(ASMJIT_WINDOWS) - //! @brief Allocate virtual memory of @a hProcess. - //! - //! @note This function is windows specific and unportable. - static void* allocProcessMemory(HANDLE hProcess, sysuint_t length, sysuint_t* allocated, bool canExecute) ASMJIT_NOTHROW; - - //! @brief Free virtual memory of @a hProcess. - //! - //! @note This function is windows specific and unportable. - static void freeProcessMemory(HANDLE hProcess, void* addr, sysuint_t length) ASMJIT_NOTHROW; -#endif // ASMJIT_WINDOWS - - //! @brief Get the alignment guaranteed by alloc(). - static sysuint_t getAlignment() ASMJIT_NOTHROW; - - //! @brief Get size of single page. - static sysuint_t getPageSize() ASMJIT_NOTHROW; -}; - -//! @} - -} // AsmJit namespace - -// [Api-End] -#include "ApiEnd.h" - -// [Guard] -#endif // _ASMJIT_PLATFORM_H diff --git a/desmume/src/utils/AsmJit/README.txt b/desmume/src/utils/AsmJit/README.txt deleted file mode 100644 index 685db2562..000000000 --- a/desmume/src/utils/AsmJit/README.txt +++ /dev/null @@ -1,115 +0,0 @@ -AsmJit - Complete x86/x64 JIT Assembler for C++ Language - Version 1.0 -====================================================================== - -http://code.google.com/p/asmjit/ - -Introduction -============ - -AsmJit is complete x86/x64 JIT Assembler for C++ language. It supports FPU, -MMX, 3dNow, SSE, SSE2, SSE3 and SSE4 intrinsics, powerful compiler that helps -to write portable functions for 32-bit (x86) and 64-bit (x64) architectures. -AsmJit can be used to create functions at runtime that can be called from -existing (but also generated) C/C++ code. - -AsmJit is crossplatform library that supports various compilers and operating -systems. Currently only limitation is x86 (32-bit) or x64 (64-bit) processor. -Currently tested operating systems are Windows (32 bit and 64 bit), Linux (32 -bit and 64 bit) and MacOSX (32 bit). - -Assembler / Compiler -==================== - -AsmJit library contains two main classes for code generation with different -goals. First main code generation class is called Assembler and contains low -level API that can be used to generate JIT binary code. It directly emits -binary stream that represents encoded x86/x64 assembler opcodes. Together -with operands and labels it can be used to generate complete code. - -There is also class named Compiler that allows to develop crossplatform -assembler code without worring about function calling conventions and -registers allocation. It can be also used to write 32 bit and 64 bit portable -code. Compiler is recommended class to use for high level code generation. - -Building & Configuring -====================== - -You have two choices when using AsmJit library: - -1. Embed files into your project - This is simplest way how to use AsmJit - library. If you want to do this, edit AsmJit/Config.h file and undefine - "// #define ASMJIT_API" macro or define ASMJIT_API using your IDE or - makefiles (for example gcc can accept -DASMJIT_API to define it). - - You will bypass shared library (dll) support by defining ASMJIT_API . - -2. Build shared library and link your project to it. This is now default way - for using AsmJit library, but can be easily changed. To build dynamically - linked library use cmake (http://www.cmake.org/) that can generate - makefiles and project files for your IDE (included is Visual Studio, - Code::Blocks, Eclipse, KDevelop and more...). - - To build shared library use this cmake command (or use provided scripts): - cmake {Replace this with AsmJit directory} DASMJIT_BUILD_LIBRARY=1 - -Directory structure -=================== - -AsmJit - Directory where are sources needed to compile AsmJit. This directory -is designed to be embeddable to your application as easy as possible. There is -also AsmJit/Config.h header where you can configure platform (if autodetection -not works for you) and application specific features. Look at platform macros -to change some backends to your preferences. - -Test - Directory with cmake project to test AsmJit library. It generates simple -command line applications for testing AsmJit functionality. It's only here as a -demonstration how easy this can be done. These applications are also examples -how to use AsmJit API. For example look at testjit for simple code generation, -testcpu for cpuid() and cpuInfo() demonstration, testcompiler for compiler -example, etc... - -Supported compilers -=================== - -AsmJit is successfully tested by following compilers: -- MSVC (VC6.0, VC7.1, VC8.0) -- GCC (3.4.X+ including MinGW and 4.1.X+, 4.3.X+, 4.4.X+) - -If you are using different compiler and you have troubles, please use AsmJit -mailing list or create an Issue (see project home page). - -Supported platforms -=================== - -Fully supported platforms at this time are X86 (32-bit) and X86_64/X64 (64-bit). -Other platforms need volunteers. Also note that AsmJit is designed to generate -assembler binary only for host CPU, don't try to generate 64-bit assembler in -32 bit mode and vica versa - this is not designed to work and will not work. - -Examples -======== - -Examples and tests can be found in these places: -- AsmJit home page -- AsmJit wiki -- AsmJit Test directory (in this package) - -License -======= - -AsmJit can be distributed under zlib license: - - -Google Groups and Mailing Lists -=============================== - -AsmJit google group: - * http://groups.google.com/group/asmjit-dev - -AsmJit mailing list: - * asmjit-dev@googlegroups.com - -Contact Author/Maintainer -========================= - -Petr Kobalicek diff --git a/desmume/src/utils/AsmJit/Regenerate.py b/desmume/src/utils/AsmJit/Regenerate.py deleted file mode 100644 index 86ef69b30..000000000 --- a/desmume/src/utils/AsmJit/Regenerate.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python - -# ============================================================================= -# [Regenerate.py - Description] -# -# This Python script will regenerate instruction names in Assembler{$ARCH}.cpp -# files. Idea is that there can be big instruction table and this script tries -# to minimize runtime relocation data of AsmJit library. -# ============================================================================= - -# ============================================================================= -# [Configuration] -# ============================================================================= - -# Files to process. -FILES = [ - "DefsX86X64.cpp" -] - -# ============================================================================= -# [Imports] -# ============================================================================= - -import os, re, string - -# ============================================================================= -# [Helpers] -# ============================================================================= - -def readFile(fileName): - handle = open(fileName, "rb") - data = handle.read() - handle.close() - return data - -def writeFile(fileName, data): - handle = open(fileName, "wb") - handle.truncate() - handle.write(data) - handle.close() - -# ============================================================================= -# [Main] -# ============================================================================= - -def processFile(fileName): - data = readFile(fileName); - - din = data - r = re.compile(r"instructionDescription\[\][\s]*=[\s]*{(?P[^}])*}") - m = r.search(din) - - if not m: - print "Cannot match instruction data in " + fileName - exit(0) - - din = din[m.start():m.end()] - dout = "" - - dinst = [] - daddr = [] - hinst = {} - - r = re.compile(r'\"(?P[A-Za-z0-9_ ]+)\"') - dpos = 0 - for m in r.finditer(din): - inst = m.group("INST") - - if not inst in hinst: - dinst.append(inst) - hinst[inst] = dpos - - daddr.append(dpos) - dpos += len(inst) + 1 - - dout += "const char instructionName[] =\n" - for i in xrange(len(dinst)): - dout += " \"" + dinst[i] + "\\0\"\n" - dout += " ;\n" - - dout += "\n" - - for i in xrange(len(dinst)): - dout += "#define INST_" + dinst[i].upper().replace(" ", "_") + "_INDEX" + " " + str(daddr[i]) + "\n" - - mb_string = "// ${INSTRUCTION_DATA_BEGIN}\n" - me_string = "// ${INSTRUCTION_DATA_END}\n" - - mb = data.index(mb_string) - me = data.index(me_string) - - data = data[:mb + len(mb_string)] + dout + data[me:] - - writeFile(fileName, data) - -for fileName in FILES: - processFile(fileName) diff --git a/desmume/src/utils/AsmJit/Util.cpp b/desmume/src/utils/AsmJit/Util.cpp deleted file mode 100644 index e8945e67b..000000000 --- a/desmume/src/utils/AsmJit/Util.cpp +++ /dev/null @@ -1,266 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Dependencies] -#include "Build.h" -#include "Util_p.h" - -// [Api-Begin] -#include "ApiBegin.h" - -namespace AsmJit { - -// ============================================================================ -// [AsmJit::Util] -// ============================================================================ - -static const char letters[] = "0123456789ABCDEF"; - -char* Util::mycpy(char* dst, const char* src, sysuint_t len) ASMJIT_NOTHROW -{ - if (src == NULL) return dst; - - if (len == (sysuint_t)-1) - { - while (*src) *dst++ = *src++; - } - else - { - memcpy(dst, src, len); - dst += len; - } - - return dst; -} - -char* Util::myfill(char* dst, const int c, sysuint_t len) ASMJIT_NOTHROW -{ - memset(dst, c, len); - return dst + len; -} - -char* Util::myhex(char* dst, const uint8_t* src, sysuint_t len) ASMJIT_NOTHROW -{ - for (sysuint_t i = len; i; i--, dst += 2, src += 1) - { - dst[0] = letters[(src[0] >> 4) & 0xF]; - dst[1] = letters[(src[0] ) & 0xF]; - } - - return dst; -} - -// Not too efficient, but this is mainly for debugging:) -char* Util::myutoa(char* dst, sysuint_t i, sysuint_t base) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(base <= 16); - - char buf[128]; - char* p = buf + 128; - - do { - sysint_t b = i % base; - *--p = letters[b]; - i /= base; - } while (i); - - return Util::mycpy(dst, p, (sysuint_t)(buf + 128 - p)); -} - -char* Util::myitoa(char* dst, sysint_t i, sysuint_t base) ASMJIT_NOTHROW -{ - if (i < 0) - { - *dst++ = '-'; - i = -i; - } - - return Util::myutoa(dst, (sysuint_t)i, base); -} - -// ============================================================================ -// [AsmJit::Buffer] -// ============================================================================ - -void Buffer::emitData(const void* dataPtr, sysuint_t dataLen) ASMJIT_NOTHROW -{ - sysint_t max = getCapacity() - getOffset(); - if ((sysuint_t)max < dataLen) - { - if (!realloc(getOffset() + dataLen)) return; - } - - memcpy(_cur, dataPtr, dataLen); - _cur += dataLen; -} - -bool Buffer::realloc(sysint_t to) ASMJIT_NOTHROW -{ - if (getCapacity() < to) - { - sysint_t len = getOffset(); - - uint8_t *newdata; - if (_data) - newdata = (uint8_t*)ASMJIT_REALLOC(_data, to); - else - newdata = (uint8_t*)ASMJIT_MALLOC(to); - if (!newdata) return false; - - _data = newdata; - _cur = newdata + len; - _max = newdata + to; - _max -= (to >= _growThreshold) ? _growThreshold : to; - - _capacity = to; - } - - return true; -} - -bool Buffer::grow() ASMJIT_NOTHROW -{ - sysint_t to = _capacity; - - if (to < 512) - to = 1024; - else if (to > 65536) - to += 65536; - else - to <<= 1; - - return realloc(to); -} - -void Buffer::clear() ASMJIT_NOTHROW -{ - _cur = _data; -} - -void Buffer::free() ASMJIT_NOTHROW -{ - if (!_data) return; - ASMJIT_FREE(_data); - - _data = NULL; - _cur = NULL; - _max = NULL; - _capacity = 0; -} - -uint8_t* Buffer::take() ASMJIT_NOTHROW -{ - uint8_t* data = _data; - - _data = NULL; - _cur = NULL; - _max = NULL; - _capacity = 0; - - return data; -} - -// ============================================================================ -// [AsmJit::Zone] -// ============================================================================ - -Zone::Zone(sysuint_t chunkSize) ASMJIT_NOTHROW -{ - _chunks = NULL; - _total = 0; - _chunkSize = chunkSize; -} - -Zone::~Zone() ASMJIT_NOTHROW -{ - freeAll(); -} - -void* Zone::zalloc(sysuint_t size) ASMJIT_NOTHROW -{ - // Align to 4 or 8 bytes. - size = (size + sizeof(sysint_t)-1) & ~(sizeof(sysint_t)-1); - - Chunk* cur = _chunks; - - if (!cur || cur->getRemainingBytes() < size) - { - sysuint_t chSize = _chunkSize; - if (chSize < size) chSize = size; - - cur = (Chunk*)ASMJIT_MALLOC(sizeof(Chunk) - sizeof(void*) + chSize); - if (!cur) return NULL; - - cur->prev = _chunks; - cur->pos = 0; - cur->size = _chunkSize; - _chunks = cur; - } - - uint8_t* p = cur->data + cur->pos; - cur->pos += size; - _total += size; - return (void*)p; -} - -char* Zone::zstrdup(const char* str) ASMJIT_NOTHROW -{ - if (str == NULL) return NULL; - - sysuint_t len = strlen(str); - if (len == 0) return NULL; - - // Include NULL terminator. - len++; - - // Limit string length. - if (len > 256) len = 256; - - char* m = reinterpret_cast(zalloc((len + 15) & ~15)); - if (!m) return NULL; - - memcpy(m, str, len); - m[len-1] = '\0'; - return m; -} - -void Zone::clear() ASMJIT_NOTHROW -{ - Chunk* cur = _chunks; - if (!cur) return; - - _chunks->pos = 0; - _chunks->prev = NULL; - _total = 0; - - cur = cur->prev; - while (cur) - { - Chunk* prev = cur->prev; - ASMJIT_FREE(cur); - cur = prev; - } -} - -void Zone::freeAll() ASMJIT_NOTHROW -{ - Chunk* cur = _chunks; - - _chunks = NULL; - _total = 0; - - while (cur) - { - Chunk* prev = cur->prev; - ASMJIT_FREE(cur); - cur = prev; - } -} - -} // AsmJit namespace - -// [Api-End] -#include "ApiEnd.h" diff --git a/desmume/src/utils/AsmJit/Util.h b/desmume/src/utils/AsmJit/Util.h deleted file mode 100644 index 94dc1df62..000000000 --- a/desmume/src/utils/AsmJit/Util.h +++ /dev/null @@ -1,914 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_UTIL_H -#define _ASMJIT_UTIL_H - -// [Dependencies] -#include "Build.h" - -#include -#include - -namespace AsmJit { - -//! @addtogroup AsmJit_Util -//! @{ - -// ============================================================================ -// [AsmJit::Macros] -// ============================================================================ - -// Skip documenting this. -#if !defined(ASMJIT_NODOC) -struct ASMJIT_HIDDEN _DontInitialize {}; -struct ASMJIT_HIDDEN _Initialize {}; -#endif // !ASMJIT_NODOC - -// ============================================================================ -// [AsmJit::Util] -// ============================================================================ - -namespace Util { - -// ============================================================================ -// [AsmJit::Util::isInt?] -// ============================================================================ - -//! @brief Returns @c true if a given integer @a x is signed 8-bit integer -static inline bool isInt8(sysint_t x) ASMJIT_NOTHROW { return x >= -128 && x <= 127; } -//! @brief Returns @c true if a given integer @a x is unsigned 8-bit integer -static inline bool isUInt8(sysint_t x) ASMJIT_NOTHROW { return x >= 0 && x <= 255; } - -//! @brief Returns @c true if a given integer @a x is signed 16-bit integer -static inline bool isInt16(sysint_t x) ASMJIT_NOTHROW { return x >= -32768 && x <= 32767; } -//! @brief Returns @c true if a given integer @a x is unsigned 16-bit integer -static inline bool isUInt16(sysint_t x) ASMJIT_NOTHROW { return x >= 0 && x <= 65535; } - -//! @brief Returns @c true if a given integer @a x is signed 16-bit integer -static inline bool isInt32(sysint_t x) ASMJIT_NOTHROW -{ -#if defined(ASMJIT_X86) - return true; -#else - return x >= ASMJIT_INT64_C(-2147483648) && x <= ASMJIT_INT64_C(2147483647); -#endif -} -//! @brief Returns @c true if a given integer @a x is unsigned 16-bit integer -static inline bool isUInt32(sysint_t x) ASMJIT_NOTHROW -{ -#if defined(ASMJIT_X86) - return x >= 0; -#else - return x >= 0 && x <= ASMJIT_INT64_C(4294967295); -#endif -} - -// ============================================================================ -// [Bit Utils] -// ============================================================================ - -static inline uint32_t maskFromIndex(uint32_t x) -{ - return (1U << x); -} - -static inline uint32_t maskUpToIndex(uint32_t x) -{ - if (x >= 32) - return 0xFFFFFFFF; - else - return (1U << x) - 1; -} - -// From http://graphics.stanford.edu/~seander/bithacks.html . -static inline uint32_t bitCount(uint32_t x) -{ - x = x - ((x >> 1) & 0x55555555U); - x = (x & 0x33333333U) + ((x >> 2) & 0x33333333U); - return (((x + (x >> 4)) & 0xF0F0F0FU) * 0x1010101U) >> 24; -} - -static inline uint32_t findFirstBit(uint32_t mask) ASMJIT_NOTHROW -{ - for (uint32_t i = 0, bit = 1; i < sizeof(uint32_t) * 8; i++, bit <<= 1) - { - if (mask & bit) return i; - } - - // INVALID_VALUE. - return 0xFFFFFFFF; -} - -// ============================================================================ -// [Alignment] -// ============================================================================ - -// Align variable @a x to 16-bytes. -template -static inline T alignTo16(const T& x) -{ - return (x + (T)15) & (T)~15; -} - -// Return the size needed to align variable @a x to 16-bytes. -template -static inline T deltaTo16(const T& x) -{ - T aligned = alignTo16(x); - return aligned - x; -} - -} // Util namespace - -// ============================================================================ -// [AsmJit::function_cast<>] -// ============================================================================ - -//! @brief Cast used to cast pointer to function. It's like reinterpret_cast<>, -//! but uses internally C style cast to work with MinGW. -//! -//! If you are using single compiler and @c reinterpret_cast<> works for you, -//! there is no reason to use @c AsmJit::function_cast<>. If you are writing -//! cross-platform software with various compiler support, consider using -//! @c AsmJit::function_cast<> instead of @c reinterpret_cast<>. -template -static inline T function_cast(Z* p) ASMJIT_NOTHROW { return (T)p; } - -// ============================================================================ -// [AsmJit::(X)MMData] -// ============================================================================ - -//! @brief Structure used for MMX specific data (64-bit). -//! -//! This structure can be used to load / store data from / to MMX register. -union ASMJIT_HIDDEN MMData -{ - // -------------------------------------------------------------------------- - // [Methods] - // -------------------------------------------------------------------------- - - //! @brief Set all eight signed 8-bit integers. - inline void setSB( - int8_t x0, int8_t x1, int8_t x2, int8_t x3, int8_t x4, int8_t x5, int8_t x6, int8_t x7) ASMJIT_NOTHROW - { - sb[0] = x0; sb[1] = x1; sb[2] = x2; sb[3] = x3; sb[4] = x4; sb[5] = x5; sb[6] = x6; sb[7] = x7; - } - - //! @brief Set all eight unsigned 8-bit integers. - inline void setUB( - uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7) ASMJIT_NOTHROW - { - ub[0] = x0; ub[1] = x1; ub[2] = x2; ub[3] = x3; ub[4] = x4; ub[5] = x5; ub[6] = x6; ub[7] = x7; - } - - //! @brief Set all four signed 16-bit integers. - inline void setSW( - int16_t x0, int16_t x1, int16_t x2, int16_t x3) ASMJIT_NOTHROW - { - sw[0] = x0; sw[1] = x1; sw[2] = x2; sw[3] = x3; - } - - //! @brief Set all four unsigned 16-bit integers. - inline void setUW( - uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3) ASMJIT_NOTHROW - { - uw[0] = x0; uw[1] = x1; uw[2] = x2; uw[3] = x3; - } - - //! @brief Set all two signed 32-bit integers. - inline void setSD( - int32_t x0, int32_t x1) ASMJIT_NOTHROW - { - sd[0] = x0; sd[1] = x1; - } - - //! @brief Set all two unsigned 32-bit integers. - inline void setUD( - uint32_t x0, uint32_t x1) ASMJIT_NOTHROW - { - ud[0] = x0; ud[1] = x1; - } - - //! @brief Set signed 64-bit integer. - inline void setSQ( - int64_t x0) ASMJIT_NOTHROW - { - sq[0] = x0; - } - - //! @brief Set unsigned 64-bit integer. - inline void setUQ( - uint64_t x0) ASMJIT_NOTHROW - { - uq[0] = x0; - } - - //! @brief Set all two SP-FP values. - inline void setSF( - float x0, float x1) ASMJIT_NOTHROW - { - sf[0] = x0; sf[1] = x1; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! @brief Array of eight signed 8-bit integers. - int8_t sb[8]; - //! @brief Array of eight unsigned 8-bit integers. - uint8_t ub[8]; - //! @brief Array of four signed 16-bit integers. - int16_t sw[4]; - //! @brief Array of four unsigned 16-bit integers. - uint16_t uw[4]; - //! @brief Array of two signed 32-bit integers. - int32_t sd[2]; - //! @brief Array of two unsigned 32-bit integers. - uint32_t ud[2]; - //! @brief Array of one signed 64-bit integer. - int64_t sq[1]; - //! @brief Array of one unsigned 64-bit integer. - uint64_t uq[1]; - - //! @brief Array of two SP-FP values. - float sf[2]; -}; - -//! @brief Structure used for SSE specific data (128-bit). -//! -//! This structure can be used to load / store data from / to SSE register. -//! -//! @note Always align SSE data to 16-bytes. -union ASMJIT_HIDDEN XMMData -{ - // -------------------------------------------------------------------------- - // [Methods] - // -------------------------------------------------------------------------- - - //! @brief Set all sixteen signed 8-bit integers. - inline void setSB( - int8_t x0, int8_t x1, int8_t x2 , int8_t x3 , int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , - int8_t x8, int8_t x9, int8_t x10, int8_t x11, int8_t x12, int8_t x13, int8_t x14, int8_t x15) ASMJIT_NOTHROW - { - sb[0] = x0; sb[1] = x1; sb[ 2] = x2 ; sb[3 ] = x3 ; sb[4 ] = x4 ; sb[5 ] = x5 ; sb[6 ] = x6 ; sb[7 ] = x7 ; - sb[8] = x8; sb[9] = x9; sb[10] = x10; sb[11] = x11; sb[12] = x12; sb[13] = x13; sb[14] = x14; sb[15] = x15; - } - - //! @brief Set all sixteen unsigned 8-bit integers. - inline void setUB( - uint8_t x0, uint8_t x1, uint8_t x2 , uint8_t x3 , uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , - uint8_t x8, uint8_t x9, uint8_t x10, uint8_t x11, uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15) ASMJIT_NOTHROW - { - ub[0] = x0; ub[1] = x1; ub[ 2] = x2 ; ub[3 ] = x3 ; ub[4 ] = x4 ; ub[5 ] = x5 ; ub[6 ] = x6 ; ub[7 ] = x7 ; - ub[8] = x8; ub[9] = x9; ub[10] = x10; ub[11] = x11; ub[12] = x12; ub[13] = x13; ub[14] = x14; ub[15] = x15; - } - - //! @brief Set all eight signed 16-bit integers. - inline void setSW( - int16_t x0, int16_t x1, int16_t x2, int16_t x3, int16_t x4, int16_t x5, int16_t x6, int16_t x7) ASMJIT_NOTHROW - { - sw[0] = x0; sw[1] = x1; sw[2] = x2; sw[3] = x3; sw[4] = x4; sw[5] = x5; sw[6] = x6; sw[7] = x7; - } - - //! @brief Set all eight unsigned 16-bit integers. - inline void setUW( - uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7) ASMJIT_NOTHROW - { - uw[0] = x0; uw[1] = x1; uw[2] = x2; uw[3] = x3; uw[4] = x4; uw[5] = x5; uw[6] = x6; uw[7] = x7; - } - - //! @brief Set all four signed 32-bit integers. - inline void setSD( - int32_t x0, int32_t x1, int32_t x2, int32_t x3) ASMJIT_NOTHROW - { - sd[0] = x0; sd[1] = x1; sd[2] = x2; sd[3] = x3; - } - - //! @brief Set all four unsigned 32-bit integers. - inline void setUD( - uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) ASMJIT_NOTHROW - { - ud[0] = x0; ud[1] = x1; ud[2] = x2; ud[3] = x3; - } - - //! @brief Set all two signed 64-bit integers. - inline void setSQ( - int64_t x0, int64_t x1) ASMJIT_NOTHROW - { - sq[0] = x0; sq[1] = x1; - } - - //! @brief Set all two unsigned 64-bit integers. - inline void setUQ( - uint64_t x0, uint64_t x1) ASMJIT_NOTHROW - { - uq[0] = x0; uq[1] = x1; - } - - //! @brief Set all four SP-FP floats. - inline void setSF( - float x0, float x1, float x2, float x3) ASMJIT_NOTHROW - { - sf[0] = x0; sf[1] = x1; sf[2] = x2; sf[3] = x3; - } - - //! @brief Set all two DP-FP floats. - inline void setDF( - double x0, double x1) ASMJIT_NOTHROW - { - df[0] = x0; df[1] = x1; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! @brief Array of sixteen signed 8-bit integers. - int8_t sb[16]; - //! @brief Array of sixteen unsigned 8-bit integers. - uint8_t ub[16]; - //! @brief Array of eight signed 16-bit integers. - int16_t sw[8]; - //! @brief Array of eight unsigned 16-bit integers. - uint16_t uw[8]; - //! @brief Array of four signed 32-bit integers. - int32_t sd[4]; - //! @brief Array of four unsigned 32-bit integers. - uint32_t ud[4]; - //! @brief Array of two signed 64-bit integers. - int64_t sq[2]; - //! @brief Array of two unsigned 64-bit integers. - uint64_t uq[2]; - - //! @brief Array of four 32-bit single precision floating points. - float sf[4]; - //! @brief Array of two 64-bit double precision floating points. - double df[2]; -}; - -// ============================================================================ -// [AsmJit::Buffer] -// ============================================================================ - -//! @brief Buffer used to store instruction stream in AsmJit. -//! -//! This class can be dangerous, if you don't know how it works. Assembler -//! instruction stream is usually constructed by multiple calls of emit -//! functions that emits bytes, words, dwords or qwords. But to decrease -//! AsmJit library size and improve performance, we are not checking for -//! buffer overflow for each emit operation, but only once in highler level -//! emit instruction. -//! -//! So, if you want to use this class, you need to do buffer checking yourself -//! by using @c ensureSpace() method. It's designed to grow buffer if needed. -//! Threshold for growing is named @c growThreshold() and it means count of -//! bytes for emitting single operation. Default size is set to 16 bytes, -//! because x86 and x64 instruction can't be larger (so it's space to hold 1 -//! instruction). -//! -//! Example using Buffer: -//! -//! @code -//! // Buffer instance, growThreshold == 16 -//! // (no memory allocated in constructor). -//! AsmJit::Buffer buf(16); -//! -//! // Begin of emit stream, ensure space can fail on out of memory error. -//! if (buf.ensureSpace()) -//! { -//! // here, you can emit up to 16 (growThreshold) bytes -//! buf.emitByte(0x00); -//! buf.emitByte(0x01); -//! buf.emitByte(0x02); -//! buf.emitByte(0x03); -//! ... -//! } -//! @endcode -struct ASMJIT_API Buffer -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - inline Buffer(sysint_t growThreshold = 16) ASMJIT_NOTHROW : - _data(NULL), - _cur(NULL), - _max(NULL), - _capacity(0), - _growThreshold(growThreshold) - { - } - - inline ~Buffer() ASMJIT_NOTHROW - { - if (_data) ASMJIT_FREE(_data); - } - - //! @brief Get start of buffer. - inline uint8_t* getData() const ASMJIT_NOTHROW { return _data; } - - //! @brief Get current pointer in code buffer. - inline uint8_t* getCur() const ASMJIT_NOTHROW { return _cur; } - - //! @brief Get maximum pointer in code buffer for growing. - inline uint8_t* getMax() const ASMJIT_NOTHROW { return _max; } - - //! @brief Get current offset in buffer. - inline sysint_t getOffset() const ASMJIT_NOTHROW { return (sysint_t)(_cur - _data); } - - //! @brief Get capacity of buffer. - inline sysint_t getCapacity() const ASMJIT_NOTHROW { return _capacity; } - - //! @brief Get grow threshold. - inline sysint_t getGrowThreshold() const ASMJIT_NOTHROW { return _growThreshold; } - - //! @brief Ensure space for next instruction - inline bool ensureSpace() ASMJIT_NOTHROW { return (_cur >= _max) ? grow() : true; } - - //! @brief Sets offset to @a o and returns previous offset. - //! - //! This method can be used to truncate buffer or it's used to - //! overwrite specific position in buffer by Assembler. - inline sysint_t toOffset(sysint_t o) ASMJIT_NOTHROW - { - ASMJIT_ASSERT(o < _capacity); - - sysint_t prev = (sysint_t)(_cur - _data); - _cur = _data + o; - return prev; - } - - //! @brief Reallocate buffer. - //! - //! It's only used for growing, buffer is never reallocated to smaller - //! number than current capacity() is. - bool realloc(sysint_t to) ASMJIT_NOTHROW; - - //! @brief Used to grow the buffer. - //! - //! It will typically realloc to twice size of capacity(), but if capacity() - //! is large, it will use smaller steps. - bool grow() ASMJIT_NOTHROW; - - //! @brief Clear everything, but not deallocate buffer. - void clear() ASMJIT_NOTHROW; - - //! @brief Free buffer and NULL all pointers. - void free() ASMJIT_NOTHROW; - - //! @brief Take ownership of the buffer data and purge @c Buffer instance. - uint8_t* take() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Emit] - // -------------------------------------------------------------------------- - - //! @brief Emit Byte. - inline void emitByte(uint8_t x) ASMJIT_NOTHROW - { - *_cur++ = x; - } - - //! @brief Emit Word (2 bytes). - inline void emitWord(uint16_t x) ASMJIT_NOTHROW - { - *(uint16_t *)_cur = x; - _cur += 2; - } - - //! @brief Emit DWord (4 bytes). - inline void emitDWord(uint32_t x) ASMJIT_NOTHROW - { - *(uint32_t *)_cur = x; - _cur += 4; - } - - //! @brief Emit QWord (8 bytes). - inline void emitQWord(uint64_t x) ASMJIT_NOTHROW - { - *(uint64_t *)_cur = x; - _cur += 8; - } - - //! @brief Emit system signed integer (4 or 8 bytes). - inline void emitSysInt(sysint_t x) ASMJIT_NOTHROW - { - *(sysint_t *)_cur = x; - _cur += sizeof(sysint_t); - } - - //! @brief Emit system unsigned integer (4 or 8 bytes). - inline void emitSysUInt(sysuint_t x) ASMJIT_NOTHROW - { - *(sysuint_t *)_cur = x; - _cur += sizeof(sysuint_t); - } - - //! @brief Emit custom data. - void emitData(const void* ptr, sysuint_t len) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Get / Set] - // -------------------------------------------------------------------------- - - //! @brief Set byte at position @a pos. - inline uint8_t getByteAt(sysint_t pos) const ASMJIT_NOTHROW - { - return *reinterpret_cast(_data + pos); - } - - //! @brief Set word at position @a pos. - inline uint16_t getWordAt(sysint_t pos) const ASMJIT_NOTHROW - { - return *reinterpret_cast(_data + pos); - } - - //! @brief Set word at position @a pos. - inline uint32_t getDWordAt(sysint_t pos) const ASMJIT_NOTHROW - { - return *reinterpret_cast(_data + pos); - } - - //! @brief Set word at position @a pos. - inline uint64_t getQWordAt(sysint_t pos) const ASMJIT_NOTHROW - { - return *reinterpret_cast(_data + pos); - } - - //! @brief Set byte at position @a pos. - inline void setByteAt(sysint_t pos, uint8_t x) ASMJIT_NOTHROW - { - *reinterpret_cast(_data + pos) = x; - } - - //! @brief Set word at position @a pos. - inline void setWordAt(sysint_t pos, uint16_t x) ASMJIT_NOTHROW - { - *reinterpret_cast(_data + pos) = x; - } - - //! @brief Set word at position @a pos. - inline void setDWordAt(sysint_t pos, uint32_t x) ASMJIT_NOTHROW - { - *reinterpret_cast(_data + pos) = x; - } - - //! @brief Set word at position @a pos. - inline void setQWordAt(sysint_t pos, uint64_t x) ASMJIT_NOTHROW - { - *reinterpret_cast(_data + pos) = x; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - // All members are public, because they can be accessed and modified by - // Assembler/Compiler directly. - - //! @brief Beginning position of buffer. - uint8_t* _data; - //! @brief Current position in buffer. - uint8_t* _cur; - //! @brief Maximum position in buffer for realloc. - uint8_t* _max; - - //! @brief Buffer capacity (in bytes). - sysint_t _capacity; - - //! @brief Grow threshold - sysint_t _growThreshold; -}; - -// ============================================================================ -// [AsmJit::PodVector<>] -// ============================================================================ - -//! @brief Template used to store and manage array of POD data. -//! -//! This template has these adventages over other vector<> templates: -//! - Non-copyable (designed to be non-copyable, we want it) -//! - No copy-on-write (some implementations of stl can use it) -//! - Optimized for working only with POD types -//! - Uses ASMJIT_... memory management macros -template -struct PodVector -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create new instance of PodVector template. Data will not - //! be allocated (will be NULL). - inline PodVector() ASMJIT_NOTHROW : _data(NULL), _length(0), _capacity(0) - { - } - - //! @brief Destroy PodVector and free all data. - inline ~PodVector() ASMJIT_NOTHROW - { - if (_data) ASMJIT_FREE(_data); - } - - // -------------------------------------------------------------------------- - // [Data] - // -------------------------------------------------------------------------- - - //! @brief Get vector data. - inline T* getData() ASMJIT_NOTHROW { return _data; } - //! @overload - inline const T* getData() const ASMJIT_NOTHROW { return _data; } - //! @brief Get vector length. - inline sysuint_t getLength() const ASMJIT_NOTHROW { return _length; } - //! @brief get vector capacity (allocation capacity). - inline sysuint_t getCapacity() const ASMJIT_NOTHROW { return _capacity; } - - // -------------------------------------------------------------------------- - // [Manipulation] - // -------------------------------------------------------------------------- - - //! @brief Clear vector data, but not free internal buffer. - void clear() ASMJIT_NOTHROW - { - _length = 0; - } - - //! @brief Clear vector data and free internal buffer. - void free() ASMJIT_NOTHROW - { - if (_data) - { - ASMJIT_FREE(_data); - _data = 0; - _length = 0; - _capacity = 0; - } - } - - //! @brief Prepend @a item to vector. - bool prepend(const T& item) ASMJIT_NOTHROW - { - if (_length == _capacity && !_grow()) return false; - - memmove(_data + 1, _data, sizeof(T) * _length); - memcpy(_data, &item, sizeof(T)); - - _length++; - return true; - } - - //! @brief Insert an @a item at the @a index. - bool insert(sysuint_t index, const T& item) ASMJIT_NOTHROW - { - ASMJIT_ASSERT(index <= _length); - if (_length == _capacity && !_grow()) return false; - - T* dst = _data + index; - memmove(dst + 1, dst, _length - index); - memcpy(dst, &item, sizeof(T)); - - _length++; - return true; - } - - //! @brief Append @a item to vector. - bool append(const T& item) ASMJIT_NOTHROW - { - if (_length == _capacity && !_grow()) return false; - - memcpy(_data + _length, &item, sizeof(T)); - - _length++; - return true; - } - - //! @brief Get index of @a val or (sysuint_t)-1 if not found. - sysuint_t indexOf(const T& val) const ASMJIT_NOTHROW - { - sysuint_t i = 0, len = _length; - for (i = 0; i < len; i++) { if (_data[i] == val) return i; } - return (sysuint_t)-1; - } - - //! @brief Remove element at index @a i. - void removeAt(sysuint_t i) ASMJIT_NOTHROW - { - ASMJIT_ASSERT(i < _length); - - T* dst = _data + i; - _length--; - memmove(dst, dst + 1, _length - i); - } - - //! @brief Swap this pod-vector with @a other. - void swap(PodVector& other) ASMJIT_NOTHROW - { - T* _tmp_data = _data; - sysuint_t _tmp_length = _length; - sysuint_t _tmp_capacity = _capacity; - - _data = other._data; - _length = other._length; - _capacity = other._capacity; - - other._data = _tmp_data; - other._length = _tmp_length; - other._capacity = _tmp_capacity; - } - - //! @brief Get item at position @a i. - inline T& operator[](sysuint_t i) ASMJIT_NOTHROW - { - ASMJIT_ASSERT(i < _length); - return _data[i]; - } - //! @brief Get item at position @a i. - inline const T& operator[](sysuint_t i) const ASMJIT_NOTHROW - { - ASMJIT_ASSERT(i < _length); - return _data[i]; - } - - //! @brief Append the item and return address so it can be initialized. - T* newItem() ASMJIT_NOTHROW - { - if (_length == _capacity && !_grow()) return NULL; - return _data + (_length++); - } - - // -------------------------------------------------------------------------- - // [Private] - // -------------------------------------------------------------------------- - -private: - //! @brief Called to grow internal array. - bool _grow() ASMJIT_NOTHROW - { - return _realloc(_capacity < 16 ? 16 : _capacity * 2); - } - - //! @brief Realloc internal array to fit @a to items. - bool _realloc(sysuint_t to) ASMJIT_NOTHROW - { - ASMJIT_ASSERT(to >= _length); - - T* p = reinterpret_cast(_data - ? ASMJIT_REALLOC(_data, to * sizeof(T)) - : ASMJIT_MALLOC(to * sizeof(T))); - if (!p) return false; - - _data = p; - _capacity = to; - return true; - } - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - - //! @brief Items data. - T* _data; - //! @brief Length of buffer (count of items in array). - sysuint_t _length; - //! @brief Capacity of buffer (maximum items that can fit to current array). - sysuint_t _capacity; - -private: - ASMJIT_DISABLE_COPY(PodVector) -}; - -// ============================================================================ -// [AsmJit::Zone] -// ============================================================================ - -//! @brief Memory allocator designed to fast alloc memory that will be freed -//! in one step. -//! -//! @note This is hackery for performance. Concept is that objects created -//! by @c Zone are freed all at once. This means that lifetime of -//! these objects are same as zone object itselt. -//! -//! All emittables, variables, labels and states allocated by @c Compiler are -//! allocated through @c Zone object. -struct ASMJIT_API Zone -{ - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! @brief Create new instance of @c Zone. - //! @param chunkSize Default size for one zone chunk. - Zone(sysuint_t chunkSize) ASMJIT_NOTHROW; - - //! @brief Destroy zone instance. - ~Zone() ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Methods] - // -------------------------------------------------------------------------- - - //! @brief Allocate @c size bytes of memory and return pointer to it. - //! - //! Pointer allocated by this way will be valid until @c Zone object is - //! destroyed. To create class by this way use placement @c new and - //! @c delete operators: - //! - //! @code - //! // Example of allocating simple class - //! - //! // Your class - //! class Object - //! { - //! // members... - //! }; - //! - //! // Your function - //! void f() - //! { - //! // We are using AsmJit namespace - //! using namespace AsmJit - //! - //! // Create zone object with chunk size of 65536 bytes. - //! Zone zone(65536); - //! - //! // Create your objects using zone object allocating, for example: - //! Object* obj = new(zone.alloc(sizeof(YourClass))) Object(); - //! - //! // ... lifetime of your objects ... - //! - //! // Destroy your objects: - //! obj->~Object(); - //! - //! // Zone destructor will free all memory allocated through it, - //! // alternative is to call @c zone.freeAll(). - //! } - //! @endcode - void* zalloc(sysuint_t size) ASMJIT_NOTHROW; - - //! @brief Helper to duplicate string. - char* zstrdup(const char* str) ASMJIT_NOTHROW; - - //! @brief Free all allocated memory except first block that remains for reuse. - //! - //! Note that this method will invalidate all instances using this memory - //! allocated by this zone instance. - void clear() ASMJIT_NOTHROW; - - //! @brief Free all allocated memory at once. - //! - //! Note that this method will invalidate all instances using this memory - //! allocated by this zone instance. - void freeAll() ASMJIT_NOTHROW; - - //! @brief Get total size of allocated objects - by @c alloc(). - inline sysuint_t getTotal() const ASMJIT_NOTHROW { return _total; } - //! @brief Get (default) chunk size. - inline sysuint_t getChunkSize() const ASMJIT_NOTHROW { return _chunkSize; } - - // -------------------------------------------------------------------------- - // [Chunk] - // -------------------------------------------------------------------------- - - //! @internal - //! - //! @brief One allocated chunk of memory. - struct ASMJIT_HIDDEN Chunk - { - //! @brief Link to previous chunk. - Chunk* prev; - //! @brief Position in this chunk. - sysuint_t pos; - //! @brief Size of this chunk (in bytes). - sysuint_t size; - - //! @brief Data. - uint8_t data[sizeof(void*)]; - - //! @brief Get count of remaining (unused) bytes in chunk. - inline sysuint_t getRemainingBytes() const ASMJIT_NOTHROW { return size - pos; } - }; - - // -------------------------------------------------------------------------- - // [Members] - // -------------------------------------------------------------------------- - -private: - //! @brief Last allocated chunk of memory. - Chunk* _chunks; - //! @brief Total size of allocated objects - by @c alloc() method. - sysuint_t _total; - //! @brief One chunk size. - sysuint_t _chunkSize; -}; - -//! @} - -} // AsmJit namespace - -#endif // _ASMJIT_UTIL_H diff --git a/desmume/src/utils/AsmJit/Util_p.h b/desmume/src/utils/AsmJit/Util_p.h deleted file mode 100644 index 929e04a2d..000000000 --- a/desmume/src/utils/AsmJit/Util_p.h +++ /dev/null @@ -1,111 +0,0 @@ -// [AsmJit] -// Complete JIT Assembler for C++ Language. -// -// [License] -// Zlib - See COPYING file in this package. - -// [Guard] -#ifndef _ASMJIT_UTIL_P_H -#define _ASMJIT_UTIL_P_H - -// [Dependencies] -#include "Util.h" - -#include -#include - -namespace AsmJit { - -//! @addtogroup AsmJit_Util -//! @{ - -// ============================================================================ -// [AsmJit::Util] -// ============================================================================ - -namespace Util -{ - // -------------------------------------------------------------------------- - // [AsmJit::floatAsInt32, int32AsFloat] - // -------------------------------------------------------------------------- - - //! @internal - //! - //! @brief used to cast from float to 32-bit integer and vica versa. - union I32FPUnion - { - //! @brief 32-bit signed integer value. - int32_t i; - //! @brief 32-bit SP-FP value. - float f; - }; - - //! @internal - //! - //! @brief used to cast from double to 64-bit integer and vica versa. - union I64FPUnion - { - //! @brief 64-bit signed integer value. - int64_t i; - //! @brief 64-bit DP-FP value. - double f; - }; - - //! @brief Binary cast from 32-bit integer to SP-FP value (@c float). - static inline float int32AsFloat(int32_t i) ASMJIT_NOTHROW - { - I32FPUnion u; - u.i = i; - return u.f; - } - - //! @brief Binary cast SP-FP value (@c float) to 32-bit integer. - static inline int32_t floatAsInt32(float f) ASMJIT_NOTHROW - { - I32FPUnion u; - u.f = f; - return u.i; - } - - //! @brief Binary cast from 64-bit integer to DP-FP value (@c double). - static inline double int64AsDouble(int64_t i) ASMJIT_NOTHROW - { - I64FPUnion u; - u.i = i; - return u.f; - } - - //! @brief Binary cast from DP-FP value (@c double) to 64-bit integer. - static inline int64_t doubleAsInt64(double f) ASMJIT_NOTHROW - { - I64FPUnion u; - u.f = f; - return u.i; - } - - // -------------------------------------------------------------------------- - // [Str Utils] - // -------------------------------------------------------------------------- - - ASMJIT_HIDDEN char* mycpy(char* dst, const char* src, sysuint_t len = (sysuint_t)-1) ASMJIT_NOTHROW; - ASMJIT_HIDDEN char* myfill(char* dst, const int c, sysuint_t len) ASMJIT_NOTHROW; - ASMJIT_HIDDEN char* myhex(char* dst, const uint8_t* src, sysuint_t len) ASMJIT_NOTHROW; - ASMJIT_HIDDEN char* myutoa(char* dst, sysuint_t i, sysuint_t base = 10) ASMJIT_NOTHROW; - ASMJIT_HIDDEN char* myitoa(char* dst, sysint_t i, sysuint_t base = 10) ASMJIT_NOTHROW; - - // -------------------------------------------------------------------------- - // [Mem Utils] - // -------------------------------------------------------------------------- - - static inline void memset32(uint32_t* p, uint32_t c, sysuint_t len) ASMJIT_NOTHROW - { - sysuint_t i; - for (i = 0; i < len; i++) p[i] = c; - } -} // Util namespace - -//! @} - -} // AsmJit namespace - -#endif // _ASMJIT_UTIL_P_H diff --git a/desmume/src/utils/AsmJit/core.h b/desmume/src/utils/AsmJit/core.h new file mode 100644 index 000000000..d1c3f3ba5 --- /dev/null +++ b/desmume/src/utils/AsmJit/core.h @@ -0,0 +1,37 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_H +#define _ASMJIT_CORE_H + +// [Dependencies - AsmJit] +#include "core/build.h" + +#include "core/assembler.h" +#include "core/assert.h" +#include "core/buffer.h" +#include "core/compiler.h" +#include "core/compilercontext.h" +#include "core/compilerfunc.h" +#include "core/compileritem.h" +#include "core/cpuinfo.h" +#include "core/defs.h" +#include "core/func.h" +#include "core/intutil.h" +#include "core/lock.h" +#include "core/logger.h" +#include "core/memorymanager.h" +#include "core/memorymarker.h" +#include "core/operand.h" +#include "core/podvector.h" +#include "core/stringbuilder.h" +#include "core/stringutil.h" +#include "core/virtualmemory.h" +#include "core/zonememory.h" + +// [Guard] +#endif // _ASMJIT_CORE_H diff --git a/desmume/src/utils/AsmJit/ApiBegin.h b/desmume/src/utils/AsmJit/core/apibegin.h similarity index 72% rename from desmume/src/utils/AsmJit/ApiBegin.h rename to desmume/src/utils/AsmJit/core/apibegin.h index 2d2880fb9..f34fee134 100644 --- a/desmume/src/utils/AsmJit/ApiBegin.h +++ b/desmume/src/utils/AsmJit/core/apibegin.h @@ -4,7 +4,7 @@ // [License] // Zlib - See COPYING file in this package. -// MSVC +// [MSVC] #if defined(_MSC_VER) // Disable some warnings we know about @@ -22,3 +22,12 @@ #define snprintf _snprintf #endif // _MSC_VER + +// [GNUC] +#if defined(__GNUC__) +// GCC warnings fix: I can't understand why GCC has no interface to push/pop +// specific warnings. +// # if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 402001 +// # pragma GCC diagnostic ignored "-w" +// # endif +#endif // __GNUC__ diff --git a/desmume/src/utils/AsmJit/ApiEnd.h b/desmume/src/utils/AsmJit/core/apiend.h similarity index 81% rename from desmume/src/utils/AsmJit/ApiEnd.h rename to desmume/src/utils/AsmJit/core/apiend.h index 8fdff9738..7bf288336 100644 --- a/desmume/src/utils/AsmJit/ApiEnd.h +++ b/desmume/src/utils/AsmJit/core/apiend.h @@ -4,6 +4,7 @@ // [License] // Zlib - See COPYING file in this package. +// [MSVC] #if defined(_MSC_VER) // Pop disabled warnings by ApiBegin.h @@ -14,3 +15,7 @@ #undef snprintf #endif // _MSC_VER + +// [GNUC] +#if defined(__GNUC__) +#endif // __GNUC__ diff --git a/desmume/src/utils/AsmJit/core/assembler.cpp b/desmume/src/utils/AsmJit/core/assembler.cpp new file mode 100644 index 000000000..8088a72a3 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/assembler.cpp @@ -0,0 +1,217 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/assembler.h" +#include "../core/memorymanager.h" +#include "../core/intutil.h" + +// [Dependenceis - C] +#include + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::Assembler - Construction / Destruction] +// ============================================================================ + +Assembler::Assembler(Context* context) : + _zoneMemory(16384 - sizeof(ZoneChunk) - 32), + _buffer(), + _context(context != NULL + ? context + : static_cast(JitContext::getGlobal())), + _logger(NULL), + _error(kErrorOk), + _properties(0), + _emitOptions(0), + _trampolineSize(0), + _inlineComment(NULL), + _unusedLinks(NULL) +{ +} + +Assembler::~Assembler() +{ +} + +// ============================================================================ +// [AsmJit::Assembler - Logging] +// ============================================================================ + +void Assembler::setLogger(Logger* logger) +{ + _logger = logger; +} + +// ============================================================================ +// [AsmJit::Assembler - Error Handling] +// ============================================================================ + +void Assembler::setError(uint32_t error) +{ + _error = error; + if (_error == kErrorOk) + return; + + if (_logger) + _logger->logFormat("*** ASSEMBLER ERROR: %s (%u).\n", getErrorString(error), (unsigned int)error); +} + +// ============================================================================ +// [AsmJit::Assembler - Properties] +// ============================================================================ + +uint32_t Assembler::getProperty(uint32_t propertyId) const +{ + if (propertyId > 31) + return 0; + + return (_properties & (IntUtil::maskFromIndex(propertyId))) != 0; +} + +void Assembler::setProperty(uint32_t propertyId, uint32_t value) +{ + if (propertyId > 31) + return; + + if (value) + _properties |= IntUtil::maskFromIndex(propertyId); + else + _properties &= ~IntUtil::maskFromIndex(propertyId); +} + +// ============================================================================ +// [AsmJit::Assembler - TakeCode] +// ============================================================================ + +uint8_t* Assembler::takeCode() +{ + uint8_t* code = _buffer.take(); + _relocData.clear(); + _zoneMemory.clear(); + + if (_error != kErrorOk) + setError(kErrorOk); + + return code; +} + +// ============================================================================ +// [AsmJit::Assembler - Clear / Reset] +// ============================================================================ + +void Assembler::clear() +{ + _purge(); + + if (_error != kErrorOk) + setError(kErrorOk); +} + +void Assembler::reset() +{ + _purge(); + + _zoneMemory.reset(); + _buffer.reset(); + + _labels.reset(); + _relocData.reset(); + + if (_error != kErrorOk) + setError(kErrorOk); +} + +void Assembler::_purge() +{ + _zoneMemory.clear(); + _buffer.clear(); + + _emitOptions = 0; + _trampolineSize = 0; + + _inlineComment = NULL; + _unusedLinks = NULL; + + _labels.clear(); + _relocData.clear(); +} + +// ============================================================================ +// [AsmJit::Assembler - Emit] +// ============================================================================ + +void Assembler::embed(const void* data, size_t len) +{ + if (!canEmit()) + return; + + if (_logger) + { + size_t i, j; + size_t max; + + char buf[128]; + char dot[] = ".data "; + char* p; + + memcpy(buf, dot, ASMJIT_ARRAY_SIZE(dot) - 1); + + for (i = 0; i < len; i += 16) + { + max = (len - i < 16) ? len - i : 16; + p = buf + ASMJIT_ARRAY_SIZE(dot) - 1; + + for (j = 0; j < max; j++) + p += sprintf(p, "%02X", reinterpret_cast(data)[i+j]); + + *p++ = '\n'; + *p = '\0'; + + _logger->logString(buf); + } + } + + _buffer.emitData(data, len); +} + +// ============================================================================ +// [AsmJit::Assembler - Helpers] +// ============================================================================ + +Assembler::LabelLink* Assembler::_newLabelLink() +{ + LabelLink* link = _unusedLinks; + + if (link) + { + _unusedLinks = link->prev; + } + else + { + link = (LabelLink*)_zoneMemory.alloc(sizeof(LabelLink)); + if (link == NULL) return NULL; + } + + // clean link + link->prev = NULL; + link->offset = 0; + link->displacement = 0; + link->relocId = -1; + + return link; +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/assembler.h b/desmume/src/utils/AsmJit/core/assembler.h new file mode 100644 index 000000000..17bacf73a --- /dev/null +++ b/desmume/src/utils/AsmJit/core/assembler.h @@ -0,0 +1,500 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_ASSEMBLER_H +#define _ASMJIT_CORE_ASSEMBLER_H + +// [Dependencies - AsmJit] +#include "../core/buffer.h" +#include "../core/context.h" +#include "../core/defs.h" +#include "../core/logger.h" +#include "../core/podvector.h" +#include "../core/zonememory.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::Assembler] +// ============================================================================ + +//! @brief Base class for @ref Assembler. +//! +//! This class implements core setialization API only. The platform specific +//! methods and intrinsics is implemented by derived classes. +//! +//! @sa @c Assembler. +struct Assembler +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Creates Assembler instance. + ASMJIT_API Assembler(Context* context); + //! @brief Destroys Assembler instance + ASMJIT_API virtual ~Assembler(); + + // -------------------------------------------------------------------------- + // [LabelLink] + // -------------------------------------------------------------------------- + + //! @brief Data structure used to link linked-labels. + struct LabelLink + { + //! @brief Previous link. + LabelLink* prev; + //! @brief Offset. + sysint_t offset; + //! @brief Inlined displacement. + sysint_t displacement; + //! @brief RelocId if link must be absolute when relocated. + sysint_t relocId; + }; + + // -------------------------------------------------------------------------- + // [LabelData] + // -------------------------------------------------------------------------- + + //! @brief Label data. + struct LabelData + { + //! @brief Label offset. + sysint_t offset; + //! @brief Label links chain. + LabelLink* links; + }; + + // -------------------------------------------------------------------------- + // [RelocData] + // -------------------------------------------------------------------------- + + // X86 architecture uses 32-bit absolute addressing model by memory operands, + // but 64-bit mode uses relative addressing model (RIP + displacement). In + // code we are always using relative addressing model for referencing labels + // and embedded data. In 32-bit mode we must patch all references to absolute + // address before we can call generated function. We are patching only memory + // operands. + + //! @brief Code relocation data (relative vs absolute addresses). + struct RelocData + { + //! @brief Type of relocation. + uint32_t type; + //! @brief Size of relocation (4 or 8 bytes). + uint32_t size; + //! @brief Offset from code begin address. + sysint_t offset; + + //! @brief Relative displacement or absolute address. + union + { + //! @brief Relative displacement from code begin address (not to @c offset). + sysint_t destination; + //! @brief Absolute address where to jump; + void* address; + }; + }; + + // -------------------------------------------------------------------------- + // [Context] + // -------------------------------------------------------------------------- + + //! @brief Get code generator. + inline Context* getContext() const + { return _context; } + + // -------------------------------------------------------------------------- + // [Memory Management] + // -------------------------------------------------------------------------- + + //! @brief Get zone memory manager. + inline ZoneMemory* getZoneMemory() const + { return const_cast(&_zoneMemory); } + + // -------------------------------------------------------------------------- + // [Logging] + // -------------------------------------------------------------------------- + + //! @brief Get logger. + inline Logger* getLogger() const + { return _logger; } + + //! @brief Set logger to @a logger. + ASMJIT_API virtual void setLogger(Logger* logger); + + // -------------------------------------------------------------------------- + // [Error Handling] + // -------------------------------------------------------------------------- + + //! @brief Get error code. + inline uint32_t getError() const + { return _error; } + + //! @brief Set error code. + //! + //! This method is virtual, because higher classes can use it to catch all + //! errors. + ASMJIT_API virtual void setError(uint32_t error); + + // -------------------------------------------------------------------------- + // [Properties] + // -------------------------------------------------------------------------- + + //! @brief Get assembler property. + ASMJIT_API virtual uint32_t getProperty(uint32_t propertyId) const; + + //! @brief Set assembler property. + ASMJIT_API virtual void setProperty(uint32_t propertyId, uint32_t value); + + // -------------------------------------------------------------------------- + // [Capacity] + // -------------------------------------------------------------------------- + + //! @brief Get capacity of internal code buffer. + inline size_t getCapacity() const + { return _buffer.getCapacity(); } + + // -------------------------------------------------------------------------- + // [Offset] + // -------------------------------------------------------------------------- + + //! @brief Return current offset in buffer. + inline size_t getOffset() const + { return _buffer.getOffset(); } + + //! @brief Set offset to @a o and returns previous offset. + //! + //! This method can be used to truncate code (previous offset is not + //! recorded) or to overwrite instruction stream at position @a o. + //! + //! @return Previous offset value that can be uset to set offset back later. + inline size_t toOffset(size_t o) + { return _buffer.toOffset(o); } + + // -------------------------------------------------------------------------- + // [GetCode / GetCodeSize] + // -------------------------------------------------------------------------- + + //! @brief Return start of assembler code buffer. + //! + //! Note that buffer address can change if you emit instruction or something + //! else. Use this pointer only when you finished or make sure you do not + //! use returned pointer after emitting. + inline uint8_t* getCode() const + { return _buffer.getData(); } + + //! @brief Return current offset in buffer (same as getOffset() + getTramplineSize()). + inline size_t getCodeSize() const + { return _buffer.getOffset() + getTrampolineSize(); } + + // -------------------------------------------------------------------------- + // [TakeCode] + // -------------------------------------------------------------------------- + + //! @brief Take internal code buffer and NULL all pointers (you take the ownership). + ASMJIT_API uint8_t* takeCode(); + + // -------------------------------------------------------------------------- + // [Clear / Reset] + // -------------------------------------------------------------------------- + + //! @brief Clear everything, but not deallocate buffers. + ASMJIT_API void clear(); + + //! @brief Reset everything (means also to free all buffers). + ASMJIT_API void reset(); + + //! @brief Called by clear() and reset() to clear all data related to derived + //! class implementation. + ASMJIT_API virtual void _purge(); + + // -------------------------------------------------------------------------- + // [EnsureSpace] + // -------------------------------------------------------------------------- + + //! @brief Ensure space for next instruction. + //! + //! Note that this method can return false. It's rare and probably you never + //! get this, but in some situations it's still possible. + inline bool ensureSpace() + { return _buffer.ensureSpace(); } + + // -------------------------------------------------------------------------- + // [GetTrampolineSize] + // -------------------------------------------------------------------------- + + //! @brief Get size of all possible trampolines needed to successfuly generate + //! relative jumps to absolute addresses. This value is only non-zero if jmp + //! of call instructions were used with immediate operand (this means jump or + //! call absolute address directly). + //! + //! Currently only _emitJmpOrCallReloc() method can increase trampoline size + //! value. + inline size_t getTrampolineSize() const + { return _trampolineSize; } + + // -------------------------------------------------------------------------- + // [Buffer - Getters] + // -------------------------------------------------------------------------- + + //! @brief Get byte at position @a pos. + inline uint8_t getByteAt(size_t pos) const + { return _buffer.getByteAt(pos); } + + //! @brief Get word at position @a pos. + inline uint16_t getWordAt(size_t pos) const + { return _buffer.getWordAt(pos); } + + //! @brief Get dword at position @a pos. + inline uint32_t getDWordAt(size_t pos) const + { return _buffer.getDWordAt(pos); } + + //! @brief Get qword at position @a pos. + inline uint64_t getQWordAt(size_t pos) const + { return _buffer.getQWordAt(pos); } + + //! @brief Get int32_t at position @a pos. + inline int32_t getInt32At(size_t pos) const + { return (int32_t)_buffer.getDWordAt(pos); } + + //! @brief Get int64_t at position @a pos. + inline int64_t getInt64At(size_t pos) const + { return (int64_t)_buffer.getQWordAt(pos); } + + //! @brief Get intptr_t at position @a pos. + inline intptr_t getIntPtrTAt(size_t pos) const + { return _buffer.getIntPtrTAt(pos); } + + //! @brief Get uintptr_t at position @a pos. + inline uintptr_t getUIntPtrTAt(size_t pos) const + { return _buffer.getUIntPtrTAt(pos); } + + //! @brief Get uintptr_t at position @a pos. + inline size_t getSizeTAt(size_t pos) const + { return _buffer.getSizeTAt(pos); } + + // -------------------------------------------------------------------------- + // [Buffer - Setters] + // -------------------------------------------------------------------------- + + //! @brief Set byte at position @a pos. + inline void setByteAt(size_t pos, uint8_t x) + { _buffer.setByteAt(pos, x); } + + //! @brief Set word at position @a pos. + inline void setWordAt(size_t pos, uint16_t x) + { _buffer.setWordAt(pos, x); } + + //! @brief Set dword at position @a pos. + inline void setDWordAt(size_t pos, uint32_t x) + { _buffer.setDWordAt(pos, x); } + + //! @brief Set qword at position @a pos. + inline void setQWordAt(size_t pos, uint64_t x) + { _buffer.setQWordAt(pos, x); } + + //! @brief Set int32_t at position @a pos. + inline void setInt32At(size_t pos, int32_t x) + { _buffer.setDWordAt(pos, (uint32_t)x); } + + //! @brief Set int64_t at position @a pos. + inline void setInt64At(size_t pos, int64_t x) + { _buffer.setQWordAt(pos, (uint64_t)x); } + + //! @brief Set intptr_t at position @a pos. + inline void setIntPtrTAt(size_t pos, intptr_t x) + { _buffer.setIntPtrTAt(pos, x); } + + //! @brief Set uintptr_t at position @a pos. + inline void setUInt64At(size_t pos, uintptr_t x) + { _buffer.setUIntPtrTAt(pos, x); } + + //! @brief Set size_t at position @a pos. + inline void setSizeTAt(size_t pos, size_t x) + { _buffer.setSizeTAt(pos, x); } + + // -------------------------------------------------------------------------- + // [CanEmit] + // -------------------------------------------------------------------------- + + //! @brief Get whether the instruction can be emitted. + //! + //! This function behaves like @c ensureSpace(), but it also checks if + //! assembler is in error state and in that case it returns @c false. + //! Assembler internally always uses this function before new instruction is + //! emitted. + //! + //! It's implemented like: + //! return ensureSpace() && !getError(); + inline bool canEmit() + { + // If there is an error, we can't emit another instruction until last error + // is cleared by calling @c setError(kErrorOk). If something caused the + // error while generating code it's probably fatal in all cases. You can't + // use generated code anymore, because you are not sure about the status. + if (_error) + return false; + + // The ensureSpace() method returns true on success and false on failure. We + // are catching return value and setting error code here. + if (ensureSpace()) + return true; + + // If we are here, there is memory allocation error. Note that this is HEAP + // allocation error, virtual allocation error can be caused only by + // AsmJit::VirtualMemory class! + setError(kErrorNoHeapMemory); + return false; + } + + // -------------------------------------------------------------------------- + // [Emit] + // + // These functions are not protected against buffer overrun. Each place of + // code which calls these functions ensures that there is some space using + // canEmit() method. Emitters are internally protected in AsmJit::Buffer, + // but only in debug builds. + // -------------------------------------------------------------------------- + + //! @brief Emit Byte to internal buffer. + inline void _emitByte(uint8_t x) + { _buffer.emitByte(x); } + + //! @brief Emit word (2 bytes) to internal buffer. + inline void _emitWord(uint16_t x) + { _buffer.emitWord(x); } + + //! @brief Emit dword (4 bytes) to internal buffer. + inline void _emitDWord(uint32_t x) + { _buffer.emitDWord(x); } + + //! @brief Emit qword (8 bytes) to internal buffer. + inline void _emitQWord(uint64_t x) + { _buffer.emitQWord(x); } + + //! @brief Emit Int32 (4 bytes) to internal buffer. + inline void _emitInt32(int32_t x) + { _buffer.emitDWord((uint32_t)x); } + + //! @brief Emit Int64 (8 bytes) to internal buffer. + inline void _emitInt64(int64_t x) + { _buffer.emitQWord((uint64_t)x); } + + //! @brief Emit intptr_t (4 or 8 bytes) to internal buffer. + inline void _emitIntPtrT(intptr_t x) + { _buffer.emitIntPtrT(x); } + + //! @brief Emit uintptr_t (4 or 8 bytes) to internal buffer. + inline void _emitUIntPtrT(uintptr_t x) + { _buffer.emitUIntPtrT(x); } + + //! @brief Emit size_t (4 or 8 bytes) to internal buffer. + inline void _emitSizeT(size_t x) + { _buffer.emitSizeT(x); } + + //! @brief Embed data into instruction stream. + ASMJIT_API void embed(const void* data, size_t len); + + // -------------------------------------------------------------------------- + // [Reloc] + // -------------------------------------------------------------------------- + + //! @brief Relocate code to a given address @a dst. + //! + //! @param dst Where the relocated code should me stored. The pointer can be + //! address returned by virtual memory allocator or your own address if you + //! want only to store the code for later reuse (or load, etc...). + //! @param addressBase Base address used for relocation. When using JIT code + //! generation, this will be the same as @a dst, only casted to system + //! integer type. But when generating code for remote process then the value + //! can be different. + //! + //! @retval The bytes used. Code-generator can create trampolines which are + //! used when calling other functions inside the JIT code. However, these + //! trampolines can be unused so the relocCode() returns the exact size needed + //! for the function. + //! + //! A given buffer will be overwritten, to get number of bytes required use + //! @c getCodeSize(). + virtual size_t relocCode(void* dst, sysuint_t addressBase) const = 0; + + //! @brief Simplifed version of @c relocCode() method designed for JIT. + //! + //! @overload + inline size_t relocCode(void* dst) const + { return relocCode(dst, (uintptr_t)dst); } + + // -------------------------------------------------------------------------- + // [Make] + // -------------------------------------------------------------------------- + + //! @brief Make is convenience method to make currently serialized code and + //! return pointer to generated function. + //! + //! What you need is only to cast this pointer to your function type and call + //! it. Note that if there was an error and calling @c getError() method not + //! returns @c kErrorOk (zero) then this function always return @c NULL and + //! error value remains the same. + virtual void* make() = 0; + + // -------------------------------------------------------------------------- + // [Helpers] + // -------------------------------------------------------------------------- + + ASMJIT_API LabelLink* _newLabelLink(); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief ZoneMemory management. + ZoneMemory _zoneMemory; + //! @brief Binary code buffer. + Buffer _buffer; + + //! @brief Context (for example @ref JitContext). + Context* _context; + //! @brief Logger. + Logger* _logger; + + //! @brief Error code. + uint32_t _error; + //! @brief Properties. + uint32_t _properties; + //! @brief Emit flags for next instruction (cleared after emit). + uint32_t _emitOptions; + //! @brief Size of possible trampolines. + uint32_t _trampolineSize; + + //! @brief Inline comment that will be logged by the next instruction and + //! set to NULL. + const char* _inlineComment; + //! @brief Linked list of unused links (@c LabelLink* structures) + LabelLink* _unusedLinks; + + //! @brief Labels data. + PodVector _labels; + //! @brief Relocations data. + PodVector _relocData; +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_ASSEMBLER_H diff --git a/desmume/src/utils/AsmJit/core/assert.cpp b/desmume/src/utils/AsmJit/core/assert.cpp new file mode 100644 index 000000000..87e651d3f --- /dev/null +++ b/desmume/src/utils/AsmJit/core/assert.cpp @@ -0,0 +1,34 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/assert.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +// helpers +namespace AsmJit { + +// ============================================================================ +// [AsmJit::Assert] +// ============================================================================ + +void assertionFailure(const char* file, int line, const char* exp) +{ + fprintf(stderr, + "*** ASSERTION FAILURE at %s (line %d)\n" + "*** %s\n", file, line, exp); + + exit(1); +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/assert.h b/desmume/src/utils/AsmJit/core/assert.h new file mode 100644 index 000000000..4e4db908c --- /dev/null +++ b/desmume/src/utils/AsmJit/core/assert.h @@ -0,0 +1,65 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_ASSERT_H +#define _ASMJIT_CORE_ASSERT_H + +// [Dependencies - AsmJit] +#include "../core/build.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::Assert] +// ============================================================================ + +//! @brief Called in debug build on assertion failure. +//! @param file Source file name where it happened. +//! @param line Line in the source file. +//! @param exp Expression what failed. +//! +//! If you have problems with assertions simply put a breakpoint into +//! AsmJit::assertionFailure() method (AsmJit/Core/Assert.cpp file) and examine +//! call stack. +ASMJIT_API void assertionFailure(const char* file, int line, const char* exp); + +// ============================================================================ +// [ASMJIT_ASSERT] +// ============================================================================ + +#if defined(ASMJIT_DEBUG) + +#if !defined(ASMJIT_ASSERT) +#define ASMJIT_ASSERT(exp) \ + do { \ + if (!(exp)) ::AsmJit::assertionFailure(__FILE__, __LINE__, #exp); \ + } while(0) +#endif + +#else + +#if !defined(ASMJIT_ASSERT) +#define ASMJIT_ASSERT(exp) ASMJIT_NOP() +#endif + +#endif // DEBUG + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_ASSERT_H diff --git a/desmume/src/utils/AsmJit/core/buffer.cpp b/desmume/src/utils/AsmJit/core/buffer.cpp new file mode 100644 index 000000000..e33a73968 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/buffer.cpp @@ -0,0 +1,102 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/buffer.h" +#include "../core/defs.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::Buffer] +// ============================================================================ + +void Buffer::emitData(const void* ptr, size_t len) +{ + size_t max = getCapacity() - getOffset(); + + if (max < len && !realloc(getOffset() + len)) + { + return; + } + + memcpy(_cur, ptr, len); + _cur += len; +} + +bool Buffer::realloc(size_t to) +{ + if (getCapacity() < to) + { + size_t len = getOffset(); + uint8_t *newdata; + + if (_data != NULL) + newdata = (uint8_t*)ASMJIT_REALLOC(_data, to); + else + newdata = (uint8_t*)ASMJIT_MALLOC(to); + + if (newdata == NULL) + return false; + + _data = newdata; + _cur = newdata + len; + _max = newdata + to; + _max -= (to >= kBufferGrow) ? kBufferGrow : to; + + _capacity = to; + } + + return true; +} + +bool Buffer::grow() +{ + size_t to = _capacity; + + if (to < 512) + to = 1024; + else if (to > 65536) + to += 65536; + else + to <<= 1; + + return realloc(to); +} + +void Buffer::reset() +{ + if (_data == NULL) + return; + ASMJIT_FREE(_data); + + _data = NULL; + _cur = NULL; + _max = NULL; + _capacity = 0; +} + +uint8_t* Buffer::take() +{ + uint8_t* data = _data; + + _data = NULL; + _cur = NULL; + _max = NULL; + _capacity = 0; + + return data; +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/buffer.h b/desmume/src/utils/AsmJit/core/buffer.h new file mode 100644 index 000000000..38af2c50a --- /dev/null +++ b/desmume/src/utils/AsmJit/core/buffer.h @@ -0,0 +1,348 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_BUFFER_H +#define _ASMJIT_CORE_BUFFER_H + +// [Dependencies - AsmJit] +#include "../core/assert.h" +#include "../core/build.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +struct Buffer; + +// ============================================================================ +// [AsmJit::Buffer] +// ============================================================================ + +//! @brief Buffer used to store instruction stream in AsmJit. +//! +//! This class can be dangerous, if you don't know how it works. Assembler +//! instruction stream is usually constructed by multiple calls of emit +//! functions that emits bytes, words, dwords or qwords. But to decrease +//! AsmJit library size and improve performance, we are not checking for +//! buffer overflow for each emit operation, but only once in highler level +//! emit instruction. +//! +//! So, if you want to use this class, you need to do buffer checking yourself +//! by using @c ensureSpace() method. It's designed to grow buffer if needed. +//! Threshold for growing is named @c growThreshold() and it means count of +//! bytes for emitting single operation. Default size is set to 16 bytes, +//! because x86 and x64 instruction can't be larger (so it's space to hold 1 +//! instruction). +//! +//! Example using Buffer: +//! +//! @code +//! // Buffer instance, growThreshold == 16 +//! // (no memory allocated in constructor). +//! AsmJit::Buffer buf(16); +//! +//! // Begin of emit stream, ensure space can fail on out of memory error. +//! if (buf.ensureSpace()) +//! { +//! // here, you can emit up to 16 (growThreshold) bytes +//! buf.emitByte(0x00); +//! buf.emitByte(0x01); +//! buf.emitByte(0x02); +//! buf.emitByte(0x03); +//! ... +//! } +//! @endcode +struct Buffer +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + inline Buffer() : + _data(NULL), + _cur(NULL), + _max(NULL), + _capacity(0) + { + } + + inline ~Buffer() + { + if (_data) ASMJIT_FREE(_data); + } + + //! @brief Get start of buffer. + inline uint8_t* getData() const { return _data; } + + //! @brief Get current pointer in code buffer. + inline uint8_t* getCur() const { return _cur; } + + //! @brief Get maximum pointer in code buffer for growing. + inline uint8_t* getMax() const { return _max; } + + //! @brief Get current offset in buffer. + inline size_t getOffset() const { return (size_t)(_cur - _data); } + + //! @brief Get capacity of buffer. + inline size_t getCapacity() const { return _capacity; } + + //! @brief Ensure space for next instruction + inline bool ensureSpace() { return (_cur >= _max) ? grow() : true; } + + //! @brief Sets offset to @a o and returns previous offset. + //! + //! This method can be used to truncate buffer or it's used to + //! overwrite specific position in buffer by Assembler. + inline size_t toOffset(size_t offset) + { + ASMJIT_ASSERT(offset < _capacity); + + size_t prev = (size_t)(_cur - _data); + _cur = _data + offset; + return prev; + } + + //! @brief Reallocate buffer. + //! + //! It's only used for growing, buffer is never reallocated to smaller + //! number than current capacity() is. + ASMJIT_API bool realloc(size_t to); + + //! @brief Used to grow the buffer. + //! + //! It will typically realloc to twice size of capacity(), but if capacity() + //! is large, it will use smaller steps. + ASMJIT_API bool grow(); + + //! @brief Clear everything, but not deallocate buffer. + inline void clear() { _cur = _data; } + + //! @brief Free buffer and NULL all pointers. + ASMJIT_API void reset(); + + //! @brief Take ownership of the buffer data and purge @c Buffer instance. + ASMJIT_API uint8_t* take(); + + // -------------------------------------------------------------------------- + // [Emit] + // -------------------------------------------------------------------------- + + //! @brief Emit Byte. + inline void emitByte(uint8_t x) + { + ASMJIT_ASSERT(getOffset() + 1 <= _capacity); + + *_cur++ = x; + } + + //! @brief Emit Word (2 bytes). + inline void emitWord(uint16_t x) + { + ASMJIT_ASSERT(getOffset() + 2 <= _capacity); + + *(uint16_t *)_cur = x; + _cur += 2; + } + + //! @brief Emit DWord (4 bytes). + inline void emitDWord(uint32_t x) + { + ASMJIT_ASSERT(getOffset() + 4 <= _capacity); + + *(uint32_t *)_cur = x; + _cur += 4; + } + + //! @brief Emit QWord (8 bytes). + inline void emitQWord(uint64_t x) + { + ASMJIT_ASSERT(getOffset() + 8 <= _capacity); + + *(uint64_t *)_cur = x; + _cur += 8; + } + + //! @brief Emit intptr_t (4 or 8 bytes). + inline void emitIntPtrT(intptr_t x) + { + ASMJIT_ASSERT(getOffset() + sizeof(intptr_t) <= _capacity); + + *(intptr_t *)_cur = x; + _cur += sizeof(intptr_t); + } + + //! @brief Emit uintptr_t (4 or 8 bytes). + inline void emitUIntPtrT(uintptr_t x) + { + ASMJIT_ASSERT(getOffset() + sizeof(uintptr_t) <= _capacity); + + *(uintptr_t *)_cur = x; + _cur += sizeof(uintptr_t); + } + + //! @brief Emit size_t (4 or 8 bytes). + inline void emitSizeT(size_t x) + { + ASMJIT_ASSERT(getOffset() + sizeof(size_t) <= _capacity); + + *(size_t *)_cur = x; + _cur += sizeof(size_t); + } + + //! @brief Emit custom data. + ASMJIT_API void emitData(const void* ptr, size_t len); + + // -------------------------------------------------------------------------- + // [Get / Set] + // -------------------------------------------------------------------------- + + //! @brief Set byte at position @a pos. + inline uint8_t getByteAt(size_t pos) const + { + ASMJIT_ASSERT(pos + 1 <= _capacity); + + return *reinterpret_cast(_data + pos); + } + + //! @brief Set word at position @a pos. + inline uint16_t getWordAt(size_t pos) const + { + ASMJIT_ASSERT(pos + 2 <= _capacity); + + return *reinterpret_cast(_data + pos); + } + + //! @brief Set dword at position @a pos. + inline uint32_t getDWordAt(size_t pos) const + { + ASMJIT_ASSERT(pos + 4 <= _capacity); + + return *reinterpret_cast(_data + pos); + } + + //! @brief Set qword at position @a pos. + inline uint64_t getQWordAt(size_t pos) const + { + ASMJIT_ASSERT(pos + 8 <= _capacity); + + return *reinterpret_cast(_data + pos); + } + + //! @brief Set intptr_t at position @a pos. + inline intptr_t getIntPtrTAt(size_t pos) const + { + ASMJIT_ASSERT(pos + sizeof(intptr_t) <= _capacity); + + return *reinterpret_cast(_data + pos); + } + + //! @brief Set uintptr_t at position @a pos. + inline uintptr_t getUIntPtrTAt(size_t pos) const + { + ASMJIT_ASSERT(pos + sizeof(uintptr_t) <= _capacity); + + return *reinterpret_cast(_data + pos); + } + + //! @brief Set size_t at position @a pos. + inline uintptr_t getSizeTAt(size_t pos) const + { + ASMJIT_ASSERT(pos + sizeof(size_t) <= _capacity); + + return *reinterpret_cast(_data + pos); + } + + //! @brief Set byte at position @a pos. + inline void setByteAt(size_t pos, uint8_t x) + { + ASMJIT_ASSERT(pos + 1 <= _capacity); + + *reinterpret_cast(_data + pos) = x; + } + + //! @brief Set word at position @a pos. + inline void setWordAt(size_t pos, uint16_t x) + { + ASMJIT_ASSERT(pos + 2 <= _capacity); + + *reinterpret_cast(_data + pos) = x; + } + + //! @brief Set dword at position @a pos. + inline void setDWordAt(size_t pos, uint32_t x) + { + ASMJIT_ASSERT(pos + 4 <= _capacity); + + *reinterpret_cast(_data + pos) = x; + } + + //! @brief Set qword at position @a pos. + inline void setQWordAt(size_t pos, uint64_t x) + { + ASMJIT_ASSERT(pos + 8 <= _capacity); + + *reinterpret_cast(_data + pos) = x; + } + + //! @brief Set intptr_t at position @a pos. + inline void setIntPtrTAt(size_t pos, intptr_t x) + { + ASMJIT_ASSERT(pos + sizeof(intptr_t) <= _capacity); + + *reinterpret_cast(_data + pos) = x; + } + + //! @brief Set uintptr_t at position @a pos. + inline void setUIntPtrTAt(size_t pos, uintptr_t x) + { + ASMJIT_ASSERT(pos + sizeof(uintptr_t) <= _capacity); + + *reinterpret_cast(_data + pos) = x; + } + + //! @brief Set size_t at position @a pos. + inline void setSizeTAt(size_t pos, size_t x) + { + ASMJIT_ASSERT(pos + sizeof(size_t) <= _capacity); + + *reinterpret_cast(_data + pos) = x; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + // All members are public, because they can be accessed and modified by + // Assembler/Compiler directly. + + //! @brief Beginning position of buffer. + uint8_t* _data; + //! @brief Current position in buffer. + uint8_t* _cur; + //! @brief Maximum position in buffer for realloc. + uint8_t* _max; + + //! @brief Buffer capacity (in bytes). + size_t _capacity; +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +#endif // _ASMJIT_CORE_BUFFER_H diff --git a/desmume/src/utils/AsmJit/Build.h b/desmume/src/utils/AsmJit/core/build.h similarity index 50% rename from desmume/src/utils/AsmJit/Build.h rename to desmume/src/utils/AsmJit/core/build.h index c3af32c77..7ae634398 100644 --- a/desmume/src/utils/AsmJit/Build.h +++ b/desmume/src/utils/AsmJit/core/build.h @@ -5,23 +5,32 @@ // Zlib - See COPYING file in this package. // [Guard] -#ifndef _ASMJIT_BUILD_H -#define _ASMJIT_BUILD_H +#ifndef _ASMJIT_CORE_BUILD_H +#define _ASMJIT_CORE_BUILD_H // [Include] -#include "Config.h" +#include "../config.h" + +#if defined(ASMJIT_EXPORTS) +# if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +# define _CRT_SECURE_NO_WARNINGS +# endif // _MSC_VER +#endif // ASMJIT_EXPORTS // Here should be optional include files that's needed fo successfuly // use macros defined here. Remember, AsmJit uses only AsmJit namespace // and all macros are used within it. #include #include +#include -// ---------------------------------------------------------------------------- +#include + +// ============================================================================ // [AsmJit - OS] -// ---------------------------------------------------------------------------- +// ============================================================================ -#if defined(WINDOWS) || defined(__WINDOWS__) || defined(_WIN32) || defined(_WIN64) +#if defined(WINDOWS) || defined(_WINDOWS) || defined(__WINDOWS__) || defined(_WIN32) || defined(_WIN64) # define ASMJIT_WINDOWS #elif defined(__linux__) || defined(__unix__) || \ defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ @@ -33,9 +42,9 @@ # define ASMJIT_POSIX #endif -// ---------------------------------------------------------------------------- +// ============================================================================ // [AsmJit - Architecture] -// ---------------------------------------------------------------------------- +// ============================================================================ // define it only if it's not defined. In some systems we can // use -D command in compiler to bypass this autodetection. @@ -49,32 +58,25 @@ # endif #endif -// ---------------------------------------------------------------------------- +// ============================================================================ // [AsmJit - API] -// ---------------------------------------------------------------------------- - -// Hide AsmJit symbols that we don't want to export (AssemblerIntrinsics class for example). -#if !defined(ASMJIT_HIDDEN) -# if defined(__GNUC__) && __GNUC__ >= 4 -# define ASMJIT_HIDDEN __attribute__((visibility("hidden"))) -# endif // __GNUC__ && __GNUC__ >= 4 -#endif // ASMJIT_HIDDEN +// ============================================================================ // Make AsmJit as shared library by default. #if !defined(ASMJIT_API) # if defined(ASMJIT_WINDOWS) # if defined(__GNUC__) -# if defined(AsmJit_EXPORTS) +# if defined(ASMJIT_EXPORTS) # define ASMJIT_API __attribute__((dllexport)) # else # define ASMJIT_API __attribute__((dllimport)) -# endif // AsmJit_EXPORTS +# endif // ASMJIT_EXPORTS # else -# if defined(AsmJit_EXPORTS) +# if defined(ASMJIT_EXPORTS) # define ASMJIT_API __declspec(dllexport) # else # define ASMJIT_API __declspec(dllimport) -# endif // AsmJit_EXPORTS +# endif // ASMJIT_EXPORTS # endif // __GNUC__ # else # if defined(__GNUC__) @@ -86,21 +88,13 @@ # endif #endif // ASMJIT_API -#if defined(ASMJIT_API) -# define ASMJIT_VAR extern ASMJIT_API -#else -# define ASMJIT_API -# define ASMJIT_VAR -#endif // ASMJIT_API - -// If not detected, fallback to nothing. -#if !defined(ASMJIT_HIDDEN) -# define ASMJIT_HIDDEN -#endif // ASMJIT_HIDDEN - -#if !defined(ASMJIT_NOTHROW) -#define ASMJIT_NOTHROW throw() -#endif // ASMJIT_NOTHROW +#if !defined(ASMJIT_VAR) +# if defined(ASMJIT_API) +# define ASMJIT_VAR extern ASMJIT_API +# else +# define ASMJIT_VAR +# endif // ASMJIT_API +#endif // !ASMJIT_VAR // [AsmJit - Memory Management] #if !defined(ASMJIT_MALLOC) @@ -115,9 +109,9 @@ # define ASMJIT_FREE ::free #endif // ASMJIT_FREE -// ---------------------------------------------------------------------------- +// ============================================================================ // [AsmJit - Calling Conventions] -// ---------------------------------------------------------------------------- +// ============================================================================ #if defined(ASMJIT_X86) # if defined(__GNUC__) @@ -147,94 +141,58 @@ #endif // ASMJIT_NOP // [AsmJit - C++ Compiler Support] -#define ASMJIT_TYPE_TO_TYPE(type) type +#define ASMJIT_TYPE_TO_TYPE(_Type_) _Type_ #define ASMJIT_HAS_STANDARD_DEFINE_OPTIONS #define ASMJIT_HAS_PARTIAL_TEMPLATE_SPECIALIZATION // Support for VC6 #if defined(_MSC_VER) && (_MSC_VER < 1400) -#undef ASMJIT_TYPE_TO_TYPE + namespace AsmJit { template struct _Type2Type { typedef T Type; }; } -#define ASMJIT_TYPE_TO_TYPE(T) _Type2Type::Type + +#undef ASMJIT_TYPE_TO_TYPE +#define ASMJIT_TYPE_TO_TYPE(_Type_) ::AsmJit::_Type2Type<_Type_>::Type #undef ASMJIT_HAS_STANDARD_DEFINE_OPTIONS #undef ASMJIT_HAS_PARTIAL_TEMPLATE_SPECIALIZATION #endif -// ---------------------------------------------------------------------------- +// ============================================================================ // [AsmJit - Types] -// ---------------------------------------------------------------------------- +// ============================================================================ -#if defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1600) - -// Use -#include +#if defined(__MINGW32__) || defined(__MINGW64__) +# include +#endif // __MINGW32__ || __MINGW64__ +#if defined(_MSC_VER) && (_MSC_VER < 1600) +# if (_MSC_VER < 1300) +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +# else +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef signed __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +# endif // _MSC_VER #else - -// Use typedefs. -#if defined(_MSC_VER) -#if (_MSC_VER < 1300) - -#ifndef HAVE_INT8_T - typedef char int8_t; -#endif -#ifndef HAVE_INT16_T - typedef short int16_t; -#endif -#ifndef HAVE_INT32_T - typedef int int32_t; -#endif -#ifndef HAVE_UINT8_T - typedef unsigned char uint8_t; -#endif -#ifndef HAVE_UINT16_T - typedef unsigned short uint16_t; -#endif -#ifndef HAVE_UINT32_T - typedef unsigned int uint32_t; -#endif -#ifndef HAVE_INT64_T - typedef __int64 int64_t; -#endif -#ifndef HAVE_UINT64_T - typedef unsigned __int64 uint64_t; -#endif - -#else - -#ifndef HAVE_INT8_T - typedef __int8 int8_t; -#endif -#ifndef HAVE_INT16_T - typedef __int16 int16_t; -#endif -#ifndef HAVE_INT32_T - typedef __int32 int32_t; -#endif -#ifndef HAVE_INT64_T - typedef __int64 int64_t; -#endif -#ifndef HAVE_UINT8_T - typedef unsigned __int8 uint8_t; -#endif -#ifndef HAVE_UINT16_T - typedef unsigned __int16 uint16_t; -#endif -#ifndef HAVE_UINT32_T - typedef unsigned __int32 uint32_t; -#endif -#ifndef HAVE_UINT64_T - typedef unsigned __int64 uint64_t; -#endif //HAVE_U_INT64_T - -#endif // _MSC_VER -#endif // _MSC_VER -#endif // STDINT.H +# include +# include +#endif typedef unsigned char uchar; typedef unsigned short ushort; @@ -257,20 +215,21 @@ typedef uint64_t sysuint_t; # define ASMJIT_UINT64_C(num) num##ULL #endif -// ---------------------------------------------------------------------------- +// ============================================================================ // [AsmJit - C++ Macros] -// ---------------------------------------------------------------------------- +// ============================================================================ #define ASMJIT_ARRAY_SIZE(A) (sizeof(A) / sizeof(*A)) -#define ASMJIT_DISABLE_COPY(__type__) \ +#define ASMJIT_NO_COPY(__type__) \ private: \ inline __type__(const __type__& other); \ - inline __type__& operator=(const __type__& other); + inline __type__& operator=(const __type__& other); \ +public: -// ---------------------------------------------------------------------------- +// ============================================================================ // [AsmJit - Debug] -// ---------------------------------------------------------------------------- +// ============================================================================ // If ASMJIT_DEBUG and ASMJIT_NO_DEBUG is not defined then ASMJIT_DEBUG will be // detected using the compiler specific macros. This enables to set the build @@ -282,40 +241,49 @@ private: \ #endif // _DEBUG #endif // !ASMJIT_DEBUG && !ASMJIT_NO_DEBUG - -// ---------------------------------------------------------------------------- -// [AsmJit - Assert] -// ---------------------------------------------------------------------------- -namespace AsmJit { -ASMJIT_API void assertionFailure(const char* file, int line, const char* exp); -} // AsmJit namespace +// ============================================================================ +// [AsmJit - Initialize/DontInitialize] +// ============================================================================ -#if defined(ASMJIT_DEBUG) -# if !defined(ASMJIT_ASSERT) -# define ASMJIT_ASSERT(exp) do { if (!(exp)) ::AsmJit::assertionFailure(__FILE__, __LINE__, #exp); } while(0) -# endif -#else -# if !defined(ASMJIT_ASSERT) -# define ASMJIT_ASSERT(exp) ASMJIT_NOP() -# endif -#endif // DEBUG +// TODO: This should be moved to AsmJit namespace! -// GCC warnings fix: I can't understand why GCC has no interface to push/pop -// specific warnings. -// #if defined(__GNUC__) -// # if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 402001 -// # pragma GCC diagnostic ignored "-w" -// # endif -// #endif // __GNUC__ +// Skip documenting this. +#if !defined(ASMJIT_NODOC) +struct _Initialize {}; +struct _DontInitialize {}; +#endif // !ASMJIT_NODOC -// ---------------------------------------------------------------------------- +// ============================================================================ +// [AsmJit - Void] +// ============================================================================ + +// TODO: This should be moved to AsmJit namespace! + +//! @brief Void type which can be used in @ref FunctionDeclaration templates. +struct Void {}; + +// ============================================================================ +// [asmjit_cast<>] +// ============================================================================ + +//! @brief Cast used to cast pointer to function. It's like reinterpret_cast<>, +//! but uses internally C style cast to work with MinGW. +//! +//! If you are using single compiler and @c reinterpret_cast<> works for you, +//! there is no reason to use @c asmjit_cast<>. If you are writing +//! cross-platform software with various compiler support, consider using +//! @c asmjit_cast<> instead of @c reinterpret_cast<>. +template +static inline T asmjit_cast(Z* p) { return (T)p; } + +// ============================================================================ // [AsmJit - OS Support] -// ---------------------------------------------------------------------------- +// ============================================================================ #if defined(ASMJIT_WINDOWS) #include #endif // ASMJIT_WINDOWS // [Guard] -#endif // _ASMJIT_BUILD_H +#endif // _ASMJIT_CORE_BUILD_H diff --git a/desmume/src/utils/AsmJit/core/compiler.cpp b/desmume/src/utils/AsmJit/core/compiler.cpp new file mode 100644 index 000000000..e47f71f5f --- /dev/null +++ b/desmume/src/utils/AsmJit/core/compiler.cpp @@ -0,0 +1,274 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/assembler.h" +#include "../core/compiler.h" +#include "../core/compilercontext.h" +#include "../core/compilerfunc.h" +#include "../core/compileritem.h" +#include "../core/cpuinfo.h" +#include "../core/intutil.h" +#include "../core/logger.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::Compiler - Construction / Destruction] +// ============================================================================ + +Compiler::Compiler(Context* context) : + _zoneMemory(16384 - sizeof(ZoneChunk) - 32), + _linkMemory(1024 - 32), + _context(context != NULL ? context : static_cast(JitContext::getGlobal())), + _logger(NULL), + _error(0), + _properties(0), + _emitOptions(0), + _finished(false), + _first(NULL), + _last(NULL), + _current(NULL), + _func(NULL), + _cc(NULL), + _varNameId(0) +{ +} + +Compiler::~Compiler() +{ + reset(); +} + +// ============================================================================ +// [AsmJit::Compiler - Logging] +// ============================================================================ + +void Compiler::setLogger(Logger* logger) +{ + _logger = logger; +} + +// ============================================================================ +// [AsmJit::Compiler - Error Handling] +// ============================================================================ + +void Compiler::setError(uint32_t error) +{ + _error = error; + if (_error == kErrorOk) + return; + + if (_logger) + _logger->logFormat("*** COMPILER ERROR: %s (%u).\n", getErrorString(error), (unsigned int)error); +} + +// ============================================================================ +// [AsmJit::Compiler - Properties] +// ============================================================================ + +uint32_t Compiler::getProperty(uint32_t propertyId) +{ + if (propertyId > 31) + return 0; + + return (_properties & IntUtil::maskFromIndex(propertyId)) != 0; +} + +void Compiler::setProperty(uint32_t propertyId, uint32_t value) +{ + if (propertyId > 31) + return; + + if (value) + _properties |= IntUtil::maskFromIndex(propertyId); + else + _properties &= ~IntUtil::maskFromIndex(propertyId); +} + +// ============================================================================ +// [AsmJit::Compiler - Clear / Reset] +// ============================================================================ + +void Compiler::clear() +{ + _purge(); + + if (_error != kErrorOk) + setError(kErrorOk); +} + +void Compiler::reset() +{ + _purge(); + + _zoneMemory.reset(); + _linkMemory.reset(); + + _targets.reset(); + _vars.reset(); + + if (_error != kErrorOk) + setError(kErrorOk); +} + +void Compiler::_purge() +{ + _zoneMemory.clear(); + _linkMemory.clear(); + + _emitOptions = 0; + _finished = false; + + _first = NULL; + _last = NULL; + _current = NULL; + _func = NULL; + + _targets.clear(); + _vars.clear(); + + _cc = NULL; + _varNameId = 0; +} + +// ============================================================================ +// [AsmJit::Compiler - Item Management] +// ============================================================================ + +CompilerItem* Compiler::setCurrentItem(CompilerItem* item) +{ + CompilerItem* old = _current; + _current = item; + return old; +} + +void Compiler::addItem(CompilerItem* item) +{ + ASMJIT_ASSERT(item != NULL); + ASMJIT_ASSERT(item->_prev == NULL); + ASMJIT_ASSERT(item->_next == NULL); + + if (_current == NULL) + { + if (_first == NULL) + { + _first = item; + _last = item; + } + else + { + item->_next = _first; + _first->_prev = item; + _first = item; + } + } + else + { + CompilerItem* prev = _current; + CompilerItem* next = _current->_next; + + item->_prev = prev; + item->_next = next; + + prev->_next = item; + if (next) + next->_prev = item; + else + _last = item; + } + + _current = item; +} + +void Compiler::addItemAfter(CompilerItem* item, CompilerItem* ref) +{ + ASMJIT_ASSERT(item != NULL); + ASMJIT_ASSERT(item->_prev == NULL); + ASMJIT_ASSERT(item->_next == NULL); + ASMJIT_ASSERT(ref != NULL); + + CompilerItem* prev = ref; + CompilerItem* next = ref->_next; + + item->_prev = prev; + item->_next = next; + + prev->_next = item; + if (next) + next->_prev = item; + else + _last = item; +} + +void Compiler::removeItem(CompilerItem* item) +{ + CompilerItem* prev = item->_prev; + CompilerItem* next = item->_next; + + if (_first == item) { _first = next; } else { prev->_next = next; } + if (_last == item) { _last = prev; } else { next->_prev = prev; } + + item->_prev = NULL; + item->_next = NULL; + + if (_current == item) + _current = prev; +} + +// ============================================================================ +// [AsmJit::Compiler - Comment] +// ============================================================================ + +void Compiler::comment(const char* fmt, ...) +{ + char buf[128]; + char* p = buf; + + if (fmt) + { + *p++ = ';'; + *p++ = ' '; + + va_list ap; + va_start(ap, fmt); + p += vsnprintf(p, 100, fmt, ap); + va_end(ap); + } + + *p++ = '\n'; + *p = '\0'; + + CompilerComment* item = Compiler_newItem(this, buf); + addItem(item); +} + +// ============================================================================ +// [AsmJit::Compiler - Embed] +// ============================================================================ + +void Compiler::embed(const void* data, size_t len) +{ + // Align length to 16 bytes. + size_t alignedSize = IntUtil::align(len, sizeof(uintptr_t)); + void* p = _zoneMemory.alloc(sizeof(CompilerEmbed) - sizeof(void*) + alignedSize); + + if (p == NULL) + return; + + CompilerEmbed* item = new(p) CompilerEmbed(this, data, len); + addItem(item); +} + +} // AsmJit namespace + +// [Api-Begin] +#include "../core/apibegin.h" diff --git a/desmume/src/utils/AsmJit/core/compiler.h b/desmume/src/utils/AsmJit/core/compiler.h new file mode 100644 index 000000000..79cc11b2d --- /dev/null +++ b/desmume/src/utils/AsmJit/core/compiler.h @@ -0,0 +1,359 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_COMPILER_H +#define _ASMJIT_CORE_COMPILER_H + +// [Dependencies - AsmJit] +#include "../core/assembler.h" +#include "../core/context.h" +#include "../core/func.h" +#include "../core/operand.h" +#include "../core/podvector.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +struct Compiler; +struct CompilerAlign; +struct CompilerComment; +struct CompilerContext; +struct CompilerEmbed; +struct CompilerFuncCall; +struct CompilerFuncDecl; +struct CompilerFuncEnd; +struct CompilerInst; +struct CompilerItem; +struct CompilerMark; +struct CompilerState; +struct CompilerTarget; +struct CompilerVar; + +// ============================================================================ +// [AsmJit::CompilerState] +// ============================================================================ + +//! @brief Compiler state base. +struct CompilerState +{ +}; + +// ============================================================================ +// [AsmJit::CompilerVar] +// ============================================================================ + +//! @brief Compiler variable base. +struct CompilerVar +{ + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get variable name. + inline const char* getName() const { return _name; } + //! @brief Get variable id. + inline uint32_t getId() const { return _id; } + + //! @brief Get variable type. + inline uint32_t getType() const { return _type; } + //! @brief Get variable class. + inline uint32_t getClass() const { return _class; } + //! @brief Get variable priority. + inline uint32_t getPriority() const { return _priority; } + //! @brief Get variable size. + inline uint32_t getSize() const { return _size; } + + //! @brief Get whether the variable is a function argument. + inline bool isArgument() const { return static_cast(_isRegArgument | _isMemArgument); } + //! @brief Get whether the variable is a function argument passed through register. + inline bool isRegArgument() const { return static_cast(_isRegArgument); } + //! @brief Get whether the variable is a function argument passed through memory. + inline bool isMemArgument() const { return static_cast(_isMemArgument); } + + //! @brief Get variable content can be calculated by a simple instruction. + inline bool isCalculated() const { return static_cast(_isCalculated); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Variable name. + const char* _name; + //! @brief Variable id. + uint32_t _id; + + //! @brief Variable type. + uint8_t _type; + //! @brief Variable class. + uint8_t _class; + //! @brief Variable priority. + uint8_t _priority; + + //! @brief Whether the variable is a function argument passed through register. + uint8_t _isRegArgument : 1; + //! @brief Whether the variable is a function argument passed through memory. + uint8_t _isMemArgument : 1; + //! @brief Whether variable content can be calculated by a simple instruction. + //! + //! This is used mainly by MMX and SSE2 code. This flag indicates that + //! register allocator should never reserve memory for this variable, because + //! the content can be generated by a single instruction (for example PXOR). + uint8_t _isCalculated : 1; + //! @internal. + uint8_t _unused : 5; + + //! @brief Variable size. + uint32_t _size; +}; + +// ============================================================================ +// [AsmJit::Compiler] +// ============================================================================ + +//! @brief Compiler. +//! +//! @sa @ref Assembler. +struct Compiler +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref Compiler instance. + ASMJIT_API Compiler(Context* context); + //! @brief Destroy the @ref Compiler instance. + ASMJIT_API virtual ~Compiler(); + + // -------------------------------------------------------------------------- + // [Context] + // -------------------------------------------------------------------------- + + //! @brief Get code generator. + inline Context* getContext() const + { return _context; } + + // -------------------------------------------------------------------------- + // [Memory Management] + // -------------------------------------------------------------------------- + + //! @brief Get zone memory manager. + inline ZoneMemory& getZoneMemory() + { return _zoneMemory; } + + //! @brief Get link memory manager. + inline ZoneMemory& getLinkMemory() + { return _linkMemory; } + + // -------------------------------------------------------------------------- + // [Logging] + // -------------------------------------------------------------------------- + + //! @brief Get logger. + inline Logger* getLogger() const + { return _logger; } + + //! @brief Set logger to @a logger. + ASMJIT_API virtual void setLogger(Logger* logger); + + // -------------------------------------------------------------------------- + // [Error Handling] + // -------------------------------------------------------------------------- + + //! @brief Get error code. + inline uint32_t getError() const + { return _error; } + + //! @brief Set error code. + //! + //! This method is virtual, because higher classes can use it to catch all + //! errors. + ASMJIT_API virtual void setError(uint32_t error); + + // -------------------------------------------------------------------------- + // [Properties] + // -------------------------------------------------------------------------- + + //! @brief Get compiler property. + ASMJIT_API virtual uint32_t getProperty(uint32_t propertyId); + //! @brief Set compiler property. + ASMJIT_API virtual void setProperty(uint32_t propertyId, uint32_t value); + + // -------------------------------------------------------------------------- + // [Clear / Reset] + // -------------------------------------------------------------------------- + + //! @brief Clear everything, but not deallocate buffers. + //! + //! @note This method will destroy your code. + ASMJIT_API void clear(); + + //! @brief Free internal buffer, all emitters and NULL all pointers. + //! + //! @note This method will destroy your code. + ASMJIT_API void reset(); + + //! @brief Called by clear() and reset() to clear all data related to derived + //! class implementation. + ASMJIT_API virtual void _purge(); + + // -------------------------------------------------------------------------- + // [Item Management] + // -------------------------------------------------------------------------- + + //! @brief Get first item. + inline CompilerItem* getFirstItem() const + { return _first; } + + //! @brief Get last item. + inline CompilerItem* getLastItem() const + { return _last; } + + //! @brief Get current item. + //! + //! @note If this method returns @c NULL it means that nothing has been + //! emitted yet. + inline CompilerItem* getCurrentItem() const + { return _current; } + + //! @brief Get current function. + inline CompilerFuncDecl* getFunc() const + { return _func; } + + //! @brief Set current item to @a item and return the previous current one. + ASMJIT_API CompilerItem* setCurrentItem(CompilerItem* item); + + //! @brief Add item after current item to @a item and set current item to + //! @a item. + ASMJIT_API void addItem(CompilerItem* item); + + //! @brief Add item after @a ref. + ASMJIT_API void addItemAfter(CompilerItem* item, CompilerItem* ref); + + //! @brief Remove item @a item. + ASMJIT_API void removeItem(CompilerItem* item); + + // -------------------------------------------------------------------------- + // [Comment] + // -------------------------------------------------------------------------- + + //! @brief Emit a single comment line. + //! + //! @note Comment is not directly sent to logger, but instead it's stored as + //! @ref CompilerComment item emitted when @c serialize() method is called. + ASMJIT_API void comment(const char* fmt, ...); + + // -------------------------------------------------------------------------- + // [Embed] + // -------------------------------------------------------------------------- + + //! @brief Embed data. + ASMJIT_API void embed(const void* data, size_t len); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief ZoneMemory allocator, used to allocate compiler items. + ZoneMemory _zoneMemory; + //! @brief ZoneMemory allocator, used to alloc small data structures like + //! linked lists. + ZoneMemory _linkMemory; + + //! @brief Context. + Context* _context; + //! @brief Logger. + Logger* _logger; + + //! @brief Error code. + uint32_t _error; + //! @brief Properties. + uint32_t _properties; + //! @brief Contains options for next emitted instruction, clear after each emit. + uint32_t _emitOptions; + //! @brief Whether compiler was finished the job (register allocator, etc...). + uint32_t _finished; + + //! @brief First item. + CompilerItem* _first; + //! @brief Last item. + CompilerItem* _last; + //! @brief Current item. + CompilerItem* _current; + //! @brief Current function. + CompilerFuncDecl* _func; + + //! @brief Targets. + PodVector _targets; + //! @brief Variables. + PodVector _vars; + + //! @brief Compiler context instance, only available after prepare(). + CompilerContext* _cc; + + //! @brief Variable name id (used to generate unique names per function). + int _varNameId; +}; + +// ============================================================================ +// [AsmJit::Compiler - Helpers] +// ============================================================================ + +template +inline T* Compiler_newItem(Compiler* self) +{ + void* addr = self->getZoneMemory().alloc(sizeof(T)); + return new(addr) T(self); +} + +template +inline T* Compiler_newItem(Compiler* self, P1 p1) +{ + void* addr = self->getZoneMemory().alloc(sizeof(T)); + return new(addr) T(self, p1); +} + +template +inline T* Compiler_newItem(Compiler* self, P1 p1, P2 p2) +{ + void* addr = self->getZoneMemory().alloc(sizeof(T)); + return new(addr) T(self, p1, p2); +} + +template +inline T* Compiler_newItem(Compiler* self, P1 p1, P2 p2, P3 p3) +{ + void* addr = self->getZoneMemory().alloc(sizeof(T)); + return new(addr) T(self, p1, p2, p3); +} + +template +inline T* Compiler_newItem(Compiler* self, P1 p1, P2 p2, P3 p3, P4 p4) +{ + void* addr = self->getZoneMemory().alloc(sizeof(T)); + return new(addr) T(self, p1, p2, p3, p4); +} + +template +inline T* Compiler_newItem(Compiler* self, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) +{ + void* addr = self->getZoneMemory().alloc(sizeof(T)); + return new(addr) T(self, p1, p2, p3, p4, p5); +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_COMPILER_H diff --git a/desmume/src/utils/AsmJit/core/compilercontext.cpp b/desmume/src/utils/AsmJit/core/compilercontext.cpp new file mode 100644 index 000000000..cf2af7639 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/compilercontext.cpp @@ -0,0 +1,42 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/compilercontext.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::CompilerContext - Construction / Destruction] +// ============================================================================ + +CompilerContext::CompilerContext(Compiler* compiler) : + _zoneMemory(8192 - sizeof(ZoneChunk) - 32), + _compiler(compiler), + _func(NULL), + _start(NULL), + _stop(NULL), + _extraBlock(NULL), + _state(NULL), + _active(NULL), + _currentOffset(0), + _isUnreachable(0) +{ +} + +CompilerContext::~CompilerContext() +{ +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/compilercontext.h b/desmume/src/utils/AsmJit/core/compilercontext.h new file mode 100644 index 000000000..d92aac25b --- /dev/null +++ b/desmume/src/utils/AsmJit/core/compilercontext.h @@ -0,0 +1,90 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_COMPILERCONTEXT_H +#define _ASMJIT_CORE_COMPILERCONTEXT_H + +// [Dependencies - AsmJit] +#include "../core/compiler.h" +#include "../core/compilerfunc.h" +#include "../core/compileritem.h" +#include "../core/zonememory.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::CompilerContext] +// ============================================================================ + +struct CompilerContext +{ + ASMJIT_NO_COPY(CompilerContext) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_API CompilerContext(Compiler* compiler); + ASMJIT_API virtual ~CompilerContext(); + + // -------------------------------------------------------------------------- + // [Accessor] + // -------------------------------------------------------------------------- + + inline Compiler* getCompiler() const + { return _compiler; } + + inline CompilerFuncDecl* getFunc() const + { return _func; } + + inline CompilerItem* getExtraBlock() const + { return _extraBlock; } + + inline void setExtraBlock(CompilerItem* item) + { _extraBlock = item; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief ZoneMemory manager. + ZoneMemory _zoneMemory; + + //! @brief Compiler. + Compiler* _compiler; + //! @brief Function. + CompilerFuncDecl* _func; + + //! @brief Start of the current active scope. + CompilerItem* _start; + //! @brief End of the current active scope. + CompilerItem* _stop; + //! @brief Item that is used to insert some code after the function body. + CompilerItem* _extraBlock; + + //! @brief Current state (used by register allocator). + CompilerState* _state; + //! @brief Link to circular double-linked list containing all active variables + //! of the current state. + CompilerVar* _active; + + //! @brief Current offset, used in prepare() stage. Each item should increment it. + uint32_t _currentOffset; + //! @brief Whether current code is unreachable. + uint32_t _isUnreachable; +}; + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_COMPILERCONTEXT_H diff --git a/desmume/src/utils/AsmJit/core/compilerfunc.cpp b/desmume/src/utils/AsmJit/core/compilerfunc.cpp new file mode 100644 index 000000000..45e9e2847 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/compilerfunc.cpp @@ -0,0 +1,178 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/assembler.h" +#include "../core/compiler.h" +#include "../core/compilerfunc.h" +#include "../core/compileritem.h" +#include "../core/intutil.h" +#include "../core/logger.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::CompilerFuncDecl - Construction / Destruction] +// ============================================================================ + +CompilerFuncDecl::CompilerFuncDecl(Compiler* compiler) : + CompilerItem(compiler, kCompilerItemFuncDecl), + _entryTarget(NULL), + _exitTarget(NULL), + _end(NULL), + _decl(NULL), + _vars(NULL), + _funcHints(0), + _funcFlags(0), + _funcCallStackSize(0) +{ +} + +CompilerFuncDecl::~CompilerFuncDecl() +{ +} + +// ============================================================================ +// [AsmJit::CompilerFuncDecl - Hints] +// ============================================================================ + +void CompilerFuncDecl::setHint(uint32_t hint, uint32_t value) +{ + if (hint > 31) + return; + + if (value) + _funcHints |= IntUtil::maskFromIndex(hint); + else + _funcHints &= ~IntUtil::maskFromIndex(hint); +} + +uint32_t CompilerFuncDecl::getHint(uint32_t hint) const +{ + if (hint > 31) + return 0; + + return (_funcHints & IntUtil::maskFromIndex(hint)) != 0; +} + +// ============================================================================ +// [AsmJit::CompilerFuncEnd - Construction / Destruction] +// ============================================================================ + +CompilerFuncEnd::CompilerFuncEnd(Compiler* compiler, CompilerFuncDecl* func) : + CompilerItem(compiler, kCompilerItemFuncEnd), + _func(func) +{ +} + +CompilerFuncEnd::~CompilerFuncEnd() +{ +} + +// ============================================================================ +// [AsmJit::CompilerFuncEnd - Interface] +// ============================================================================ + +CompilerItem* CompilerFuncEnd::translate(CompilerContext& cc) +{ + _isTranslated = true; + return NULL; +} + +// ============================================================================ +// [AsmJit::CompilerFuncRet - Construction / Destruction] +// ============================================================================ + +CompilerFuncRet::CompilerFuncRet(Compiler* compiler, CompilerFuncDecl* func, const Operand* first, const Operand* second) : + CompilerItem(compiler, kCompilerItemFuncRet), + _func(func) +{ + if (first != NULL) + _ret[0] = *first; + + if (second != NULL) + _ret[1] = *second; +} + +CompilerFuncRet::~CompilerFuncRet() +{ +} + +// ============================================================================ +// [AsmJit::CompilerFuncRet - Misc] +// ============================================================================ + +bool CompilerFuncRet::mustEmitJump() const +{ + // Iterate over next items until we found an item which emits a real instruction. + CompilerItem* item = this->getNext(); + + while (item) + { + switch (item->getType()) + { + // Interesting item. + case kCompilerItemEmbed: + case kCompilerItemInst: + case kCompilerItemFuncCall: + case kCompilerItemFuncRet: + return true; + + // Non-interesting item. + case kCompilerItemComment: + case kCompilerItemMark: + case kCompilerItemAlign: + case kCompilerItemHint: + break; + + case kCompilerItemTarget: + if (static_cast(item)->getLabel().getId() == getFunc()->getExitLabel().getId()) + return false; + break; + + // Invalid items - these items shouldn't be here. We are inside the + // function, after prolog. + case kCompilerItemFuncDecl: + break; + + // We can't go forward from here. + case kCompilerItemFuncEnd: + return false; + } + + item = item->getNext(); + } + + return false; +} + +// ============================================================================ +// [AsmJit::CompilerFuncCall - Construction / Destruction] +// ============================================================================ + +CompilerFuncCall::CompilerFuncCall(Compiler* compiler, CompilerFuncDecl* caller, const Operand* target) : + CompilerItem(compiler, kCompilerItemFuncCall), + _caller(caller), + _decl(NULL), + _args(NULL) +{ + if (target != NULL) + _target = *target; +} + +CompilerFuncCall::~CompilerFuncCall() +{ +} + +} // AsmJit namespace + +// [Api-Begin] +#include "../core/apibegin.h" diff --git a/desmume/src/utils/AsmJit/core/compilerfunc.h b/desmume/src/utils/AsmJit/core/compilerfunc.h new file mode 100644 index 000000000..70677fcce --- /dev/null +++ b/desmume/src/utils/AsmJit/core/compilerfunc.h @@ -0,0 +1,357 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_COMPILERFUNC_H +#define _ASMJIT_CORE_COMPILERFUNC_H + +// [Dependencies - AsmJit] +#include "../core/compiler.h" +#include "../core/compileritem.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::CompilerFuncDecl] +// ============================================================================ + +//! @brief Compiler function declaration item. +//! +//! Functions are base blocks for generating assembler output. Each generated +//! assembler stream needs standard entry and leave sequences thats compatible +//! with the operating system conventions (ABI). +//! +//! Function class can be used to generate function prolog) and epilog sequences +//! that are compatible with the demanded calling convention and to allocate and +//! manage variables that can be allocated/spilled during compilation time. +//! +//! @note To create a function use @c Compiler::newFunc() method, do not +//! create any form of compiler function items using new operator. +//! +//! @sa @ref CompilerState, @ref CompilerVar. +struct CompilerFuncDecl : public CompilerItem +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @c CompilerFuncDecl instance. + //! + //! @note Always use @c AsmJit::Compiler::newFunc() to create @c Function + //! instance. + ASMJIT_API CompilerFuncDecl(Compiler* compiler); + //! @brief Destroy the @c CompilerFuncDecl instance. + ASMJIT_API virtual ~CompilerFuncDecl(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get function entry label. + //! + //! Entry label can be used to call this function from another code that's + //! being generated. + inline const Label& getEntryLabel() const + { return _entryLabel; } + + //! @brief Get function exit label. + //! + //! Use exit label to jump to function epilog. + inline const Label& getExitLabel() const + { return _exitLabel; } + + //! @brief Get function entry target. + inline CompilerTarget* getEntryTarget() const + { return _entryTarget; } + + //! @brief Get function exit target. + inline CompilerTarget* getExitTarget() const + { return _exitTarget; } + + //! @brief Get function end item. + inline CompilerFuncEnd* getEnd() const + { return _end; } + + //! @brief Get function declaration. + inline FuncDecl* getDecl() const + { return _decl; } + + //! @brief Get function arguments as variables. + inline CompilerVar** getVars() const + { return _vars; } + + //! @brief Get function argument at @a index. + inline CompilerVar* getVar(uint32_t index) const + { + ASMJIT_ASSERT(index < _decl->getArgumentsCount()); + return _vars[index]; + } + + //! @brief Get function hints. + inline uint32_t getFuncHints() const + { return _funcHints; } + + //! @brief Get function flags. + inline uint32_t getFuncFlags() const + { return _funcFlags; } + + //! @brief Get whether the _funcFlags has @a flag + inline bool hasFuncFlag(uint32_t flag) const + { return (_funcFlags & flag) != 0; } + + //! @brief Set function @a flag. + inline void setFuncFlag(uint32_t flag) + { _funcFlags |= flag; } + + //! @brief Clear function @a flag. + inline void clearFuncFlag(uint32_t flag) + { _funcFlags &= ~flag; } + + //! @brief Get whether the function is also a caller. + inline bool isCaller() const + { return hasFuncFlag(kFuncFlagIsCaller); } + + //! @brief Get whether the function is finished. + inline bool isFinished() const + { return hasFuncFlag(kFuncFlagIsFinished); } + + //! @brief Get whether the function is naked. + inline bool isNaked() const + { return hasFuncFlag(kFuncFlagIsNaked); } + + //! @brief Get stack size needed to call other functions. + inline int32_t getFuncCallStackSize() const + { return _funcCallStackSize; } + + // -------------------------------------------------------------------------- + // [Hints] + // -------------------------------------------------------------------------- + + //! @brief Set function hint. + ASMJIT_API virtual void setHint(uint32_t hint, uint32_t value); + //! @brief Get function hint. + ASMJIT_API virtual uint32_t getHint(uint32_t hint) const; + + // -------------------------------------------------------------------------- + // [Prototype] + // -------------------------------------------------------------------------- + + virtual void setPrototype( + uint32_t convention, + uint32_t returnType, + const uint32_t* arguments, + uint32_t argumentsCount) = 0; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Function entry label. + Label _entryLabel; + //! @brief Function exit label. + Label _exitLabel; + + //! @brief Function entry target. + CompilerTarget* _entryTarget; + //! @brief Function exit target. + CompilerTarget* _exitTarget; + + //! @brief Function end item. + CompilerFuncEnd* _end; + + //! @brief Function declaration. + FuncDecl* _decl; + //! @brief Function arguments as compiler variables. + CompilerVar** _vars; + + //! @brief Function hints; + uint32_t _funcHints; + //! @brief Function flags. + uint32_t _funcFlags; + + //! @brief Stack size needed to call other functions. + int32_t _funcCallStackSize; +}; + +// ============================================================================ +// [AsmJit::CompilerFuncEnd] +// ============================================================================ + +//! @brief Compiler function end item. +//! +//! This item does nothing; it's only used by @ref Compiler to mark specific +//! location in the code. The @c CompilerFuncEnd is similar to @c CompilerMark, +//! except that it overrides @c translate() to return @c NULL. +struct CompilerFuncEnd : public CompilerItem +{ + ASMJIT_NO_COPY(CompilerFuncEnd) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerMark instance. + ASMJIT_API CompilerFuncEnd(Compiler* compiler, CompilerFuncDecl* func); + //! @brief Destroy the @ref CompilerMark instance. + ASMJIT_API virtual ~CompilerFuncEnd(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get related function. + inline CompilerFuncDecl* getFunc() const + { return _func; } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual CompilerItem* translate(CompilerContext& cc); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Related function. + CompilerFuncDecl* _func; +}; + +// ============================================================================ +// [AsmJit::CompilerFuncRet] +// ============================================================================ + +//! @brief Compiler return from function item. +struct CompilerFuncRet : public CompilerItem +{ + ASMJIT_NO_COPY(CompilerFuncRet) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerFuncRet instance. + ASMJIT_API CompilerFuncRet(Compiler* compiler, CompilerFuncDecl* func, + const Operand* first, const Operand* second); + //! @brief Destroy the @ref CompilerFuncRet instance. + ASMJIT_API virtual ~CompilerFuncRet(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @Brief Get the related function. + inline CompilerFuncDecl* getFunc() const + { return _func; } + + //! @brief Get the first return operand. + inline Operand& getFirst() + { return _ret[0]; } + + //! @overload + inline const Operand& getFirst() const + { return _ret[0]; } + + //! @brief Get the second return operand. + inline Operand& getSecond() + { return _ret[1]; } + + //! @overload + inline const Operand& getSecond() const + { return _ret[1]; } + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + //! @brief Get whether jump to epilog has to be emitted. + ASMJIT_API bool mustEmitJump() const; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Related function. + CompilerFuncDecl* _func; + //! @brief Return operand(s). + Operand _ret[2]; +}; + +// ============================================================================ +// [AsmJit::CompilerFuncCall] +// ============================================================================ + +//! @brief Compiler function call item. +struct CompilerFuncCall : public CompilerItem +{ + ASMJIT_NO_COPY(CompilerFuncCall) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerFuncCall instance. + ASMJIT_API CompilerFuncCall(Compiler* compiler, CompilerFuncDecl* caller, const Operand* target); + //! @brief Destroy the @ref CompilerFuncCall instance. + ASMJIT_API virtual ~CompilerFuncCall(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get caller. + inline CompilerFuncDecl* getCaller() const + { return _caller; } + + //! @brief Get function declaration. + inline FuncDecl* getDecl() const + { return _decl; } + + //! @brief Get target operand. + inline Operand& getTarget() + { return _target; } + + //! @overload + inline const Operand& getTarget() const + { return _target; } + + // -------------------------------------------------------------------------- + // [Prototype] + // -------------------------------------------------------------------------- + + virtual void setPrototype(uint32_t convention, uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount) = 0; + + //! @brief Set function prototype. + inline void setPrototype(uint32_t convention, const FuncPrototype& func) + { setPrototype(convention, func.getReturnType(), func.getArguments(), func.getArgumentsCount()); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Caller (the function which does the call). + CompilerFuncDecl* _caller; + //! @brief Function declaration. + FuncDecl* _decl; + + //! @brief Operand (address of function, register, label, ...). + Operand _target; + //! @brief Return operands. + Operand _ret[2]; + //! @brief Arguments operands. + Operand* _args; +}; + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_COMPILERFUNC_H diff --git a/desmume/src/utils/AsmJit/core/compileritem.cpp b/desmume/src/utils/AsmJit/core/compileritem.cpp new file mode 100644 index 000000000..60d94bc02 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/compileritem.cpp @@ -0,0 +1,299 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/assembler.h" +#include "../core/compiler.h" +#include "../core/compilercontext.h" +#include "../core/compilerfunc.h" +#include "../core/compileritem.h" +#include "../core/intutil.h" +#include "../core/logger.h" + +// [Dependencies - C] +#include + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::CompilerItem - Construction / Destruction] +// ============================================================================ + +CompilerItem::CompilerItem(Compiler* compiler, uint32_t type) : + _compiler(compiler), + _prev(NULL), + _next(NULL), + _comment(NULL), + _type(static_cast(type)), + _isTranslated(false), + _isUnreachable(false), + _reserved(0), + _offset(kInvalidValue) +{ +} + +CompilerItem::~CompilerItem() +{ +} + +// ============================================================================ +// [AsmJit::CompilerItem - Interface] +// ============================================================================ + +void CompilerItem::prepare(CompilerContext& cc) +{ + _offset = cc._currentOffset; +} + +CompilerItem* CompilerItem::translate(CompilerContext& cc) +{ + return translated(); +} + +void CompilerItem::emit(Assembler& a) {} +void CompilerItem::post(Assembler& a) {} + +// ============================================================================ +// [AsmJit::CompilerItem - Misc] +// ============================================================================ + +int CompilerItem::getMaxSize() const +{ + // Default maximum size is -1 which means that it's not known. + return -1; +} + +bool CompilerItem::_tryUnuseVar(CompilerVar* v) +{ + return false; +} + +// ============================================================================ +// [AsmJit::CompilerItem - Comment] +// ============================================================================ + +void CompilerItem::setComment(const char* str) +{ + _comment = _compiler->getZoneMemory().sdup(str); +} + +void CompilerItem::formatComment(const char* fmt, ...) +{ + // The capacity should be large enough. + char buf[128]; + + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap); + va_end(ap); + + // I don't know if vsnprintf can produce non-null terminated string, in case + // it can, we terminate it here. + buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0'; + + setComment(buf); +} + +// ============================================================================ +// [AsmJit::CompilerMark - Construction / Destruction] +// ============================================================================ + +CompilerMark::CompilerMark(Compiler* compiler) : + CompilerItem(compiler, kCompilerItemMark) +{ +} + +CompilerMark::~CompilerMark() +{ +} + +// ============================================================================ +// [AsmJit::CompilerMark - Misc] +// ============================================================================ + +int CompilerMark::getMaxSize() const +{ + return 0; +} + +// ============================================================================ +// [AsmJit::CompilerComment - Construction / Destruction] +// ============================================================================ + +CompilerComment::CompilerComment(Compiler* compiler, const char* str) : + CompilerItem(compiler, kCompilerItemComment) +{ + if (str != NULL) + setComment(str); +} + +CompilerComment::~CompilerComment() +{ +} + +// ============================================================================ +// [AsmJit::CompilerComment - Interface] +// ============================================================================ + +void CompilerComment::emit(Assembler& a) +{ + Logger* logger = a.getLogger(); + if (logger == NULL || !logger->isUsed()) + return; + + logger->logString(logger->getInstructionPrefix()); + logger->logString(getComment()); +} + +// ============================================================================ +// [AsmJit::CompilerComment - Misc] +// ============================================================================ + +int CompilerComment::getMaxSize() const +{ + return 0; +} + +// ============================================================================ +// [AsmJit::CompilerEmbed - Construction / Destruction] +// ============================================================================ + +CompilerEmbed::CompilerEmbed(Compiler* compiler, const void* data, size_t length) : + CompilerItem(compiler, kCompilerItemEmbed) +{ + _length = length; + memcpy(_data, data, length); +} + +CompilerEmbed::~CompilerEmbed() +{ +} + +// ============================================================================ +// [AsmJit::CompilerEmbed - Interface] +// ============================================================================ + +void CompilerEmbed::emit(Assembler& a) +{ + a.embed(_data, _length); +} + +// ============================================================================ +// [AsmJit::CompilerEmbed - Misc] +// ============================================================================ + +int CompilerEmbed::getMaxSize() const +{ + return (int)_length;; +} + +// ============================================================================ +// [AsmJit::CompilerAlign - Construction / Destruction] +// ============================================================================ + +CompilerAlign::CompilerAlign(Compiler* compiler, uint32_t size) : + CompilerItem(compiler, kCompilerItemAlign), _size(size) +{ +} + +CompilerAlign::~CompilerAlign() +{ +} + +// ============================================================================ +// [AsmJit::CompilerAlign - Misc] +// ============================================================================ + +int CompilerAlign::getMaxSize() const +{ + if (_size == 0) + return 0; + else + return static_cast(_size - 1); +} + +// ============================================================================ +// [AsmJit::CompilerHint - Construction / Destruction] +// ============================================================================ + +CompilerHint::CompilerHint(Compiler* compiler, CompilerVar* var, uint32_t hintId, uint32_t hintValue) : + CompilerItem(compiler, kCompilerItemHint), + _var(var), + _hintId(hintId), + _hintValue(hintValue) +{ + ASMJIT_ASSERT(var != NULL); +} + +CompilerHint::~CompilerHint() +{ +} + +// ============================================================================ +// [AsmJit::CompilerTarget - Construction / Destruction] +// ============================================================================ + +CompilerTarget::CompilerTarget(Compiler* compiler, const Label& label) : + CompilerItem(compiler, kCompilerItemTarget), + _label(label), + _from(NULL), + _state(NULL), + _jumpsCount(0) +{ +} + +CompilerTarget::~CompilerTarget() +{ +} + +// ============================================================================ +// [AsmJit::CompilerTarget - Misc] +// ============================================================================ + +int CompilerTarget::getMaxSize() const +{ + return 0; +} + +// ============================================================================ +// [AsmJit::CompilerInst - Construction / Destruction] +// ============================================================================ + +CompilerInst::CompilerInst(Compiler* compiler, uint32_t code, Operand* opData, uint32_t opCount) : + CompilerItem(compiler, kCompilerItemInst), + _code(code), + _emitOptions(static_cast(compiler->_emitOptions)), + _instFlags(0), + _operandsCount(static_cast(opCount)), + _variablesCount(0), + _operands(opData) +{ + // Each created instruction takes emit options and clears it. + compiler->_emitOptions = 0; +} + +CompilerInst::~CompilerInst() +{ +} + +// ============================================================================ +// [AsmJit::CompilerInst - GetJumpTarget] +// ============================================================================ + +CompilerTarget* CompilerInst::getJumpTarget() const +{ + return NULL; +} + +} // AsmJit namespace + +// [Api-Begin] +#include "../core/apibegin.h" diff --git a/desmume/src/utils/AsmJit/core/compileritem.h b/desmume/src/utils/AsmJit/core/compileritem.h new file mode 100644 index 000000000..c41d26dc8 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/compileritem.h @@ -0,0 +1,546 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_COMPILERITEM_H +#define _ASMJIT_CORE_COMPILERITEM_H + +// [Dependencies - AsmJit] +#include "../core/compiler.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::CompilerItem] +// ============================================================================ + +//! @brief Compiler item. +//! +//! @ref CompilerItem represents items generated by compiler by calling its +//! methods to build functions, instruction stream, bind labels, etc... Each +//! item contains its type information and virtual methods which are called at +//! various compilation steps. +struct CompilerItem +{ + ASMJIT_NO_COPY(CompilerItem) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create new @ref CompilerItem. + //! + //! @note Always use @ref Compiler to create an item! + ASMJIT_API CompilerItem(Compiler* compiler, uint32_t type); + + //! @brief Destroy @ref CompilerItem. + //! + //! @note @ref Compiler keeps links into all items so it can destroy them + //! when code generation finished or in the case that @ref Compiler was + //! destroyed early (for example if an error happened). Never destroy items + //! manually! + ASMJIT_API virtual ~CompilerItem(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get associated compiler instance. + inline Compiler* getCompiler() const + { return _compiler; } + + //! @brief Get previous item in the compiler stream. + inline CompilerItem* getPrev() const + { return _prev; } + + //! @brief Get next item in the compiler stream. + inline CompilerItem* getNext() const + { return _next; } + + //! @brief Get comment string. + inline const char* getComment() const + { return _comment; } + + //! @brief Get type of item, see @ref kCompilerItem. + inline uint32_t getType() const + { return _type; } + + //! @brief Get whether the item was translated. + inline bool isTranslated() const + { return _isTranslated; } + + //! @brief Get whether the item is unreachable. + inline bool isUnreachable() const + { return _isUnreachable; } + + //! @brief Get the item offset in the compiler stream. + //! + //! The offset is not byte offset, each item increments offset by 1 and this + //! value is then used by register allocator. The offset is set by compiler + //! by the register allocator, don't use it in your code. + inline uint32_t getOffset() const + { return _offset; } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + //! @brief Step 1. Extract item variables, update statistics, ... + ASMJIT_API virtual void prepare(CompilerContext& cc); + //! @brief Step 2. Translate instruction, alloc variables, ... + ASMJIT_API virtual CompilerItem* translate(CompilerContext& cc); + //! @brief Step 3. Emit to @c Assembler. + ASMJIT_API virtual void emit(Assembler& a); + //! @brief Step 4. Last post step (verify, add data, etc). + ASMJIT_API virtual void post(Assembler& a); + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + //! @brief Get maximum size of of this when serialized into @ref Assembler + //! item in bytes. + ASMJIT_API virtual int getMaxSize() const; + + //! @brief Try to unuse the variable @a. + //! + //! Returns @c true only if the variable will be unused by the instruction, + //! otherwise @c false is returned. + ASMJIT_API virtual bool _tryUnuseVar(CompilerVar* v); + + // -------------------------------------------------------------------------- + // [Comment] + // -------------------------------------------------------------------------- + + //! @brief Set comment string to @a str. + ASMJIT_API void setComment(const char* str); + + //! @brief Format comment string using @a fmt string and variable argument list. + ASMJIT_API void formatComment(const char* fmt, ...); + + // -------------------------------------------------------------------------- + // [Protected] + // -------------------------------------------------------------------------- + +protected: + //! @brief Mark item as translated and return next. + inline CompilerItem* translated() + { + ASMJIT_ASSERT(_isTranslated == false); + + _isTranslated = true; + return _next; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +public: + //! @brief Compiler which owns this item. + Compiler* _compiler; + //! @brief Previous item. + CompilerItem* _prev; + //! @brief Next item. + CompilerItem* _next; + //! @brief Inline comment string, initially set to NULL. + const char* _comment; + + //! @brief Type of the item, see @ref kCompilerItem. + uint32_t _type : 8; + //! @brief Whether the item was translated, see @c translate(). + uint32_t _isTranslated : 1; + //! @brief Whether the item is unreachable. + uint32_t _isUnreachable : 1; + //! @brief Reserved for future use. + uint32_t _reserved : 22; + + //! @brief Stream offset (not byte-offset). + uint32_t _offset; +}; + +// ============================================================================ +// [AsmJit::CompilerMark] +// ============================================================================ + +//! @brief Compiler mark item. +//! +//! This item does nothing and it's only used by @ref Compiler to mark some +//! specific location in the compiler stream. +struct CompilerMark : public CompilerItem +{ + ASMJIT_NO_COPY(CompilerMark) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerMark instance. + ASMJIT_API CompilerMark(Compiler* compiler); + //! @brief Destroy the @ref CompilerMark instance. + ASMJIT_API virtual ~CompilerMark(); + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual int getMaxSize() const; +}; + +// ============================================================================ +// [AsmJit::CompilerComment] +// ============================================================================ + +//! @brief Compiler comment item. +//! +//! Comments allows to comment your assembler stream for better debugging +//! and visualization. Comments are usually ignored in release builds unless +//! the logger is present. +struct CompilerComment : public CompilerItem +{ + ASMJIT_NO_COPY(CompilerComment) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerComment instance. + ASMJIT_API CompilerComment(Compiler* compiler, const char* comment = NULL); + //! @brief Destroy the @ref CompilerComment instance. + ASMJIT_API virtual ~CompilerComment(); + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void emit(Assembler& a); + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual int getMaxSize() const; +}; + +// ============================================================================ +// [AsmJit::CompilerEmbed] +// ============================================================================ + +//! @brief Compiler embed item. +//! +//! Embed item is used to embed data into final assembler stream. The data is +//! considered to be RAW, there is no analysis. +struct CompilerEmbed : public CompilerItem +{ + ASMJIT_NO_COPY(CompilerEmbed) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerEmbed instance. + ASMJIT_API CompilerEmbed(Compiler* compiler, const void* data, size_t length); + //! @brief Destroy the @ref CompilerEmbed instance. + ASMJIT_API virtual ~CompilerEmbed(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get pointer to embedded data. + uint8_t* getData() const + { return const_cast(_data); } + + //! @brief Get length of embedded data. + size_t getLength() const + { return _length; } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void emit(Assembler& a); + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual int getMaxSize() const; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Data length. + size_t _length; + //! @brief Data buffer (that will be embedded to the assembler stream). + uint8_t _data[sizeof(void*)]; +}; + +// ============================================================================ +// [AsmJit::CompilerAlign] +// ============================================================================ + +//! @brief Compiler align item. +struct CompilerAlign : public CompilerItem +{ + ASMJIT_NO_COPY(CompilerAlign) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerAlign instance. + ASMJIT_API CompilerAlign(Compiler* compiler, uint32_t size = 0); + //! @brief Destroy the @ref CompilerAlign instance. + ASMJIT_API virtual ~CompilerAlign(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get align size in bytes. + inline uint32_t getSize() const + { return _size; } + + //! @brief Set align size in bytes to @a size. + inline void setSize(uint32_t size) + { _size = size; } + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual int getMaxSize() const; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Align size. + uint32_t _size; +}; + +// ============================================================================ +// [AsmJit::CompilerHint] +// ============================================================================ + +//! @brief Compiler variable hint item. +struct CompilerHint : public CompilerItem +{ + ASMJIT_NO_COPY(CompilerHint) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerHint instance. + ASMJIT_API CompilerHint(Compiler* compiler, CompilerVar* var, uint32_t hintId, uint32_t hintValue); + //! @brief Destroy the @ref CompilerHint instance. + ASMJIT_API virtual ~CompilerHint(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get variable. + inline CompilerVar* getVar() const + { return _var; } + + //! @brief Get hint it (see @ref kVarHint). + inline uint32_t getHintId() const + { return _hintId; } + + //! @brief Set hint it (see @ref kVarHint). + inline void setHintId(uint32_t hintId) + { _hintId = hintId; } + + //! @brief Get hint value. + inline uint32_t getHintValue() const + { return _hintValue; } + + //! @brief Set hint value. + inline void setHintValue(uint32_t hintValue) + { _hintValue = hintValue; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Variable. + CompilerVar* _var; + //! @brief Variable hint id. + uint32_t _hintId; + //! @brief Variable hint value. + uint32_t _hintValue; +}; + +// ============================================================================ +// [AsmJit::CompilerTarget] +// ============================================================================ + +//! @brief Compiler target item. +struct CompilerTarget : public CompilerItem +{ + ASMJIT_NO_COPY(CompilerTarget) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerTarget instance. + ASMJIT_API CompilerTarget(Compiler* compiler, const Label& target); + //! @brief Destroy the @ref CompilerTarget instance. + ASMJIT_API virtual ~CompilerTarget(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Return label bound to this target. + inline const Label& getLabel() const + { return _label; } + + //! @brief Get first jmp instruction. + inline CompilerInst* getFrom() const + { return _from; } + + //! @brief Get register allocator state for this target. + inline CompilerState* getState() const + { return _state; } + + //! @brief Get number of jumps to this target. + inline uint32_t getJumpsCount() const + { return _jumpsCount; } + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual int getMaxSize() const; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Label. + Label _label; + //! @brief First jump instruction that points to this target (label). + CompilerInst* _from; + //! @brief State at this location. + CompilerState* _state; + //! @brief Count of jumps here. + uint32_t _jumpsCount; +}; + +// ============================================================================ +// [AsmJit::CompilerInst] +// ============================================================================ + +//! @brief Compiler instruction item. +struct CompilerInst : public CompilerItem +{ + ASMJIT_NO_COPY(CompilerInst) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerInst instance. + ASMJIT_API CompilerInst(Compiler* compiler, uint32_t code, Operand* opData, uint32_t opCount); + //! @brief Destroy the @ref CompilerInst instance. + ASMJIT_API virtual ~CompilerInst(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get instruction code, see @c kInstCode. + inline uint32_t getCode() const + { return _code; } + + //! @brief Set instruction code to @a code. + //! + //! Please do not modify instruction code if you are not know what you are + //! doing. Incorrect instruction code or operands can raise assertion() at + //! runtime. + inline void setCode(uint32_t code) + { _code = code; } + + //! @brief Get emit options (compiler specific). + inline uint32_t getEmitOptions() const + { return _emitOptions; } + + //! @brief Get instruction flags (compiler specific). + inline uint32_t getInstFlags() const + { return _instFlags; } + + //! @brief Get whether the instruction has flag @a flag. + inline bool hasInstFlag(uint8_t flag) const + { return (_instFlags & flag) != 0; } + + //! @brief Set instruction @a flag. + inline void setInstFlag(uint8_t flag) + { _instFlags |= flag; } + + //! @brief Clear instruction @a flag. + inline void clearInstFlag(uint8_t flag) + { _instFlags &= ~flag; } + + //! @brief Get count of operands in operands array. + inline uint32_t getOperandsCount() const + { return _operandsCount; } + + //! @brief Get count of variables in variables array. + inline uint32_t getVariablesCount() const + { return _variablesCount; } + + //! @brief Get operands array (3 operands total). + inline Operand* getOperands() { return _operands; } + //! @brief Get operands array (3 operands total). + inline const Operand* getOperands() const { return _operands; } + + // -------------------------------------------------------------------------- + // [GetJumpTarget] + // -------------------------------------------------------------------------- + + //! @brief Get possible jump target. + //! + //! If this instruction is conditional or normal jump then return value is + //! the label location (@ref CompilerTarget), otherwise the return value is + //! @c NULL. + ASMJIT_API virtual CompilerTarget* getJumpTarget() const; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Instruction code, see @c kInstCode. + uint32_t _code; + + //! @brief Emit options. + uint8_t _emitOptions; + //! @brief Instruction flags. + uint8_t _instFlags; + //! @brief Operands count. + uint8_t _operandsCount; + //! @brief Variables count. + uint8_t _variablesCount; + + //! @brief Operands. + Operand* _operands; +}; + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_COMPILERITEM_H diff --git a/desmume/src/utils/AsmJit/CodeGenerator.cpp b/desmume/src/utils/AsmJit/core/context.cpp similarity index 63% rename from desmume/src/utils/AsmJit/CodeGenerator.cpp rename to desmume/src/utils/AsmJit/core/context.cpp index 8d2ef7e18..df141b19c 100644 --- a/desmume/src/utils/AsmJit/CodeGenerator.cpp +++ b/desmume/src/utils/AsmJit/core/context.cpp @@ -4,99 +4,90 @@ // [License] // Zlib - See COPYING file in this package. -// [Dependencies] -#include "Assembler.h" -#include "CodeGenerator.h" -#include "Defs.h" -#include "MemoryManager.h" -#include "MemoryMarker.h" +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/assembler.h" +#include "../core/context.h" +#include "../core/defs.h" +#include "../core/memorymanager.h" +#include "../core/memorymarker.h" namespace AsmJit { // ============================================================================ -// [AsmJit::CodeGenerator - Construction / Destruction] +// [AsmJit::Context - Construction / Destruction] // ============================================================================ -CodeGenerator::CodeGenerator() -{ -} - -CodeGenerator::~CodeGenerator() -{ -} +Context::Context() {} +Context::~Context() {} // ============================================================================ -// [AsmJit::CodeGenerator - GetGlobal] +// [AsmJit::JitContext - Construction / Destruction] // ============================================================================ -JitCodeGenerator* CodeGenerator::getGlobal() -{ - static JitCodeGenerator global; - return &global; -} - -// ============================================================================ -// [AsmJit::JitCodeGenerator - Construction / Destruction] -// ============================================================================ - -JitCodeGenerator::JitCodeGenerator() : +JitContext::JitContext() : _memoryManager(NULL), _memoryMarker(NULL), - _allocType(MEMORY_ALLOC_FREEABLE) + _allocType(kMemAllocFreeable) { } -JitCodeGenerator::~JitCodeGenerator() +JitContext::~JitContext() { } // ============================================================================ -// [AsmJit::JitCodeGenerator - Generate] +// [AsmJit::JitContext - Generate] // ============================================================================ -uint32_t JitCodeGenerator::generate(void** dest, Assembler* assembler) +uint32_t JitContext::generate(void** dest, Assembler* assembler) { // Disallow empty code generation. - sysuint_t codeSize = assembler->getCodeSize(); + size_t codeSize = assembler->getCodeSize(); if (codeSize == 0) { *dest = NULL; - return AsmJit::ERROR_NO_FUNCTION; + return kErrorNoFunction; } // Switch to global memory manager if not provided. MemoryManager* memmgr = getMemoryManager(); if (memmgr == NULL) - { memmgr = MemoryManager::getGlobal(); - } void* p = memmgr->alloc(codeSize, getAllocType()); if (p == NULL) { *dest = NULL; - return ERROR_NO_VIRTUAL_MEMORY; + return kErrorNoVirtualMemory; } // Relocate the code. - sysuint_t relocatedSize = assembler->relocCode(p); + size_t relocatedSize = assembler->relocCode(p); // Return unused memory to MemoryManager. if (relocatedSize < codeSize) - { memmgr->shrink(p, relocatedSize); - } // Mark memory if MemoryMarker provided. if (_memoryMarker) - { _memoryMarker->mark(p, relocatedSize); - } // Return the code. *dest = p; - return ERROR_NONE; + return kErrorOk; +} + +// ============================================================================ +// [AsmJit::JitContext - GetGlobal] +// ============================================================================ + +JitContext* JitContext::getGlobal() +{ + static JitContext global; + return &global; } } // AsmJit namespace diff --git a/desmume/src/utils/AsmJit/CodeGenerator.h b/desmume/src/utils/AsmJit/core/context.h similarity index 71% rename from desmume/src/utils/AsmJit/CodeGenerator.h rename to desmume/src/utils/AsmJit/core/context.h index fa6a93f7b..d14fb6a1f 100644 --- a/desmume/src/utils/AsmJit/CodeGenerator.h +++ b/desmume/src/utils/AsmJit/core/context.h @@ -5,11 +5,11 @@ // Zlib - See COPYING file in this package. // [Guard] -#ifndef _ASMJIT_CODEGENERATOR_H -#define _ASMJIT_CODEGENERATOR_H +#ifndef _ASMJIT_CORE_CONTEXT_H +#define _ASMJIT_CORE_CONTEXT_H -// [Dependencies] -#include "Build.h" +// [Dependencies - AsmJit] +#include "../core/build.h" namespace AsmJit { @@ -18,26 +18,27 @@ namespace AsmJit { // ============================================================================ struct Assembler; -struct JitCodeGenerator; struct MemoryManager; struct MemoryMarker; // ============================================================================ -// [AsmJit::CodeGenerator] +// [AsmJit::Context] // ============================================================================ -//! @brief Code generator is core class for changing behavior of code generated -//! by @c Assembler or @c Compiler. -struct ASMJIT_API CodeGenerator +//! @brief Class for changing behavior of code generated by @ref Assembler and +//! @ref Compiler. +struct Context { + ASMJIT_NO_COPY(Context) + // -------------------------------------------------------------------------- // [Construction / Destruction] // -------------------------------------------------------------------------- - //! @brief Create a @c CodeGenerator instance. - CodeGenerator(); - //! @brief Destroy the @c CodeGenerator instance. - virtual ~CodeGenerator(); + //! @brief Create a @c Context instance. + ASMJIT_API Context(); + //! @brief Destroy the @c Context instance. + ASMJIT_API virtual ~Context(); // -------------------------------------------------------------------------- // [Interface] @@ -55,33 +56,26 @@ struct ASMJIT_API CodeGenerator //! it to allocate memory for JIT code, saving code to remote process or a //! shared library. //! - //! @retrurn Error value, see @c ERROR_CODE. + //! @retrurn Error value, see @c kError. virtual uint32_t generate(void** dest, Assembler* assembler) = 0; - - // -------------------------------------------------------------------------- - // [Statics] - // -------------------------------------------------------------------------- - - static JitCodeGenerator* getGlobal(); - -private: - ASMJIT_DISABLE_COPY(CodeGenerator) }; // ============================================================================ -// [AsmJit::JitCodeGenerator] +// [AsmJit::JitContext] // ============================================================================ -struct JitCodeGenerator : public CodeGenerator +struct JitContext : public Context { + ASMJIT_NO_COPY(JitContext) + // -------------------------------------------------------------------------- // [Construction / Destruction] // -------------------------------------------------------------------------- - //! @brief Create a @c JitCodeGenerator instance. - JitCodeGenerator(); - //! @brief Destroy the @c JitCodeGenerator instance. - virtual ~JitCodeGenerator(); + //! @brief Create a @c JitContext instance. + ASMJIT_API JitContext(); + //! @brief Destroy the @c JitContext instance. + ASMJIT_API virtual ~JitContext(); // -------------------------------------------------------------------------- // [Memory Manager and Alloc Type] @@ -93,35 +87,49 @@ struct JitCodeGenerator : public CodeGenerator // members accessed by these accessors. //! @brief Get the @c MemoryManager instance. - inline MemoryManager* getMemoryManager() const { return _memoryManager; } + inline MemoryManager* getMemoryManager() const + { return _memoryManager; } + //! @brief Set the @c MemoryManager instance. - inline void setMemoryManager(MemoryManager* memoryManager) { _memoryManager = memoryManager; } + inline void setMemoryManager(MemoryManager* memoryManager) + { _memoryManager = memoryManager; } //! @brief Get the type of allocation. - inline uint32_t getAllocType() const { return _allocType; } + inline uint32_t getAllocType() const + { return _allocType; } + //! @brief Set the type of allocation. - inline void setAllocType(uint32_t allocType) { _allocType = allocType; } + inline void setAllocType(uint32_t allocType) + { _allocType = allocType; } // -------------------------------------------------------------------------- // [Memory Marker] // -------------------------------------------------------------------------- //! @brief Get the @c MemoryMarker instance. - inline MemoryMarker* getMemoryMarker() const { return _memoryMarker; } + inline MemoryMarker* getMemoryMarker() const + { return _memoryMarker; } + //! @brief Set the @c MemoryMarker instance. - inline void setMemoryMarker(MemoryMarker* memoryMarker) { _memoryMarker = memoryMarker; } + inline void setMemoryMarker(MemoryMarker* memoryMarker) + { _memoryMarker = memoryMarker; } // -------------------------------------------------------------------------- // [Interface] // -------------------------------------------------------------------------- - virtual uint32_t generate(void** dest, Assembler* assembler); + ASMJIT_API virtual uint32_t generate(void** dest, Assembler* assembler); + + // -------------------------------------------------------------------------- + // [Statics] + // -------------------------------------------------------------------------- + + ASMJIT_API static JitContext* getGlobal(); // -------------------------------------------------------------------------- // [Members] // -------------------------------------------------------------------------- -protected: //! @brief Memory manager. MemoryManager* _memoryManager; //! @brief Memory marker. @@ -129,12 +137,9 @@ protected: //! @brief Type of allocation. uint32_t _allocType; - -private: - ASMJIT_DISABLE_COPY(JitCodeGenerator) }; } // AsmJit namespace // [Guard] -#endif // _ASMJIT_CODEGENERATOR_H +#endif // _ASMJIT_CORE_CONTEXT_H diff --git a/desmume/src/utils/AsmJit/core/cpuinfo.cpp b/desmume/src/utils/AsmJit/core/cpuinfo.cpp new file mode 100644 index 000000000..63c2d57eb --- /dev/null +++ b/desmume/src/utils/AsmJit/core/cpuinfo.cpp @@ -0,0 +1,88 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/cpuinfo.h" + +#if defined(ASMJIT_X86) || defined(ASMJIT_X64) +#include "../x86/x86cpuinfo.h" +#else +// ? +#endif // ASMJIT_X86 || ASMJIT_X64 + +// [Dependencies - Windows] +#if defined(ASMJIT_WINDOWS) +# include +#endif // ASMJIT_WINDOWS + +// [Dependencies - Posix] +#if defined(ASMJIT_POSIX) +# include +# include +# include +# include +#endif // ASMJIT_POSIX + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::CpuInfo - DetectNumberOfProcessors] +// ============================================================================ + +uint32_t CpuInfo::detectNumberOfProcessors() +{ +#if defined(ASMJIT_WINDOWS) + SYSTEM_INFO info; + ::GetSystemInfo(&info); + return info.dwNumberOfProcessors; +#elif defined(ASMJIT_POSIX) && defined(_SC_NPROCESSORS_ONLN) + // It seems that sysconf returns the number of "logical" processors on both + // mac and linux. So we get the number of "online logical" processors. + long res = ::sysconf(_SC_NPROCESSORS_ONLN); + if (res == -1) return 1; + + return static_cast(res); +#else + return 1; +#endif +} + +// ============================================================================ +// [AsmJit::CpuInfo - GetGlobal] +// ============================================================================ + +#if defined(ASMJIT_X86) || defined(ASMJIT_X64) +struct InitializedCpuInfo : public X86CpuInfo +{ + inline InitializedCpuInfo() : + X86CpuInfo() + { + x86CpuDetect(this); + } +}; +#else +#error "AsmJit::CpuInfo - Unsupported CPU or compiler." +#endif // ASMJIT_X86 || ASMJIT_X64 + +const CpuInfo* CpuInfo::getGlobal() +{ +#if defined(ASMJIT_X86) || defined(ASMJIT_X64) + static InitializedCpuInfo cpuInfo; +#else +#error "AsmJit::CpuInfo - Unsupported CPU or compiler." +#endif // ASMJIT_X86 || ASMJIT_X64 + return &cpuInfo; +} + +} // AsmJit + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/cpuinfo.h b/desmume/src/utils/AsmJit/core/cpuinfo.h new file mode 100644 index 000000000..02037fa77 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/cpuinfo.h @@ -0,0 +1,113 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_CPUINFO_H +#define _ASMJIT_CORE_CPUINFO_H + +// [Dependencies - AsmJit] +#include "../core/build.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::CpuInfo] +// ============================================================================ + +//! @brief Informations about host cpu. +struct CpuInfo +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + inline CpuInfo(uint32_t size = sizeof(CpuInfo)) : + _size(size) + { + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get CPU vendor string. + inline const char* getVendorString() const { return _vendorString; } + //! @brief Get CPU brand string. + inline const char* getBrandString() const { return _brandString; } + + //! @brief Get CPU vendor ID. + inline uint32_t getVendorId() const { return _vendorId; } + //! @brief Get CPU family ID. + inline uint32_t getFamily() const { return _family; } + //! @brief Get CPU model ID. + inline uint32_t getModel() const { return _model; } + //! @brief Get CPU stepping. + inline uint32_t getStepping() const { return _stepping; } + //! @brief Get CPU count. + inline uint32_t getNumberOfProcessors() const { return _numberOfProcessors; } + //! @brief Get CPU features. + inline uint32_t getFeatures() const { return _features; } + //! @brief Get CPU bugs. + inline uint32_t getBugs() const { return _bugs; } + + //! @brief Get whether CPU has feature @a feature. + inline bool hasFeature(uint32_t feature) { return (_features & feature) != 0; } + //! @brief Get whether CPU has bug @a bug. + inline bool hasBug(uint32_t bug) { return (_bugs & bug) != 0; } + + // -------------------------------------------------------------------------- + // [Statics] + // -------------------------------------------------------------------------- + + //! @brief Detect number of processors. + ASMJIT_API static uint32_t detectNumberOfProcessors(); + + //! @brief Get global instance of @ref CpuInfo. + ASMJIT_API static const CpuInfo* getGlobal(); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Size of CpuInfo structure (in bytes). + uint32_t _size; + + //! @brief Cpu short vendor string. + char _vendorString[16]; + //! @brief Cpu long vendor string (brand). + char _brandString[64]; + + //! @brief Cpu vendor id (see @c AsmJit::CpuInfo::VendorId enum). + uint32_t _vendorId; + //! @brief Cpu family ID. + uint32_t _family; + //! @brief Cpu model ID. + uint32_t _model; + //! @brief Cpu stepping. + uint32_t _stepping; + //! @brief Number of processors or cores. + uint32_t _numberOfProcessors; + //! @brief Cpu features bitfield, see @c AsmJit::CpuInfo::Feature enum). + uint32_t _features; + //! @brief Cpu bugs bitfield, see @c AsmJit::CpuInfo::Bug enum). + uint32_t _bugs; +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_CPUINFO_H diff --git a/desmume/src/utils/AsmJit/Defs.cpp b/desmume/src/utils/AsmJit/core/defs.cpp similarity index 62% rename from desmume/src/utils/AsmJit/Defs.cpp rename to desmume/src/utils/AsmJit/core/defs.cpp index 7dae17f40..de6e3e573 100644 --- a/desmume/src/utils/AsmJit/Defs.cpp +++ b/desmume/src/utils/AsmJit/core/defs.cpp @@ -4,15 +4,21 @@ // [License] // Zlib - See COPYING file in this package. -// [Dependencies] -#include "Defs.h" +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/defs.h" // [Api-Begin] -#include "ApiBegin.h" +#include "../core/apibegin.h" namespace AsmJit { -const char* getErrorString(uint32_t error) ASMJIT_NOTHROW +// ============================================================================ +// [AsmJit::getErrorString] +// ============================================================================ + +const char* getErrorString(uint32_t error) { static const char* errorMessage[] = { "No error", @@ -38,7 +44,8 @@ const char* getErrorString(uint32_t error) ASMJIT_NOTHROW }; // Saturate error code to be able to use errorMessage[]. - if (error > _ERROR_COUNT) error = _ERROR_COUNT; + if (error > kErrorCount) + error = kErrorCount; return errorMessage[error]; } @@ -46,4 +53,4 @@ const char* getErrorString(uint32_t error) ASMJIT_NOTHROW } // AsmJit // [Api-End] -#include "ApiEnd.h" +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/defs.h b/desmume/src/utils/AsmJit/core/defs.h new file mode 100644 index 000000000..d02716224 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/defs.h @@ -0,0 +1,598 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_DEFS_H +#define _ASMJIT_CORE_DEFS_H + +// [Dependencies - AsmJit] +#include "../core/build.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::Global] +// ============================================================================ + +enum +{ + //! @brief Invalid operand identifier. + kInvalidValue = 0xFFFFFFFFU, + //! @brief Minimum reserved bytes in @ref Buffer. + kBufferGrow = 32U +}; + +static const size_t kInvalidSize = (size_t)-1; + +// ============================================================================ +// [AsmJit::kStringBuilderOpType] +// ============================================================================ + +//! @brief String builder operation. +enum kStringBuilderOpType +{ + //! @brief Replace the current content by a given content. + kStringBuilderOpSet = 0, + //! @brief Append a given content to the current content. + kStringBuilderOpAppend = 1 +}; + +// ============================================================================ +// [AsmJit::kStringBuilderNumType] +// ============================================================================ + +enum kStringBuilderNumFlags +{ + kStringBuilderNumShowSign = (1U << 0), + kStringBuilderNumShowSpace = (1U << 1), + kStringBuilderNumAlternate = (1U << 2), + kStringBuilderNumSigned = (1U << 31) +}; + +// ============================================================================ +// [AsmJit::kLoggerOption] +// ============================================================================ + +enum kLoggerFlag +{ + //! @brief Whether logger is enabled or disabled. + //! + //! Default @c true. + kLoggerIsEnabled = 0x00000001, + + //! @brief Whether logger is enabled and can be used. + //! + //! This value can be set by inherited classes to inform @c Logger that + //! assigned stream (or something that can log output) is invalid. If + //! @c _used is false it means that there is no logging output and AsmJit + //! shouldn't use this logger (because all messages will be lost). + //! + //! This is designed only to optimize cases that logger exists, but its + //! configured not to output messages. The API inside Logging and AsmJit + //! should only check this value when needed. The API outside AsmJit should + //! check only whether logging is @c _enabled. + //! + //! Default @c true. + kLoggerIsUsed = 0x00000002, + + //! @brief Whether to output instructions also in binary form. + kLoggerOutputBinary = 0x00000010, + //! @brief Whether to output immediates as hexadecimal numbers. + kLoggerOutputHexImmediate = 0x00000020, + //! @brief Whether to output displacements as hexadecimal numbers. + kLoggerOutputHexDisplacement = 0x00000040 +}; + +// ============================================================================ +// [AsmJit::kCpu] +// ============================================================================ + +//! @brief Cpu vendor IDs. +//! +//! Cpu vendor IDs are specific for AsmJit library. Vendor ID is not directly +//! read from cpuid result, instead it's based on CPU vendor string. +enum kCpu +{ + //! @brief Unknown CPU vendor. + kCpuUnknown = 0, + + //! @brief Intel CPU vendor. + kCpuIntel = 1, + //! @brief AMD CPU vendor. + kCpuAmd = 2, + //! @brief National Semiconductor CPU vendor (applies also to Cyrix processors). + kCpuNSM = 3, + //! @brief Transmeta CPU vendor. + kCpuTransmeta = 4, + //! @brief VIA CPU vendor. + kCpuVia = 5 +}; + +// ============================================================================ +// [AsmJit::kMemAllocType] +// ============================================================================ + +//! @brief Types of allocation used by @c AsmJit::MemoryManager::alloc() method. +enum kMemAllocType +{ + //! @brief Allocate memory that can be freed by @c AsmJit::MemoryManager::free() + //! method. + kMemAllocFreeable = 0, + //! @brief Allocate permanent memory that will be never freed. + kMemAllocPermanent = 1 +}; + +// ============================================================================ +// [AsmJit::kOperandType] +// ============================================================================ + +//! @brief Operand types that can be encoded in @c Op operand. +enum kOperandType +{ + //! @brief Operand is none, used only internally (not initialized Operand). + //! + //! This operand is not valid. + kOperandNone = 0x00, + //! @brief Operand is label. + kOperandLabel = 0x01, + //! @brief Operand is register. + kOperandReg = 0x02, + //! @brief Operand is variable. + kOperandVar = 0x04, + //! @brief Operand is memory. + kOperandMem = 0x08, + //! @brief Operand is immediate. + kOperandImm = 0x10 +}; + +// ============================================================================ +// [AsmJit::kOperandMemType] +// ============================================================================ + +//! @brief Type of memory operand. +enum kOperandMemType +{ + //! @brief Operand is combination of register(s) and displacement (native). + kOperandMemNative = 0, + //! @brief Operand is label. + kOperandMemLabel = 1, + //! @brief Operand is absolute memory location (supported mainly in 32-bit mode) + kOperandMemAbsolute = 2, +}; + +// ============================================================================ +// [AsmJit::kOperandId] +// ============================================================================ + +//! @brief Operand ID masks used to determine the operand type. +enum kOperandId +{ + //! @brief Operand id type mask (part used for operand type). + kOperandIdTypeMask = 0xC0000000, + //! @brief Label operand mark id. + kOperandIdTypeLabel = 0x40000000, + //! @brief Variable operand mark id. + kOperandIdTypeVar = 0x80000000, + + //! @brief Operand id value mask (part used for IDs). + kOperandIdValueMask = 0x3FFFFFFF +}; + +// ============================================================================ +// [AsmJit::kRegType / kRegIndex] +// ============================================================================ + +enum +{ + //! @brief Mask for register type. + kRegTypeMask = 0xFF00, + + //! @brief Mask for register code (index). + kRegIndexMask = 0xFF, + //! @brief Invalid register index. + kRegIndexInvalid = 0xFF +}; + +// ============================================================================ +// [AsmJit::kCondHint] +// ============================================================================ + +//! @brief Condition hint. +enum kCondHint +{ + //! @brief No hint. + kCondHintNone = 0x00, + //! @brief Condition is likely to be taken. + kCondHintLikely = 0x01, + //! @brief Condition is unlikely to be taken. + kCondHintUnlikely = 0x02 +}; + +// ============================================================================ +// [AsmJit::kFuncAnonymous] +// ============================================================================ + +enum +{ + //! @brief Maximum allowed arguments per function declaration / call. + kFuncArgsMax = 32, + //! @brief Invalid stack offset in function or function parameter. + kFuncStackInvalid = -1 +}; + +// ============================================================================ +// [AsmJit::kFuncConv] +// ============================================================================ + +enum kFuncConv +{ + //! @brief Calling convention is invalid (can't be used). + kFuncConvNone = 0 +}; + +// ============================================================================ +// [AsmJit::kFuncHint] +// ============================================================================ + +//! @brief Function hints. +enum kFuncHint +{ + //! @brief Make naked function (without using ebp/erp in prolog / epilog). + kFuncHintNaked = 0 +}; + +// ============================================================================ +// [AsmJit::kFuncFlags] +// ============================================================================ + +//! @brief Function flags. +enum kFuncFlags +{ + //! @brief Whether another function is called from this function. + //! + //! If another function is called from this function, it's needed to prepare + //! stack for it. If this member is true then it's likely that true will be + //! also @c _isEspAdjusted one. + kFuncFlagIsCaller = (1U << 0), + + //! @brief Whether the function is finished using @c Compiler::endFunc(). + kFuncFlagIsFinished = (1U << 1), + + //! @brief Whether the function is using naked (minimal) prolog / epilog. + kFuncFlagIsNaked = (1U << 2) +}; + +// ============================================================================ +// [AsmJit::kFuncArgsDirection] +// ============================================================================ + +//! @brief Function arguments direction. +enum kFuncArgsDirection +{ + //! @brief Arguments are passed left to right. + //! + //! This arguments direction is unusual to C programming, it's used by pascal + //! compilers and in some calling conventions by Borland compiler). + kFuncArgsLTR = 0, + //! @brief Arguments are passed right ro left + //! + //! This is default argument direction in C programming. + kFuncArgsRTL = 1 +}; + +// ============================================================================ +// [AsmJit::kInstCode] +// ============================================================================ + +enum kInstCode +{ + //! @brief No instruction. + kInstNone = 0 +}; + +// ============================================================================ +// [AsmJit::kVarAllocFlags] +// ============================================================================ + +//! @brief Variable alloc mode. +enum kVarAllocFlags +{ + //! @brief Allocating variable to read only. + //! + //! Read only variables are used to optimize variable spilling. If variable + //! is some time ago deallocated and it's not marked as changed (so it was + //! all the life time read only) then spill is simply NOP (no mov instruction + //! is generated to move it to it's home memory location). + kVarAllocRead = 0x01, + //! @brief Allocating variable to write only (overwrite). + //! + //! Overwriting means that if variable is in memory, there is no generated + //! instruction to move variable from memory to register, because that + //! register will be overwritten by next instruction. This is used as a + //! simple optimization to improve generated code by @c Compiler. + kVarAllocWrite = 0x02, + //! @brief Allocating variable to read / write. + //! + //! Variable allocated for read / write is marked as changed. This means that + //! if variable must be later spilled into memory, mov (or similar) + //! instruction will be generated. + kVarAllocReadWrite = 0x03, + + //! @brief Variable can be allocated in register. + kVarAllocRegister = 0x04, + //! @brief Variable can be allocated only to a special register. + kVarAllocSpecial = 0x08, + + //! @brief Variable can be allocated in memory. + kVarAllocMem = 0x10, + + //! @brief Unuse the variable after use. + kVarAllocUnuseAfterUse = 0x20 +}; + +// ============================================================================ +// [AsmJit::kVarHint] +// ============================================================================ + +//! @brief Variable hint (used by @ref Compiler). +//! +//! @sa @ref Compiler. +enum kVarHint +{ + //! @brief Alloc variable. + kVarHintAlloc = 0, + //! @brief Spill variable. + kVarHintSpill = 1, + //! @brief Save variable if modified. + kVarHintSave = 2, + //! @brief Save variable if modified and mark it as unused. + kVarHintSaveAndUnuse = 3, + //! @brief Mark variable as unused. + kVarHintUnuse = 4 +}; + +// ============================================================================ +// [AsmJit::kVarPolicy] +// ============================================================================ + +//! @brief Variable allocation method. +//! +//! Variable allocation method is used by compiler and it means if compiler +//! should first allocate preserved registers or not. Preserved registers are +//! registers that must be saved / restored by generated function. +//! +//! This option is for people who are calling C/C++ functions from JIT code so +//! Compiler can recude generating push/pop sequences before and after call, +//! respectively. +enum kVarPolicy +{ + //! @brief Allocate preserved registers first. + kVarPolicyPreservedFirst = 0, + //! @brief Allocate preserved registers last (default). + kVarPolicyPreservedLast = 1 +}; + +// ============================================================================ +// [AsmJit::kVarState] +// ============================================================================ + +//! @brief State of variable. +//! +//! @note State of variable is used only during make process and it's not +//! visible to the developer. +enum kVarState +{ + //! @brief Variable is currently not used. + kVarStateUnused = 0, + //! @brief Variable is in register. + //! + //! Variable is currently allocated in register. + kVarStateReg = 1, + //! @brief Variable is in memory location or spilled. + //! + //! Variable was spilled from register to memory or variable is used for + //! memory only storage. + kVarStateMem = 2 +}; + +// ============================================================================ +// [AsmJit::kVarType] +// ============================================================================ + +enum kVarType +{ + //! @brief Invalid variable type. + kVarTypeInvalid = 0xFF +}; + +// ============================================================================ +// [AsmJit::kScale] +// ============================================================================ + +//! @brief Scale which can be used for addressing (it the target instruction +//! supports it). +//! +//! See @c Op and addressing methods like @c byte_ptr(), @c word_ptr(), +//! @c dword_ptr(), etc... +enum kScale +{ + //! @brief No scale. + kScaleNone = 0, + //! @brief Scale 2 times (same as shifting to left by 1). + kScale2Times = 1, + //! @brief Scale 4 times (same as shifting to left by 2). + kScale4Times = 2, + //! @brief Scale 8 times (same as shifting to left by 3). + kScale8Times = 3 +}; + +// ============================================================================ +// [AsmJit::kSize] +// ============================================================================ + +//! @brief Size of registers and pointers. +enum kSize +{ + //! @brief 1 byte size. + kSizeByte = 1, + //! @brief 2 bytes size. + kSizeWord = 2, + //! @brief 4 bytes size. + kSizeDWord = 4, + //! @brief 8 bytes size. + kSizeQWord = 8, + //! @brief 10 bytes size. + kSizeTWord = 10, + //! @brief 16 bytes size. + kSizeDQWord = 16 +}; + +// ============================================================================ +// [AsmJit::kRelocMode] +// ============================================================================ + +enum kRelocMode +{ + kRelocAbsToAbs = 0, + kRelocRelToAbs = 1, + kRelocAbsToRel = 2, + kRelocTrampoline = 3 +}; + +// ============================================================================ +// [AsmJit::kCompilerItem] +// ============================================================================ + +//! @brief Type of @ref CompilerItem. +//! +//! Each @c CompilerItem contains information about its type. Compiler can +//! optimize instruction stream by analyzing items and each type is hint +//! for it. The most used/serialized items are instructions +//! (@c kCompilerItemInst). +enum kCompilerItem +{ + //! @brief Invalid item (can't be used). + kCompilerItemNone = 0, + //! @brief Item is mark, see @ref CompilerMark. + kCompilerItemMark, + //! @brief Item is comment, see @ref CompilerComment. + kCompilerItemComment, + //! @brief Item is embedded data, see @ref CompilerEmbed. + kCompilerItemEmbed, + //! @brief Item is .align directive, see @ref CompilerAlign. + kCompilerItemAlign, + //! @brief Item is variable hint (alloc, spill, use, unuse), see @ref CompilerHint. + kCompilerItemHint, + //! @brief Item is instruction, see @ref CompilerInst. + kCompilerItemInst, + //! @brief Item is target, see @ref CompilerTarget. + kCompilerItemTarget, + //! @brief Item is function call, see @ref CompilerFuncCall. + kCompilerItemFuncCall, + //! @brief Item is function declaration, see @ref CompilerFuncDecl. + kCompilerItemFuncDecl, + //! @brief Item is an end of the function, see @ref CompilerFuncEnd. + kCompilerItemFuncEnd, + //! @brief Item is function return, see @ref CompilerFuncRet. + kCompilerItemFuncRet +}; + +// ============================================================================ +// [AsmJit::kError] +// ============================================================================ + +//! @brief Error codes. +enum kError +{ + //! @brief No error (success). + //! + //! This is default state and state you want. + kErrorOk = 0, + + //! @brief Memory allocation error (@c ASMJIT_MALLOC returned @c NULL). + kErrorNoHeapMemory = 1, + //! @brief Virtual memory allocation error (@c VirtualMemory returned @c NULL). + kErrorNoVirtualMemory = 2, + + //! @brief Unknown instruction. This happens only if instruction code is + //! out of bounds. Shouldn't happen. + kErrorUnknownInstruction = 3, + //! @brief Illegal instruction, usually generated by AsmJit::Assembler + //! class when emitting instruction opcode. If this error is generated the + //! target buffer is not affected by this invalid instruction. + //! + //! You can also get this error code if you are under x64 (64-bit x86) and + //! you tried to decode instruction using AH, BH, CH or DH register with REX + //! prefix. These registers can't be accessed if REX prefix is used and AsmJit + //! didn't check for this situation in intrinsics (@c Compiler takes care of + //! this and rearrange registers if needed). + //! + //! Examples that will raise @c kErrorIllegalInstruction error (a is + //! @c Assembler instance): + //! + //! @code + //! a.mov(dword_ptr(eax), al); // Invalid address size. + //! a.mov(byte_ptr(r10), ah); // Undecodable instruction (AH used with r10 + //! // which can be encoded only using REX prefix) + //! @endcode + //! + //! @note In debug mode you get assertion failure instead of setting error + //! code. + kErrorIllegalInstruction = 4, + //! @brief Illegal addressing used (unencodable). + kErrorIllegalAddressing = 5, + //! @brief Short jump instruction used, but displacement is out of bounds. + kErrorIllegalShortJump = 6, + + //! @brief No function defined. + kErrorNoFunction = 7, + //! @brief Function generation is not finished by using @c Compiler::endFunc() + //! or something bad happened during generation related to function. This can + //! be missing compiler item, etc... + kErrorIncompleteFunction = 8, + + //! @brief Compiler can't allocate registers, because all of them are used. + //! + //! @note AsmJit is able to spill registers so this error really shouldn't + //! happen unless all registers have priority 0 (which means never spill). + kErrorNoRegisters = 9, + //! @brief Compiler can't allocate one register to multiple destinations. + //! + //! This error can only happen using special instructions like cmpxchg8b and + //! others where there are more destination operands (implicit). + kErrorOverlappedRegisters = 10, + + //! @brief Tried to call function using incompatible argument. + kErrorIncompatibleArgumentType = 11, + //! @brief Incompatible return value. + kErrorIncompatibleReturnType = 12, + + //! @brief Count of error codes by AsmJit. Can grow in future. + kErrorCount +}; + +// ============================================================================ +// [AsmJit::API] +// ============================================================================ + +//! @brief Translates error code (see @c kError) into text representation. +ASMJIT_API const char* getErrorString(uint32_t error); + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_DEFS_H diff --git a/desmume/src/utils/AsmJit/core/func.cpp b/desmume/src/utils/AsmJit/core/func.cpp new file mode 100644 index 000000000..fd3b14917 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/func.cpp @@ -0,0 +1,19 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/func.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { +} // AsmJit + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/func.h b/desmume/src/utils/AsmJit/core/func.h new file mode 100644 index 000000000..2681ad3f9 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/func.h @@ -0,0 +1,505 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_FUNC_H +#define _ASMJIT_CORE_FUNC_H + +// [Dependencies - AsmJit] +#include "../core/assert.h" +#include "../core/defs.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [Forward Declaration] +// ============================================================================ + +template +struct TypeId; + +// ============================================================================ +// [AsmJit::TypeId] +// ============================================================================ + +#if defined(ASMJIT_HAS_PARTIAL_TEMPLATE_SPECIALIZATION) + +#define ASMJIT_DECLARE_TYPE_CORE(_PtrId_) \ + template \ + struct TypeId \ + { \ + enum \ + { \ + Id = static_cast(::AsmJit::kVarTypeInvalid) \ + }; \ + }; \ + \ + template \ + struct TypeId { enum { Id = _PtrId_ }; } + +#else + +// Code without partial template specialization is a bit complex. We need to +// determine whether the size of the return value of this function is equal +// to sizeof(char) or sizeof(void*). Any sizeof() can be used to distinguish +// between these two, but these are commonly used in other libraries as well. +template +char TypeId_NoPtiHelper(T*(*)()); +// And specialization. +void* TypeId_NoPtiHelper(...); + +#define ASMJIT_DECLARE_TYPE_CORE(_PtrId_) \ + template \ + struct TypeId \ + { \ + enum \ + { \ + Id = (sizeof( ::AsmJit::TypeId_NoPtiHelper((T(*)())0) ) == sizeof(char) \ + ? static_cast(_PtrId_) \ + : static_cast(::AsmJit::kVarTypeInvalid)) \ + }; \ + } + +#endif // ASMJIT_HAS_PARTIAL_TEMPLATE_SPECIALIZATION + +//! @brief Declare C/C++ type-id mapped to @c AsmJit::kX86VarType. +#define ASMJIT_DECLARE_TYPE_ID(_T_, _Id_) \ + template<> \ + struct TypeId<_T_> { enum { Id = _Id_ }; } + +// ============================================================================ +// [AsmJit::FuncArg] +// ============================================================================ + +//! @brief Function argument translated from @ref FuncPrototype. +struct FuncArg +{ + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + inline uint32_t getVarType() const + { return _varType; } + + inline uint32_t getRegIndex() const + { return _regIndex; } + + inline bool hasRegIndex() const + { return _regIndex != kRegIndexInvalid; } + + inline int32_t getStackOffset() const + { return static_cast(_stackOffset); } + + inline bool hasStackOffset() const + { return _stackOffset != kFuncStackInvalid; } + + //! @brief Get whether the argument is assigned, for private use only. + inline bool isAssigned() const + { return (_regIndex != kRegIndexInvalid) | (_stackOffset != kFuncStackInvalid); } + + // -------------------------------------------------------------------------- + // [Reset] + // -------------------------------------------------------------------------- + + //! @brief Reset the function argument to "unassigned state". + inline void reset() + { _packed = 0xFFFFFFFF; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + union + { + struct + { + //! @brief Variable type, see @c kVarType. + uint8_t _varType; + //! @brief Register index is argument is passed through register. + uint8_t _regIndex; + //! @brief Stack offset if argument is passed through stack. + int16_t _stackOffset; + }; + + //! @brief All members packed into single 32-bit integer. + uint32_t _packed; + }; +}; + +// ============================================================================ +// [AsmJit::FuncPrototype] +// ============================================================================ + +//! @brief Function prototype. +//! +//! Function prototype contains information about function return type, count +//! of arguments and their types. Function definition is low level structure +//! which doesn't contain platform or calling convention specific information. +struct FuncPrototype +{ + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get function return value. + inline uint32_t getReturnType() const + { return _returnType; } + + //! @brief Get count of function arguments. + inline uint32_t getArgumentsCount() const + { return _argumentsCount; } + + //! @brief Get argument at index @a id. + inline uint32_t getArgument(uint32_t id) const + { + ASMJIT_ASSERT(id < _argumentsCount); + return _arguments[id]; + } + + //! @brief Get function arguments' IDs. + inline const uint32_t* getArguments() const + { return _arguments; } + + //! @brief Set function definition - return type and arguments. + inline void _setPrototype(uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount) + { + _returnType = returnType; + _arguments = arguments; + _argumentsCount = argumentsCount; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint32_t _returnType; + uint32_t _argumentsCount; + const uint32_t* _arguments; +}; + +// ============================================================================ +// [AsmJit::FuncDecl] +// ============================================================================ + +//! @brief Function declaration. +struct FuncDecl +{ + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get function return value or @ref kInvalidValue if it's void. + inline uint32_t getReturnType() const + { return _returnType; } + + //! @brief Get count of function arguments. + inline uint32_t getArgumentsCount() const + { return _argumentsCount; } + + //! @brief Get function arguments array. + inline FuncArg* getArguments() + { return _arguments; } + + //! @brief Get function arguments array (const). + inline const FuncArg* getArguments() const + { return _arguments; } + + //! @brief Get function argument at index @a index. + inline FuncArg& getArgument(size_t index) + { + ASMJIT_ASSERT(index < static_cast(_argumentsCount)); + return _arguments[index]; + } + + //! @brief Get function argument at index @a index. + inline const FuncArg& getArgument(size_t index) const + { + ASMJIT_ASSERT(index < static_cast(_argumentsCount)); + return _arguments[index]; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Function return type. + uint8_t _returnType; + //! @brief Count of arguments (in @c _argumentsList). + uint8_t _argumentsCount; + //! @brief Reserved for future use (alignment). + uint8_t _reserved0[2]; + + //! @brief Function arguments array. + FuncArg _arguments[kFuncArgsMax]; +}; + +// ============================================================================ +// [AsmJit::FuncBuilderX] +// ============================================================================ + +//! @brief Custom function builder for up to 32 function arguments. +struct FuncBuilderX : public FuncPrototype +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + inline FuncBuilderX() + { _setPrototype(kVarTypeInvalid, _argumentsData, 0); } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + template + inline void setReturnTypeT() + { setReturnTypeRaw(TypeId::Id); } + + template + inline void setArgumentT(uint32_t id) + { setArgumentRaw(id, TypeId::Id); } + + template + inline void addArgumentT() + { addArgumentRaw(TypeId::Id); } + + inline void setReturnTypeRaw(uint32_t returnType) + { _returnType = returnType; } + + inline void setArgumentRaw(uint32_t id, uint32_t type) + { + ASMJIT_ASSERT(id < _argumentsCount); + _argumentsData[id] = type; + } + + inline void addArgumentRaw(uint32_t type) + { + ASMJIT_ASSERT(_argumentsCount < kFuncArgsMax); + _argumentsData[_argumentsCount++] = type; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + uint32_t _argumentsData[kFuncArgsMax]; +}; + +//! @brief Class used to build function without arguments. +template +struct FuncBuilder0 : public FuncPrototype +{ + inline FuncBuilder0() + { + _setPrototype(TypeId::Id, NULL, 0); + } +}; + +//! @brief Class used to build function with 1 argument. +template +struct FuncBuilder1 : public FuncPrototype +{ + inline FuncBuilder1() + { + static const uint32_t arguments[] = + { + TypeId::Id + }; + + _setPrototype(TypeId::Id, arguments, ASMJIT_ARRAY_SIZE(arguments)); + } +}; + +//! @brief Class used to build function with 2 arguments. +template +struct FuncBuilder2 : public FuncPrototype +{ + inline FuncBuilder2() + { + static const uint32_t arguments[] = + { + TypeId::Id, + TypeId::Id + }; + + _setPrototype(TypeId::Id, arguments, ASMJIT_ARRAY_SIZE(arguments)); + } +}; + +//! @brief Class used to build function with 3 arguments. +template +struct FuncBuilder3 : public FuncPrototype +{ + inline FuncBuilder3() + { + static const uint32_t arguments[] = + { + TypeId::Id, + TypeId::Id, + TypeId::Id + }; + + _setPrototype(TypeId::Id, arguments, ASMJIT_ARRAY_SIZE(arguments)); + } +}; + +//! @brief Class used to build function with 4 arguments. +template +struct FuncBuilder4 : public FuncPrototype +{ + inline FuncBuilder4() + { + static const uint32_t arguments[] = + { + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id + }; + + _setPrototype(TypeId::Id, arguments, ASMJIT_ARRAY_SIZE(arguments)); + } +}; + +//! @brief Class used to build function with 5 arguments. +template +struct FuncBuilder5 : public FuncPrototype +{ + inline FuncBuilder5() + { + static const uint32_t arguments[] = + { + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id + }; + + _setPrototype(TypeId::Id, arguments, ASMJIT_ARRAY_SIZE(arguments)); + } +}; + +//! @brief Class used to build function with 6 arguments. +template +struct FuncBuilder6 : public FuncPrototype +{ + inline FuncBuilder6() + { + static const uint32_t arguments[] = + { + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id + }; + + _setPrototype(TypeId::Id, arguments, ASMJIT_ARRAY_SIZE(arguments)); + } +}; + +//! @brief Class used to build function with 7 arguments. +template +struct FuncBuilder7 : public FuncPrototype +{ + inline FuncBuilder7() + { + static const uint32_t arguments[] = + { + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id + }; + + _setPrototype(TypeId::Id, arguments, ASMJIT_ARRAY_SIZE(arguments)); + } +}; + +//! @brief Class used to build function with 8 arguments. +template +struct FuncBuilder8 : public FuncPrototype +{ + inline FuncBuilder8() + { + static const uint32_t arguments[] = + { + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id + }; + + _setPrototype(TypeId::Id, arguments, ASMJIT_ARRAY_SIZE(arguments)); + } +}; + +//! @brief Class used to build function with 9 arguments. +template +struct FuncBuilder9 : public FuncPrototype +{ + inline FuncBuilder9() + { + static const uint32_t arguments[] = + { + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id + }; + + _setPrototype(TypeId::Id, arguments, ASMJIT_ARRAY_SIZE(arguments)); + } +}; + +//! @brief Class used to build function with 10 arguments. +template +struct FuncBuilder10 : public FuncPrototype +{ + inline FuncBuilder10() + { + static const uint32_t arguments[] = + { + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id, + TypeId::Id + }; + + _setPrototype(TypeId::Id, arguments, ASMJIT_ARRAY_SIZE(arguments)); + } +}; + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_FUNC_H diff --git a/desmume/src/utils/AsmJit/core/intutil.h b/desmume/src/utils/AsmJit/core/intutil.h new file mode 100644 index 000000000..0125db745 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/intutil.h @@ -0,0 +1,262 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_INTUTIL_H +#define _ASMJIT_CORE_INTUTIL_H + +// [Dependencies - AsmJit] +#include "../core/assert.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::I32FPUnion] +// ============================================================================ + +//! @internal +//! +//! @brief used to cast from float to 32-bit integer and vica versa. +union I32FPUnion +{ + //! @brief 32-bit signed integer value. + int32_t i; + //! @brief 32-bit SP-FP value. + float f; +}; + +// ============================================================================ +// [AsmJit::I64FPUnion] +// ============================================================================ + +//! @internal +//! +//! @brief used to cast from double to 64-bit integer and vica versa. +union I64FPUnion +{ + //! @brief 64-bit signed integer value. + int64_t i; + //! @brief 64-bit DP-FP value. + double f; +}; + +// ============================================================================ +// [AsmJit::IntUtil] +// ============================================================================ + +namespace IntUtil +{ + // -------------------------------------------------------------------------- + // [Min/Max] + // -------------------------------------------------------------------------- + + // NOTE: Because some environments declare min() and max() as macros, we + // decided to use different name so we never collide. + + template + static inline T _min(const T& a, const T& b) { return a < b ? a : b; } + template + static inline T _max(const T& a, const T& b) { return a > b ? a : b; } + + // -------------------------------------------------------------------------- + // [Limits] + // -------------------------------------------------------------------------- + + template + static inline T maxValue() { return ~T(0); } + + // -------------------------------------------------------------------------- + // [IsInt / IsUInt] + // -------------------------------------------------------------------------- + + //! @brief Returns @c true if a given integer @a x is signed 8-bit integer + static inline bool isInt8(intptr_t x) { return x >= -128 && x <= 127; } + //! @brief Returns @c true if a given integer @a x is unsigned 8-bit integer + static inline bool isUInt8(intptr_t x) { return x >= 0 && x <= 255; } + + //! @brief Returns @c true if a given integer @a x is signed 16-bit integer + static inline bool isInt16(intptr_t x) { return x >= -32768 && x <= 32767; } + //! @brief Returns @c true if a given integer @a x is unsigned 16-bit integer + static inline bool isUInt16(intptr_t x) { return x >= 0 && x <= 65535; } + + //! @brief Returns @c true if a given integer @a x is signed 16-bit integer + static inline bool isInt32(intptr_t x) + { +#if defined(ASMJIT_X86) + return true; +#else + return x >= ASMJIT_INT64_C(-2147483648) && x <= ASMJIT_INT64_C(2147483647); +#endif + } + //! @brief Returns @c true if a given integer @a x is unsigned 16-bit integer + static inline bool isUInt32(intptr_t x) + { +#if defined(ASMJIT_X86) + return x >= 0; +#else + return x >= 0 && x <= ASMJIT_INT64_C(4294967295); +#endif + } + + // -------------------------------------------------------------------------- + // [Masking] + // -------------------------------------------------------------------------- + + static inline uint32_t maskFromIndex(uint32_t x) + { + ASMJIT_ASSERT(x < 32); + return (1U << x); + } + + static inline uint32_t maskUpToIndex(uint32_t x) + { + if (x >= 32) + return 0xFFFFFFFF; + else + return (1U << x) - 1; + } + + // -------------------------------------------------------------------------- + // [Bits] + // -------------------------------------------------------------------------- + + // From http://graphics.stanford.edu/~seander/bithacks.html . + static inline uint32_t bitCount(uint32_t x) + { + x = x - ((x >> 1) & 0x55555555U); + x = (x & 0x33333333U) + ((x >> 2) & 0x33333333U); + return (((x + (x >> 4)) & 0x0F0F0F0FU) * 0x01010101U) >> 24; + } + + static inline uint32_t findFirstBit(uint32_t mask) + { + for (uint32_t i = 0; i < sizeof(uint32_t) * 8; i++, mask >>= 1) + { + if (mask & 0x1) + return i; + } + + // kInvalidValue. + return 0xFFFFFFFF; + } + + // -------------------------------------------------------------------------- + // [Alignment] + // -------------------------------------------------------------------------- + + template + static inline bool isAligned(T base, T alignment) + { + return (base % alignment) == 0; + } + + //! @brief Align @a base to @a alignment. + template + static inline T align(T base, T alignment) + { + return (base + (alignment - 1)) & ~(alignment - 1); + } + + //! @brief Get delta required to align @a base to @a alignment. + template + static inline T delta(T base, T alignment) + { + return align(base, alignment) - base; + } + + // -------------------------------------------------------------------------- + // [Round] + // -------------------------------------------------------------------------- + + template + static inline T roundUp(T base, T alignment) + { + T over = base % alignment; + return base + (over > 0 ? alignment - over : 0); + } + + template + static inline T roundUpToPowerOf2(T base) + { + // Implementation is from "Hacker's Delight" by Henry S. Warren, Jr., + // figure 3-3, page 48, where the function is called clp2. + base -= 1; + + // I'm trying to make this portable and MSVC strikes me the warning C4293: + // "Shift count negative or too big, undefined behavior" + // Fixing... +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4293) +#endif // _MSC_VER + + base = base | (base >> 1); + base = base | (base >> 2); + base = base | (base >> 4); + + if (sizeof(T) >= 2) base = base | (base >> 8); + if (sizeof(T) >= 4) base = base | (base >> 16); + if (sizeof(T) >= 8) base = base | (base >> 32); + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif // _MSC_VER + + return base + 1; + } + + // -------------------------------------------------------------------------- + // [Cast] + // -------------------------------------------------------------------------- + + //! @brief Binary cast from 32-bit integer to SP-FP value (@c float). + static inline float int32AsFloat(int32_t i) + { + I32FPUnion u; + u.i = i; + return u.f; + } + + //! @brief Binary cast SP-FP value (@c float) to 32-bit integer. + static inline int32_t floatAsInt32(float f) + { + I32FPUnion u; + u.f = f; + return u.i; + } + + //! @brief Binary cast from 64-bit integer to DP-FP value (@c double). + static inline double int64AsDouble(int64_t i) + { + I64FPUnion u; + u.i = i; + return u.f; + } + + //! @brief Binary cast from DP-FP value (@c double) to 64-bit integer. + static inline int64_t doubleAsInt64(double f) + { + I64FPUnion u; + u.f = f; + return u.i; + } +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_INTUTIL_H diff --git a/desmume/src/utils/AsmJit/core/lock.h b/desmume/src/utils/AsmJit/core/lock.h new file mode 100644 index 000000000..ce0437c27 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/lock.h @@ -0,0 +1,136 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_LOCK_H +#define _ASMJIT_CORE_LOCK_H + +// [Dependencies - AsmJit] +#include "../core/build.h" + +// [Dependencies - Windows] +#if defined(ASMJIT_WINDOWS) +# include +#endif // ASMJIT_WINDOWS + +// [Dependencies - Posix] +#if defined(ASMJIT_POSIX) +# include +#endif // ASMJIT_POSIX + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::Lock] +// ============================================================================ + +//! @brief Lock - used in thread-safe code for locking. +struct Lock +{ + ASMJIT_NO_COPY(Lock) + + // -------------------------------------------------------------------------- + // [Windows] + // -------------------------------------------------------------------------- + +#if defined(ASMJIT_WINDOWS) + typedef CRITICAL_SECTION Handle; + + //! @brief Create a new @ref Lock instance. + inline Lock() { InitializeCriticalSection(&_handle); } + //! @brief Destroy the @ref Lock instance. + inline ~Lock() { DeleteCriticalSection(&_handle); } + + //! @brief Lock. + inline void lock() { EnterCriticalSection(&_handle); } + //! @brief Unlock. + inline void unlock() { LeaveCriticalSection(&_handle); } + +#endif // ASMJIT_WINDOWS + + // -------------------------------------------------------------------------- + // [Posix] + // -------------------------------------------------------------------------- + +#if defined(ASMJIT_POSIX) + typedef pthread_mutex_t Handle; + + //! @brief Create a new @ref Lock instance. + inline Lock() { pthread_mutex_init(&_handle, NULL); } + //! @brief Destroy the @ref Lock instance. + inline ~Lock() { pthread_mutex_destroy(&_handle); } + + //! @brief Lock. + inline void lock() { pthread_mutex_lock(&_handle); } + //! @brief Unlock. + inline void unlock() { pthread_mutex_unlock(&_handle); } +#endif // ASMJIT_POSIX + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get handle. + inline Handle& getHandle() { return _handle; } + //! @overload + inline const Handle& getHandle() const { return _handle; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Handle. + Handle _handle; +}; + +// ============================================================================ +// [AsmJit::AutoLock] +// ============================================================================ + +//! @brief Scope auto locker. +struct AutoLock +{ + ASMJIT_NO_COPY(AutoLock) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Locks @a target. + inline AutoLock(Lock& target) : _target(target) + { + _target.lock(); + } + + //! @brief Unlocks target. + inline ~AutoLock() + { + _target.unlock(); + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Pointer to target (lock). + Lock& _target; +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_LOCK_H diff --git a/desmume/src/utils/AsmJit/core/logger.cpp b/desmume/src/utils/AsmJit/core/logger.cpp new file mode 100644 index 000000000..15ed43527 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/logger.cpp @@ -0,0 +1,196 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/logger.h" + +// [Dependencies - C] +#include + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::Logger - Construction / Destruction] +// ============================================================================ + +Logger::Logger() : + _flags(kLoggerIsEnabled | kLoggerIsUsed) +{ + memset(_instructionPrefix, 0, ASMJIT_ARRAY_SIZE(_instructionPrefix)); +} + +Logger::~Logger() +{ +} + +// ============================================================================ +// [AsmJit::Logger - Logging] +// ============================================================================ + +void Logger::logFormat(const char* fmt, ...) +{ + char buf[1024]; + size_t len; + + va_list ap; + va_start(ap, fmt); + len = vsnprintf(buf, 1023, fmt, ap); + va_end(ap); + + logString(buf, len); +} + +// ============================================================================ +// [AsmJit::Logger - Enabled] +// ============================================================================ + +void Logger::setEnabled(bool enabled) +{ + if (enabled) + _flags |= kLoggerIsEnabled | kLoggerIsUsed; + else + _flags &= ~(kLoggerIsEnabled | kLoggerIsUsed); +} + +// ============================================================================ +// [AsmJit::Logger - LogBinary] +// ============================================================================ + +void Logger::setLogBinary(bool value) +{ + if (value) + _flags |= kLoggerOutputBinary; + else + _flags &= ~kLoggerOutputBinary; +} + +// ============================================================================ +// [AsmJit::Logger - HexImmediate] +// ============================================================================ + +void Logger::setHexImmediate(bool value) +{ + if (value) + _flags |= kLoggerOutputHexImmediate; + else + _flags &= ~kLoggerOutputHexImmediate; +} + +// ============================================================================ +// [AsmJit::Logger - HexDisplacement] +// ============================================================================ + +void Logger::setHexDisplacement(bool value) +{ + if (value) + _flags |= kLoggerOutputHexDisplacement; + else + _flags &= ~kLoggerOutputHexDisplacement; +} + +// ============================================================================ +// [AsmJit::Logger - InstructionPrefix] +// ============================================================================ + +void Logger::setInstructionPrefix(const char* prefix) +{ + memset(_instructionPrefix, 0, ASMJIT_ARRAY_SIZE(_instructionPrefix)); + + if (!prefix) + return; + + size_t length = strnlen(prefix, ASMJIT_ARRAY_SIZE(_instructionPrefix) - 1); + memcpy(_instructionPrefix, prefix, length); +} + +// ============================================================================ +// [AsmJit::FileLogger - Construction / Destruction] +// ============================================================================ + +FileLogger::FileLogger(FILE* stream) + : _stream(NULL) +{ + setStream(stream); +} + +FileLogger::~FileLogger() +{ +} + +// ============================================================================ +// [AsmJit::FileLogger - Accessors] +// ============================================================================ + +//! @brief Set file stream. +void FileLogger::setStream(FILE* stream) +{ + _stream = stream; + + if (isEnabled() && _stream != NULL) + _flags |= kLoggerIsUsed; + else + _flags &= ~kLoggerIsUsed; +} + +// ============================================================================ +// [AsmJit::FileLogger - Logging] +// ============================================================================ + +void FileLogger::logString(const char* buf, size_t len) +{ + if (!isUsed()) + return; + + if (len == kInvalidSize) + len = strlen(buf); + + fwrite(buf, 1, len, _stream); +} + +// ============================================================================ +// [AsmJit::FileLogger - Enabled] +// ============================================================================ + +void FileLogger::setEnabled(bool enabled) +{ + if (enabled) + _flags |= kLoggerIsEnabled | (_stream != NULL ? kLoggerIsUsed : 0); + else + _flags &= ~(kLoggerIsEnabled | kLoggerIsUsed); +} + +// ============================================================================ +// [AsmJit::StringLogger - Construction / Destruction] +// ============================================================================ + +StringLogger::StringLogger() +{ +} + +StringLogger::~StringLogger() +{ +} + +// ============================================================================ +// [AsmJit::StringLogger - Logging] +// ============================================================================ + +void StringLogger::logString(const char* buf, size_t len) +{ + if (!isUsed()) + return; + _stringBuilder.appendString(buf, len); +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/logger.h b/desmume/src/utils/AsmJit/core/logger.h new file mode 100644 index 000000000..1990f168c --- /dev/null +++ b/desmume/src/utils/AsmJit/core/logger.h @@ -0,0 +1,244 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_LOGGER_H +#define _ASMJIT_CORE_LOGGER_H + +// [Dependencies - AsmJit] +#include "../core/build.h" +#include "../core/defs.h" +#include "../core/stringbuilder.h" + +// [Dependencies - C] +#include + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Logging +//! @{ + +// ============================================================================ +// [AsmJit::Logger] +// ============================================================================ + +//! @brief Abstract logging class. +//! +//! This class can be inherited and reimplemented to fit into your logging +//! subsystem. When reimplementing use @c AsmJit::Logger::log() method to +//! log into your stream. +//! +//! This class also contain @c _enabled member that can be used to enable +//! or disable logging. +struct Logger +{ + ASMJIT_NO_COPY(Logger) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create logger. + ASMJIT_API Logger(); + //! @brief Destroy logger. + ASMJIT_API virtual ~Logger(); + + // -------------------------------------------------------------------------- + // [Logging] + // -------------------------------------------------------------------------- + + //! @brief Abstract method to log output. + //! + //! Default implementation that is in @c AsmJit::Logger is to do nothing. + //! It's virtual to fit to your logging system. + virtual void logString(const char* buf, size_t len = kInvalidSize) = 0; + + //! @brief Log formatter message (like sprintf) sending output to @c logString() method. + ASMJIT_API virtual void logFormat(const char* fmt, ...); + + // -------------------------------------------------------------------------- + // [Flags] + // -------------------------------------------------------------------------- + + //! @brief Get logger flags (used internally by Assembler/Compiler). + inline uint32_t getFlags() const { return _flags; } + + // -------------------------------------------------------------------------- + // [Enabled] + // -------------------------------------------------------------------------- + + //! @brief Return @c true if logging is enabled. + inline bool isEnabled() const { return (_flags & kLoggerIsEnabled) != 0; } + + //! @brief Set logging to enabled or disabled. + ASMJIT_API virtual void setEnabled(bool enabled); + + // -------------------------------------------------------------------------- + // [Used] + // -------------------------------------------------------------------------- + + //! @brief Get whether the logger should be used. + inline bool isUsed() const { return (_flags & kLoggerIsUsed) != 0; } + + // -------------------------------------------------------------------------- + // [LogBinary] + // -------------------------------------------------------------------------- + + //! @brief Get whether logging of binary output is enabled. + inline bool getLogBinary() const { return (_flags & kLoggerOutputBinary) != 0; } + //! @brief Enable or disable binary output logging. + ASMJIT_API void setLogBinary(bool value); + + // -------------------------------------------------------------------------- + // [HexImmediate] + // -------------------------------------------------------------------------- + + inline bool getHexImmediate() const { return (_flags & kLoggerOutputHexImmediate) != 0; } + ASMJIT_API void setHexImmediate(bool value); + + // -------------------------------------------------------------------------- + // [HexDisplacement] + // -------------------------------------------------------------------------- + + inline bool getHexDisplacement() const { return (_flags & kLoggerOutputHexDisplacement) != 0; } + ASMJIT_API void setHexDisplacement(bool value); + + // -------------------------------------------------------------------------- + // [InstructionPrefix] + // -------------------------------------------------------------------------- + + //! @brief Get instruction prefix. + inline const char* getInstructionPrefix() const { return _instructionPrefix; } + //! @brief Set instruction prefix. + ASMJIT_API void setInstructionPrefix(const char* prefix); + //! @brief Reset instruction prefix. + inline void resetInstructionPrefix() { setInstructionPrefix(NULL); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Flags, see @ref kLoggerFlag. + uint32_t _flags; + + //! @brief Instrictions and macro-instructions prefix. + char _instructionPrefix[12]; +}; + +// ============================================================================ +// [AsmJit::FileLogger] +// ============================================================================ + +//! @brief Logger that can log to standard C @c FILE* stream. +struct FileLogger : public Logger +{ + ASMJIT_NO_COPY(FileLogger) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @c FileLogger. + //! @param stream FILE stream where logging will be sent (can be @c NULL + //! to disable logging). + ASMJIT_API FileLogger(FILE* stream = NULL); + + //! @brief Destroy the @ref FileLogger. + ASMJIT_API virtual ~FileLogger(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get @c FILE* stream. + //! + //! @note Return value can be @c NULL. + inline FILE* getStream() const { return _stream; } + + //! @brief Set @c FILE* stream. + //! + //! @param stream @c FILE stream where to log output (can be @c NULL to + //! disable logging). + ASMJIT_API void setStream(FILE* stream); + + // -------------------------------------------------------------------------- + // [Logging] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void logString(const char* buf, size_t len = kInvalidSize); + + // -------------------------------------------------------------------------- + // [Enabled] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void setEnabled(bool enabled); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief C file stream. + FILE* _stream; +}; + +// ============================================================================ +// [AsmJit::StringLogger] +// ============================================================================ + +//! @brief String logger. +struct StringLogger : public Logger +{ + ASMJIT_NO_COPY(StringLogger) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create new @ref StringLogger. + ASMJIT_API StringLogger(); + + //! @brief Destroy the @ref StringLogger. + ASMJIT_API virtual ~StringLogger(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get char* pointer which represents the serialized + //! string. + //! + //! The pointer is owned by @ref StringLogger, it can't be modified or freed. + inline const char* getString() const { return _stringBuilder.getData(); } + + //! @brief Clear the serialized string. + inline void clearString() { _stringBuilder.clear(); } + + // -------------------------------------------------------------------------- + // [Logging] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void logString(const char* buf, size_t len = kInvalidSize); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Output. + StringBuilder _stringBuilder; +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_LOGGER_H diff --git a/desmume/src/utils/AsmJit/MemoryManager.cpp b/desmume/src/utils/AsmJit/core/memorymanager.cpp similarity index 74% rename from desmume/src/utils/AsmJit/MemoryManager.cpp rename to desmume/src/utils/AsmJit/core/memorymanager.cpp index 915278aab..a0d3c2a25 100644 --- a/desmume/src/utils/AsmJit/MemoryManager.cpp +++ b/desmume/src/utils/AsmJit/core/memorymanager.cpp @@ -4,18 +4,16 @@ // [License] // Zlib - See COPYING file in this package. -// [Dependencies] -#include "Build.h" -#include "MemoryManager.h" -#include "Platform.h" +#define ASMJIT_EXPORTS -#include -#include - -#include +// [Dependencies - AsmJit] +#include "../core/assert.h" +#include "../core/lock.h" +#include "../core/memorymanager.h" +#include "../core/virtualmemory.h" // [Api-Begin] -#include "ApiBegin.h" +#include "../core/apibegin.h" // This file contains implementation of virtual memory management for AsmJit // library. The initial concept is to keep this implementation simple but @@ -55,70 +53,70 @@ namespace AsmJit { // [Bits Manipulation] // ============================================================================ -#define BITS_PER_ENTITY (sizeof(sysuint_t) * 8) +#define BITS_PER_ENTITY (sizeof(size_t) * 8) -static void _SetBit(sysuint_t* buf, sysuint_t index) ASMJIT_NOTHROW +static void _SetBit(size_t* buf, size_t index) { - sysuint_t i = index / BITS_PER_ENTITY; // sysuint_t[] - sysuint_t j = index % BITS_PER_ENTITY; // sysuint_t[][] bit index + size_t i = index / BITS_PER_ENTITY; // size_t[] + size_t j = index % BITS_PER_ENTITY; // size_t[][] bit index buf += i; - *buf |= (sysuint_t)1 << j; + *buf |= (size_t)1 << j; } -static void _ClearBit(sysuint_t* buf, sysuint_t index) ASMJIT_NOTHROW +static void _ClearBit(size_t* buf, size_t index) { - sysuint_t i = index / BITS_PER_ENTITY; // sysuint_t[] - sysuint_t j = index % BITS_PER_ENTITY; // sysuint_t[][] bit index + size_t i = index / BITS_PER_ENTITY; // size_t[] + size_t j = index % BITS_PER_ENTITY; // size_t[][] bit index buf += i; - *buf &= ~((sysuint_t)1 << j); + *buf &= ~((size_t)1 << j); } -static void _SetBits(sysuint_t* buf, sysuint_t index, sysuint_t len) ASMJIT_NOTHROW +static void _SetBits(size_t* buf, size_t index, size_t len) { if (len == 0) return; - sysuint_t i = index / BITS_PER_ENTITY; // sysuint_t[] - sysuint_t j = index % BITS_PER_ENTITY; // sysuint_t[][] bit index + size_t i = index / BITS_PER_ENTITY; // size_t[] + size_t j = index % BITS_PER_ENTITY; // size_t[][] bit index // How many bytes process in the first group. - sysuint_t c = BITS_PER_ENTITY - j; + size_t c = BITS_PER_ENTITY - j; if (c > len) c = len; // Offset. buf += i; - *buf++ |= (((sysuint_t)-1) >> (BITS_PER_ENTITY - c)) << j; + *buf++ |= ((~(size_t)0) >> (BITS_PER_ENTITY - c)) << j; len -= c; while (len >= BITS_PER_ENTITY) { - *buf++ = (sysuint_t)-1; + *buf++ = ~(size_t)0; len -= BITS_PER_ENTITY; } if (len) { - *buf |= (((sysuint_t)-1) >> (BITS_PER_ENTITY - len)); + *buf |= ((~(size_t)0) >> (BITS_PER_ENTITY - len)); } } -static void _ClearBits(sysuint_t* buf, sysuint_t index, sysuint_t len) ASMJIT_NOTHROW +static void _ClearBits(size_t* buf, size_t index, size_t len) { if (len == 0) return; - sysuint_t i = index / BITS_PER_ENTITY; // sysuint_t[] - sysuint_t j = index % BITS_PER_ENTITY; // sysuint_t[][] bit index + size_t i = index / BITS_PER_ENTITY; // size_t[] + size_t j = index % BITS_PER_ENTITY; // size_t[][] bit index // How many bytes process in the first group. - sysuint_t c = BITS_PER_ENTITY - j; + size_t c = BITS_PER_ENTITY - j; if (c > len) c = len; // Offset. buf += i; - *buf++ &= ~((((sysuint_t)-1) >> (BITS_PER_ENTITY - c)) << j); + *buf++ &= ~(((~(size_t)0) >> (BITS_PER_ENTITY - c)) << j); len -= c; while (len >= BITS_PER_ENTITY) @@ -129,7 +127,7 @@ static void _ClearBits(sysuint_t* buf, sysuint_t index, sysuint_t len) ASMJIT_NO if (len) { - *buf &= ((sysuint_t)-1) << len; + *buf &= (~(size_t)0) << len; } } @@ -141,7 +139,7 @@ static void _ClearBits(sysuint_t* buf, sysuint_t index, sysuint_t len) ASMJIT_NO #define M_MOD(x, y) ((x) % (y)) template -struct ASMJIT_HIDDEN RbNode +struct RbNode { // -------------------------------------------------------------------------- // [Node red-black tree tree, key is mem pointer]. @@ -170,36 +168,36 @@ inline bool isRed(RbNode* node) return node != NULL && node->red; } -struct ASMJIT_HIDDEN MemNode : public RbNode +struct MemNode : public RbNode { // -------------------------------------------------------------------------- // [Node double-linked list] // -------------------------------------------------------------------------- - MemNode* prev; // Prev node in list. - MemNode* next; // Next node in list. + MemNode* prev; // Prev node in list. + MemNode* next; // Next node in list. // -------------------------------------------------------------------------- // [Chunk Data] // -------------------------------------------------------------------------- - sysuint_t size; // How many bytes contain this node. - sysuint_t blocks; // How many blocks are here. - sysuint_t density; // Minimum count of allocated bytes in this node (also alignment). - sysuint_t used; // How many bytes are used in this node. - sysuint_t largestBlock; // Contains largest block that can be allocated. + size_t size; // How many bytes contain this node. + size_t blocks; // How many blocks are here. + size_t density; // Minimum count of allocated bytes in this node (also alignment). + size_t used; // How many bytes are used in this node. + size_t largestBlock; // Contains largest block that can be allocated. - sysuint_t* baUsed; // Contains bits about used blocks. - // (0 = unused, 1 = used). - sysuint_t* baCont; // Contains bits about continuous blocks. - // (0 = stop, 1 = continue). + size_t* baUsed; // Contains bits about used blocks. + // (0 = unused, 1 = used). + size_t* baCont; // Contains bits about continuous blocks. + // (0 = stop, 1 = continue). // -------------------------------------------------------------------------- // [Methods] // -------------------------------------------------------------------------- // Get available space. - inline sysuint_t getAvailable() const ASMJIT_NOTHROW { return size - used; } + inline size_t getAvailable() const { return size - used; } inline void fillData(MemNode* other) { @@ -220,49 +218,49 @@ struct ASMJIT_HIDDEN MemNode : public RbNode // ============================================================================ //! @brief Permanent node. -struct ASMJIT_HIDDEN PermanentNode +struct PermanentNode { uint8_t* mem; // Base pointer (virtual memory address). - sysuint_t size; // Count of bytes allocated. - sysuint_t used; // Count of bytes used. + size_t size; // Count of bytes allocated. + size_t used; // Count of bytes used. PermanentNode* prev; // Pointer to prev chunk or NULL. // Get available space. - inline sysuint_t getAvailable() const ASMJIT_NOTHROW { return size - used; } + inline size_t getAvailable() const { return size - used; } }; // ============================================================================ // [AsmJit::MemoryManagerPrivate] // ============================================================================ -struct ASMJIT_HIDDEN MemoryManagerPrivate +struct MemoryManagerPrivate { // -------------------------------------------------------------------------- // [Construction / Destruction] // -------------------------------------------------------------------------- #if !defined(ASMJIT_WINDOWS) - MemoryManagerPrivate() ASMJIT_NOTHROW; + MemoryManagerPrivate(); #else - MemoryManagerPrivate(HANDLE hProcess) ASMJIT_NOTHROW; + MemoryManagerPrivate(HANDLE hProcess); #endif // ASMJIT_WINDOWS - ~MemoryManagerPrivate() ASMJIT_NOTHROW; + ~MemoryManagerPrivate(); // -------------------------------------------------------------------------- // [Allocation] // -------------------------------------------------------------------------- - MemNode* createNode(sysuint_t size, sysuint_t density) ASMJIT_NOTHROW; + MemNode* createNode(size_t size, size_t density); - void* allocPermanent(sysuint_t vsize) ASMJIT_NOTHROW; - void* allocFreeable(sysuint_t vsize) ASMJIT_NOTHROW; + void* allocPermanent(size_t vsize); + void* allocFreeable(size_t vsize); - bool free(void* address) ASMJIT_NOTHROW; - bool shrink(void* address, sysuint_t used) ASMJIT_NOTHROW; - void freeAll(bool keepVirtualMemory) ASMJIT_NOTHROW; + bool free(void* address); + bool shrink(void* address, size_t used); + void freeAll(bool keepVirtualMemory); // Helpers to avoid ifdefs in the code. - inline uint8_t* allocVirtualMemory(sysuint_t size, sysuint_t* vsize) ASMJIT_NOTHROW + inline uint8_t* allocVirtualMemory(size_t size, size_t* vsize) { #if !defined(ASMJIT_WINDOWS) return (uint8_t*)VirtualMemory::alloc(size, vsize, true); @@ -271,7 +269,7 @@ struct ASMJIT_HIDDEN MemoryManagerPrivate #endif } - inline void freeVirtualMemory(void* vmem, sysuint_t vsize) ASMJIT_NOTHROW + inline void freeVirtualMemory(void* vmem, size_t vsize) { #if !defined(ASMJIT_WINDOWS) VirtualMemory::free(vmem, vsize); @@ -284,11 +282,11 @@ struct ASMJIT_HIDDEN MemoryManagerPrivate // [NodeList RB-Tree] // -------------------------------------------------------------------------- - bool checkTree() ASMJIT_NOTHROW; + bool checkTree(); - void insertNode(MemNode* node) ASMJIT_NOTHROW; - MemNode* removeNode(MemNode* node) ASMJIT_NOTHROW; - MemNode* findPtr(uint8_t* mem) ASMJIT_NOTHROW; + void insertNode(MemNode* node); + MemNode* removeNode(MemNode* node); + MemNode* findPtr(uint8_t* mem); // -------------------------------------------------------------------------- // [Members] @@ -299,10 +297,10 @@ struct ASMJIT_HIDDEN MemoryManagerPrivate #endif // ASMJIT_WINDOWS Lock _lock; // Lock for thread safety. - sysuint_t _newChunkSize; // Default node size. - sysuint_t _newChunkDensity; // Default node density. - sysuint_t _allocated; // How many bytes are allocated. - sysuint_t _used; // How many bytes are used. + size_t _newChunkSize; // Default node size. + size_t _newChunkDensity; // Default node density. + size_t _allocated; // How many bytes are allocated. + size_t _used; // How many bytes are used. // Memory nodes list. MemNode* _first; @@ -324,9 +322,9 @@ struct ASMJIT_HIDDEN MemoryManagerPrivate // ============================================================================ #if !defined(ASMJIT_WINDOWS) -MemoryManagerPrivate::MemoryManagerPrivate() ASMJIT_NOTHROW : +MemoryManagerPrivate::MemoryManagerPrivate() : #else -MemoryManagerPrivate::MemoryManagerPrivate(HANDLE hProcess) ASMJIT_NOTHROW : +MemoryManagerPrivate::MemoryManagerPrivate(HANDLE hProcess) : _hProcess(hProcess), #endif _newChunkSize(65536), @@ -342,7 +340,7 @@ MemoryManagerPrivate::MemoryManagerPrivate(HANDLE hProcess) ASMJIT_NOTHROW : { } -MemoryManagerPrivate::~MemoryManagerPrivate() ASMJIT_NOTHROW +MemoryManagerPrivate::~MemoryManagerPrivate() { // Freeable memory cleanup - Also frees the virtual memory if configured to. freeAll(_keepVirtualMemory); @@ -364,16 +362,16 @@ MemoryManagerPrivate::~MemoryManagerPrivate() ASMJIT_NOTHROW // Allocates virtual memory node and MemNode structure. // // Returns MemNode* on success, otherwise NULL. -MemNode* MemoryManagerPrivate::createNode(sysuint_t size, sysuint_t density) ASMJIT_NOTHROW +MemNode* MemoryManagerPrivate::createNode(size_t size, size_t density) { - sysuint_t vsize; + size_t vsize; uint8_t* vmem = allocVirtualMemory(size, &vsize); // Out of memory. if (vmem == NULL) return NULL; - sysuint_t blocks = (vsize / density); - sysuint_t bsize = (((blocks + 7) >> 3) + sizeof(sysuint_t) - 1) & ~(sysuint_t)(sizeof(sysuint_t)-1); + size_t blocks = (vsize / density); + size_t bsize = (((blocks + 7) >> 3) + sizeof(size_t) - 1) & ~(size_t)(sizeof(size_t) - 1); MemNode* node = reinterpret_cast(ASMJIT_MALLOC(sizeof(MemNode))); uint8_t* data = reinterpret_cast(ASMJIT_MALLOC(bsize * 2)); @@ -404,21 +402,22 @@ MemNode* MemoryManagerPrivate::createNode(sysuint_t size, sysuint_t density) ASM node->largestBlock = vsize; memset(data, 0, bsize * 2); - node->baUsed = reinterpret_cast(data); - node->baCont = reinterpret_cast(data + bsize); + node->baUsed = reinterpret_cast(data); + node->baCont = reinterpret_cast(data + bsize); return node; } -void* MemoryManagerPrivate::allocPermanent(sysuint_t vsize) ASMJIT_NOTHROW +void* MemoryManagerPrivate::allocPermanent(size_t vsize) { - static const sysuint_t permanentAlignment = 32; - static const sysuint_t permanentNodeSize = 32768; + static const size_t permanentAlignment = 32; + static const size_t permanentNodeSize = 32768; - sysuint_t over = vsize % permanentAlignment; - if (over) over = permanentAlignment - over; - sysuint_t alignedSize = vsize + over; + size_t over = vsize % permanentAlignment; + if (over) + over = permanentAlignment - over; + size_t alignedSize = vsize + over; AutoLock locked(_lock); PermanentNode* node = _permanent; @@ -427,9 +426,9 @@ void* MemoryManagerPrivate::allocPermanent(sysuint_t vsize) ASMJIT_NOTHROW while (node && alignedSize > node->getAvailable()) node = node->prev; // Or allocate new node. - if (!node) + if (node == NULL) { - sysuint_t nodeSize = permanentNodeSize; + size_t nodeSize = permanentNodeSize; if (vsize > nodeSize) nodeSize = vsize; node = (PermanentNode*)ASMJIT_MALLOC(sizeof(PermanentNode)); @@ -460,14 +459,14 @@ void* MemoryManagerPrivate::allocPermanent(sysuint_t vsize) ASMJIT_NOTHROW return (void*)result; } -void* MemoryManagerPrivate::allocFreeable(sysuint_t vsize) ASMJIT_NOTHROW +void* MemoryManagerPrivate::allocFreeable(size_t vsize) { - sysuint_t i; // Current index. - sysuint_t need; // How many we need to be freed. - sysuint_t minVSize; + size_t i; // Current index. + size_t need; // How many we need to be freed. + size_t minVSize; // Align to 32 bytes (our default alignment). - vsize = (vsize + 31) & ~(sysuint_t)31; + vsize = (vsize + 31) & ~(size_t)31; if (vsize == 0) return NULL; AutoLock locked(_lock); @@ -488,13 +487,13 @@ void* MemoryManagerPrivate::allocFreeable(sysuint_t vsize) ASMJIT_NOTHROW continue; } - sysuint_t* up = node->baUsed; // Current ubits address. - sysuint_t ubits; // Current ubits[0] value. - sysuint_t bit; // Current bit mask. - sysuint_t blocks = node->blocks; // Count of blocks in node. - sysuint_t cont = 0; // How many bits are currently freed in find loop. - sysuint_t maxCont = 0; // Largest continuous block (bits count). - sysuint_t j; + size_t* up = node->baUsed; // Current ubits address. + size_t ubits; // Current ubits[0] value. + size_t bit; // Current bit mask. + size_t blocks = node->blocks; // Count of blocks in node. + size_t cont = 0; // How many bits are currently freed in find loop. + size_t maxCont = 0; // Largest continuous block (bits count). + size_t j; need = M_DIV((vsize + node->density - 1), node->density); i = 0; @@ -505,7 +504,7 @@ void* MemoryManagerPrivate::allocFreeable(sysuint_t vsize) ASMJIT_NOTHROW ubits = *up++; // Fast skip used blocks. - if (ubits == (sysuint_t)-1) + if (ubits == ~(size_t)0) { if (cont > maxCont) maxCont = cont; cont = 0; @@ -514,7 +513,7 @@ void* MemoryManagerPrivate::allocFreeable(sysuint_t vsize) ASMJIT_NOTHROW continue; } - sysuint_t max = BITS_PER_ENTITY; + size_t max = BITS_PER_ENTITY; if (i + max > blocks) max = blocks - i; for (j = 0, bit = 1; j < max; bit <<= 1) @@ -522,7 +521,7 @@ void* MemoryManagerPrivate::allocFreeable(sysuint_t vsize) ASMJIT_NOTHROW j++; if ((ubits & bit) == 0) { - if (++cont == need) { i += j; i -= cont; goto found; } + if (++cont == need) { i += j; i -= cont; goto _Found; } continue; } @@ -543,7 +542,7 @@ void* MemoryManagerPrivate::allocFreeable(sysuint_t vsize) ASMJIT_NOTHROW // If we are here, we failed to find existing memory block and we must // allocate new. { - sysuint_t chunkSize = _newChunkSize; + size_t chunkSize = _newChunkSize; if (chunkSize < vsize) chunkSize = vsize; node = createNode(chunkSize, _newChunkDensity); @@ -561,14 +560,14 @@ void* MemoryManagerPrivate::allocFreeable(sysuint_t vsize) ASMJIT_NOTHROW _allocated += node->size; } -found: +_Found: // Update bits. _SetBits(node->baUsed, i, need); _SetBits(node->baCont, i, need - 1); // Update statistics. { - sysuint_t u = need * node->density; + size_t u = need * node->density; node->used += u; node->largestBlock = 0; _used += u; @@ -580,7 +579,7 @@ found: return result; } -bool MemoryManagerPrivate::free(void* address) ASMJIT_NOTHROW +bool MemoryManagerPrivate::free(void* address) { if (address == NULL) return true; @@ -590,17 +589,17 @@ bool MemoryManagerPrivate::free(void* address) ASMJIT_NOTHROW if (node == NULL) return false; - sysuint_t offset = (sysuint_t)((uint8_t*)address - (uint8_t*)node->mem); - sysuint_t bitpos = M_DIV(offset, node->density); - sysuint_t i = (bitpos / BITS_PER_ENTITY); + size_t offset = (size_t)((uint8_t*)address - (uint8_t*)node->mem); + size_t bitpos = M_DIV(offset, node->density); + size_t i = (bitpos / BITS_PER_ENTITY); - sysuint_t* up = node->baUsed + i; // Current ubits address. - sysuint_t* cp = node->baCont + i; // Current cbits address. - sysuint_t ubits = *up; // Current ubits[0] value. - sysuint_t cbits = *cp; // Current cbits[0] value. - sysuint_t bit = (sysuint_t)1 << (bitpos % BITS_PER_ENTITY); + size_t* up = node->baUsed + i; // Current ubits address. + size_t* cp = node->baCont + i; // Current cbits address. + size_t ubits = *up; // Current ubits[0] value. + size_t cbits = *cp; // Current cbits[0] value. + size_t bit = (size_t)1 << (bitpos % BITS_PER_ENTITY); - sysuint_t cont = 0; + size_t cont = 0; bool stop; for (;;) @@ -665,7 +664,7 @@ bool MemoryManagerPrivate::free(void* address) ASMJIT_NOTHROW return true; } -bool MemoryManagerPrivate::shrink(void* address, sysuint_t used) ASMJIT_NOTHROW +bool MemoryManagerPrivate::shrink(void* address, size_t used) { if (address == NULL) return false; if (used == 0) return free(address); @@ -676,18 +675,18 @@ bool MemoryManagerPrivate::shrink(void* address, sysuint_t used) ASMJIT_NOTHROW if (node == NULL) return false; - sysuint_t offset = (sysuint_t)((uint8_t*)address - (uint8_t*)node->mem); - sysuint_t bitpos = M_DIV(offset, node->density); - sysuint_t i = (bitpos / BITS_PER_ENTITY); + size_t offset = (size_t)((uint8_t*)address - (uint8_t*)node->mem); + size_t bitpos = M_DIV(offset, node->density); + size_t i = (bitpos / BITS_PER_ENTITY); - sysuint_t* up = node->baUsed + i; // Current ubits address. - sysuint_t* cp = node->baCont + i; // Current cbits address. - sysuint_t ubits = *up; // Current ubits[0] value. - sysuint_t cbits = *cp; // Current cbits[0] value. - sysuint_t bit = (sysuint_t)1 << (bitpos % BITS_PER_ENTITY); + size_t* up = node->baUsed + i; // Current ubits address. + size_t* cp = node->baCont + i; // Current cbits address. + size_t ubits = *up; // Current ubits[0] value. + size_t cbits = *cp; // Current cbits[0] value. + size_t bit = (size_t)1 << (bitpos % BITS_PER_ENTITY); - sysuint_t cont = 0; - sysuint_t usedBlocks = (used + node->density - 1) / node->density; + size_t cont = 0; + size_t usedBlocks = (used + node->density - 1) / node->density; bool stop; @@ -709,14 +708,14 @@ bool MemoryManagerPrivate::shrink(void* address, sysuint_t used) ASMJIT_NOTHROW } // Free the tail blocks. - cont = (sysuint_t)-1; - goto enterFreeLoop; + cont = ~(size_t)0; + goto _EnterFreeLoop; for (;;) { stop = (cbits & bit) == 0; ubits &= ~bit; -enterFreeLoop: +_EnterFreeLoop: cbits &= ~bit; bit <<= 1; @@ -743,7 +742,7 @@ enterFreeLoop: return true; } -void MemoryManagerPrivate::freeAll(bool keepVirtualMemory) ASMJIT_NOTHROW +void MemoryManagerPrivate::freeAll(bool keepVirtualMemory) { MemNode* node = _first; @@ -751,7 +750,9 @@ void MemoryManagerPrivate::freeAll(bool keepVirtualMemory) ASMJIT_NOTHROW { MemNode* next = node->next; - if (!keepVirtualMemory) freeVirtualMemory(node->mem, node->size); + if (!keepVirtualMemory) + freeVirtualMemory(node->mem, node->size); + ASMJIT_FREE(node->baUsed); ASMJIT_FREE(node); @@ -817,12 +818,12 @@ static inline MemNode* rbRotateDouble(MemNode* root, int dir) return rbRotateSingle(root, dir); } -bool MemoryManagerPrivate::checkTree() ASMJIT_NOTHROW +bool MemoryManagerPrivate::checkTree() { return rbAssert(_root) > 0; } -void MemoryManagerPrivate::insertNode(MemNode* node) ASMJIT_NOTHROW +void MemoryManagerPrivate::insertNode(MemNode* node) { if (_root == NULL) { @@ -905,7 +906,7 @@ void MemoryManagerPrivate::insertNode(MemNode* node) ASMJIT_NOTHROW } } -MemNode* MemoryManagerPrivate::removeNode(MemNode* node) ASMJIT_NOTHROW +MemNode* MemoryManagerPrivate::removeNode(MemNode* node) { // False tree root. RbNode head = {0}; @@ -996,7 +997,7 @@ MemNode* MemoryManagerPrivate::removeNode(MemNode* node) ASMJIT_NOTHROW return q; } -MemNode* MemoryManagerPrivate::findPtr(uint8_t* mem) ASMJIT_NOTHROW +MemNode* MemoryManagerPrivate::findPtr(uint8_t* mem) { MemNode* cur = _root; while (cur) @@ -1031,15 +1032,15 @@ MemNode* MemoryManagerPrivate::findPtr(uint8_t* mem) ASMJIT_NOTHROW // [AsmJit::MemoryManager] // ============================================================================ -MemoryManager::MemoryManager() ASMJIT_NOTHROW +MemoryManager::MemoryManager() { } -MemoryManager::~MemoryManager() ASMJIT_NOTHROW +MemoryManager::~MemoryManager() { } -MemoryManager* MemoryManager::getGlobal() ASMJIT_NOTHROW +MemoryManager* MemoryManager::getGlobal() { static VirtualMemoryManager memmgr; return &memmgr; @@ -1050,54 +1051,54 @@ MemoryManager* MemoryManager::getGlobal() ASMJIT_NOTHROW // ============================================================================ #if !defined(ASMJIT_WINDOWS) -VirtualMemoryManager::VirtualMemoryManager() ASMJIT_NOTHROW +VirtualMemoryManager::VirtualMemoryManager() { MemoryManagerPrivate* d = new(std::nothrow) MemoryManagerPrivate(); _d = (void*)d; } #else -VirtualMemoryManager::VirtualMemoryManager() ASMJIT_NOTHROW +VirtualMemoryManager::VirtualMemoryManager() { MemoryManagerPrivate* d = new(std::nothrow) MemoryManagerPrivate(GetCurrentProcess()); _d = (void*)d; } -VirtualMemoryManager::VirtualMemoryManager(HANDLE hProcess) ASMJIT_NOTHROW +VirtualMemoryManager::VirtualMemoryManager(HANDLE hProcess) { MemoryManagerPrivate* d = new(std::nothrow) MemoryManagerPrivate(hProcess); _d = (void*)d; } #endif // ASMJIT_WINDOWS -VirtualMemoryManager::~VirtualMemoryManager() ASMJIT_NOTHROW +VirtualMemoryManager::~VirtualMemoryManager() { MemoryManagerPrivate* d = reinterpret_cast(_d); delete d; } -void* VirtualMemoryManager::alloc(sysuint_t size, uint32_t type) ASMJIT_NOTHROW +void* VirtualMemoryManager::alloc(size_t size, uint32_t type) { MemoryManagerPrivate* d = reinterpret_cast(_d); - if (type == MEMORY_ALLOC_PERMANENT) + if (type == kMemAllocPermanent) return d->allocPermanent(size); else return d->allocFreeable(size); } -bool VirtualMemoryManager::free(void* address) ASMJIT_NOTHROW +bool VirtualMemoryManager::free(void* address) { MemoryManagerPrivate* d = reinterpret_cast(_d); return d->free(address); } -bool VirtualMemoryManager::shrink(void* address, sysuint_t used) ASMJIT_NOTHROW +bool VirtualMemoryManager::shrink(void* address, size_t used) { MemoryManagerPrivate* d = reinterpret_cast(_d); return d->shrink(address, used); } -void VirtualMemoryManager::freeAll() ASMJIT_NOTHROW +void VirtualMemoryManager::freeAll() { MemoryManagerPrivate* d = reinterpret_cast(_d); @@ -1105,25 +1106,25 @@ void VirtualMemoryManager::freeAll() ASMJIT_NOTHROW return d->freeAll(false); } -sysuint_t VirtualMemoryManager::getUsedBytes() ASMJIT_NOTHROW +size_t VirtualMemoryManager::getUsedBytes() { MemoryManagerPrivate* d = reinterpret_cast(_d); return d->_used; } -sysuint_t VirtualMemoryManager::getAllocatedBytes() ASMJIT_NOTHROW +size_t VirtualMemoryManager::getAllocatedBytes() { MemoryManagerPrivate* d = reinterpret_cast(_d); return d->_allocated; } -bool VirtualMemoryManager::getKeepVirtualMemory() const ASMJIT_NOTHROW +bool VirtualMemoryManager::getKeepVirtualMemory() const { MemoryManagerPrivate* d = reinterpret_cast(_d); return d->_keepVirtualMemory; } -void VirtualMemoryManager::setKeepVirtualMemory(bool keepVirtualMemory) ASMJIT_NOTHROW +void VirtualMemoryManager::setKeepVirtualMemory(bool keepVirtualMemory) { MemoryManagerPrivate* d = reinterpret_cast(_d); d->_keepVirtualMemory = keepVirtualMemory; @@ -1135,7 +1136,7 @@ void VirtualMemoryManager::setKeepVirtualMemory(bool keepVirtualMemory) ASMJIT_N #if defined(ASMJIT_MEMORY_MANAGER_DUMP) -struct ASMJIT_HIDDEN GraphVizContext +struct GraphVizContext { GraphVizContext(); ~GraphVizContext(); @@ -1194,7 +1195,9 @@ void VirtualMemoryManager::dump(const char* fileName) { MemoryManagerPrivate* d = reinterpret_cast(_d); GraphVizContext ctx; - if (!ctx.openFile(fileName)) return; + + if (!ctx.openFile(fileName)) + return; fprintf(ctx.file, "digraph {\n"); if (d->_root) ctx.dumpNode(d->_root); @@ -1205,4 +1208,4 @@ void VirtualMemoryManager::dump(const char* fileName) } // AsmJit namespace // [Api-End] -#include "ApiEnd.h" +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/MemoryManager.h b/desmume/src/utils/AsmJit/core/memorymanager.h similarity index 72% rename from desmume/src/utils/AsmJit/MemoryManager.h rename to desmume/src/utils/AsmJit/core/memorymanager.h index 7d7410757..f95438add 100644 --- a/desmume/src/utils/AsmJit/MemoryManager.h +++ b/desmume/src/utils/AsmJit/core/memorymanager.h @@ -5,15 +5,15 @@ // Zlib - See COPYING file in this package. // [Guard] -#ifndef _ASMJIT_MEMORYMANAGER_H -#define _ASMJIT_MEMORYMANAGER_H +#ifndef _ASMJIT_CORE_MEMORYMANAGER_H +#define _ASMJIT_CORE_MEMORYMANAGER_H -// [Dependencies] -#include "Build.h" -#include "Defs.h" +// [Dependencies - AsmJit] +#include "../core/build.h" +#include "../core/defs.h" // [Api-Begin] -#include "ApiBegin.h" +#include "../core/apibegin.h" // [Debug] // #define ASMJIT_MEMORY_MANAGER_DUMP @@ -32,17 +32,17 @@ namespace AsmJit { //! This class is pure virtual. You can get default virtual memory manager using //! @c getGlobal() method. If you want to create more memory managers with same //! functionality as global memory manager use @c VirtualMemoryManager class. -struct ASMJIT_API MemoryManager +struct MemoryManager { // -------------------------------------------------------------------------- // [Construction / Destruction] // -------------------------------------------------------------------------- //! @brief Create memory manager instance. - MemoryManager() ASMJIT_NOTHROW; + ASMJIT_API MemoryManager(); //! @brief Destroy memory manager instance, this means also to free all memory //! blocks. - virtual ~MemoryManager() ASMJIT_NOTHROW; + ASMJIT_API virtual ~MemoryManager(); // -------------------------------------------------------------------------- // [Interface] @@ -53,62 +53,70 @@ struct ASMJIT_API MemoryManager //! Note that if you are implementing your own virtual memory manager then you //! can quitly ignore type of allocation. This is mainly for AsmJit to memory //! manager that allocated memory will be never freed. - virtual void* alloc(sysuint_t size, uint32_t type = MEMORY_ALLOC_FREEABLE) ASMJIT_NOTHROW = 0; + virtual void* alloc(size_t size, uint32_t type = kMemAllocFreeable) = 0; //! @brief Free previously allocated memory at a given @a address. - virtual bool free(void* address) ASMJIT_NOTHROW = 0; + virtual bool free(void* address) = 0; //! @brief Free some tail memory. - virtual bool shrink(void* address, sysuint_t used) ASMJIT_NOTHROW = 0; + virtual bool shrink(void* address, size_t used) = 0; //! @brief Free all allocated memory. - virtual void freeAll() ASMJIT_NOTHROW = 0; + virtual void freeAll() = 0; //! @brief Get how many bytes are currently used. - virtual sysuint_t getUsedBytes() ASMJIT_NOTHROW = 0; + virtual size_t getUsedBytes() = 0; //! @brief Get how many bytes are currently allocated. - virtual sysuint_t getAllocatedBytes() ASMJIT_NOTHROW = 0; + virtual size_t getAllocatedBytes() = 0; + + // -------------------------------------------------------------------------- + // [Statics] + // -------------------------------------------------------------------------- //! @brief Get global memory manager instance. //! //! Global instance is instance of @c VirtualMemoryManager class. Global memory //! manager is used by default by @ref Assembler::make() and @ref Compiler::make() //! methods. - static MemoryManager* getGlobal() ASMJIT_NOTHROW; + ASMJIT_API static MemoryManager* getGlobal(); }; +// ============================================================================ +// [AsmJit::VirtualMemoryManager] +// ============================================================================ + //! @brief Reference implementation of memory manager that uses //! @ref AsmJit::VirtualMemory class to allocate chunks of virtual memory //! and bit arrays to manage it. -struct ASMJIT_API VirtualMemoryManager : public MemoryManager +struct VirtualMemoryManager : public MemoryManager { // -------------------------------------------------------------------------- // [Construction / Destruction] // -------------------------------------------------------------------------- //! @brief Create a @c VirtualMemoryManager instance. - VirtualMemoryManager() ASMJIT_NOTHROW; + ASMJIT_API VirtualMemoryManager(); #if defined(ASMJIT_WINDOWS) //! @brief Create a @c VirtualMemoryManager instance for process @a hProcess. //! //! This is specialized version of constructor available only for windows and //! usable to alloc/free memory of different process. - VirtualMemoryManager(HANDLE hProcess) ASMJIT_NOTHROW; + ASMJIT_API VirtualMemoryManager(HANDLE hProcess); #endif // ASMJIT_WINDOWS //! @brief Destroy the @c VirtualMemoryManager instance, this means also to //! free all blocks. - virtual ~VirtualMemoryManager() ASMJIT_NOTHROW; + ASMJIT_API virtual ~VirtualMemoryManager(); // -------------------------------------------------------------------------- // [Interface] // -------------------------------------------------------------------------- - virtual void* alloc(sysuint_t size, uint32_t type = MEMORY_ALLOC_FREEABLE) ASMJIT_NOTHROW; - virtual bool free(void* address) ASMJIT_NOTHROW; - virtual bool shrink(void* address, sysuint_t used) ASMJIT_NOTHROW; - virtual void freeAll() ASMJIT_NOTHROW; + ASMJIT_API virtual void* alloc(size_t size, uint32_t type = kMemAllocFreeable); + ASMJIT_API virtual bool free(void* address); + ASMJIT_API virtual bool shrink(void* address, size_t used); + ASMJIT_API virtual void freeAll(); - virtual sysuint_t getUsedBytes() ASMJIT_NOTHROW; - virtual sysuint_t getAllocatedBytes() ASMJIT_NOTHROW; + ASMJIT_API virtual size_t getUsedBytes(); + ASMJIT_API virtual size_t getAllocatedBytes(); // -------------------------------------------------------------------------- // [Virtual Memory Manager Specific] @@ -118,7 +126,7 @@ struct ASMJIT_API VirtualMemoryManager : public MemoryManager //! destroyed. //! //! @sa @c setKeepVirtualMemory(). - bool getKeepVirtualMemory() const ASMJIT_NOTHROW; + ASMJIT_API bool getKeepVirtualMemory() const; //! @brief Set whether to keep allocated memory after memory manager is //! destroyed. @@ -129,10 +137,10 @@ struct ASMJIT_API VirtualMemoryManager : public MemoryManager //! VirtualMemoryManager destructor. After destruction all internal //! structures are freed, only the process virtual memory remains. //! - //! @note Memory allocated with MEMORY_ALLOC_PERMANENT is always kept. + //! @note Memory allocated with kMemAllocPermanent is always kept. //! //! @sa @c getKeepVirtualMemory(). - void setKeepVirtualMemory(bool keepVirtualMemory) ASMJIT_NOTHROW; + ASMJIT_API void setKeepVirtualMemory(bool keepVirtualMemory); // -------------------------------------------------------------------------- // [Debug] @@ -142,14 +150,13 @@ struct ASMJIT_API VirtualMemoryManager : public MemoryManager //! @brief Dump memory manager tree into file. //! //! Generated output is using DOT language (from graphviz package). - void dump(const char* fileName); + ASMJIT_API void dump(const char* fileName); #endif // ASMJIT_MEMORY_MANAGER_DUMP // -------------------------------------------------------------------------- // [Members] // -------------------------------------------------------------------------- -protected: //! @brief Pointer to private data hidden from the public API. void* _d; }; @@ -159,7 +166,7 @@ protected: } // AsmJit namespace // [Api-End] -#include "ApiEnd.h" +#include "../core/apiend.h" // [Guard] -#endif // _ASMJIT_MEMORYMANAGER_H +#endif // _ASMJIT_CORE_MEMORYMANAGER_H diff --git a/desmume/src/utils/AsmJit/MemoryMarker.cpp b/desmume/src/utils/AsmJit/core/memorymarker.cpp similarity index 61% rename from desmume/src/utils/AsmJit/MemoryMarker.cpp rename to desmume/src/utils/AsmJit/core/memorymarker.cpp index adb64ffdd..0b25b4fee 100644 --- a/desmume/src/utils/AsmJit/MemoryMarker.cpp +++ b/desmume/src/utils/AsmJit/core/memorymarker.cpp @@ -4,12 +4,14 @@ // [License] // Zlib - See COPYING file in this package. -// [Dependencies] -#include "Build.h" -#include "MemoryMarker.h" +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/build.h" +#include "../core/memorymarker.h" // [Api-Begin] -#include "ApiBegin.h" +#include "../core/apibegin.h" namespace AsmJit { @@ -17,10 +19,10 @@ namespace AsmJit { // [AsmJit::MemoryMarker] // ============================================================================ -MemoryMarker::MemoryMarker() ASMJIT_NOTHROW {} -MemoryMarker::~MemoryMarker() ASMJIT_NOTHROW {} +MemoryMarker::MemoryMarker() {} +MemoryMarker::~MemoryMarker() {} } // AsmJit namespace // [Api-End] -#include "ApiEnd.h" +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/MemoryMarker.h b/desmume/src/utils/AsmJit/core/memorymarker.h similarity index 67% rename from desmume/src/utils/AsmJit/MemoryMarker.h rename to desmume/src/utils/AsmJit/core/memorymarker.h index ef5038c09..4c5c9db70 100644 --- a/desmume/src/utils/AsmJit/MemoryMarker.h +++ b/desmume/src/utils/AsmJit/core/memorymarker.h @@ -5,15 +5,15 @@ // Zlib - See COPYING file in this package. // [Guard] -#ifndef _ASMJIT_MEMORYMARKER_H -#define _ASMJIT_MEMORYMARKER_H +#ifndef _ASMJIT_CORE_MEMORYMARKER_H +#define _ASMJIT_CORE_MEMORYMARKER_H -// [Dependencies] -#include "Build.h" -#include "Defs.h" +// [Dependencies - AsmJit] +#include "../core/build.h" +#include "../core/defs.h" // [Api-Begin] -#include "ApiBegin.h" +#include "../core/apibegin.h" namespace AsmJit { @@ -25,23 +25,22 @@ namespace AsmJit { // ============================================================================ //! @brief Virtual memory marker interface. -struct ASMJIT_API MemoryMarker +struct MemoryMarker { + ASMJIT_NO_COPY(MemoryMarker) + // -------------------------------------------------------------------------- // [Construction / Destruction] // -------------------------------------------------------------------------- - MemoryMarker() ASMJIT_NOTHROW; - virtual ~MemoryMarker() ASMJIT_NOTHROW; + ASMJIT_API MemoryMarker(); + ASMJIT_API virtual ~MemoryMarker(); // -------------------------------------------------------------------------- // [Interface] // -------------------------------------------------------------------------- - virtual void mark(const void* ptr, sysuint_t size) ASMJIT_NOTHROW = 0; - -private: - ASMJIT_DISABLE_COPY(MemoryMarker) + virtual void mark(const void* ptr, size_t size) = 0; }; //! @} @@ -49,7 +48,7 @@ private: } // AsmJit namespace // [Api-End] -#include "ApiEnd.h" +#include "../core/apiend.h" // [Guard] -#endif // _ASMJIT_MEMORYMARKER_H +#endif // _ASMJIT_CORE_MEMORYMARKER_H diff --git a/desmume/src/utils/AsmJit/Assembler.h b/desmume/src/utils/AsmJit/core/operand.cpp similarity index 52% rename from desmume/src/utils/AsmJit/Assembler.h rename to desmume/src/utils/AsmJit/core/operand.cpp index 2b0b9f578..b382584ac 100644 --- a/desmume/src/utils/AsmJit/Assembler.h +++ b/desmume/src/utils/AsmJit/core/operand.cpp @@ -4,33 +4,39 @@ // [License] // Zlib - See COPYING file in this package. -// [Guard] -#ifndef _ASMJIT_ASSEMBLER_H -#define _ASMJIT_ASSEMBLER_H +#define ASMJIT_EXPORTS -// [Dependencies] -#include "Build.h" +// [Dependencies - AsmJit] +#include "../core/operand.h" + +// [Api-Begin] +#include "../core/apibegin.h" namespace AsmJit { // ============================================================================ -// [Forward Declarations] +// [AsmJit::Operand] // ============================================================================ -struct Logger; -struct MemoryManager; -struct EInstruction; +const Operand noOperand; + +// ============================================================================ +// [AsmJit::Imm] +// ============================================================================ + +//! @brief Create signed immediate value operand. +Imm imm(sysint_t i) +{ + return Imm(i, false); +} + +//! @brief Create unsigned immediate value operand. +Imm uimm(sysuint_t i) +{ + return Imm((sysint_t)i, true); +} } // AsmJit namespace -// ============================================================================ -// [Platform Specific] -// ============================================================================ - -// [X86 / X64] -#if defined(ASMJIT_X86) || defined(ASMJIT_X64) -#include "AssemblerX86X64.h" -#endif // ASMJIT_X86 || ASMJIT_X64 - -// [Guard] -#endif // _ASMJIT_ASSEMBLER_H +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/operand.h b/desmume/src/utils/AsmJit/core/operand.h new file mode 100644 index 000000000..56bec5222 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/operand.h @@ -0,0 +1,585 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_OPERAND_H +#define _ASMJIT_CORE_OPERAND_H + +// [Dependencies - AsmJit] +#include "../core/defs.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::_OperandData] +// ============================================================================ + +//! @internal +//! +//! @brief Base operand data. +struct _OpBase +{ + //! @brief Type of operand, see @c kOperandType. + uint8_t op; + //! @brief Size of operand (register, address, immediate, or variable). + uint8_t size; + //! @brief Not used. + uint8_t reserved[2]; + + //! @brief Operand ID (private variable for @c Assembler and @c Compiler classes). + //! + //! @note Uninitialized operand has always zero id. + uint32_t id; +}; + +//! @internal +//! +//! @brief Label operand data. +struct _OpLabel +{ + //! @brief Type of operand, see @c kOperandType (in this case @c kOperandLabel). + uint8_t op; + //! @brief Size of label, currently not used. + uint8_t size; + //! @brief Not used. + uint8_t reserved[2]; + + //! @brief Operand ID. + uint32_t id; +}; + +//! @internal +//! +//! @brief Register operand data. +struct _OpReg +{ + //! @brief Type of operand, see @c kOperandType (in this case @c kOperandReg). + uint8_t op; + //! @brief Size of register. + uint8_t size; + //! @brief Not used. + uint8_t reserved[2]; + + //! @brief Operand id. + uint32_t id; + //! @brief Register/Variable code, see @c REG. + uint32_t code; +}; + +//! @internal +//! +//! @brief Variable operand data. +struct _OpVar +{ + //! @brief Type of operand, see @c kOperandType (in this case @c kOperandVar). + uint8_t op; + //! @brief Size of variable (0 if don't known). + uint8_t size; + //! @brief Not used. + uint8_t reserved[2]; + + //! @brief Operand ID. + uint32_t id; + + //! @brief Type (and later also code) of register, see @c kX86RegType, @c kX86RegCode. + //! + //! @note Register code and variable code are two different things. In most + //! cases regCode is very related to varType, but general purpose registers + //! are divided to 64-bit, 32-bit, 16-bit and 8-bit entities so the regCode + //! can be used to access these, varType remains unchanged from the + //! initialization state. Variable type describes mainly variable type and + //! home memory size. + uint32_t regCode; + + //! @brief Type of variable. See @c kX86VarType enum. + uint32_t varType; +}; + +//! @internal +//! +//! @brief Memory operand data. +struct _OpMem +{ + //! @brief Type of operand, see @c kOperandType (in this case @c kOperandMem). + uint8_t op; + //! @brief Size of pointer. + uint8_t size; + + //! @brief Memory operand type, see @c kOperandMemType. + uint8_t type; + //! @brief Segment override prefix, see @c kX86Seg. + uint8_t segment : 4; + //! @brief Emit MOV/LEA instruction using 16-bit/32-bit form of base/index + //! registers. + uint8_t sizePrefix : 1; + //! @brief Index register shift/scale (0 to 3 inclusive, see @c kScale). + uint8_t shift : 3; + + //! @brief Operand ID. + uint32_t id; + + //! @brief Base register index, variable or label id. + uint32_t base; + //! @brief Index register index or variable id. + uint32_t index; + + //! @brief Target (for 32-bit, absolute address). + void* target; + //! @brief Displacement. + sysint_t displacement; +}; + +//! @internal +//! +//! @brief Immediate operand data. +struct _OpImm +{ + //! @brief Type of operand, see @c kOperandType (in this case @c kOperandImm).. + uint8_t op; + //! @brief Size of immediate (or 0 to autodetect). + uint8_t size; + //! @brief @c true if immediate is unsigned. + uint8_t isUnsigned; + //! @brief Not used. + uint8_t reserved; + + //! @brief Operand ID. + uint32_t id; + //! @brief Immediate value. + sysint_t value; +}; + +//! @internal +//! +//! @brief Binary operand data. +struct _OpBin +{ + //! @brief First four 32-bit integers. + uint32_t u32[4]; + //! @brief Second two 32-bit or 64-bit integers. + uintptr_t uptr[2]; +}; + +// ============================================================================ +// [AsmJit::Operand] +// ============================================================================ + +//! @brief Operand can contain register, memory location, immediate, or label. +struct Operand +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create an uninitialized operand. + inline Operand() + { + memset(this, 0, sizeof(Operand)); + _base.id = kInvalidValue; + } + + //! @brief Create a reference to @a other operand. + inline Operand(const Operand& other) + { + _init(other); + } + +#if !defined(ASMJIT_NODOC) + inline Operand(const _DontInitialize&) {} +#endif // ASMJIT_NODOC + + // -------------------------------------------------------------------------- + // [Init & Copy] + // -------------------------------------------------------------------------- + + //! @internal + //! + //! @brief Initialize operand to @a other (used by constructors). + inline void _init(const Operand& other) + { memcpy(this, &other, sizeof(Operand)); } + + //! @internal + //! + //! @brief Initialize operand to @a other (used by assign operators). + inline void _copy(const Operand& other) + { memcpy(this, &other, sizeof(Operand)); } + + // -------------------------------------------------------------------------- + // [Data] + // -------------------------------------------------------------------------- + + template + inline T& getData() { return reinterpret_cast(_base); } + + template + inline const T& getData() const { return reinterpret_cast(_base); } + + // -------------------------------------------------------------------------- + // [Type] + // -------------------------------------------------------------------------- + + //! @brief Get type of the operand, see @c kOperandType. + inline uint32_t getType() const + { return _base.op; } + + //! @brief Get whether the operand is none (@c kOperandNone). + inline bool isNone() const + { return (_base.op == kOperandNone); } + + //! @brief Get whether the operand is any (general purpose, mmx or sse) register (@c kOperandReg). + inline bool isReg() const + { return (_base.op == kOperandReg); } + + //! @brief Get whether the operand is memory address (@c kOperandMem). + inline bool isMem() const + { return (_base.op == kOperandMem); } + + //! @brief Get whether the operand is immediate (@c kOperandImm). + inline bool isImm() const + { return (_base.op == kOperandImm); } + + //! @brief Get whether the operand is label (@c kOperandLabel). + inline bool isLabel() const + { return (_base.op == kOperandLabel); } + + //! @brief Get whether the operand is variable (@c kOperandVar). + inline bool isVar() const + { return (_base.op == kOperandVar); } + + //! @brief Get whether the operand is variable or memory. + inline bool isVarMem() const + { return ((_base.op & (kOperandVar | kOperandMem)) != 0); } + + //! @brief Get whether the operand is register and type of register is @a regType. + inline bool isRegType(uint32_t regType) const + { return (_base.op == kOperandReg) & ((_reg.code & kRegTypeMask) == regType); } + + //! @brief Get whether the operand is register and code of register is @a regCode. + inline bool isRegCode(uint32_t regCode) const + { return (_base.op == kOperandReg) & (_reg.code == regCode); } + + //! @brief Get whether the operand is register and index of register is @a regIndex. + inline bool isRegIndex(uint32_t regIndex) const + { return (_base.op == kOperandReg) & ((_reg.code & kRegIndexMask) == (regIndex & kRegIndexMask)); } + + //! @brief Get whether the operand is any register or memory. + inline bool isRegMem() const + { return ((_base.op & (kOperandReg | kOperandMem)) != 0); } + + //! @brief Get whether the operand is register of @a regType type or memory. + inline bool isRegTypeMem(uint32_t regType) const + { return ((_base.op == kOperandReg) & ((_reg.code & kRegTypeMask) == regType)) | (_base.op == kOperandMem); } + + // -------------------------------------------------------------------------- + // [Size] + // -------------------------------------------------------------------------- + + //! @brief Get size of the operand in bytes. + inline uint32_t getSize() const + { return _base.size; } + + // -------------------------------------------------------------------------- + // [Id] + // -------------------------------------------------------------------------- + + //! @brief Return operand Id (Operand Id's are used internally by + //! @c Assembler and @c Compiler classes). + //! + //! @note There is no way how to change or remove operand id. If you don't + //! need the operand just assign different operand to this one. + inline uint32_t getId() const + { return _base.id; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + union + { + //! @brief Base operand data. + _OpBase _base; + //! @brief Label operand data. + _OpLabel _lbl; + //! @brief Register operand data. + _OpReg _reg; + //! @brief Variable operand data. + _OpVar _var; + //! @brief Memory operand data. + _OpMem _mem; + //! @brief Immediate operand data. + _OpImm _imm; + //! @brief Binary data. + _OpBin _bin; + }; +}; + +ASMJIT_VAR const Operand noOperand; + +// ============================================================================ +// [AsmJit::Reg] +// ============================================================================ + +//! @brief Base class for all register operands. +struct Reg : public Operand +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new base register. + inline Reg(uint32_t code, uint32_t size) : Operand(_DontInitialize()) + { + _reg.op = kOperandReg; + _reg.size = (uint8_t)size; + _reg.id = kInvalidValue; + _reg.code = code; + } + + //! @brief Create a new reference to @a other. + inline Reg(const Reg& other) : Operand(other) {} + +#if !defined(ASMJIT_NODOC) + inline Reg(const _DontInitialize& dontInitialize) : Operand(dontInitialize) {} +#endif // ASMJIT_NODOC + + // -------------------------------------------------------------------------- + // [Reg Specific] + // -------------------------------------------------------------------------- + + //! @brief Get register code, see @c REG. + inline uint32_t getRegCode() const + { return (uint32_t)(_reg.code); } + + //! @brief Get register type, see @c REG. + inline uint32_t getRegType() const + { return (uint32_t)(_reg.code & kRegTypeMask); } + + //! @brief Get register index (value from 0 to 7/15). + inline uint32_t getRegIndex() const + { return (uint32_t)(_reg.code & kRegIndexMask); } + + //! @brief Get whether register code is equal to @a code. + inline bool isRegCode(uint32_t code) const + { return _reg.code == code; } + + //! @brief Get whether register code is equal to @a type. + inline bool isRegType(uint32_t type) const + { return (uint32_t)(_reg.code & kRegTypeMask) == type; } + + //! @brief Get whether register index is equal to @a index. + inline bool isRegIndex(uint32_t index) const + { return (uint32_t)(_reg.code & kRegIndexMask) == index; } + + //! @brief Set register code to @a code. + inline Reg& setCode(uint32_t code) + { + _reg.code = code; + return *this; + } + + //! @brief Set register size to @a size. + inline Reg& setSize(uint32_t size) + { + _reg.size = static_cast(size); + return *this; + } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + inline Reg& operator=(const Reg& other) + { _copy(other); return *this; } + + inline bool operator==(const Reg& other) const + { return getRegCode() == other.getRegCode(); } + + inline bool operator!=(const Reg& other) const + { return getRegCode() != other.getRegCode(); } +}; + +// ============================================================================ +// [AsmJit::Imm] +// ============================================================================ + +//! @brief Immediate operand. +//! +//! Immediate operand is part of instruction (it's inlined after it). +//! +//! To create immediate operand, use @c imm() and @c uimm() constructors +//! or constructors provided by @c Immediate class itself. +struct Imm : public Operand +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new immediate value (initial value is 0). + Imm() : Operand(_DontInitialize()) + { + _imm.op = kOperandImm; + _imm.size = 0; + _imm.isUnsigned = false; + _imm.reserved = 0; + + _imm.id = kInvalidValue; + _imm.value = 0; + } + + //! @brief Create a new signed immediate value, assigning the value to @a i. + Imm(sysint_t i) : Operand(_DontInitialize()) + { + _imm.op = kOperandImm; + _imm.size = 0; + _imm.isUnsigned = false; + _imm.reserved = 0; + + _imm.id = kInvalidValue; + _imm.value = i; + } + + //! @brief Create a new signed or unsigned immediate value, assigning the value to @a i. + Imm(sysint_t i, bool isUnsigned) : Operand(_DontInitialize()) + { + _imm.op = kOperandImm; + _imm.size = 0; + _imm.isUnsigned = isUnsigned; + _imm.reserved = 0; + + _imm.id = kInvalidValue; + _imm.value = i; + } + + //! @brief Create a new immediate value from @a other. + inline Imm(const Imm& other) : Operand(other) + { + } + + // -------------------------------------------------------------------------- + // [Immediate Specific] + // -------------------------------------------------------------------------- + + //! @brief Get whether an immediate is unsigned value. + inline bool isUnsigned() const + { return _imm.isUnsigned != 0; } + + //! @brief Get signed immediate value. + inline sysint_t getValue() const + { return _imm.value; } + + //! @brief Get unsigned immediate value. + inline sysuint_t getUValue() const + { return static_cast(_imm.value); } + + //! @brief Set immediate value as signed type to @a val. + inline Imm& setValue(sysint_t val, bool isUnsigned = false) + { + _imm.value = val; + _imm.isUnsigned = isUnsigned; + return *this; + } + + //! @brief Set immediate value as unsigned type to @a val. + inline Imm& setUValue(sysuint_t val) + { + _imm.value = (sysint_t)val; + _imm.isUnsigned = true; + return *this; + } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + //! @brief Assign a signed value @a val to the immediate operand. + inline Imm& operator=(sysint_t val) + { setValue(val); return *this; } + + //! @brief Assign @a other to the immediate operand. + inline Imm& operator=(const Imm& other) + { _copy(other); return *this; } +}; + +//! @brief Create signed immediate value operand. +ASMJIT_API Imm imm(sysint_t i); + +//! @brief Create unsigned immediate value operand. +ASMJIT_API Imm uimm(sysuint_t i); + +// ============================================================================ +// [AsmJit::Label] +// ============================================================================ + +//! @brief Label (jump target or data location). +//! +//! Label represents locations typically used as jump targets, but may be also +//! used as position where are stored constants or static variables. If you +//! want to use @c Label you need first to associate it with @c Assembler or +//! @c Compiler instance. To create new label use @c Assembler::newLabel() or +//! @c Compiler::newLabel(). +//! +//! Example of using labels: +//! +//! @code +//! // Create Assembler or Compiler instance. +//! X86Assembler a; +//! +//! // Create Label instance. +//! Label L_1(a); +//! +//! // ... your code ... +//! +//! // Using label, see @c AsmJit::Assembler or @c AsmJit::Compiler. +//! a.jump(L_1); +//! +//! // ... your code ... +//! +//! // Bind label to current position, see @c AsmJit::Assembler::bind() or +//! // @c AsmJit::Compiler::bind(). +//! a.bind(L_1); +//! @endcode +struct Label : public Operand +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create new, unassociated label. + inline Label() : Operand(_DontInitialize()) + { + _lbl.op = kOperandLabel; + _lbl.size = 0; + _lbl.id = kInvalidValue; + } + + //! @brief Create reference to another label. + inline Label(const Label& other) : Operand(other) {} + + //! @brief Destroy the label. + inline ~Label() {} + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline Label& operator=(const Label& other) + { _copy(other); return *this; } + + inline bool operator==(const Label& other) const { return _base.id == other._base.id; } + inline bool operator!=(const Label& other) const { return _base.id != other._base.id; } +#endif // ASMJIT_NODOC +}; + +//! @} + +} // AsmJit namespace + +// [Guard] +#endif // _ASMJIT_CORE_OPERAND_H diff --git a/desmume/src/utils/AsmJit/core/podvector.h b/desmume/src/utils/AsmJit/core/podvector.h new file mode 100644 index 000000000..d94edf46d --- /dev/null +++ b/desmume/src/utils/AsmJit/core/podvector.h @@ -0,0 +1,224 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_PODVECTOR_H +#define _ASMJIT_CORE_PODVECTOR_H + +// [Dependencies - AsmJit] +#include "../core/assert.h" +#include "../core/defs.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::PodVector] +// ============================================================================ + +//! @brief Template used to store and manage array of POD data. +//! +//! This template has these adventages over other vector<> templates: +//! - Non-copyable (designed to be non-copyable, we want it) +//! - No copy-on-write (some implementations of stl can use it) +//! - Optimized for working only with POD types +//! - Uses ASMJIT_... memory management macros +template +struct PodVector +{ + ASMJIT_NO_COPY(PodVector) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create new instance of PodVector template. Data will not + //! be allocated (will be NULL). + inline PodVector() : + _data(NULL), + _length(0), + _capacity(0) + { + } + + //! @brief Destroy PodVector and free all data. + inline ~PodVector() + { + if (_data != NULL) + ASMJIT_FREE(_data); + } + + // -------------------------------------------------------------------------- + // [Data] + // -------------------------------------------------------------------------- + + //! @brief Get data. + inline T* getData() { return _data; } + //! @overload + inline const T* getData() const { return _data; } + + //! @brief Get length. + inline size_t getLength() const { return _length; } + //! @brief Get capacity. + inline size_t getCapacity() const { return _capacity; } + + // -------------------------------------------------------------------------- + // [Manipulation] + // -------------------------------------------------------------------------- + + //! @brief Clear vector data, but not free internal buffer. + void clear() + { + _length = 0; + } + + //! @brief Clear vector data and free internal buffer. + void reset() + { + if (_data != NULL) + { + ASMJIT_FREE(_data); + _data = 0; + _length = 0; + _capacity = 0; + } + } + + //! @brief Prepend @a item to vector. + bool prepend(const T& item) + { + if (_length == _capacity && !_grow()) return false; + + memmove(_data + 1, _data, sizeof(T) * _length); + memcpy(_data, &item, sizeof(T)); + + _length++; + return true; + } + + //! @brief Insert an @a item at the @a index. + bool insert(size_t index, const T& item) + { + ASMJIT_ASSERT(index <= _length); + if (_length == _capacity && !_grow()) return false; + + T* dst = _data + index; + memmove(dst + 1, dst, _length - index); + memcpy(dst, &item, sizeof(T)); + + _length++; + return true; + } + + //! @brief Append @a item to vector. + bool append(const T& item) + { + if (_length == _capacity && !_grow()) return false; + + memcpy(_data + _length, &item, sizeof(T)); + + _length++; + return true; + } + + //! @brief Get index of @a val or kInvalidSize if not found. + size_t indexOf(const T& val) const + { + size_t i = 0, len = _length; + for (i = 0; i < len; i++) { if (_data[i] == val) return i; } + return kInvalidSize; + } + + //! @brief Remove element at index @a i. + void removeAt(size_t i) + { + ASMJIT_ASSERT(i < _length); + + T* dst = _data + i; + _length--; + memmove(dst, dst + 1, _length - i); + } + + //! @brief Swap this pod-vector with @a other. + void swap(PodVector& other) + { + T* _tmp_data = _data; + size_t _tmp_length = _length; + size_t _tmp_capacity = _capacity; + + _data = other._data; + _length = other._length; + _capacity = other._capacity; + + other._data = _tmp_data; + other._length = _tmp_length; + other._capacity = _tmp_capacity; + } + + //! @brief Get item at position @a i. + inline T& operator[](size_t i) + { + ASMJIT_ASSERT(i < _length); + return _data[i]; + } + //! @brief Get item at position @a i. + inline const T& operator[](size_t i) const + { + ASMJIT_ASSERT(i < _length); + return _data[i]; + } + + //! @brief Append the item and return address so it can be initialized. + T* newItem() + { + if (_length == _capacity && !_grow()) return NULL; + return _data + (_length++); + } + + // -------------------------------------------------------------------------- + // [Private] + // -------------------------------------------------------------------------- + + //! @brief Called to grow internal array. + bool _grow() + { + return _realloc(_capacity < 16 ? 16 : _capacity * 2); + } + + //! @brief Realloc internal array to fit @a to items. + bool _realloc(size_t to) + { + ASMJIT_ASSERT(to >= _length); + + T* p = reinterpret_cast(_data ? ASMJIT_REALLOC(_data, to * sizeof(T)) : ASMJIT_MALLOC(to * sizeof(T))); + + if (p == NULL) + return false; + + _data = p; + _capacity = to; + return true; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Items data. + T* _data; + //! @brief Length of buffer (count of items in array). + size_t _length; + //! @brief Capacity of buffer (maximum items that can fit to current array). + size_t _capacity; +}; + +//! @} + +} // AsmJit namespace + +#endif // _ASMJIT_CORE_PODVECTOR_H diff --git a/desmume/src/utils/AsmJit/core/stringbuilder.cpp b/desmume/src/utils/AsmJit/core/stringbuilder.cpp new file mode 100644 index 000000000..fc6b6dd56 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/stringbuilder.cpp @@ -0,0 +1,401 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/defs.h" +#include "../core/intutil.h" +#include "../core/stringbuilder.h" + +// [Dependencies - C] +#include + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// Should be placed in read-only memory. +static const char StringBuilder_empty[4] = { 0 }; + +// ============================================================================ +// [AsmJit::StringBuilder - Construction / Destruction] +// ============================================================================ + +StringBuilder::StringBuilder() : + _data(const_cast(StringBuilder_empty)), + _length(0), + _capacity(0), + _canFree(false) +{ +} + +StringBuilder::~StringBuilder() +{ + if (_canFree) + ASMJIT_FREE(_data); +} + +// ============================================================================ +// [AsmJit::StringBuilder - Prepare / Reserve] +// ============================================================================ + +char* StringBuilder::prepare(uint32_t op, size_t len) +{ + // -------------------------------------------------------------------------- + // [Set] + // -------------------------------------------------------------------------- + + if (op == kStringBuilderOpSet) + { + // We don't care here, but we can't return a NULL pointer since it indicates + // failure in memory allocation. + if (len == 0) + { + if (_data != StringBuilder_empty) + _data[0] = 0; + + _length = 0; + return _data; + } + + if (_capacity < len) + { + if (len >= IntUtil::maxValue() - sizeof(uintptr_t) * 2) + return NULL; + + size_t to = IntUtil::align(len, sizeof(uintptr_t)); + if (to < 256 - sizeof(uintptr_t)) + to = 256 - sizeof(uintptr_t); + + char* newData = static_cast(ASMJIT_MALLOC(to + sizeof(uintptr_t))); + if (newData == NULL) + { + clear(); + return NULL; + } + + if (_canFree) + ASMJIT_FREE(_data); + + _data = newData; + _capacity = to + sizeof(uintptr_t) - 1; + _canFree = true; + } + + _data[len] = 0; + _length = len; + + ASMJIT_ASSERT(_length <= _capacity); + return _data; + } + + // -------------------------------------------------------------------------- + // [Append] + // -------------------------------------------------------------------------- + + else + { + // We don't care here, but we can't return a NULL pointer since it indicates + // failure in memory allocation. + if (len == 0) + return _data + _length; + + // Overflow. + if (IntUtil::maxValue() - sizeof(uintptr_t) * 2 - _length < len) + return NULL; + + size_t after = _length + len; + if (_capacity < after) + { + size_t to = _capacity; + + if (to < 256) + to = 256; + + while (to < 1024 * 1024 && to < after) + { + to *= 2; + } + + if (to < after) + { + to = after; + if (to < (IntUtil::maxValue() - 1024 * 32)) + to = IntUtil::align(to, 1024 * 32); + } + + to = IntUtil::align(to, sizeof(uintptr_t)); + char* newData = static_cast(ASMJIT_MALLOC(to + sizeof(uintptr_t))); + + if (newData == NULL) + return NULL; + + ::memcpy(newData, _data, _length); + + if (_canFree) + ASMJIT_FREE(_data); + + _data = newData; + _capacity = to + sizeof(uintptr_t) - 1; + _canFree = true; + } + + char* ret = _data + _length; + _data[after] = 0; + _length = after; + + ASMJIT_ASSERT(_length <= _capacity); + return ret; + } +} + +bool StringBuilder::reserve(size_t to) +{ + if (_capacity >= to) + return true; + + if (to >= IntUtil::maxValue() - sizeof(uintptr_t) * 2) + return false; + + to = IntUtil::align(to, sizeof(uintptr_t)); + + char* newData = static_cast(ASMJIT_MALLOC(to + sizeof(uintptr_t))); + if (newData == NULL) + return false; + + ::memcpy(newData, _data, _length + 1); + if (_canFree) + ASMJIT_FREE(_data); + + _data = newData; + _capacity = to + sizeof(uintptr_t) - 1; + _canFree = true; + return true; +} + +// ============================================================================ +// [AsmJit::StringBuilder - Clear] +// ============================================================================ + +void StringBuilder::clear() +{ + if (_data != StringBuilder_empty) + _data[0] = 0; + _length = 0; +} + +// ============================================================================ +// [AsmJit::StringBuilder - Methods] +// ============================================================================ + +bool StringBuilder::_opString(uint32_t op, const char* str, size_t len) +{ + if (len == kInvalidSize) + len = ::strlen(str); + + char* p = prepare(op, len); + if (p == NULL) + return false; + + ::memcpy(p, str, len); + return true; +} + +bool StringBuilder::_opChars(uint32_t op, char c, size_t len) +{ + char* p = prepare(op, len); + if (p == NULL) + return false; + + ::memset(p, c, len); + return true; +} + +static const char StringBuilder_numbers[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +bool StringBuilder::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) +{ + if (base < 2 || base > 36) + base = 10; + + char buf[128]; + char* p = buf + ASMJIT_ARRAY_SIZE(buf); + + uint64_t orig = i; + char sign = '\0'; + + // -------------------------------------------------------------------------- + // [Sign] + // -------------------------------------------------------------------------- + + if ((flags & kStringBuilderNumSigned) != 0 && static_cast(i) < 0) + { + i = static_cast(-static_cast(i)); + sign = '-'; + } + else if ((flags & kStringBuilderNumShowSign) != 0) + { + sign = '+'; + } + else if ((flags & kStringBuilderNumShowSpace) != 0) + { + sign = ' '; + } + + // -------------------------------------------------------------------------- + // [Number] + // -------------------------------------------------------------------------- + + do { + uint64_t d = i / base; + uint64_t r = i % base; + + *--p = StringBuilder_numbers[r]; + i = d; + } while (i); + + size_t numberLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p); + + // -------------------------------------------------------------------------- + // [Alternate Form] + // -------------------------------------------------------------------------- + + if ((flags & kStringBuilderNumAlternate) != 0) + { + if (base == 8) + { + if (orig != 0) + *--p = '0'; + } + if (base == 16) + { + *--p = 'x'; + *--p = '0'; + } + } + + // -------------------------------------------------------------------------- + // [Width] + // -------------------------------------------------------------------------- + + if (sign != 0) + *--p = sign; + + if (width > 256) + width = 256; + + if (width <= numberLength) + width = 0; + else + width -= numberLength; + + // -------------------------------------------------------------------------- + // Write] + // -------------------------------------------------------------------------- + + size_t prefixLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p) - numberLength; + char* data = prepare(op, prefixLength + width + numberLength); + + if (data == NULL) + return false; + + ::memcpy(data, p, prefixLength); + data += prefixLength; + + ::memset(data, '0', width); + data += width; + + ::memcpy(data, p + prefixLength, numberLength); + return true; +} + +bool StringBuilder::_opHex(uint32_t op, const void* data, size_t len) +{ + if (len >= IntUtil::maxValue() / 2) + return false; + + char* dst = prepare(op, len); + if (dst == NULL) + return false; + + const char* src = static_cast(data); + for (size_t i = 0; i < len; i++, dst += 2, src += 1) + { + dst[0] = StringBuilder_numbers[(src[0] >> 4) & 0xF]; + dst[1] = StringBuilder_numbers[(src[0] ) & 0xF]; + } + + return true; +} + +bool StringBuilder::_opVFormat(uint32_t op, const char* fmt, va_list ap) +{ + char buf[1024]; + + vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap); + buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0'; + + return _opString(op, buf); +} + +bool StringBuilder::setFormat(const char* fmt, ...) +{ + bool result; + + va_list ap; + va_start(ap, fmt); + result = _opVFormat(kStringBuilderOpSet, fmt, ap); + va_end(ap); + + return result; +} + +bool StringBuilder::appendFormat(const char* fmt, ...) +{ + bool result; + + va_list ap; + va_start(ap, fmt); + result = _opVFormat(kStringBuilderOpAppend, fmt, ap); + va_end(ap); + + return result; +} + +bool StringBuilder::eq(const char* str, size_t len) const +{ + const char* aData = _data; + const char* bData = str; + + size_t aLength = _length; + size_t bLength = len; + + if (bLength == kInvalidSize) + { + size_t i; + for (i = 0; i < aLength; i++) + { + if (aData[i] != bData[i] || bData[i] == 0) + return false; + } + + return bData[i] == 0; + } + else + { + if (aLength != bLength) + return false; + + return ::memcmp(aData, bData, aLength) == 0; + } +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/stringbuilder.h b/desmume/src/utils/AsmJit/core/stringbuilder.h new file mode 100644 index 000000000..d4f20d96e --- /dev/null +++ b/desmume/src/utils/AsmJit/core/stringbuilder.h @@ -0,0 +1,197 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_STRINGBUILDER_H +#define _ASMJIT_CORE_STRINGBUILDER_H + +// [Dependencies - AsmJit] +#include "../core/assert.h" +#include "../core/defs.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::StringBuilder] +// ============================================================================ + +//! @brief String builder. +//! +//! String builder was designed to be able to build a string using append like +//! operation to append numbers, other strings, or signle characters. It can +//! allocate it's own buffer or use a buffer created on the stack. +//! +//! String builder contains method specific to AsmJit functionality, used for +//! logging or HTML output. +struct StringBuilder +{ + ASMJIT_NO_COPY(StringBuilder) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_API StringBuilder(); + ASMJIT_API ~StringBuilder(); + + inline StringBuilder(const _DontInitialize&) {} + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get string builder capacity. + inline size_t getCapacity() const + { return _capacity; } + + //! @brief Get length. + inline size_t getLength() const + { return _length; } + + //! @brief Get null-terminated string data. + inline char* getData() + { return _data; } + + //! @brief Get null-terminated string data (const). + inline const char* getData() const + { return _data; } + + // -------------------------------------------------------------------------- + // [Prepare / Reserve] + // -------------------------------------------------------------------------- + + //! @brief Prepare to set/append. + ASMJIT_API char* prepare(uint32_t op, size_t len); + + //! @brief Reserve @a to bytes in string builder. + ASMJIT_API bool reserve(size_t to); + + // -------------------------------------------------------------------------- + // [Clear] + // -------------------------------------------------------------------------- + + //! @brief Clear the content in String builder. + ASMJIT_API void clear(); + + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + ASMJIT_API bool _opString(uint32_t op, const char* str, size_t len = kInvalidSize); + ASMJIT_API bool _opVFormat(uint32_t op, const char* fmt, va_list ap); + ASMJIT_API bool _opChars(uint32_t op, char c, size_t len); + ASMJIT_API bool _opNumber(uint32_t op, uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0); + ASMJIT_API bool _opHex(uint32_t op, const void* data, size_t length); + + //! @brief Replace the current content by @a str of @a len. + inline bool setString(const char* str, size_t len = kInvalidSize) + { return _opString(kStringBuilderOpSet, str, len); } + + //! @brief Replace the current content by formatted string @a fmt. + inline bool setVFormat(const char* fmt, va_list ap) + { return _opVFormat(kStringBuilderOpSet, fmt, ap); } + + //! @brief Replace the current content by formatted string @a fmt. + ASMJIT_API bool setFormat(const char* fmt, ...); + + //! @brief Replace the current content by @a c of @a len. + inline bool setChars(char c, size_t len) + { return _opChars(kStringBuilderOpSet, c, len); } + + //! @brief Replace the current content by @a i.. + inline bool setNumber(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) + { return _opNumber(kStringBuilderOpSet, i, base, width, flags); } + + //! @brief Append @a str of @a len. + inline bool appendString(const char* str, size_t len = kInvalidSize) + { return _opString(kStringBuilderOpAppend, str, len); } + + //! @brief Append a formatted string @a fmt to the current content. + inline bool appendVFormat(const char* fmt, va_list ap) + { return _opVFormat(kStringBuilderOpAppend, fmt, ap); } + + //! @brief Append a formatted string @a fmt to the current content. + ASMJIT_API bool appendFormat(const char* fmt, ...); + + //! @brief Append @a c of @a len. + inline bool appendChars(char c, size_t len) + { return _opChars(kStringBuilderOpAppend, c, len); } + + //! @brief Append @a i. + inline bool appendNumber(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) + { return _opNumber(kStringBuilderOpAppend, i, base, width, flags); } + + //! @brief Check for equality with other @a str. + ASMJIT_API bool eq(const char* str, size_t len = kInvalidSize) const; + + //! @brief Check for equality with StringBuilder @a other. + inline bool eq(const StringBuilder& other) const + { return eq(other._data); } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + + inline bool operator==(const StringBuilder& other) const { return eq(other); } + inline bool operator!=(const StringBuilder& other) const { return !eq(other); } + + inline bool operator==(const char* str) const { return eq(str); } + inline bool operator!=(const char* str) const { return !eq(str); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief String data. + char* _data; + //! @brief Length. + size_t _length; + //! @brief Capacity. + size_t _capacity; + //! @brief Whether the string can be freed. + size_t _canFree; +}; + +// ============================================================================ +// [AsmJit::StringBuilderT] +// ============================================================================ + +template +struct StringBuilderT : public StringBuilder +{ + ASMJIT_NO_COPY(StringBuilderT) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + inline StringBuilderT() : + StringBuilder(_DontInitialize()) + { + _data = _embeddedData; + _data[0] = 0; + + _length = 0; + _capacity = 0; + _canFree = false; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Embedded data. + char _embeddedData[(N + sizeof(uintptr_t)) & ~(sizeof(uintptr_t) - 1)]; +}; + +//! @} + +} // AsmJit namespace + +#endif // _ASMJIT_CORE_STRINGBUILDER_H diff --git a/desmume/src/utils/AsmJit/core/stringutil.cpp b/desmume/src/utils/AsmJit/core/stringutil.cpp new file mode 100644 index 000000000..1343adb7d --- /dev/null +++ b/desmume/src/utils/AsmJit/core/stringutil.cpp @@ -0,0 +1,90 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/assert.h" +#include "../core/stringutil.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::StringUtil] +// ============================================================================ + +static const char letters[] = "0123456789ABCDEF"; + +char* StringUtil::copy(char* dst, const char* src, size_t len) +{ + if (src == NULL) + return dst; + + if (len == kInvalidSize) + { + while (*src) *dst++ = *src++; + } + else + { + memcpy(dst, src, len); + dst += len; + } + + return dst; +} + +char* StringUtil::fill(char* dst, const int c, size_t len) +{ + memset(dst, c, len); + return dst + len; +} + +char* StringUtil::hex(char* dst, const uint8_t* src, size_t len) +{ + for (size_t i = len; i; i--, dst += 2, src += 1) + { + dst[0] = letters[(src[0] >> 4) & 0xF]; + dst[1] = letters[(src[0] ) & 0xF]; + } + + return dst; +} + +// Not too efficient, but this is mainly for debugging:) +char* StringUtil::utoa(char* dst, uintptr_t i, size_t base) +{ + ASMJIT_ASSERT(base <= 16); + + char buf[128]; + char* p = buf + 128; + + do { + uintptr_t b = i % base; + *--p = letters[b]; + i /= base; + } while (i); + + return StringUtil::copy(dst, p, (size_t)(buf + 128 - p)); +} + +char* StringUtil::itoa(char* dst, intptr_t i, size_t base) +{ + if (i < 0) + { + *dst++ = '-'; + i = -i; + } + + return StringUtil::utoa(dst, (size_t)i, base); +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/stringutil.h b/desmume/src/utils/AsmJit/core/stringutil.h new file mode 100644 index 000000000..a5272037d --- /dev/null +++ b/desmume/src/utils/AsmJit/core/stringutil.h @@ -0,0 +1,43 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_STRINGUTIL_H +#define _ASMJIT_CORE_STRINGUTIL_H + +// [Dependencies - AsmJit] +#include "../core/defs.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::StringUtil] +// ============================================================================ + +//! @brief String utilities. +struct StringUtil +{ + ASMJIT_API static char* copy(char* dst, const char* src, size_t len = kInvalidSize); + ASMJIT_API static char* fill(char* dst, const int c, size_t len); + ASMJIT_API static char* hex(char* dst, const uint8_t* src, size_t len); + + ASMJIT_API static char* utoa(char* dst, uintptr_t i, size_t base = 10); + ASMJIT_API static char* itoa(char* dst, intptr_t i, size_t base = 10); + + static inline void memset32(uint32_t* p, uint32_t c, size_t len) + { + for (size_t i = 0; i < len; i++) p[i] = c; + } +}; + +//! @} + +} // AsmJit namespace + +#endif // _ASMJIT_CORE_STRINGUTIL_H diff --git a/desmume/src/utils/AsmJit/core/virtualmemory.cpp b/desmume/src/utils/AsmJit/core/virtualmemory.cpp new file mode 100644 index 000000000..32c51b193 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/virtualmemory.cpp @@ -0,0 +1,173 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/intutil.h" +#include "../core/virtualmemory.h" + +// [Dependencies - Windows] +#if defined(ASMJIT_WINDOWS) +# include +#endif // ASMJIT_WINDOWS + +// [Dependencies - Posix] +#if defined(ASMJIT_POSIX) +# include +# include +# include +#endif // ASMJIT_POSIX + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::VirtualMemory - Windows] +// ============================================================================ + +#if defined(ASMJIT_WINDOWS) +struct VirtualMemoryLocal +{ + VirtualMemoryLocal() + + { + SYSTEM_INFO info; + GetSystemInfo(&info); + + alignment = info.dwAllocationGranularity; + pageSize = IntUtil::roundUpToPowerOf2(info.dwPageSize); + } + + size_t alignment; + size_t pageSize; +}; + +static VirtualMemoryLocal& vm() + +{ + static VirtualMemoryLocal vm; + return vm; +}; + +void* VirtualMemory::alloc(size_t length, size_t* allocated, bool canExecute) + +{ + return allocProcessMemory(GetCurrentProcess(), length, allocated, canExecute); +} + +void VirtualMemory::free(void* addr, size_t length) + +{ + return freeProcessMemory(GetCurrentProcess(), addr, length); +} + +void* VirtualMemory::allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, bool canExecute) + +{ + // VirtualAlloc rounds allocated size to page size automatically. + size_t msize = IntUtil::roundUp(length, vm().pageSize); + + // Windows XP SP2 / Vista allow Data Excution Prevention (DEP). + WORD protect = canExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; + LPVOID mbase = VirtualAllocEx(hProcess, NULL, msize, MEM_COMMIT | MEM_RESERVE, protect); + if (mbase == NULL) return NULL; + + ASMJIT_ASSERT(IntUtil::isAligned(reinterpret_cast(mbase), vm().alignment)); + + if (allocated != NULL) + *allocated = msize; + return mbase; +} + +void VirtualMemory::freeProcessMemory(HANDLE hProcess, void* addr, size_t /* length */) + +{ + VirtualFreeEx(hProcess, addr, 0, MEM_RELEASE); +} + +size_t VirtualMemory::getAlignment() + +{ + return vm().alignment; +} + +size_t VirtualMemory::getPageSize() + +{ + return vm().pageSize; +} +#endif // ASMJIT_WINDOWS + +// ============================================================================ +// [AsmJit::VirtualMemory - Posix] +// ============================================================================ + +#if defined(ASMJIT_POSIX) + +// MacOS uses MAP_ANON instead of MAP_ANONYMOUS. +#if !defined(MAP_ANONYMOUS) +# define MAP_ANONYMOUS MAP_ANON +#endif // MAP_ANONYMOUS + +struct VirtualMemoryLocal +{ + VirtualMemoryLocal() + { + alignment = pageSize = ::getpagesize(); + } + + size_t alignment; + size_t pageSize; +}; + +static VirtualMemoryLocal& vm() + +{ + static VirtualMemoryLocal vm; + return vm; +} + +void* VirtualMemory::alloc(size_t length, size_t* allocated, bool canExecute) + +{ + size_t msize = IntUtil::roundUp(length, vm().pageSize); + int protection = PROT_READ | PROT_WRITE | (canExecute ? PROT_EXEC : 0); + + void* mbase = ::mmap(NULL, msize, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (mbase == MAP_FAILED) + return NULL; + + if (allocated != NULL) + *allocated = msize; + return mbase; +} + +void VirtualMemory::free(void* addr, size_t length) + +{ + munmap(addr, length); +} + +size_t VirtualMemory::getAlignment() + +{ + return vm().alignment; +} + +size_t VirtualMemory::getPageSize() + +{ + return vm().pageSize; +} +#endif // ASMJIT_POSIX + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/virtualmemory.h b/desmume/src/utils/AsmJit/core/virtualmemory.h new file mode 100644 index 000000000..efb9fd9ec --- /dev/null +++ b/desmume/src/utils/AsmJit/core/virtualmemory.h @@ -0,0 +1,80 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_VIRTUALMEMORY_H +#define _ASMJIT_CORE_VIRTUALMEMORY_H + +// [Dependencies - AsmJit] +#include "../core/build.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::VirtualMemory] +// ============================================================================ + +//! @brief Class that helps with allocating memory for executing code +//! generated by JIT compiler. +//! +//! There are defined functions that provides facility to allocate and free +//! memory where can be executed code. If processor and operating system +//! supports execution protection then you can't run code from normally +//! malloc()'ed memory. +//! +//! Functions are internally implemented by operating system dependent way. +//! VirtualAlloc() function is used for Windows operating system and mmap() +//! for posix ones. If you want to study or create your own functions, look +//! at VirtualAlloc() or mmap() documentation (depends on you target OS). +//! +//! Under posix operating systems is also useable mprotect() function, that +//! can enable execution protection to malloc()'ed memory block. +struct VirtualMemory +{ + //! @brief Allocate virtual memory. + //! + //! Pages are readable/writeable, but they are not guaranteed to be + //! executable unless 'canExecute' is true. Returns the address of + //! allocated memory, or NULL if failed. + ASMJIT_API static void* alloc(size_t length, size_t* allocated, bool canExecute); + + //! @brief Free memory allocated by @c alloc() + ASMJIT_API static void free(void* addr, size_t length); + +#if defined(ASMJIT_WINDOWS) + //! @brief Allocate virtual memory of @a hProcess. + //! + //! @note This function is Windows specific. + ASMJIT_API static void* allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, bool canExecute); + + //! @brief Free virtual memory of @a hProcess. + //! + //! @note This function is Windows specific. + ASMJIT_API static void freeProcessMemory(HANDLE hProcess, void* addr, size_t length); +#endif // ASMJIT_WINDOWS + + //! @brief Get the alignment guaranteed by alloc(). + ASMJIT_API static size_t getAlignment(); + + //! @brief Get size of single page. + ASMJIT_API static size_t getPageSize(); +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_CORE_VIRTUALMEMORY_H diff --git a/desmume/src/utils/AsmJit/core/zonememory.cpp b/desmume/src/utils/AsmJit/core/zonememory.cpp new file mode 100644 index 000000000..ff7508e85 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/zonememory.cpp @@ -0,0 +1,126 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/defs.h" +#include "../core/intutil.h" +#include "../core/zonememory.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::ZoneMemory] +// ============================================================================ + +ZoneMemory::ZoneMemory(size_t chunkSize) +{ + _chunks = NULL; + _total = 0; + _chunkSize = chunkSize; +} + +ZoneMemory::~ZoneMemory() +{ + reset(); +} + +void* ZoneMemory::alloc(size_t size) +{ + ZoneChunk* cur = _chunks; + + // Align to 4 or 8 bytes. + size = IntUtil::align(size, sizeof(size_t)); + + if (cur == NULL || cur->getRemainingBytes() < size) + { + size_t chSize = _chunkSize; + + if (chSize < size) + chSize = size; + + cur = (ZoneChunk*)ASMJIT_MALLOC(sizeof(ZoneChunk) - sizeof(void*) + chSize); + if (cur == NULL) + return NULL; + + cur->prev = _chunks; + cur->pos = 0; + cur->size = chSize; + + _chunks = cur; + } + + uint8_t* p = cur->data + cur->pos; + cur->pos += size; + _total += size; + + ASMJIT_ASSERT(cur->pos <= cur->size); + return (void*)p; +} + +char* ZoneMemory::sdup(const char* str) +{ + if (str == NULL) return NULL; + + size_t len = strlen(str); + if (len == 0) return NULL; + + // Include NULL terminator and limit string length. + if (++len > 256) + len = 256; + + char* m = reinterpret_cast(alloc(IntUtil::align(len, 16))); + if (m == NULL) + return NULL; + + memcpy(m, str, len); + m[len - 1] = '\0'; + return m; +} + +void ZoneMemory::clear() +{ + ZoneChunk* cur = _chunks; + + if (cur == NULL) + return; + + cur = cur->prev; + while (cur != NULL) + { + ZoneChunk* prev = cur->prev; + ASMJIT_FREE(cur); + cur = prev; + } + + _chunks->pos = 0; + _chunks->prev = NULL; + _total = 0; +} + +void ZoneMemory::reset() +{ + ZoneChunk* cur = _chunks; + + _chunks = NULL; + _total = 0; + + while (cur != NULL) + { + ZoneChunk* prev = cur->prev; + ASMJIT_FREE(cur); + cur = prev; + } +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/core/zonememory.h b/desmume/src/utils/AsmJit/core/zonememory.h new file mode 100644 index 000000000..d1f9e79a3 --- /dev/null +++ b/desmume/src/utils/AsmJit/core/zonememory.h @@ -0,0 +1,151 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_CORE_ZONEMEMORY_H +#define _ASMJIT_CORE_ZONEMEMORY_H + +// [Dependencies - AsmJit] +#include "../core/build.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_Core +//! @{ + +// ============================================================================ +// [AsmJit::ZoneChunk] +// ============================================================================ + +//! @internal +//! +//! @brief One allocated chunk of memory. +struct ZoneChunk +{ + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + //! @brief Get count of remaining (unused) bytes in chunk. + inline size_t getRemainingBytes() const { return size - pos; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Link to previous chunk. + ZoneChunk* prev; + //! @brief Position in this chunk. + size_t pos; + //! @brief Size of this chunk (in bytes). + size_t size; + + //! @brief Data. + uint8_t data[sizeof(void*)]; +}; + +// ============================================================================ +// [AsmJit::ZoneMemory] +// ============================================================================ + +//! @brief Memory allocator designed to fast alloc memory that will be freed +//! in one step. +//! +//! @note This is hackery for performance. Concept is that objects created +//! by @c ZoneMemory are freed all at once. This means that lifetime of +//! these objects are the same as the zone object itself. +struct ZoneMemory +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create new instance of @c ZoneMemory. + //! @param chunkSize Default size for one zone chunk. + ASMJIT_API ZoneMemory(size_t chunkSize); + + //! @brief Destroy @ref ZoneMemory instance. + ASMJIT_API ~ZoneMemory(); + + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + //! @brief Allocate @c size bytes of memory and return pointer to it. + //! + //! Pointer allocated by this way will be valid until @c ZoneMemory object + //! is destroyed. To create class by this way use placement @c new and + //! @c delete operators: + //! + //! @code + //! // Example of allocating simple class + //! + //! // Your class + //! class Object + //! { + //! // members... + //! }; + //! + //! // Your function + //! void f() + //! { + //! // We are using AsmJit namespace + //! using namespace AsmJit + //! + //! // Create zone object with chunk size of 65536 bytes. + //! ZoneMemory zone(65536); + //! + //! // Create your objects using zone object allocating, for example: + //! Object* obj = new(zone.alloc(sizeof(YourClass))) Object(); + //! + //! // ... lifetime of your objects ... + //! + //! // Destroy your objects: + //! obj->~Object(); + //! + //! // ZoneMemory destructor will free all memory allocated through it, + //! // alternative is to call @c zone.reset(). + //! } + //! @endcode + ASMJIT_API void* alloc(size_t size); + + //! @brief Helper to duplicate string. + ASMJIT_API char* sdup(const char* str); + + //! @brief Free all allocated memory except first block that remains for reuse. + //! + //! Note that this method will invalidate all instances using this memory + //! allocated by this zone instance. + ASMJIT_API void clear(); + + //! @brief Free all allocated memory at once. + //! + //! Note that this method will invalidate all instances using this memory + //! allocated by this zone instance. + ASMJIT_API void reset(); + + //! @brief Get total size of allocated objects - by @c alloc(). + inline size_t getTotal() const { return _total; } + //! @brief Get (default) chunk size. + inline size_t getChunkSize() const { return _chunkSize; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Last allocated chunk of memory. + ZoneChunk* _chunks; + //! @brief Total size of allocated objects - by @c alloc() method. + size_t _total; + //! @brief One chunk size. + size_t _chunkSize; +}; + +//! @} + +} // AsmJit namespace + +#endif // _ASMJIT_CORE_ZONEMEMORY_H diff --git a/desmume/src/utils/AsmJit/x86.h b/desmume/src/utils/AsmJit/x86.h new file mode 100644 index 000000000..125e21262 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86.h @@ -0,0 +1,26 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_X86_H +#define _ASMJIT_X86_H + +// [Dependencies - AsmJit] +#include "core.h" + +#include "x86/x86assembler.h" +#include "x86/x86compiler.h" +#include "x86/x86compilercontext.h" +#include "x86/x86compilerfunc.h" +#include "x86/x86compileritem.h" +#include "x86/x86cpuinfo.h" +#include "x86/x86defs.h" +#include "x86/x86func.h" +#include "x86/x86operand.h" +#include "x86/x86util.h" + +// [Guard] +#endif // _ASMJIT_X86_H diff --git a/desmume/src/utils/AsmJit/AssemblerX86X64.cpp b/desmume/src/utils/AsmJit/x86/x86assembler.cpp similarity index 53% rename from desmume/src/utils/AsmJit/AssemblerX86X64.cpp rename to desmume/src/utils/AsmJit/x86/x86assembler.cpp index 0fa7854ca..9d4ab0e53 100644 --- a/desmume/src/utils/AsmJit/AssemblerX86X64.cpp +++ b/desmume/src/utils/AsmJit/x86/x86assembler.cpp @@ -4,168 +4,82 @@ // [License] // Zlib - See COPYING file in this package. -// We are using sprintf() here. -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif // _MSC_VER +#define ASMJIT_EXPORTS -// [Dependencies] -#include "Assembler.h" -#include "CodeGenerator.h" -#include "CpuInfo.h" -#include "Defs.h" -#include "Logger.h" -#include "MemoryManager.h" -#include "Platform.h" -#include "Util_p.h" +// [Dependencies - AsmJit] +#include "../core/assembler.h" +#include "../core/context.h" +#include "../core/cpuinfo.h" +#include "../core/defs.h" +#include "../core/intutil.h" +#include "../core/logger.h" +#include "../core/memorymanager.h" +#include "../core/memorymarker.h" +#include "../core/stringutil.h" -#include -#include -#include - -// A little bit C++. -#include +#include "../x86/x86assembler.h" +#include "../x86/x86cpuinfo.h" +#include "../x86/x86defs.h" +#include "../x86/x86operand.h" +#include "../x86/x86util.h" // [Api-Begin] -#include "ApiBegin.h" +#include "../core/apibegin.h" namespace AsmJit { +// ============================================================================ +// [Constants] +// ============================================================================ + +enum { kMaxCommentLength = 80 }; + +// ============================================================================ +// [AsmJit::X64TrampolineWriter] +// ============================================================================ + #if defined(ASMJIT_X64) - -// ============================================================================ -// [AsmJit::TrampolineWriter] -// ============================================================================ - //! @brief Class used to determine size of trampoline and as trampoline writer. -struct ASMJIT_HIDDEN TrampolineWriter +struct X64TrampolineWriter { // Size of trampoline - enum { - TRAMPOLINE_JMP = 6, - TRAMPOLINE_ADDR = sizeof(sysint_t), - - TRAMPOLINE_SIZE = TRAMPOLINE_JMP + TRAMPOLINE_ADDR + enum + { + kSizeJmp = 6, + kSizeAddr = 8, + kSizeTotal = kSizeJmp + kSizeAddr }; // Write trampoline into code at address @a code that will jump to @a target. - static void writeTrampoline(uint8_t* code, void* target) + static void writeTrampoline(uint8_t* code, uint64_t target) { - // Jmp. - code[0] = 0xFF; - // ModM (RIP addressing). - code[1] = 0x25; - // Offset (zero). - ((uint32_t*)(code + 2))[0] = 0; - // Absolute address. - ((sysuint_t*)(code + TRAMPOLINE_JMP))[0] = (sysuint_t)target; + code[0] = 0xFF; // Jmp OpCode. + code[1] = 0x25; // ModM (RIP addressing). + ((uint32_t*)(code + 2))[0] = 0; // Offset (zero). + ((uint64_t*)(code + kSizeJmp))[0] = (uint64_t)target; // Absolute address. } }; - #endif // ASMJIT_X64 // ============================================================================ -// [AsmJit::AssemblerCore - Construction / Destruction] +// [AsmJit::X86Assembler - Construction / Destruction] // ============================================================================ -AssemblerCore::AssemblerCore(CodeGenerator* codeGenerator) ASMJIT_NOTHROW : - _zone(16384 - sizeof(Zone::Chunk) - 32), - _codeGenerator(codeGenerator != NULL ? codeGenerator : CodeGenerator::getGlobal()), - _logger(NULL), - _error(0), - _properties((1 << PROPERTY_OPTIMIZE_ALIGN)), - _emitOptions(0), - _buffer(32), // Max instruction length is 15, but we can align up to 32 bytes. - _trampolineSize(0), - _unusedLinks(NULL), - _comment(NULL) +X86Assembler::X86Assembler(Context* context) : + Assembler(context) { + _properties = IntUtil::maskFromIndex(kX86PropertyOptimizedAlign); } -AssemblerCore::~AssemblerCore() ASMJIT_NOTHROW +X86Assembler::~X86Assembler() { } // ============================================================================ -// [AsmJit::AssemblerCore - Logging] +// [AsmJit::X86Assembler - Buffer - Setters (X86-Extensions)] // ============================================================================ -void AssemblerCore::setLogger(Logger* logger) ASMJIT_NOTHROW -{ - _logger = logger; -} - -// ============================================================================ -// [AsmJit::AssemblerCore - Error Handling] -// ============================================================================ - -void AssemblerCore::setError(uint32_t error) ASMJIT_NOTHROW -{ - _error = error; - if (_error == ERROR_NONE) return; - - if (_logger) - { - _logger->logFormat("*** ASSEMBLER ERROR: %s (%u).\n", - getErrorString(error), - (unsigned int)error); - } -} - -// ============================================================================ -// [AsmJit::AssemblerCore - Properties] -// ============================================================================ - -uint32_t AssemblerCore::getProperty(uint32_t propertyId) -{ - return (_properties & (1 << propertyId)) != 0; -} - -void AssemblerCore::setProperty(uint32_t propertyId, uint32_t value) -{ - if (value) - _properties |= (1 << propertyId); - else - _properties &= ~(1 << propertyId); -} - -// ============================================================================ -// [AsmJit::AssemblerCore - Buffer] -// ============================================================================ - -void AssemblerCore::clear() ASMJIT_NOTHROW -{ - _buffer.clear(); - _relocData.clear(); - _zone.clear(); - - if (_error) setError(ERROR_NONE); -} - -void AssemblerCore::free() ASMJIT_NOTHROW -{ - _zone.freeAll(); - _buffer.free(); - _relocData.free(); - - if (_error) setError(ERROR_NONE); -} - -uint8_t* AssemblerCore::takeCode() ASMJIT_NOTHROW -{ - uint8_t* code = _buffer.take(); - _relocData.clear(); - _zone.clear(); - - if (_error) setError(ERROR_NONE); - return code; -} - -// ============================================================================ -// [AsmJit::AssemblerCore - Stream Setters / Getters] -// ============================================================================ - -void AssemblerCore::setVarAt(sysint_t pos, sysint_t i, uint8_t isUnsigned, uint32_t size) ASMJIT_NOTHROW +void X86Assembler::setVarAt(size_t pos, sysint_t i, uint8_t isUnsigned, uint32_t size) { if (size == 1 && !isUnsigned) setByteAt (pos, (int8_t )i); else if (size == 1 && isUnsigned) setByteAt (pos, (uint8_t )i); @@ -173,71 +87,31 @@ void AssemblerCore::setVarAt(sysint_t pos, sysint_t i, uint8_t isUnsigned, uint3 else if (size == 2 && isUnsigned) setWordAt (pos, (uint16_t)i); else if (size == 4 && !isUnsigned) setDWordAt(pos, (int32_t )i); else if (size == 4 && isUnsigned) setDWordAt(pos, (uint32_t)i); + #if defined(ASMJIT_X64) else if (size == 8 && !isUnsigned) setQWordAt(pos, (int64_t )i); else if (size == 8 && isUnsigned) setQWordAt(pos, (uint64_t)i); #endif // ASMJIT_X64 + else ASMJIT_ASSERT(0); } // ============================================================================ -// [AsmJit::AssemblerCore - Assembler Emitters] +// [AsmJit::X86Assembler - Emit] // ============================================================================ -bool AssemblerCore::canEmit() ASMJIT_NOTHROW +void X86Assembler::_emitModM( + uint8_t opReg, const Mem& mem, sysint_t immSize) { - // If there is an error, we can't emit another instruction until last error - // is cleared by calling @c setError(ERROR_NONE). If something caused an error - // while generating code it's probably fatal in all cases. You can't use - // generated code, because you are not sure about its status. - if (_error) return false; - - // The ensureSpace() method returns true on success and false on failure. We - // are catching return value and setting error code here. - if (ensureSpace()) return true; - - // If we are here, there is memory allocation error. Note that this is HEAP - // allocation error, virtual allocation error can be caused only by - // AsmJit::VirtualMemory class! - setError(ERROR_NO_HEAP_MEMORY); - return false; -} - -void AssemblerCore::_emitSegmentPrefix(const Operand& rm) ASMJIT_NOTHROW -{ - static const uint8_t segmentPrefixCode[6] = - { - 0x26, // ES - 0x2E, // SS - 0x36, // SS - 0x3E, // DS - 0x64, // FS - 0x65 // GS - }; - - uint32_t segmentPrefix; - - if (!rm.isMem()) - return; - - if ((segmentPrefix = reinterpret_cast(rm).getSegmentPrefix()) >= REG_NUM_SEGMENT) - return; - - _emitByte(segmentPrefixCode[segmentPrefix]); -} - -void AssemblerCore::_emitModM( - uint8_t opReg, const Mem& mem, sysint_t immSize) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(mem.getType() == OPERAND_MEM); + ASMJIT_ASSERT(mem.getType() == kOperandMem); uint8_t baseReg = mem.getBase() & 0x7; uint8_t indexReg = mem.getIndex() & 0x7; sysint_t disp = mem.getDisplacement(); uint32_t shift = mem.getShift(); - if (mem.getMemType() == OPERAND_MEM_NATIVE) + if (mem.getMemType() == kOperandMemNative) { // [base + displacemnt] if (!mem.hasIndex()) @@ -248,16 +122,14 @@ void AssemblerCore::_emitModM( uint8_t mod = 0; if (disp) - { - mod = Util::isInt8(disp) ? 1 : 2; - } + mod = IntUtil::isInt8(disp) ? 1 : 2; _emitMod(mod, opReg, 4); _emitSib(0, 4, 4); if (disp) { - if (Util::isInt8(disp)) + if (IntUtil::isInt8(disp)) _emitByte((int8_t)disp); else _emitInt32((int32_t)disp); @@ -268,7 +140,7 @@ void AssemblerCore::_emitModM( { _emitMod(0, opReg, baseReg); } - else if (Util::isInt8(disp)) + else if (IntUtil::isInt8(disp)) { _emitMod(1, opReg, baseReg); _emitByte((int8_t)disp); @@ -291,7 +163,7 @@ void AssemblerCore::_emitModM( _emitMod(0, opReg, 4); _emitSib(shift, indexReg, baseReg); } - else if (Util::isInt8(disp)) + else if (IntUtil::isInt8(disp)) { _emitMod(1, opReg, 4); _emitSib(shift, indexReg, baseReg); @@ -332,14 +204,14 @@ void AssemblerCore::_emitModM( // X86 uses absolute addressing model, all relative addresses will be // relocated to absolute ones. - if (mem.getMemType() == OPERAND_MEM_LABEL) + if (mem.getMemType() == kOperandMemLabel) { - LabelData& l_data = _labelData[mem._mem.base & OPERAND_ID_VALUE_MASK]; + LabelData& l_data = _labels[mem._mem.base & kOperandIdValueMask]; RelocData r_data; uint32_t relocId = _relocData.getLength(); // Relative addressing will be relocated to absolute address. - r_data.type = RelocData::RELATIVE_TO_ABSOLUTE; + r_data.type = kRelocRelToAbs; r_data.size = 4; r_data.offset = getOffset(); r_data.destination = disp; @@ -369,14 +241,14 @@ void AssemblerCore::_emitModM( #else // X64 uses relative addressing model - if (mem.getMemType() == OPERAND_MEM_LABEL) + if (mem.getMemType() == kOperandMemLabel) { - LabelData& l_data = _labelData[mem._mem.base & OPERAND_ID_VALUE_MASK]; + LabelData& l_data = _labels[mem._mem.base & kOperandIdValueMask]; if (mem.hasIndex()) { // Indexing is not possible. - setError(ERROR_ILLEGAL_ADDRESING); + setError(kErrorIllegalAddressing); return; } @@ -435,19 +307,41 @@ void AssemblerCore::_emitModM( } } -void AssemblerCore::_emitModRM( - uint8_t opReg, const Operand& op, sysint_t immSize) ASMJIT_NOTHROW +void X86Assembler::_emitModRM( + uint8_t opReg, const Operand& op, sysint_t immSize) { - ASMJIT_ASSERT(op.getType() == OPERAND_REG || op.getType() == OPERAND_MEM); + ASMJIT_ASSERT(op.getType() == kOperandReg || op.getType() == kOperandMem); - if (op.getType() == OPERAND_REG) - _emitModR(opReg, reinterpret_cast(op).getRegCode()); + if (op.getType() == kOperandReg) + _emitModR(opReg, reinterpret_cast(op).getRegCode()); else _emitModM(opReg, reinterpret_cast(op), immSize); } -void AssemblerCore::_emitX86Inl( - uint32_t opCode, uint8_t i16bit, uint8_t rexw, uint8_t reg, bool forceRexPrefix) ASMJIT_NOTHROW +void X86Assembler::_emitSegmentPrefix(const Operand& rm) +{ + static const uint8_t segmentCode[6] = + { + 0x26, // ES + 0x2E, // SS + 0x36, // SS + 0x3E, // DS + 0x64, // FS + 0x65 // GS + }; + + if (!rm.isMem()) + return; + + uint32_t seg = reinterpret_cast(rm).getSegment(); + if (seg >= kX86RegNumSeg) + return; + + _emitByte(segmentCode[seg]); +} + +void X86Assembler::_emitX86Inl( + uint32_t opCode, uint8_t i16bit, uint8_t rexw, uint8_t reg, bool forceRexPrefix) { // 16-bit prefix. if (i16bit) _emitByte(0x66); @@ -467,9 +361,9 @@ void AssemblerCore::_emitX86Inl( _emitByte((uint8_t)(opCode & 0x000000FF) + (reg & 0x7)); } -void AssemblerCore::_emitX86RM( +void X86Assembler::_emitX86RM( uint32_t opCode, uint8_t i16bit, uint8_t rexw, uint8_t o, - const Operand& op, sysint_t immSize, bool forceRexPrefix) ASMJIT_NOTHROW + const Operand& op, sysint_t immSize, bool forceRexPrefix) { // 16-bit prefix. if (i16bit) _emitByte(0x66); @@ -494,19 +388,19 @@ void AssemblerCore::_emitX86RM( _emitModRM(o, op, immSize); } -void AssemblerCore::_emitFpu(uint32_t opCode) ASMJIT_NOTHROW +void X86Assembler::_emitFpu(uint32_t opCode) { _emitOpCode(opCode); } -void AssemblerCore::_emitFpuSTI(uint32_t opCode, uint32_t sti) ASMJIT_NOTHROW +void X86Assembler::_emitFpuSTI(uint32_t opCode, uint32_t sti) { // Illegal stack offset. ASMJIT_ASSERT(0 <= sti && sti < 8); _emitOpCode(opCode + sti); } -void AssemblerCore::_emitFpuMEM(uint32_t opCode, uint8_t opReg, const Mem& mem) ASMJIT_NOTHROW +void X86Assembler::_emitFpuMEM(uint32_t opCode, uint8_t opReg, const Mem& mem) { // Segment prefix. _emitSegmentPrefix(mem); @@ -527,8 +421,8 @@ void AssemblerCore::_emitFpuMEM(uint32_t opCode, uint8_t opReg, const Mem& mem) _emitModM(opReg, mem, 0); } -void AssemblerCore::_emitMmu(uint32_t opCode, uint8_t rexw, uint8_t opReg, - const Operand& src, sysint_t immSize) ASMJIT_NOTHROW +void X86Assembler::_emitMmu(uint32_t opCode, uint8_t rexw, uint8_t opReg, + const Operand& src, sysint_t immSize) { // Segment prefix. _emitSegmentPrefix(src); @@ -549,13 +443,13 @@ void AssemblerCore::_emitMmu(uint32_t opCode, uint8_t rexw, uint8_t opReg, _emitByte((uint8_t)((opCode & 0x000000FF))); if (src.isReg()) - _emitModR(opReg, reinterpret_cast(src).getRegCode()); + _emitModR(opReg, reinterpret_cast(src).getRegCode()); else _emitModM(opReg, reinterpret_cast(src), immSize); } -AssemblerCore::LabelLink* AssemblerCore::_emitDisplacement( - LabelData& l_data, sysint_t inlinedDisplacement, int size) ASMJIT_NOTHROW +X86Assembler::LabelLink* X86Assembler::_emitDisplacement( + LabelData& l_data, sysint_t inlinedDisplacement, int size) { ASMJIT_ASSERT(l_data.offset == -1); ASMJIT_ASSERT(size == 1 || size == 4); @@ -577,16 +471,16 @@ AssemblerCore::LabelLink* AssemblerCore::_emitDisplacement( return link; } -void AssemblerCore::_emitJmpOrCallReloc(uint32_t instruction, void* target) ASMJIT_NOTHROW +void X86Assembler::_emitJmpOrCallReloc(uint32_t instruction, void* target) { RelocData rd; - rd.type = RelocData::ABSOLUTE_TO_RELATIVE_TRAMPOLINE; + rd.type = kRelocTrampoline; #if defined(ASMJIT_X64) // If we are compiling in 64-bit mode, we can use trampoline if relative jump // is not possible. - _trampolineSize += TrampolineWriter::TRAMPOLINE_SIZE; + _trampolineSize += X64TrampolineWriter::kSizeTotal; #endif // ARCHITECTURE_SPECIFIC rd.size = 4; @@ -599,8 +493,26 @@ void AssemblerCore::_emitJmpOrCallReloc(uint32_t instruction, void* target) ASMJ _emitInt32(0); } +//! @internal +//! +//! @brief Get whether the extended register (additional eight registers +//! introduced by 64-bit mode) is used. +static inline bool X86Assembler_isExtRegisterUsed(const Operand& op) +{ + // Hacky, but correct. + // - If operand type is register then extended register is register with + // index 8 and greater (8 to 15 inclusive). + // - If operand type is memory operand then we need to take care about + // label (in _mem.base) and kInvalidValue, we just decrement the value + // by 8 and check if it's at interval 0 to 7 inclusive (if it's there + // then it's extended register. + return (op.isReg() && (op._reg.code & kRegIndexMask) >= 8U) || + (op.isMem() && ((((uint32_t)op._mem.base - 8U) < 8U) || + (((uint32_t)op._mem.index - 8U) < 8U) )); +} + // Logging helpers. -static const char* operandSize[] = +static const char* AssemblerX86_operandSize[] = { NULL, "byte ptr ", @@ -621,7 +533,7 @@ static const char* operandSize[] = "dqword ptr " }; -static const char segmentPrefixName[] = +static const char X86Assembler_segmentName[] = "es:\0" "cs:\0" "ss:\0" @@ -630,13 +542,13 @@ static const char segmentPrefixName[] = "gs:\0" "\0\0\0\0"; -ASMJIT_HIDDEN char* dumpInstructionName(char* buf, uint32_t code) ASMJIT_NOTHROW +static char* X86Assembler_dumpInstructionName(char* buf, uint32_t code) { - ASMJIT_ASSERT(code < _INST_COUNT); - return Util::mycpy(buf, instructionDescription[code].getName()); + ASMJIT_ASSERT(code < _kX86InstCount); + return StringUtil::copy(buf, x86InstInfo[code].getName()); } -ASMJIT_HIDDEN char* dumpRegister(char* buf, uint32_t type, uint32_t index) ASMJIT_NOTHROW +char* X86Assembler_dumpRegister(char* buf, uint32_t type, uint32_t index) { // NE == Not-Encodable. const char reg8l[] = "al\0\0" "cl\0\0" "dl\0\0" "bl\0\0" "spl\0" "bpl\0" "sil\0" "dil\0" ; @@ -645,75 +557,75 @@ ASMJIT_HIDDEN char* dumpRegister(char* buf, uint32_t type, uint32_t index) ASMJI switch (type) { - case REG_TYPE_GPB_LO: + case kX86RegTypeGpbLo: if (index < 8) - return Util::mycpy(buf, ®8l[index*4]); + return StringUtil::copy(buf, ®8l[index*4]); *buf++ = 'r'; goto _EmitID; - case REG_TYPE_GPB_HI: + case kX86RegTypeGpbHi: if (index < 4) - return Util::mycpy(buf, ®8h[index*4]); + return StringUtil::copy(buf, ®8h[index*4]); _EmitNE: - return Util::mycpy(buf, "NE"); + return StringUtil::copy(buf, "NE"); - case REG_TYPE_GPW: + case kX86RegTypeGpw: if (index < 8) - return Util::mycpy(buf, ®16[index*4]); + return StringUtil::copy(buf, ®16[index*4]); *buf++ = 'r'; - buf = Util::myutoa(buf, index); + buf = StringUtil::utoa(buf, index); *buf++ = 'w'; return buf; - case REG_TYPE_GPD: + case kX86RegTypeGpd: if (index < 8) { *buf++ = 'e'; - return Util::mycpy(buf, ®16[index*4]); + return StringUtil::copy(buf, ®16[index*4]); } *buf++ = 'r'; - buf = Util::myutoa(buf, index); + buf = StringUtil::utoa(buf, index); *buf++ = 'd'; return buf; - case REG_TYPE_GPQ: + case kX86RegTypeGpq: *buf++ = 'r'; if (index < 8) - return Util::mycpy(buf, ®16[index*4]); + return StringUtil::copy(buf, ®16[index*4]); _EmitID: - return Util::myutoa(buf, index); + return StringUtil::utoa(buf, index); - case REG_TYPE_X87: + case kX86RegTypeX87: *buf++ = 's'; *buf++ = 't'; goto _EmitID; - case REG_TYPE_MM: + case kX86RegTypeMm: *buf++ = 'm'; *buf++ = 'm'; goto _EmitID; - case REG_TYPE_XMM: + case kX86RegTypeXmm: *buf++ = 'x'; *buf++ = 'm'; *buf++ = 'm'; goto _EmitID; - case REG_TYPE_YMM: + case kX86RegTypeYmm: *buf++ = 'y'; *buf++ = 'm'; *buf++ = 'm'; goto _EmitID; - case REG_TYPE_SEGMENT: - if (index < REG_NUM_SEGMENT) - return Util::mycpy(buf, &segmentPrefixName[index*4], 2); + case kX86RegTypeSeg: + if (index < kX86RegNumSeg) + return StringUtil::copy(buf, &X86Assembler_segmentName[index*4], 2); goto _EmitNE; @@ -722,63 +634,59 @@ _EmitID: } } -ASMJIT_HIDDEN char* dumpOperand(char* buf, const Operand* op, uint32_t memRegType) ASMJIT_NOTHROW +char* X86Assembler_dumpOperand(char* buf, const Operand* op, uint32_t memRegType, uint32_t loggerFlags) { if (op->isReg()) { - const BaseReg& reg = reinterpret_cast(*op); - return dumpRegister(buf, reg.getRegType(), reg.getRegIndex()); + const Reg& reg = reinterpret_cast(*op); + return X86Assembler_dumpRegister(buf, reg.getRegType(), reg.getRegIndex()); } else if (op->isMem()) { const Mem& mem = reinterpret_cast(*op); - uint32_t segmentPrefix = mem.getSegmentPrefix(); + uint32_t seg = mem.getSegment(); bool isAbsolute = false; if (op->getSize() <= 16) - { - buf = Util::mycpy(buf, operandSize[op->getSize()]); - } + buf = StringUtil::copy(buf, AssemblerX86_operandSize[op->getSize()]); - if (segmentPrefix < REG_NUM_SEGMENT) - { - buf = Util::mycpy(buf, &segmentPrefixName[segmentPrefix * 4]); - } + if (seg < kX86RegNumSeg) + buf = StringUtil::copy(buf, &X86Assembler_segmentName[seg * 4]); *buf++ = '['; switch (mem.getMemType()) { - case OPERAND_MEM_NATIVE: + case kOperandMemNative: { - // [base + index*scale + displacement] - buf = dumpRegister(buf, memRegType, mem.getBase()); + // [base + index << shift + displacement] + buf = X86Assembler_dumpRegister(buf, memRegType, mem.getBase()); break; } - case OPERAND_MEM_LABEL: + case kOperandMemLabel: { - // [label + index*scale + displacement] - buf += sprintf(buf, "L.%u", mem.getBase() & OPERAND_ID_VALUE_MASK); + // [label + index << shift + displacement] + buf += sprintf(buf, "L.%u", mem.getBase() & kOperandIdValueMask); break; } - case OPERAND_MEM_ABSOLUTE: + case kOperandMemAbsolute: { // [absolute] isAbsolute = true; - buf = Util::myutoa(buf, (sysuint_t)mem.getTarget() + mem.getDisplacement(), 16); + buf = StringUtil::utoa(buf, (sysuint_t)mem.getTarget() + mem.getDisplacement(), 16); break; } } if (mem.hasIndex()) { - buf = Util::mycpy(buf, " + "); - buf = dumpRegister(buf, memRegType, mem.getIndex()); + buf = StringUtil::copy(buf, " + "); + buf = X86Assembler_dumpRegister(buf, memRegType, mem.getIndex()); if (mem.getShift()) { - buf = Util::mycpy(buf, " * "); + buf = StringUtil::copy(buf, " * "); *buf++ = "1248"[mem.getShift() & 3]; } } @@ -786,10 +694,29 @@ ASMJIT_HIDDEN char* dumpOperand(char* buf, const Operand* op, uint32_t memRegTyp if (mem.getDisplacement() && !isAbsolute) { sysint_t d = mem.getDisplacement(); - *buf++ = ' '; - *buf++ = (d < 0) ? '-' : '+'; - *buf++ = ' '; - buf = Util::myutoa(buf, d < 0 ? -d : d); + uint32_t base = 10; + char sign = '+'; + + if (d < 0) + { + d = -d; + sign = '-'; + } + + buf[0] = ' '; + buf[1] = sign; + buf[2] = ' '; + buf += 3; + + if ((loggerFlags & kLoggerOutputHexDisplacement) != 0 && d > 9) + { + buf[0] = '0'; + buf[1] = 'x'; + buf += 2; + base = 16; + } + + buf = StringUtil::utoa(buf, static_cast(d), base); } *buf++ = ']'; @@ -798,63 +725,79 @@ ASMJIT_HIDDEN char* dumpOperand(char* buf, const Operand* op, uint32_t memRegTyp else if (op->isImm()) { const Imm& i = reinterpret_cast(*op); - return Util::myitoa(buf, (sysint_t)i.getValue()); + + sysuint_t value = i.getUValue(); + uint32_t base = 10; + + if ((loggerFlags & kLoggerOutputHexImmediate) && value > 9) + base = 16; + + if (i.isUnsigned() || base == 16) + { + return StringUtil::utoa(buf, value, base); + } + else + { + return StringUtil::itoa(buf, static_cast(value), base); + } } else if (op->isLabel()) { - return buf + sprintf(buf, "L.%u", op->getId() & OPERAND_ID_VALUE_MASK); + return buf + sprintf(buf, "L.%u", op->getId() & kOperandIdValueMask); } else { - return Util::mycpy(buf, "None"); + return StringUtil::copy(buf, "None"); } } -static char* dumpInstruction(char* buf, - uint32_t code, - uint32_t emitOptions, +static char* X86Assembler_dumpInstruction(char* buf, + uint32_t code, uint32_t emitOptions, const Operand* o0, const Operand* o1, const Operand* o2, - uint32_t memRegType) ASMJIT_NOTHROW + uint32_t memRegType, + uint32_t loggerFlags) { - if (emitOptions & EMIT_OPTION_REX_PREFIX ) buf = Util::mycpy(buf, "rex ", 4); - if (emitOptions & EMIT_OPTION_LOCK_PREFIX) buf = Util::mycpy(buf, "lock ", 5); - if (emitOptions & EMIT_OPTION_SHORT_JUMP ) buf = Util::mycpy(buf, "short ", 6); + // Rex, lock, and short prefix. + if (emitOptions & kX86EmitOptionRex) + buf = StringUtil::copy(buf, "rex ", 4); + + if (emitOptions & kX86EmitOptionLock) + buf = StringUtil::copy(buf, "lock ", 5); + + if (emitOptions & kX86EmitOptionShortJump) + buf = StringUtil::copy(buf, "short ", 6); - // Dump instruction. - buf = dumpInstructionName(buf, code); + // Dump instruction name. + buf = X86Assembler_dumpInstructionName(buf, code); // Dump operands. - if (!o0->isNone()) { *buf++ = ' '; buf = dumpOperand(buf, o0, memRegType); } - if (!o1->isNone()) { *buf++ = ','; *buf++ = ' '; buf = dumpOperand(buf, o1, memRegType); } - if (!o2->isNone()) { *buf++ = ','; *buf++ = ' '; buf = dumpOperand(buf, o2, memRegType); } + if (!o0->isNone()) { *buf++ = ' '; buf = X86Assembler_dumpOperand(buf, o0, memRegType, loggerFlags); } + if (!o1->isNone()) { *buf++ = ','; *buf++ = ' '; buf = X86Assembler_dumpOperand(buf, o1, memRegType, loggerFlags); } + if (!o2->isNone()) { *buf++ = ','; *buf++ = ' '; buf = X86Assembler_dumpOperand(buf, o2, memRegType, loggerFlags); } return buf; } -static char* dumpComment(char* buf, sysuint_t len, const uint8_t* binaryData, sysuint_t binaryLen, const char* comment) +static char* X86Assembler_dumpComment(char* buf, size_t len, const uint8_t* binaryData, size_t binaryLen, const char* comment) { - sysuint_t currentLength = len; - sysuint_t commentLength = comment ? strlen(comment) : 0; + size_t currentLength = len; + size_t commentLength = comment ? strnlen(comment, kMaxCommentLength) : 0; if (binaryLen || commentLength) { - sysuint_t align = 32; + size_t align = 32; char sep = ';'; - // Truncate if comment is too long (it shouldn't be, larger than 80 seems to - // be an exploit). - if (commentLength > 80) commentLength = 80; - - for (sysuint_t i = (binaryLen == 0); i < 2; i++) + for (size_t i = (binaryLen == 0); i < 2; i++) { char* bufBegin = buf; // Append align. if (currentLength < align) { - buf = Util::myfill(buf, ' ', align - currentLength); + buf = StringUtil::fill(buf, ' ', align - currentLength); } // Append separator. @@ -867,15 +810,16 @@ static char* dumpComment(char* buf, sysuint_t len, const uint8_t* binaryData, sy // Append binary data or comment. if (i == 0) { - buf = Util::myhex(buf, binaryData, binaryLen); - if (commentLength == 0) break; + buf = StringUtil::hex(buf, binaryData, binaryLen); + if (commentLength == 0) + break; } else { - buf = Util::mycpy(buf, comment, commentLength); + buf = StringUtil::copy(buf, comment, commentLength); } - currentLength += (sysuint_t)(buf - bufBegin); + currentLength += (size_t)(buf - bufBegin); align += 18; sep = '|'; } @@ -885,46 +829,46 @@ static char* dumpComment(char* buf, sysuint_t len, const uint8_t* binaryData, sy return buf; } -// Used for NULL operands to translate them to OPERAND_NONE. -static const uint8_t _none[sizeof(Operand)] = +static const _OpReg _patchedHiRegs[4] = { - 0 + // Operand |Size|Reserved0|Reserved1| OperandId | RegisterCode | + // ----------+----+---------+---------+--------------+-----------------------+ + { kOperandReg, 1, {0 ,0 }, kInvalidValue, kX86RegTypeGpbLo | 4 }, + { kOperandReg, 1, {0 ,0 }, kInvalidValue, kX86RegTypeGpbLo | 5 }, + { kOperandReg, 1, {0 ,0 }, kInvalidValue, kX86RegTypeGpbLo | 6 }, + { kOperandReg, 1, {0 ,0 }, kInvalidValue, kX86RegTypeGpbLo | 7 } }; -static const Operand::RegData _patchedHiRegs[4] = -{// op , size, { reserved0, reserved1 }, id , code - { OPERAND_REG, 1 , { 0 , 0 }, INVALID_VALUE, REG_TYPE_GPB_LO | 4 }, - { OPERAND_REG, 1 , { 0 , 0 }, INVALID_VALUE, REG_TYPE_GPB_LO | 5 }, - { OPERAND_REG, 1 , { 0 , 0 }, INVALID_VALUE, REG_TYPE_GPB_LO | 6 }, - { OPERAND_REG, 1 , { 0 , 0 }, INVALID_VALUE, REG_TYPE_GPB_LO | 7 } -}; - -void AssemblerCore::_emitInstruction(uint32_t code) ASMJIT_NOTHROW +void X86Assembler::_emitInstruction(uint32_t code) { - _emitInstruction(code, NULL, NULL, NULL); + _emitInstruction(code, &noOperand, &noOperand, &noOperand); } -void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0) ASMJIT_NOTHROW +void X86Assembler::_emitInstruction(uint32_t code, const Operand* o0) { - _emitInstruction(code, o0, NULL, NULL); + _emitInstruction(code, o0, &noOperand, &noOperand); } -void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1) ASMJIT_NOTHROW +void X86Assembler::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1) { - _emitInstruction(code, o0, o1, NULL); + _emitInstruction(code, o0, o1, &noOperand); } -void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2) ASMJIT_NOTHROW +void X86Assembler::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2) { + ASMJIT_ASSERT(o0 != NULL); + ASMJIT_ASSERT(o1 != NULL); + ASMJIT_ASSERT(o2 != NULL); + const Operand* _loggerOperands[3]; uint32_t bLoHiUsed = 0; #if defined(ASMJIT_X86) uint32_t forceRexPrefix = false; #else - uint32_t forceRexPrefix = _emitOptions & EMIT_OPTION_REX_PREFIX; + uint32_t forceRexPrefix = _emitOptions & kX86EmitOptionRex; #endif - uint32_t memRegType = REG_TYPE_GPN; + uint32_t memRegType = kX86RegTypeGpz; #if defined(ASMJIT_DEBUG) bool assertIllegal = false; @@ -934,27 +878,27 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope uint32_t immSize; #define _FINISHED() \ - goto end + goto _End #define _FINISHED_IMMEDIATE(_Operand_, _Size_) \ do { \ immOperand = reinterpret_cast(_Operand_); \ immSize = (_Size_); \ - goto emitImmediate; \ + goto _EmitImmediate; \ } while (0) - // Convert operands to OPERAND_NONE if needed. - if (o0 == NULL) { o0 = reinterpret_cast(_none); } else if (o0->isReg()) { bLoHiUsed |= o0->_reg.code & (REG_TYPE_GPB_LO | REG_TYPE_GPB_HI); } - if (o1 == NULL) { o1 = reinterpret_cast(_none); } else if (o1->isReg()) { bLoHiUsed |= o1->_reg.code & (REG_TYPE_GPB_LO | REG_TYPE_GPB_HI); } - if (o2 == NULL) { o2 = reinterpret_cast(_none); } else if (o2->isReg()) { bLoHiUsed |= o2->_reg.code & (REG_TYPE_GPB_LO | REG_TYPE_GPB_HI); } + // Convert operands to kOperandNone if needed. + if (o0->isReg()) bLoHiUsed |= o0->_reg.code & (kX86RegTypeGpbLo | kX86RegTypeGpbHi); + if (o1->isReg()) bLoHiUsed |= o1->_reg.code & (kX86RegTypeGpbLo | kX86RegTypeGpbHi); + if (o2->isReg()) bLoHiUsed |= o2->_reg.code & (kX86RegTypeGpbLo | kX86RegTypeGpbHi); - sysuint_t beginOffset = getOffset(); - const InstructionDescription* id = &instructionDescription[code]; + size_t beginOffset = getOffset(); + const X86InstInfo* id = &x86InstInfo[code]; - if (code >= _INST_COUNT) + if (code >= _kX86InstCount) { - setError(ERROR_UNKNOWN_INSTRUCTION); - goto cleanup; + setError(kErrorUnknownInstruction); + goto _Cleanup; } // Check if register operand is BPL, SPL, SIL, DIL and do action that depends @@ -979,51 +923,56 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope #if defined(ASMJIT_X64) // Check if there is register that makes this instruction un-encodable. - forceRexPrefix |= (uint32_t)o0->isExtendedRegisterUsed(); - forceRexPrefix |= (uint32_t)o1->isExtendedRegisterUsed(); - forceRexPrefix |= (uint32_t)o2->isExtendedRegisterUsed(); + forceRexPrefix |= (uint32_t)X86Assembler_isExtRegisterUsed(*o0); + forceRexPrefix |= (uint32_t)X86Assembler_isExtRegisterUsed(*o1); + forceRexPrefix |= (uint32_t)X86Assembler_isExtRegisterUsed(*o2); - if (o0->isRegType(REG_TYPE_GPB_LO) && (o0->_reg.code & REG_INDEX_MASK) >= 4) forceRexPrefix = true; - else if (o1->isRegType(REG_TYPE_GPB_LO) && (o1->_reg.code & REG_INDEX_MASK) >= 4) forceRexPrefix = true; - else if (o2->isRegType(REG_TYPE_GPB_LO) && (o2->_reg.code & REG_INDEX_MASK) >= 4) forceRexPrefix = true; + if (o0->isRegType(kX86RegTypeGpbLo) && (o0->_reg.code & kRegIndexMask) >= 4) forceRexPrefix = true; + else if (o1->isRegType(kX86RegTypeGpbLo) && (o1->_reg.code & kRegIndexMask) >= 4) forceRexPrefix = true; + else if (o2->isRegType(kX86RegTypeGpbLo) && (o2->_reg.code & kRegIndexMask) >= 4) forceRexPrefix = true; - if ((bLoHiUsed & REG_TYPE_GPB_HI) != 0 && forceRexPrefix) + if ((bLoHiUsed & kX86RegTypeGpbHi) != 0 && forceRexPrefix) { - goto illegalInstruction; + goto _IllegalInstruction; } #endif // ASMJIT_X64 // Patch GPB.HI operand index. - if ((bLoHiUsed & REG_TYPE_GPB_HI) != 0) + if ((bLoHiUsed & kX86RegTypeGpbHi) != 0) { - if (o0->isRegType(REG_TYPE_GPB_HI)) o0 = reinterpret_cast(&_patchedHiRegs[o0->_reg.code & REG_INDEX_MASK]); - if (o1->isRegType(REG_TYPE_GPB_HI)) o1 = reinterpret_cast(&_patchedHiRegs[o1->_reg.code & REG_INDEX_MASK]); - if (o2->isRegType(REG_TYPE_GPB_HI)) o2 = reinterpret_cast(&_patchedHiRegs[o2->_reg.code & REG_INDEX_MASK]); + if (o0->isRegType(kX86RegTypeGpbHi)) o0 = reinterpret_cast(&_patchedHiRegs[o0->_reg.code & kRegIndexMask]); + if (o1->isRegType(kX86RegTypeGpbHi)) o1 = reinterpret_cast(&_patchedHiRegs[o1->_reg.code & kRegIndexMask]); + if (o2->isRegType(kX86RegTypeGpbHi)) o2 = reinterpret_cast(&_patchedHiRegs[o2->_reg.code & kRegIndexMask]); } } // Check for buffer space (and grow if needed). - if (!canEmit()) goto cleanup; + if (!canEmit()) goto _Cleanup; - if (_emitOptions & EMIT_OPTION_LOCK_PREFIX) + if (_emitOptions & kX86EmitOptionLock) { if (!id->isLockable()) - goto illegalInstruction; + goto _IllegalInstruction; _emitByte(0xF0); } - switch (id->group) + switch (id->getGroup()) { - case InstructionDescription::G_EMIT: + case kX86InstGroupNone: { - _emitOpCode(id->opCode[0]); _FINISHED(); } - case InstructionDescription::G_ALU: + case kX86InstGroupEmit: { - uint32_t opCode = id->opCode[0]; - uint8_t opReg = (uint8_t)id->opCodeR; + _emitOpCode(id->_opCode[0]); + _FINISHED(); + } + + case kX86InstGroupArith: + { + uint32_t opCode = id->_opCode[0]; + uint8_t opReg = (uint8_t)id->_opCodeR; // Mem <- Reg if (o0->isMem() && o1->isReg()) @@ -1031,7 +980,7 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope _emitX86RM(opCode + (o1->getSize() != 1), o1->getSize() == 2, o1->getSize() == 8, - reinterpret_cast(*o1).getRegCode(), + reinterpret_cast(*o1).getRegCode(), reinterpret_cast(*o0), 0, forceRexPrefix); _FINISHED(); @@ -1043,30 +992,33 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope _emitX86RM(opCode + 2 + (o0->getSize() != 1), o0->getSize() == 2, o0->getSize() == 8, - reinterpret_cast(*o0).getRegCode(), + reinterpret_cast(*o0).getRegCode(), reinterpret_cast(*o1), 0, forceRexPrefix); _FINISHED(); } - // AL, AX, EAX, RAX register shortcuts + // Alternate Form - AL, AX, EAX, RAX. if (o0->isRegIndex(0) && o1->isImm()) { - if (o0->getSize() == 2) - _emitByte(0x66); // 16-bit. - else if (o0->getSize() == 8) - _emitByte(0x48); // REX.W. + if (o0->getSize() == 1 || !IntUtil::isInt8(static_cast(o1)->getValue())) + { + if (o0->getSize() == 2) + _emitByte(0x66); // 16-bit. + else if (o0->getSize() == 8) + _emitByte(0x48); // REX.W. - _emitByte((opReg << 3) | (0x04 + (o0->getSize() != 1))); - _FINISHED_IMMEDIATE(o1, o0->getSize() <= 4 ? o0->getSize() : 4); + _emitByte((opReg << 3) | (0x04 + (o0->getSize() != 1))); + _FINISHED_IMMEDIATE(o1, IntUtil::_min(o0->getSize(), 4)); + } } if (o0->isRegMem() && o1->isImm()) { const Imm& imm = reinterpret_cast(*o1); - immSize = Util::isInt8(imm.getValue()) ? 1 : (o0->getSize() <= 4 ? o0->getSize() : 4); + immSize = IntUtil::isInt8(imm.getValue()) ? 1 : IntUtil::_min(o0->getSize(), 4); - _emitX86RM(id->opCode[1] + (o0->getSize() != 1 ? (immSize != 1 ? 1 : 3) : 0), + _emitX86RM(id->_opCode[1] + (o0->getSize() != 1 ? (immSize != 1 ? 1 : 3) : 0), o0->getSize() == 2, o0->getSize() == 8, opReg, reinterpret_cast(*o0), @@ -1077,14 +1029,14 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope break; } - case InstructionDescription::G_BSWAP: + case kX86InstGroupBSwap: { if (o0->isReg()) { - const GPReg& dst = reinterpret_cast(*o0); + const GpReg& dst = reinterpret_cast(*o0); #if defined(ASMJIT_X64) - _emitRexR(dst.getRegType() == REG_TYPE_GPQ, 1, dst.getRegCode(), forceRexPrefix); + _emitRexR(dst.getRegType() == kX86RegTypeGpq, 1, dst.getRegCode(), forceRexPrefix); #endif // ASMJIT_X64 _emitByte(0x0F); _emitModR(1, dst.getRegCode()); @@ -1094,16 +1046,16 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope break; } - case InstructionDescription::G_BT: + case kX86InstGroupBTest: { if (o0->isRegMem() && o1->isReg()) { const Operand& dst = reinterpret_cast(*o0); - const GPReg& src = reinterpret_cast(*o1); + const GpReg& src = reinterpret_cast(*o1); - _emitX86RM(id->opCode[0], - src.isRegType(REG_TYPE_GPW), - src.isRegType(REG_TYPE_GPQ), + _emitX86RM(id->_opCode[0], + src.isRegType(kX86RegTypeGpw), + src.isRegType(kX86RegTypeGpq), src.getRegCode(), dst, 0, forceRexPrefix); @@ -1115,10 +1067,10 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope const Operand& dst = reinterpret_cast(*o0); const Imm& src = reinterpret_cast(*o1); - _emitX86RM(id->opCode[1], + _emitX86RM(id->_opCode[1], dst.getSize() == 2, dst.getSize() == 8, - (uint8_t)id->opCodeR, + (uint8_t)id->_opCodeR, dst, 1, forceRexPrefix); _FINISHED_IMMEDIATE(o1, 1); @@ -1127,9 +1079,9 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope break; } - case InstructionDescription::G_CALL: + case kX86InstGroupCall: { - if (o0->isRegTypeMem(REG_TYPE_GPN)) + if (o0->isRegTypeMem(kX86RegTypeGpz)) { const Operand& dst = reinterpret_cast(*o0); _emitX86RM(0xFF, @@ -1143,13 +1095,13 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope { const Imm& imm = reinterpret_cast(*o0); _emitByte(0xE8); - _emitJmpOrCallReloc(InstructionDescription::G_CALL, (void*)imm.getValue()); + _emitJmpOrCallReloc(kX86InstGroupCall, (void*)imm.getValue()); _FINISHED(); } if (o0->isLabel()) { - LabelData& l_data = _labelData[reinterpret_cast(o0)->getId() & OPERAND_ID_VALUE_MASK]; + LabelData& l_data = _labels[reinterpret_cast(o0)->getId() & kOperandIdValueMask]; if (l_data.offset != -1) { @@ -1174,15 +1126,15 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope break; } - case InstructionDescription::G_CRC32: + case kX86InstGroupCrc32: { if (o0->isReg() && o1->isRegMem()) { - const GPReg& dst = reinterpret_cast(*o0); + const GpReg& dst = reinterpret_cast(*o0); const Operand& src = reinterpret_cast(*o1); - ASMJIT_ASSERT(dst.getRegType() == REG_TYPE_GPD || dst.getRegType() == REG_TYPE_GPQ); + ASMJIT_ASSERT(dst.getRegType() == kX86RegTypeGpd || dst.getRegType() == kX86RegTypeGpq); - _emitX86RM(id->opCode[0] + (src.getSize() != 1), + _emitX86RM(id->_opCode[0] + (src.getSize() != 1), src.getSize() == 2, dst.getRegType() == 8, dst.getRegCode(), src, 0, forceRexPrefix); @@ -1192,19 +1144,19 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope break; } - case InstructionDescription::G_ENTER: + case kX86InstGroupEnter: { if (o0->isImm() && o1->isImm()) { _emitByte(0xC8); - _emitWord((uint16_t)(sysuint_t)reinterpret_cast(*o2).getValue()); - _emitByte((uint8_t )(sysuint_t)reinterpret_cast(*o1).getValue()); + _emitWord((uint16_t)(uintptr_t)reinterpret_cast(*o2).getValue()); + _emitByte((uint8_t )(uintptr_t)reinterpret_cast(*o1).getValue()); _FINISHED(); } break; } - case InstructionDescription::G_IMUL: + case kX86InstGroupIMul: { // 1 operand if (o0->isRegMem() && o1->isNone() && o2->isNone()) @@ -1219,16 +1171,16 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope // 2 operands else if (o0->isReg() && !o1->isNone() && o2->isNone()) { - const GPReg& dst = reinterpret_cast(*o0); - ASMJIT_ASSERT(!dst.isRegType(REG_TYPE_GPW)); + const GpReg& dst = reinterpret_cast(*o0); + ASMJIT_ASSERT(!dst.isRegType(kX86RegTypeGpw)); if (o1->isRegMem()) { const Operand& src = reinterpret_cast(*o1); _emitX86RM(0x0FAF, - dst.isRegType(REG_TYPE_GPW), - dst.isRegType(REG_TYPE_GPQ), dst.getRegCode(), src, + dst.isRegType(kX86RegTypeGpw), + dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), src, 0, forceRexPrefix); _FINISHED(); } @@ -1236,20 +1188,20 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope { const Imm& imm = reinterpret_cast(*o1); - if (Util::isInt8(imm.getValue())) + if (IntUtil::isInt8(imm.getValue())) { _emitX86RM(0x6B, - dst.isRegType(REG_TYPE_GPW), - dst.isRegType(REG_TYPE_GPQ), dst.getRegCode(), dst, + dst.isRegType(kX86RegTypeGpw), + dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), dst, 1, forceRexPrefix); _FINISHED_IMMEDIATE(&imm, 1); } else { - immSize = dst.isRegType(REG_TYPE_GPW) ? 2 : 4; + immSize = dst.isRegType(kX86RegTypeGpw) ? 2 : 4; _emitX86RM(0x69, - dst.isRegType(REG_TYPE_GPW), - dst.isRegType(REG_TYPE_GPQ), dst.getRegCode(), dst, + dst.isRegType(kX86RegTypeGpw), + dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), dst, immSize, forceRexPrefix); _FINISHED_IMMEDIATE(&imm, immSize); } @@ -1258,24 +1210,24 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope // 3 operands else if (o0->isReg() && o1->isRegMem() && o2->isImm()) { - const GPReg& dst = reinterpret_cast(*o0); + const GpReg& dst = reinterpret_cast(*o0); const Operand& src = reinterpret_cast(*o1); const Imm& imm = reinterpret_cast(*o2); - if (Util::isInt8(imm.getValue())) + if (IntUtil::isInt8(imm.getValue())) { _emitX86RM(0x6B, - dst.isRegType(REG_TYPE_GPW), - dst.isRegType(REG_TYPE_GPQ), dst.getRegCode(), src, + dst.isRegType(kX86RegTypeGpw), + dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), src, 1, forceRexPrefix); _FINISHED_IMMEDIATE(&imm, 1); } else { - immSize = dst.isRegType(REG_TYPE_GPW) ? 2 : 4; + immSize = dst.isRegType(kX86RegTypeGpw) ? 2 : 4; _emitX86RM(0x69, - dst.isRegType(REG_TYPE_GPW), - dst.isRegType(REG_TYPE_GPQ), dst.getRegCode(), src, + dst.isRegType(kX86RegTypeGpw), + dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), src, immSize, forceRexPrefix); _FINISHED_IMMEDIATE(&imm, immSize); } @@ -1284,7 +1236,7 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope break; } - case InstructionDescription::G_INC_DEC: + case kX86InstGroupIncDec: { if (o0->isRegMem()) { @@ -1292,19 +1244,19 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope // INC [r16|r32] in 64-bit mode is not encodable. #if defined(ASMJIT_X86) - if ((dst.isReg()) && (dst.isRegType(REG_TYPE_GPW) || dst.isRegType(REG_TYPE_GPD))) + if ((dst.isReg()) && (dst.isRegType(kX86RegTypeGpw) || dst.isRegType(kX86RegTypeGpd))) { - _emitX86Inl(id->opCode[0], - dst.isRegType(REG_TYPE_GPW), - 0, reinterpret_cast(dst).getRegCode(), + _emitX86Inl(id->_opCode[0], + dst.isRegType(kX86RegTypeGpw), + 0, reinterpret_cast(dst).getRegCode(), false); _FINISHED(); } #endif // ASMJIT_X86 - _emitX86RM(id->opCode[1] + (dst.getSize() != 1), + _emitX86RM(id->_opCode[1] + (dst.getSize() != 1), dst.getSize() == 2, - dst.getSize() == 8, (uint8_t)id->opCodeR, dst, + dst.getSize() == 8, (uint8_t)id->_opCodeR, dst, 0, forceRexPrefix); _FINISHED(); } @@ -1312,22 +1264,22 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope break; } - case InstructionDescription::G_J: + case kX86InstGroupJcc: { if (o0->isLabel()) { - LabelData& l_data = _labelData[reinterpret_cast(o0)->getId() & OPERAND_ID_VALUE_MASK]; + LabelData& l_data = _labels[reinterpret_cast(o0)->getId() & kOperandIdValueMask]; uint32_t hint = (uint32_t)(o1->isImm() ? reinterpret_cast(*o1).getValue() : 0); - bool isShortJump = (_emitOptions & EMIT_OPTION_SHORT_JUMP) != 0; + bool isShortJump = (_emitOptions & kX86EmitOptionShortJump) != 0; // Emit jump hint if configured for that. - if ((hint & (HINT_TAKEN | HINT_NOT_TAKEN)) && (_properties & (1 << PROPERTY_JUMP_HINTS))) + if ((hint & (kCondHintLikely | kCondHintUnlikely)) && (_properties & (1 << kX86PropertyJumpHints))) { - if (hint & HINT_TAKEN) - _emitByte(HINT_BYTE_VALUE_TAKEN); - else if (hint & HINT_NOT_TAKEN) - _emitByte(HINT_BYTE_VALUE_NOT_TAKEN); + if (hint & kCondHintLikely) + _emitByte(kX86CondPrefixLikely); + else if (hint & kCondHintUnlikely) + _emitByte(kX86CondPrefixUnlikely); } if (l_data.offset != -1) @@ -1339,24 +1291,24 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope ASMJIT_ASSERT(offs <= 0); - if (Util::isInt8(offs - rel8_size)) + if (IntUtil::isInt8(offs - rel8_size)) { - _emitByte(0x70 | (uint8_t)id->opCode[0]); + _emitByte(0x70 | (uint8_t)id->_opCode[0]); _emitByte((uint8_t)(int8_t)(offs - rel8_size)); // Change the emit options so logger can log instruction correctly. - _emitOptions |= EMIT_OPTION_SHORT_JUMP; + _emitOptions |= kX86EmitOptionShortJump; } else { if (isShortJump && _logger) { _logger->logString("*** ASSEMBLER WARNING: Emitting long conditional jump, but short jump instruction forced!\n"); - _emitOptions &= ~EMIT_OPTION_SHORT_JUMP; + _emitOptions &= ~kX86EmitOptionShortJump; } _emitByte(0x0F); - _emitByte(0x80 | (uint8_t)id->opCode[0]); + _emitByte(0x80 | (uint8_t)id->_opCode[0]); _emitInt32((int32_t)(offs - rel32_size)); } } @@ -1365,13 +1317,13 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope // Non-bound label. if (isShortJump) { - _emitByte(0x70 | (uint8_t)id->opCode[0]); + _emitByte(0x70 | (uint8_t)id->_opCode[0]); _emitDisplacement(l_data, -1, 1); } else { _emitByte(0x0F); - _emitByte(0x80 | (uint8_t)id->opCode[0]); + _emitByte(0x80 | (uint8_t)id->_opCode[0]); _emitDisplacement(l_data, -4, 4); } } @@ -1381,7 +1333,7 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope break; } - case InstructionDescription::G_JMP: + case kX86InstGroupJmp: { if (o0->isRegMem()) { @@ -1398,14 +1350,14 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope { const Imm& imm = reinterpret_cast(*o0); _emitByte(0xE9); - _emitJmpOrCallReloc(InstructionDescription::G_JMP, (void*)imm.getValue()); + _emitJmpOrCallReloc(kX86InstGroupJmp, (void*)imm.getValue()); _FINISHED(); } if (o0->isLabel()) { - LabelData& l_data = _labelData[reinterpret_cast(o0)->getId() & OPERAND_ID_VALUE_MASK]; - bool isShortJump = (_emitOptions & EMIT_OPTION_SHORT_JUMP) != 0; + LabelData& l_data = _labels[reinterpret_cast(o0)->getId() & kOperandIdValueMask]; + bool isShortJump = (_emitOptions & kX86EmitOptionShortJump) != 0; if (l_data.offset != -1) { @@ -1414,13 +1366,13 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope const sysint_t rel32_size = 5; sysint_t offs = l_data.offset - getOffset(); - if (Util::isInt8(offs - rel8_size)) + if (IntUtil::isInt8(offs - rel8_size)) { _emitByte(0xEB); _emitByte((uint8_t)(int8_t)(offs - rel8_size)); // Change the emit options so logger can log instruction correctly. - _emitOptions |= EMIT_OPTION_SHORT_JUMP; + _emitOptions |= kX86EmitOptionShortJump; } else { @@ -1429,7 +1381,7 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope if (_logger) { _logger->logString("*** ASSEMBLER WARNING: Emitting long jump, but short jump instruction forced!\n"); - _emitOptions &= ~EMIT_OPTION_SHORT_JUMP; + _emitOptions &= ~kX86EmitOptionShortJump; } } @@ -1457,11 +1409,11 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope break; } - case InstructionDescription::G_LEA: + case kX86InstGroupLea: { if (o0->isReg() && o1->isMem()) { - const GPReg& dst = reinterpret_cast(*o0); + const GpReg& dst = reinterpret_cast(*o0); const Mem& src = reinterpret_cast(*o1); // Size override prefix support. @@ -1469,15 +1421,15 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope { _emitByte(0x67); #if defined(ASMJIT_X86) - memRegType = REG_TYPE_GPW; + memRegType = kX86RegTypeGpw; #else - memRegType = REG_TYPE_GPD; + memRegType = kX86RegTypeGpd; #endif } _emitX86RM(0x8D, - dst.isRegType(REG_TYPE_GPW), - dst.isRegType(REG_TYPE_GPQ), dst.getRegCode(), src, + dst.isRegType(kX86RegTypeGpw), + dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), src, 0, forceRexPrefix); _FINISHED(); } @@ -1485,17 +1437,17 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope break; } - case InstructionDescription::G_M: + case kX86InstGroupMem: { if (o0->isMem()) { - _emitX86RM(id->opCode[0], 0, (uint8_t)id->opCode[1], (uint8_t)id->opCodeR, reinterpret_cast(*o0), 0, forceRexPrefix); + _emitX86RM(id->_opCode[0], 0, (uint8_t)id->_opCode[1], (uint8_t)id->_opCodeR, reinterpret_cast(*o0), 0, forceRexPrefix); _FINISHED(); } break; } - case InstructionDescription::G_MOV: + case kX86InstGroupMov: { const Operand& dst = *o0; const Operand& src = *o1; @@ -1503,14 +1455,14 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope switch (dst.getType() << 4 | src.getType()) { // Reg <- Reg/Mem - case (OPERAND_REG << 4) | OPERAND_REG: + case (kOperandReg << 4) | kOperandReg: { // Reg <- Sreg - if (src.isRegType(REG_TYPE_SEGMENT)) + if (src.isRegType(kX86RegTypeSeg)) { - ASMJIT_ASSERT(dst.isRegType(REG_TYPE_GPW) || - dst.isRegType(REG_TYPE_GPD) || - dst.isRegType(REG_TYPE_GPQ) ); + ASMJIT_ASSERT(dst.isRegType(kX86RegTypeGpw) || + dst.isRegType(kX86RegTypeGpd) || + dst.isRegType(kX86RegTypeGpq) ); _emitX86RM(0x8C, dst.getSize() == 2, @@ -1522,11 +1474,11 @@ void AssemblerCore::_emitInstruction(uint32_t code, const Operand* o0, const Ope } // Sreg <- Reg/Mem - if (dst.isRegType(REG_TYPE_SEGMENT)) + if (dst.isRegType(kX86RegTypeSeg)) { - ASMJIT_ASSERT(src.isRegType(REG_TYPE_GPW ) || - src.isRegType(REG_TYPE_GPD ) || - src.isRegType(REG_TYPE_GPQ ) ); + ASMJIT_ASSERT(src.isRegType(kX86RegTypeGpw ) || + src.isRegType(kX86RegTypeGpd ) || + src.isRegType(kX86RegTypeGpq ) ); _Emit_Mov_Sreg_RM: _emitX86RM(0x8E, @@ -1538,40 +1490,40 @@ _Emit_Mov_Sreg_RM: _FINISHED(); } - ASMJIT_ASSERT(src.isRegType(REG_TYPE_GPB_LO) || - src.isRegType(REG_TYPE_GPB_HI) || - src.isRegType(REG_TYPE_GPW ) || - src.isRegType(REG_TYPE_GPD ) || - src.isRegType(REG_TYPE_GPQ ) ); + ASMJIT_ASSERT(src.isRegType(kX86RegTypeGpbLo) || + src.isRegType(kX86RegTypeGpbHi) || + src.isRegType(kX86RegTypeGpw ) || + src.isRegType(kX86RegTypeGpd ) || + src.isRegType(kX86RegTypeGpq ) ); // ... fall through ... } - case (OPERAND_REG << 4) | OPERAND_MEM: + case (kOperandReg << 4) | kOperandMem: { // Sreg <- Mem - if (dst.isRegType(REG_TYPE_SEGMENT)) + if (dst.isRegType(kX86RegTypeSeg)) { goto _Emit_Mov_Sreg_RM; } - ASMJIT_ASSERT(dst.isRegType(REG_TYPE_GPB_LO) || - dst.isRegType(REG_TYPE_GPB_HI) || - dst.isRegType(REG_TYPE_GPW ) || - dst.isRegType(REG_TYPE_GPD ) || - dst.isRegType(REG_TYPE_GPQ ) ); + ASMJIT_ASSERT(dst.isRegType(kX86RegTypeGpbLo) || + dst.isRegType(kX86RegTypeGpbHi) || + dst.isRegType(kX86RegTypeGpw ) || + dst.isRegType(kX86RegTypeGpd ) || + dst.isRegType(kX86RegTypeGpq ) ); _emitX86RM(0x0000008A + (dst.getSize() != 1), - dst.isRegType(REG_TYPE_GPW), - dst.isRegType(REG_TYPE_GPQ), - reinterpret_cast(dst).getRegCode(), + dst.isRegType(kX86RegTypeGpw), + dst.isRegType(kX86RegTypeGpq), + reinterpret_cast(dst).getRegCode(), reinterpret_cast(src), 0, forceRexPrefix); _FINISHED(); } // Reg <- Imm - case (OPERAND_REG << 4) | OPERAND_IMM: + case (kOperandReg << 4) | kOperandImm: { - const GPReg& dst = reinterpret_cast(*o0); + const GpReg& dst = reinterpret_cast(*o0); const Imm& src = reinterpret_cast(*o1); // In 64-bit mode the immediate can be 64-bits long if the @@ -1581,7 +1533,7 @@ _Emit_Mov_Sreg_RM: #if defined(ASMJIT_X64) // Optimize instruction size by using 32-bit immediate if value can // fit into it. - if (immSize == 8 && Util::isInt32(src.getValue())) + if (immSize == 8 && IntUtil::isInt32(src.getValue())) { _emitX86RM(0xC7, 0, // 16BIT @@ -1595,8 +1547,8 @@ _Emit_Mov_Sreg_RM: { #endif // ASMJIT_X64 _emitX86Inl((dst.getSize() == 1 ? 0xB0 : 0xB8), - dst.isRegType(REG_TYPE_GPW), - dst.isRegType(REG_TYPE_GPQ), + dst.isRegType(kX86RegTypeGpw), + dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), forceRexPrefix); #if defined(ASMJIT_X64) } @@ -1606,9 +1558,9 @@ _Emit_Mov_Sreg_RM: } // Mem <- Reg/Sreg - case (OPERAND_MEM << 4) | OPERAND_REG: + case (kOperandMem << 4) | kOperandReg: { - if (src.isRegType(REG_TYPE_SEGMENT)) + if (src.isRegType(kX86RegTypeSeg)) { // Mem <- Sreg _emitX86RM(0x8C, @@ -1622,16 +1574,16 @@ _Emit_Mov_Sreg_RM: else { // Mem <- Reg - ASMJIT_ASSERT(src.isRegType(REG_TYPE_GPB_LO) || - src.isRegType(REG_TYPE_GPB_HI) || - src.isRegType(REG_TYPE_GPW ) || - src.isRegType(REG_TYPE_GPD ) || - src.isRegType(REG_TYPE_GPQ ) ); + ASMJIT_ASSERT(src.isRegType(kX86RegTypeGpbLo) || + src.isRegType(kX86RegTypeGpbHi) || + src.isRegType(kX86RegTypeGpw ) || + src.isRegType(kX86RegTypeGpd ) || + src.isRegType(kX86RegTypeGpq ) ); _emitX86RM(0x88 + (src.getSize() != 1), - src.isRegType(REG_TYPE_GPW), - src.isRegType(REG_TYPE_GPQ), - reinterpret_cast(src).getRegCode(), + src.isRegType(kX86RegTypeGpw), + src.isRegType(kX86RegTypeGpq), + reinterpret_cast(src).getRegCode(), reinterpret_cast(dst), 0, forceRexPrefix); _FINISHED(); @@ -1639,9 +1591,9 @@ _Emit_Mov_Sreg_RM: } // Mem <- Imm - case (OPERAND_MEM << 4) | OPERAND_IMM: + case (kOperandMem << 4) | kOperandImm: { - immSize = dst.getSize() <= 4 ? dst.getSize() : 4; + immSize = IntUtil::_min(dst.getSize(), 4); _emitX86RM(0xC6 + (dst.getSize() != 1), dst.getSize() == 2, @@ -1656,19 +1608,19 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_MOV_PTR: + case kX86InstGroupMovPtr: { if ((o0->isReg() && o1->isImm()) || (o0->isImm() && o1->isReg())) { - bool reverse = o1->getType() == OPERAND_REG; + bool reverse = o1->getType() == kOperandReg; uint8_t opCode = !reverse ? 0xA0 : 0xA2; - const GPReg& reg = reinterpret_cast(!reverse ? *o0 : *o1); + const GpReg& reg = reinterpret_cast(!reverse ? *o0 : *o1); const Imm& imm = reinterpret_cast(!reverse ? *o1 : *o0); if (reg.getRegIndex() != 0) - goto illegalInstruction; + goto _IllegalInstruction; - if (reg.isRegType(REG_TYPE_GPW)) _emitByte(0x66); + if (reg.isRegType(kX86RegTypeGpw)) _emitByte(0x66); #if defined(ASMJIT_X64) _emitRexR(reg.getSize() == 8, 0, 0, forceRexPrefix); #endif // ASMJIT_X64 @@ -1679,25 +1631,25 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_MOVSX_MOVZX: + case kX86InstGroupMovSxMovZx: { if (o0->isReg() && o1->isRegMem()) { - const GPReg& dst = reinterpret_cast(*o0); + const GpReg& dst = reinterpret_cast(*o0); const Operand& src = reinterpret_cast(*o1); if (dst.getSize() == 1) - goto illegalInstruction; + goto _IllegalInstruction; if (src.getSize() != 1 && src.getSize() != 2) - goto illegalInstruction; + goto _IllegalInstruction; if (src.getSize() == 2 && dst.getSize() == 2) - goto illegalInstruction; + goto _IllegalInstruction; - _emitX86RM(id->opCode[0] + (src.getSize() != 1), - dst.isRegType(REG_TYPE_GPW), - dst.isRegType(REG_TYPE_GPQ), + _emitX86RM(id->_opCode[0] + (src.getSize() != 1), + dst.isRegType(kX86RegTypeGpw), + dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), src, 0, forceRexPrefix); @@ -1708,11 +1660,11 @@ _Emit_Mov_Sreg_RM: } #if defined(ASMJIT_X64) - case InstructionDescription::G_MOVSXD: + case kX86InstGroupMovSxD: { if (o0->isReg() && o1->isRegMem()) { - const GPReg& dst = reinterpret_cast(*o0); + const GpReg& dst = reinterpret_cast(*o0); const Operand& src = reinterpret_cast(*o1); _emitX86RM(0x00000063, 0, @@ -1725,14 +1677,38 @@ _Emit_Mov_Sreg_RM: } #endif // ASMJIT_X64 - case InstructionDescription::G_PUSH: + case kX86InstGroupPush: { - // This section is only for immediates, memory/register operands are handled in G_POP. + if (o0->isRegType(kX86RegTypeSeg)) + { + static const uint32_t opcodeList[] = + { + 0x06, // ES. + 0x0E, // CS. + 0x16, // SS. + 0x1E, // DS. + 0x0FA0, // FS. + 0x0FA8 // GS. + }; + + unsigned int segment = reinterpret_cast(o0)->getRegIndex(); + ASMJIT_ASSERT(segment < kX86SegCount); + + unsigned int opcode = opcodeList[segment]; + + if (opcode > 0xFF) + _emitByte(opcode >> 8); + _emitByte(opcode & 0xFF); + + _FINISHED(); + } + + // This section is only for immediates, memory/register operands are handled in kX86InstGroupPop. if (o0->isImm()) { const Imm& imm = reinterpret_cast(*o0); - if (Util::isInt8(imm.getValue())) + if (IntUtil::isInt8(imm.getValue())) { _emitByte(0x6A); _FINISHED_IMMEDIATE(&imm, 1); @@ -1744,38 +1720,63 @@ _Emit_Mov_Sreg_RM: } } - // ... goto G_POP ... + // ... goto kX86InstGroupPop ... } - case InstructionDescription::G_POP: + case kX86InstGroupPop: { + if (o0->isRegType(kX86RegTypeSeg)) + { + static const uint32_t opcodeList[] = + { + 0x07, // ES. + 0, // CS. + 0x17, // SS. + 0x1F, // DS. + 0x0FA1, // FS. + 0x0FA9 // GS. + }; + + unsigned int segment = reinterpret_cast(o0)->getRegIndex(); + ASMJIT_ASSERT(segment < kX86SegCount); + + unsigned int opcode = opcodeList[segment]; + ASMJIT_ASSERT(opcode != 0); + + if (opcode > 0xFF) + _emitByte(opcode >> 8); + _emitByte(opcode & 0xFF); + + _FINISHED(); + } + if (o0->isReg()) { - ASMJIT_ASSERT(o0->isRegType(REG_TYPE_GPW) || o0->isRegType(REG_TYPE_GPN)); - _emitX86Inl(id->opCode[0], o0->isRegType(REG_TYPE_GPW), 0, reinterpret_cast(*o0).getRegCode(), forceRexPrefix); + ASMJIT_ASSERT(o0->isRegType(kX86RegTypeGpw) || o0->isRegType(kX86RegTypeGpz)); + _emitX86Inl(id->_opCode[0], o0->isRegType(kX86RegTypeGpw), 0, reinterpret_cast(*o0).getRegCode(), forceRexPrefix); _FINISHED(); } if (o0->isMem()) { - _emitX86RM(id->opCode[1], o0->getSize() == 2, 0, (uint8_t)id->opCodeR, reinterpret_cast(*o0), 0, forceRexPrefix); + _emitX86RM(id->_opCode[1], o0->getSize() == 2, 0, (uint8_t)id->_opCodeR, reinterpret_cast(*o0), 0, forceRexPrefix); _FINISHED(); } break; } - case InstructionDescription::G_R_RM: + case kX86InstGroupRegRm: { if (o0->isReg() && o1->isRegMem()) { - const GPReg& dst = reinterpret_cast(*o0); + const GpReg& dst = reinterpret_cast(*o0); const Operand& src = reinterpret_cast(*o1); ASMJIT_ASSERT(dst.getSize() != 1); - _emitX86RM(id->opCode[0], - dst.getRegType() == REG_TYPE_GPW, - dst.getRegType() == REG_TYPE_GPQ, dst.getRegCode(), src, + _emitX86RM(id->_opCode[0], + dst.getRegType() == kX86RegTypeGpw, + dst.getRegType() == kX86RegTypeGpq, dst.getRegCode(), src, 0, forceRexPrefix); _FINISHED(); } @@ -1783,7 +1784,22 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_RM_B: + case kX86InstGroupRm: + { + if (o0->isRegMem()) + { + const Operand& op = reinterpret_cast(*o0); + _emitX86RM(id->_opCode[0] + (op.getSize() != 1), + op.getSize() == 2, + op.getSize() == 8, (uint8_t)id->_opCodeR, op, + 0, forceRexPrefix); + _FINISHED(); + } + + break; + } + + case kX86InstGroupRmByte: { if (o0->isRegMem()) { @@ -1792,37 +1808,22 @@ _Emit_Mov_Sreg_RM: // Only BYTE register or BYTE/TYPELESS memory location can be used. ASMJIT_ASSERT(op.getSize() <= 1); - _emitX86RM(id->opCode[0], false, false, 0, op, 0, forceRexPrefix); + _emitX86RM(id->_opCode[0], false, false, 0, op, 0, forceRexPrefix); _FINISHED(); } break; } - case InstructionDescription::G_RM: - { - if (o0->isRegMem()) - { - const Operand& op = reinterpret_cast(*o0); - _emitX86RM(id->opCode[0] + (op.getSize() != 1), - op.getSize() == 2, - op.getSize() == 8, (uint8_t)id->opCodeR, op, - 0, forceRexPrefix); - _FINISHED(); - } - - break; - } - - case InstructionDescription::G_RM_R: + case kX86InstGroupRmReg: { if (o0->isRegMem() && o1->isReg()) { const Operand& dst = reinterpret_cast(*o0); - const GPReg& src = reinterpret_cast(*o1); - _emitX86RM(id->opCode[0] + (src.getSize() != 1), - src.getRegType() == REG_TYPE_GPW, - src.getRegType() == REG_TYPE_GPQ, src.getRegCode(), dst, + const GpReg& src = reinterpret_cast(*o1); + _emitX86RM(id->_opCode[0] + (src.getSize() != 1), + src.getRegType() == kX86RegTypeGpw, + src.getRegType() == kX86RegTypeGpq, src.getRegCode(), dst, 0, forceRexPrefix); _FINISHED(); } @@ -1830,10 +1831,10 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_REP: + case kX86InstGroupRep: { - uint32_t opCode = id->opCode[0]; - uint32_t opSize = id->opCode[1]; + uint32_t opCode = id->_opCode[0]; + uint32_t opSize = id->_opCode[1]; // Emit REP prefix (1 BYTE). _emitByte(opCode >> 24); @@ -1849,7 +1850,7 @@ _Emit_Mov_Sreg_RM: _FINISHED(); } - case InstructionDescription::G_RET: + case kX86InstGroupRet: { if (o0->isNone()) { @@ -1859,7 +1860,7 @@ _Emit_Mov_Sreg_RM: else if (o0->isImm()) { const Imm& imm = reinterpret_cast(*o0); - ASMJIT_ASSERT(Util::isUInt16(imm.getValue())); + ASMJIT_ASSERT(IntUtil::isUInt16(imm.getValue())); if (imm.getValue() == 0) { @@ -1876,9 +1877,9 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_ROT: + case kX86InstGroupRot: { - if (o0->isRegMem() && (o1->isRegCode(REG_CL) || o1->isImm())) + if (o0->isRegMem() && (o1->isRegCode(kX86RegCl) || o1->isImm())) { // generate opcode. For these operations is base 0xC0 or 0xD0. bool useImm8 = o1->isImm() && reinterpret_cast(*o1).getValue() != 1; @@ -1886,12 +1887,12 @@ _Emit_Mov_Sreg_RM: // size and operand type modifies the opcode if (o0->getSize() != 1) opCode |= 0x01; - if (o1->getType() == OPERAND_REG) opCode |= 0x02; + if (o1->getType() == kOperandReg) opCode |= 0x02; _emitX86RM(opCode, o0->getSize() == 2, o0->getSize() == 8, - (uint8_t)id->opCodeR, reinterpret_cast(*o0), + (uint8_t)id->_opCodeR, reinterpret_cast(*o0), useImm8 ? 1 : 0, forceRexPrefix); if (useImm8) @@ -1903,19 +1904,19 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_SHLD_SHRD: + case kX86InstGroupShldShrd: { - if (o0->isRegMem() && o1->isReg() && (o2->isImm() || (o2->isReg() && o2->isRegCode(REG_CL)))) + if (o0->isRegMem() && o1->isReg() && (o2->isImm() || (o2->isReg() && o2->isRegCode(kX86RegCl)))) { const Operand& dst = reinterpret_cast(*o0); - const GPReg& src1 = reinterpret_cast(*o1); + const GpReg& src1 = reinterpret_cast(*o1); const Operand& src2 = reinterpret_cast(*o2); ASMJIT_ASSERT(dst.getSize() == src1.getSize()); - _emitX86RM(id->opCode[0] + src2.isReg(), - src1.isRegType(REG_TYPE_GPW), - src1.isRegType(REG_TYPE_GPQ), + _emitX86RM(id->_opCode[0] + src2.isReg(), + src1.isRegType(kX86RegTypeGpw), + src1.isRegType(kX86RegTypeGpq), src1.getRegCode(), dst, src2.isImm() ? 1 : 0, forceRexPrefix); if (src2.isImm()) @@ -1927,22 +1928,23 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_TEST: + case kX86InstGroupTest: { if (o0->isRegMem() && o1->isReg()) { ASMJIT_ASSERT(o0->getSize() == o1->getSize()); _emitX86RM(0x84 + (o1->getSize() != 1), o1->getSize() == 2, o1->getSize() == 8, - reinterpret_cast(*o1).getRegCode(), + reinterpret_cast(*o1).getRegCode(), reinterpret_cast(*o0), 0, forceRexPrefix); _FINISHED(); } + // Alternate Form - AL, AX, EAX, RAX. if (o0->isRegIndex(0) && o1->isImm()) { - immSize = o0->getSize() <= 4 ? o0->getSize() : 4; + immSize = IntUtil::_min(o0->getSize(), 4); if (o0->getSize() == 2) _emitByte(0x66); // 16-bit. #if defined(ASMJIT_X64) @@ -1954,7 +1956,7 @@ _Emit_Mov_Sreg_RM: if (o0->isRegMem() && o1->isImm()) { - immSize = o0->getSize() <= 4 ? o0->getSize() : 4; + immSize = IntUtil::_min(o0->getSize(), 4); if (o0->getSize() == 2) _emitByte(0x66); // 16-bit. _emitSegmentPrefix(reinterpret_cast(*o0)); // Segment prefix. @@ -1969,25 +1971,25 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_XCHG: + case kX86InstGroupXchg: { if (o0->isRegMem() && o1->isReg()) { const Operand& dst = reinterpret_cast(*o0); - const GPReg& src = reinterpret_cast(*o1); + const GpReg& src = reinterpret_cast(*o1); - if (src.isRegType(REG_TYPE_GPW)) _emitByte(0x66); // 16-bit. + if (src.isRegType(kX86RegTypeGpw)) _emitByte(0x66); // 16-bit. _emitSegmentPrefix(dst); // segment prefix #if defined(ASMJIT_X64) - _emitRexRM(src.isRegType(REG_TYPE_GPQ), src.getRegCode(), dst, forceRexPrefix); + _emitRexRM(src.isRegType(kX86RegTypeGpq), src.getRegCode(), dst, forceRexPrefix); #endif // ASMJIT_X64 // Special opcode for index 0 registers (AX, EAX, RAX vs register). - if ((dst.getType() == OPERAND_REG && dst.getSize() > 1) && - (reinterpret_cast(dst).getRegCode() == 0 || - reinterpret_cast(src).getRegCode() == 0 )) + if ((dst.getType() == kOperandReg && dst.getSize() > 1) && + (reinterpret_cast(dst).getRegCode() == 0 || + reinterpret_cast(src).getRegCode() == 0 )) { - uint8_t index = reinterpret_cast(dst).getRegCode() | src.getRegCode(); + uint8_t index = reinterpret_cast(dst).getRegCode() | src.getRegCode(); _emitByte(0x90 + index); _FINISHED(); } @@ -2000,14 +2002,14 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_MOVBE: + case kX86InstGroupMovBE: { if (o0->isReg() && o1->isMem()) { _emitX86RM(0x000F38F0, - o0->isRegType(REG_TYPE_GPW), - o0->isRegType(REG_TYPE_GPQ), - reinterpret_cast(*o0).getRegCode(), + o0->isRegType(kX86RegTypeGpw), + o0->isRegType(kX86RegTypeGpq), + reinterpret_cast(*o0).getRegCode(), reinterpret_cast(*o1), 0, forceRexPrefix); _FINISHED(); @@ -2016,9 +2018,9 @@ _Emit_Mov_Sreg_RM: if (o0->isMem() && o1->isReg()) { _emitX86RM(0x000F38F1, - o1->isRegType(REG_TYPE_GPW), - o1->isRegType(REG_TYPE_GPQ), - reinterpret_cast(*o1).getRegCode(), + o1->isRegType(kX86RegTypeGpw), + o1->isRegType(kX86RegTypeGpq), + reinterpret_cast(*o1).getRegCode(), reinterpret_cast(*o0), 0, forceRexPrefix); _FINISHED(); @@ -2027,30 +2029,30 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_X87_FPU: + case kX86InstGroupX87StM: { - if (o0->isRegType(REG_TYPE_X87)) + if (o0->isRegType(kX86RegTypeX87)) { uint8_t i1 = reinterpret_cast(*o0).getRegIndex(); uint8_t i2 = 0; - if (code != INST_FCOM && code != INST_FCOMP) + if (code != kX86InstFCom && code != kX86InstFComP) { - if (!o1->isRegType(REG_TYPE_X87)) - goto illegalInstruction; + if (!o1->isRegType(kX86RegTypeX87)) + goto _IllegalInstruction; i2 = reinterpret_cast(*o1).getRegIndex(); } else if (i1 != 0 && i2 != 0) { - goto illegalInstruction; + goto _IllegalInstruction; } _emitByte(i1 == 0 - ? ((id->opCode[0] & 0xFF000000) >> 24) - : ((id->opCode[0] & 0x00FF0000) >> 16)); + ? ((id->_opCode[0] & 0xFF000000) >> 24) + : ((id->_opCode[0] & 0x00FF0000) >> 16)); _emitByte(i1 == 0 - ? ((id->opCode[0] & 0x0000FF00) >> 8) + i2 - : ((id->opCode[0] & 0x000000FF) ) + i1); + ? ((id->_opCode[0] & 0x0000FF00) >> 8) + i2 + : ((id->_opCode[0] & 0x000000FF) ) + i1); _FINISHED(); } @@ -2058,85 +2060,85 @@ _Emit_Mov_Sreg_RM: { const Mem& m = reinterpret_cast(*o0); - // segment prefix + // Segment prefix. _emitSegmentPrefix(m); _emitByte(o0->getSize() == 4 - ? ((id->opCode[0] & 0xFF000000) >> 24) - : ((id->opCode[0] & 0x00FF0000) >> 16)); - _emitModM((uint8_t)id->opCodeR, m, 0); + ? ((id->_opCode[0] & 0xFF000000) >> 24) + : ((id->_opCode[0] & 0x00FF0000) >> 16)); + _emitModM((uint8_t)id->_opCodeR, m, 0); _FINISHED(); } break; } - case InstructionDescription::G_X87_STI: + case kX86InstGroupX87StI: { - if (o0->isRegType(REG_TYPE_X87)) + if (o0->isRegType(kX86RegTypeX87)) { uint8_t i = reinterpret_cast(*o0).getRegIndex(); - _emitByte((uint8_t)((id->opCode[0] & 0x0000FF00) >> 8)); - _emitByte((uint8_t)((id->opCode[0] & 0x000000FF) + i)); + _emitByte((uint8_t)((id->_opCode[0] & 0x0000FF00) >> 8)); + _emitByte((uint8_t)((id->_opCode[0] & 0x000000FF) + i)); _FINISHED(); } break; } - case InstructionDescription::G_X87_FSTSW: + case kX86InstGroupX87Status: { if (o0->isReg() && - reinterpret_cast(*o0).getRegType() <= REG_TYPE_GPQ && - reinterpret_cast(*o0).getRegIndex() == 0) + reinterpret_cast(*o0).getRegType() <= kX86RegTypeGpq && + reinterpret_cast(*o0).getRegIndex() == 0) { - _emitOpCode(id->opCode[1]); + _emitOpCode(id->_opCode[1]); _FINISHED(); } if (o0->isMem()) { - _emitX86RM(id->opCode[0], 0, 0, (uint8_t)id->opCodeR, reinterpret_cast(*o0), 0, forceRexPrefix); + _emitX86RM(id->_opCode[0], 0, 0, (uint8_t)id->_opCodeR, reinterpret_cast(*o0), 0, forceRexPrefix); _FINISHED(); } break; } - case InstructionDescription::G_X87_MEM_STI: + case kX86InstGroupX87FldFst: { - if (o0->isRegType(REG_TYPE_X87)) + if (o0->isRegType(kX86RegTypeX87)) { - _emitByte((uint8_t)((id->opCode[1] & 0xFF000000) >> 24)); - _emitByte((uint8_t)((id->opCode[1] & 0x00FF0000) >> 16) + + _emitByte((uint8_t)((id->_opCode[1] & 0xFF000000) >> 24)); + _emitByte((uint8_t)((id->_opCode[1] & 0x00FF0000) >> 16) + reinterpret_cast(*o0).getRegIndex()); _FINISHED(); } - // ... fall through to G_X87_MEM ... + // ... fall through to kX86InstGroupX87Mem ... } - case InstructionDescription::G_X87_MEM: + case kX86InstGroupX87Mem: { if (!o0->isMem()) - goto illegalInstruction; + goto _IllegalInstruction; const Mem& m = reinterpret_cast(*o0); uint8_t opCode = 0x00, mod = 0; - if (o0->getSize() == 2 && (id->oflags[0] & InstructionDescription::O_FM_2)) + if (o0->getSize() == 2 && (id->_opFlags[0] & kX86InstOpStM2)) { - opCode = (uint8_t)((id->opCode[0] & 0xFF000000) >> 24); - mod = (uint8_t)id->opCodeR; + opCode = (uint8_t)((id->_opCode[0] & 0xFF000000) >> 24); + mod = (uint8_t)id->_opCodeR; } - if (o0->getSize() == 4 && (id->oflags[0] & InstructionDescription::O_FM_4)) + if (o0->getSize() == 4 && (id->_opFlags[0] & kX86InstOpStM4)) { - opCode = (uint8_t)((id->opCode[0] & 0x00FF0000) >> 16); - mod = (uint8_t)id->opCodeR; + opCode = (uint8_t)((id->_opCode[0] & 0x00FF0000) >> 16); + mod = (uint8_t)id->_opCodeR; } - if (o0->getSize() == 8 && (id->oflags[0] & InstructionDescription::O_FM_8)) + if (o0->getSize() == 8 && (id->_opFlags[0] & kX86InstOpStM8)) { - opCode = (uint8_t)((id->opCode[0] & 0x0000FF00) >> 8); - mod = (uint8_t)((id->opCode[0] & 0x000000FF) ); + opCode = (uint8_t)((id->_opCode[0] & 0x0000FF00) >> 8); + mod = (uint8_t)((id->_opCode[0] & 0x000000FF) ); } if (opCode) @@ -2150,40 +2152,40 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_MMU_MOV: + case kX86InstGroupMmuMov: { - ASMJIT_ASSERT(id->oflags[0] != 0); - ASMJIT_ASSERT(id->oflags[1] != 0); + ASMJIT_ASSERT(id->_opFlags[0] != 0); + ASMJIT_ASSERT(id->_opFlags[1] != 0); // Check parameters (X)MM|GP32_64 <- (X)MM|GP32_64|Mem|Imm - if ((o0->isMem() && (id->oflags[0] & InstructionDescription::O_MEM) == 0) || - (o0->isRegType(REG_TYPE_MM ) && (id->oflags[0] & InstructionDescription::O_MM ) == 0) || - (o0->isRegType(REG_TYPE_XMM) && (id->oflags[0] & InstructionDescription::O_XMM) == 0) || - (o0->isRegType(REG_TYPE_GPD) && (id->oflags[0] & InstructionDescription::O_GD ) == 0) || - (o0->isRegType(REG_TYPE_GPQ) && (id->oflags[0] & InstructionDescription::O_GQ ) == 0) || - (o1->isRegType(REG_TYPE_MM ) && (id->oflags[1] & InstructionDescription::O_MM ) == 0) || - (o1->isRegType(REG_TYPE_XMM) && (id->oflags[1] & InstructionDescription::O_XMM) == 0) || - (o1->isRegType(REG_TYPE_GPD) && (id->oflags[1] & InstructionDescription::O_GD ) == 0) || - (o1->isRegType(REG_TYPE_GPQ) && (id->oflags[1] & InstructionDescription::O_GQ ) == 0) || - (o1->isMem() && (id->oflags[1] & InstructionDescription::O_MEM) == 0) ) + if ((o0->isMem() && (id->_opFlags[0] & kX86InstOpMem) == 0) || + (o0->isRegType(kX86RegTypeMm ) && (id->_opFlags[0] & kX86InstOpMm ) == 0) || + (o0->isRegType(kX86RegTypeXmm) && (id->_opFlags[0] & kX86InstOpXmm) == 0) || + (o0->isRegType(kX86RegTypeGpd) && (id->_opFlags[0] & kX86InstOpGd ) == 0) || + (o0->isRegType(kX86RegTypeGpq) && (id->_opFlags[0] & kX86InstOpGq ) == 0) || + (o1->isRegType(kX86RegTypeMm ) && (id->_opFlags[1] & kX86InstOpMm ) == 0) || + (o1->isRegType(kX86RegTypeXmm) && (id->_opFlags[1] & kX86InstOpXmm) == 0) || + (o1->isRegType(kX86RegTypeGpd) && (id->_opFlags[1] & kX86InstOpGd ) == 0) || + (o1->isRegType(kX86RegTypeGpq) && (id->_opFlags[1] & kX86InstOpGq ) == 0) || + (o1->isMem() && (id->_opFlags[1] & kX86InstOpMem) == 0) ) { - goto illegalInstruction; + goto _IllegalInstruction; } // Illegal. if (o0->isMem() && o1->isMem()) - goto illegalInstruction; + goto _IllegalInstruction; - uint8_t rexw = ((id->oflags[0] | id->oflags[1]) & InstructionDescription::O_NOREX) + uint8_t rexw = ((id->_opFlags[0] | id->_opFlags[1]) & kX86InstOpNoRex) ? 0 - : o0->isRegType(REG_TYPE_GPQ) | o1->isRegType(REG_TYPE_GPQ); + : o0->isRegType(kX86RegTypeGpq) | o1->isRegType(kX86RegTypeGpq); // (X)MM|Reg <- (X)MM|Reg if (o0->isReg() && o1->isReg()) { - _emitMmu(id->opCode[0], rexw, - reinterpret_cast(*o0).getRegCode(), - reinterpret_cast(*o1), + _emitMmu(id->_opCode[0], rexw, + reinterpret_cast(*o0).getRegCode(), + reinterpret_cast(*o1), 0); _FINISHED(); } @@ -2191,8 +2193,8 @@ _Emit_Mov_Sreg_RM: // (X)MM|Reg <- Mem if (o0->isReg() && o1->isMem()) { - _emitMmu(id->opCode[0], rexw, - reinterpret_cast(*o0).getRegCode(), + _emitMmu(id->_opCode[0], rexw, + reinterpret_cast(*o0).getRegCode(), reinterpret_cast(*o1), 0); _FINISHED(); @@ -2201,8 +2203,8 @@ _Emit_Mov_Sreg_RM: // Mem <- (X)MM|Reg if (o0->isMem() && o1->isReg()) { - _emitMmu(id->opCode[1], rexw, - reinterpret_cast(*o1).getRegCode(), + _emitMmu(id->_opCode[1], rexw, + reinterpret_cast(*o1).getRegCode(), reinterpret_cast(*o0), 0); _FINISHED(); @@ -2211,21 +2213,21 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_MMU_MOVD: + case kX86InstGroupMmuMovD: { - if ((o0->isRegType(REG_TYPE_MM) || o0->isRegType(REG_TYPE_XMM)) && (o1->isRegType(REG_TYPE_GPD) || o1->isMem())) + if ((o0->isRegType(kX86RegTypeMm) || o0->isRegType(kX86RegTypeXmm)) && (o1->isRegType(kX86RegTypeGpd) || o1->isMem())) { - _emitMmu(o0->isRegType(REG_TYPE_XMM) ? 0x66000F6E : 0x00000F6E, 0, - reinterpret_cast(*o0).getRegCode(), + _emitMmu(o0->isRegType(kX86RegTypeXmm) ? 0x66000F6E : 0x00000F6E, 0, + reinterpret_cast(*o0).getRegCode(), reinterpret_cast(*o1), 0); _FINISHED(); } - if ((o0->isRegType(REG_TYPE_GPD) || o0->isMem()) && (o1->isRegType(REG_TYPE_MM) || o1->isRegType(REG_TYPE_XMM))) + if ((o0->isRegType(kX86RegTypeGpd) || o0->isMem()) && (o1->isRegType(kX86RegTypeMm) || o1->isRegType(kX86RegTypeXmm))) { - _emitMmu(o1->isRegType(REG_TYPE_XMM) ? 0x66000F7E : 0x00000F7E, 0, - reinterpret_cast(*o1).getRegCode(), + _emitMmu(o1->isRegType(kX86RegTypeXmm) ? 0x66000F7E : 0x00000F7E, 0, + reinterpret_cast(*o1).getRegCode(), reinterpret_cast(*o0), 0); _FINISHED(); @@ -2234,96 +2236,96 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_MMU_MOVQ: + case kX86InstGroupMmuMovQ: { - if (o0->isRegType(REG_TYPE_MM) && o1->isRegType(REG_TYPE_MM)) + if (o0->isRegType(kX86RegTypeMm) && o1->isRegType(kX86RegTypeMm)) { _emitMmu(0x00000F6F, 0, - reinterpret_cast(*o0).getRegCode(), - reinterpret_cast(*o1), + reinterpret_cast(*o0).getRegCode(), + reinterpret_cast(*o1), 0); _FINISHED(); } - if (o0->isRegType(REG_TYPE_XMM) && o1->isRegType(REG_TYPE_XMM)) + if (o0->isRegType(kX86RegTypeXmm) && o1->isRegType(kX86RegTypeXmm)) { _emitMmu(0xF3000F7E, 0, - reinterpret_cast(*o0).getRegCode(), - reinterpret_cast(*o1), + reinterpret_cast(*o0).getRegCode(), + reinterpret_cast(*o1), 0); _FINISHED(); } // Convenience - movdq2q - if (o0->isRegType(REG_TYPE_MM) && o1->isRegType(REG_TYPE_XMM)) + if (o0->isRegType(kX86RegTypeMm) && o1->isRegType(kX86RegTypeXmm)) { _emitMmu(0xF2000FD6, 0, - reinterpret_cast(*o0).getRegCode(), - reinterpret_cast(*o1), + reinterpret_cast(*o0).getRegCode(), + reinterpret_cast(*o1), 0); _FINISHED(); } // Convenience - movq2dq - if (o0->isRegType(REG_TYPE_XMM) && o1->isRegType(REG_TYPE_MM)) + if (o0->isRegType(kX86RegTypeXmm) && o1->isRegType(kX86RegTypeMm)) { _emitMmu(0xF3000FD6, 0, - reinterpret_cast(*o0).getRegCode(), - reinterpret_cast(*o1), + reinterpret_cast(*o0).getRegCode(), + reinterpret_cast(*o1), 0); _FINISHED(); } - if (o0->isRegType(REG_TYPE_MM) && o1->isMem()) + if (o0->isRegType(kX86RegTypeMm) && o1->isMem()) { _emitMmu(0x00000F6F, 0, - reinterpret_cast(*o0).getRegCode(), + reinterpret_cast(*o0).getRegCode(), reinterpret_cast(*o1), 0); _FINISHED(); } - if (o0->isRegType(REG_TYPE_XMM) && o1->isMem()) + if (o0->isRegType(kX86RegTypeXmm) && o1->isMem()) { _emitMmu(0xF3000F7E, 0, - reinterpret_cast(*o0).getRegCode(), + reinterpret_cast(*o0).getRegCode(), reinterpret_cast(*o1), 0); _FINISHED(); } - if (o0->isMem() && o1->isRegType(REG_TYPE_MM)) + if (o0->isMem() && o1->isRegType(kX86RegTypeMm)) { _emitMmu(0x00000F7F, 0, - reinterpret_cast(*o1).getRegCode(), + reinterpret_cast(*o1).getRegCode(), reinterpret_cast(*o0), 0); _FINISHED(); } - if (o0->isMem() && o1->isRegType(REG_TYPE_XMM)) + if (o0->isMem() && o1->isRegType(kX86RegTypeXmm)) { _emitMmu(0x66000FD6, 0, - reinterpret_cast(*o1).getRegCode(), + reinterpret_cast(*o1).getRegCode(), reinterpret_cast(*o0), 0); _FINISHED(); } #if defined(ASMJIT_X64) - if ((o0->isRegType(REG_TYPE_MM) || o0->isRegType(REG_TYPE_XMM)) && (o1->isRegType(REG_TYPE_GPQ) || o1->isMem())) + if ((o0->isRegType(kX86RegTypeMm) || o0->isRegType(kX86RegTypeXmm)) && (o1->isRegType(kX86RegTypeGpq) || o1->isMem())) { - _emitMmu(o0->isRegType(REG_TYPE_XMM) ? 0x66000F6E : 0x00000F6E, 1, - reinterpret_cast(*o0).getRegCode(), + _emitMmu(o0->isRegType(kX86RegTypeXmm) ? 0x66000F6E : 0x00000F6E, 1, + reinterpret_cast(*o0).getRegCode(), reinterpret_cast(*o1), 0); _FINISHED(); } - if ((o0->isRegType(REG_TYPE_GPQ) || o0->isMem()) && (o1->isRegType(REG_TYPE_MM) || o1->isRegType(REG_TYPE_XMM))) + if ((o0->isRegType(kX86RegTypeGpq) || o0->isMem()) && (o1->isRegType(kX86RegTypeMm) || o1->isRegType(kX86RegTypeXmm))) { - _emitMmu(o1->isRegType(REG_TYPE_XMM) ? 0x66000F7E : 0x00000F7E, 1, - reinterpret_cast(*o1).getRegCode(), + _emitMmu(o1->isRegType(kX86RegTypeXmm) ? 0x66000F7E : 0x00000F7E, 1, + reinterpret_cast(*o1).getRegCode(), reinterpret_cast(*o0), 0); _FINISHED(); @@ -2333,7 +2335,49 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_MMU_PREFETCH: + case kX86InstGroupMmuExtract: + { + if (!(o0->isRegMem() && + (o1->isRegType(kX86RegTypeXmm) || (code == kX86InstPExtrW && o1->isRegType(kX86RegTypeMm))) && + o2->isImm())) + { + goto _IllegalInstruction; + } + + uint32_t opCode = id->_opCode[0]; + uint8_t isGpdGpq = o0->isRegType(kX86RegTypeGpd) | o0->isRegType(kX86RegTypeGpq); + + if (code == kX86InstPExtrB && (o0->getSize() != 0 && o0->getSize() != 1) && !isGpdGpq) + goto _IllegalInstruction; + if (code == kX86InstPExtrW && (o0->getSize() != 0 && o0->getSize() != 2) && !isGpdGpq) + goto _IllegalInstruction; + if (code == kX86InstPExtrD && (o0->getSize() != 0 && o0->getSize() != 4) && !isGpdGpq) + goto _IllegalInstruction; + if (code == kX86InstPExtrQ && (o0->getSize() != 0 && o0->getSize() != 8) && !isGpdGpq) + goto _IllegalInstruction; + + if (o1->isRegType(kX86RegTypeXmm)) opCode |= 0x66000000; + + if (o0->isReg()) + { + _emitMmu(opCode, id->_opCodeR | (uint8_t)o0->isRegType(kX86RegTypeGpq), + reinterpret_cast(*o1).getRegCode(), + reinterpret_cast(*o0), 1); + _FINISHED_IMMEDIATE(o2, 1); + } + + if (o0->isMem()) + { + _emitMmu(opCode, (uint8_t)id->_opCodeR, + reinterpret_cast(*o1).getRegCode(), + reinterpret_cast(*o0), 1); + _FINISHED_IMMEDIATE(o2, 1); + } + + break; + } + + case kX86InstGroupMmuPrefetch: { if (o0->isMem() && o1->isImm()) { @@ -2347,161 +2391,119 @@ _Emit_Mov_Sreg_RM: break; } - case InstructionDescription::G_MMU_PEXTR: + case kX86InstGroupMmuRmI: { - if (!(o0->isRegMem() && - (o1->isRegType(REG_TYPE_XMM) || (code == INST_PEXTRW && o1->isRegType(REG_TYPE_MM))) && - o2->isImm())) - { - goto illegalInstruction; - } - - uint32_t opCode = id->opCode[0]; - uint8_t isGpdGpq = o0->isRegType(REG_TYPE_GPD) | o0->isRegType(REG_TYPE_GPQ); - - if (code == INST_PEXTRB && (o0->getSize() != 0 && o0->getSize() != 1) && !isGpdGpq) - goto illegalInstruction; - if (code == INST_PEXTRW && (o0->getSize() != 0 && o0->getSize() != 2) && !isGpdGpq) - goto illegalInstruction; - if (code == INST_PEXTRD && (o0->getSize() != 0 && o0->getSize() != 4) && !isGpdGpq) - goto illegalInstruction; - if (code == INST_PEXTRQ && (o0->getSize() != 0 && o0->getSize() != 8) && !isGpdGpq) - goto illegalInstruction; - - if (o1->isRegType(REG_TYPE_XMM)) opCode |= 0x66000000; - - if (o0->isReg()) - { - _emitMmu(opCode, id->opCodeR | (uint8_t)o0->isRegType(REG_TYPE_GPQ), - reinterpret_cast(*o1).getRegCode(), - reinterpret_cast(*o0), 1); - _FINISHED_IMMEDIATE(o2, 1); - } - - if (o0->isMem()) - { - _emitMmu(opCode, (uint8_t)id->opCodeR, - reinterpret_cast(*o1).getRegCode(), - reinterpret_cast(*o0), 1); - _FINISHED_IMMEDIATE(o2, 1); - } - - break; - } - - case InstructionDescription::G_MMU_RMI: - { - ASMJIT_ASSERT(id->oflags[0] != 0); - ASMJIT_ASSERT(id->oflags[1] != 0); + ASMJIT_ASSERT(id->_opFlags[0] != 0); + ASMJIT_ASSERT(id->_opFlags[1] != 0); // Check parameters (X)MM|GP32_64 <- (X)MM|GP32_64|Mem|Imm if (!o0->isReg() || - (o0->isRegType(REG_TYPE_MM ) && (id->oflags[0] & InstructionDescription::O_MM ) == 0) || - (o0->isRegType(REG_TYPE_XMM) && (id->oflags[0] & InstructionDescription::O_XMM) == 0) || - (o0->isRegType(REG_TYPE_GPD) && (id->oflags[0] & InstructionDescription::O_GD ) == 0) || - (o0->isRegType(REG_TYPE_GPQ) && (id->oflags[0] & InstructionDescription::O_GQ ) == 0) || - (o1->isRegType(REG_TYPE_MM ) && (id->oflags[1] & InstructionDescription::O_MM ) == 0) || - (o1->isRegType(REG_TYPE_XMM) && (id->oflags[1] & InstructionDescription::O_XMM) == 0) || - (o1->isRegType(REG_TYPE_GPD) && (id->oflags[1] & InstructionDescription::O_GD ) == 0) || - (o1->isRegType(REG_TYPE_GPQ) && (id->oflags[1] & InstructionDescription::O_GQ ) == 0) || - (o1->isMem() && (id->oflags[1] & InstructionDescription::O_MEM) == 0) || - (o1->isImm() && (id->oflags[1] & InstructionDescription::O_IMM) == 0)) + (o0->isRegType(kX86RegTypeMm ) && (id->_opFlags[0] & kX86InstOpMm ) == 0) || + (o0->isRegType(kX86RegTypeXmm) && (id->_opFlags[0] & kX86InstOpXmm) == 0) || + (o0->isRegType(kX86RegTypeGpd) && (id->_opFlags[0] & kX86InstOpGd ) == 0) || + (o0->isRegType(kX86RegTypeGpq) && (id->_opFlags[0] & kX86InstOpGq ) == 0) || + (o1->isRegType(kX86RegTypeMm ) && (id->_opFlags[1] & kX86InstOpMm ) == 0) || + (o1->isRegType(kX86RegTypeXmm) && (id->_opFlags[1] & kX86InstOpXmm) == 0) || + (o1->isRegType(kX86RegTypeGpd) && (id->_opFlags[1] & kX86InstOpGd ) == 0) || + (o1->isRegType(kX86RegTypeGpq) && (id->_opFlags[1] & kX86InstOpGq ) == 0) || + (o1->isMem() && (id->_opFlags[1] & kX86InstOpMem) == 0) || + (o1->isImm() && (id->_opFlags[1] & kX86InstOpImm) == 0)) { - goto illegalInstruction; + goto _IllegalInstruction; } uint32_t prefix = - ((id->oflags[0] & InstructionDescription::O_MM_XMM) == InstructionDescription::O_MM_XMM && o0->isRegType(REG_TYPE_XMM)) || - ((id->oflags[1] & InstructionDescription::O_MM_XMM) == InstructionDescription::O_MM_XMM && o1->isRegType(REG_TYPE_XMM)) + ((id->_opFlags[0] & kX86InstOpMmXmm) == kX86InstOpMmXmm && o0->isRegType(kX86RegTypeXmm)) || + ((id->_opFlags[1] & kX86InstOpMmXmm) == kX86InstOpMmXmm && o1->isRegType(kX86RegTypeXmm)) ? 0x66000000 : 0x00000000; - uint8_t rexw = ((id->oflags[0] | id->oflags[1]) & InstructionDescription::O_NOREX) + uint8_t rexw = ((id->_opFlags[0] | id->_opFlags[1]) & kX86InstOpNoRex) ? 0 - : o0->isRegType(REG_TYPE_GPQ) | o1->isRegType(REG_TYPE_GPQ); + : o0->isRegType(kX86RegTypeGpq) | o1->isRegType(kX86RegTypeGpq); // (X)MM <- (X)MM (opcode0) if (o1->isReg()) { - if ((id->oflags[1] & (InstructionDescription::O_MM_XMM | InstructionDescription::O_GQD)) == 0) - goto illegalInstruction; - _emitMmu(id->opCode[0] | prefix, rexw, - reinterpret_cast(*o0).getRegCode(), - reinterpret_cast(*o1), 0); + if ((id->_opFlags[1] & (kX86InstOpMmXmm | kX86InstOpGqd)) == 0) + goto _IllegalInstruction; + _emitMmu(id->_opCode[0] | prefix, rexw, + reinterpret_cast(*o0).getRegCode(), + reinterpret_cast(*o1), 0); _FINISHED(); } // (X)MM <- Mem (opcode0) if (o1->isMem()) { - if ((id->oflags[1] & InstructionDescription::O_MEM) == 0) - goto illegalInstruction; - _emitMmu(id->opCode[0] | prefix, rexw, - reinterpret_cast(*o0).getRegCode(), + if ((id->_opFlags[1] & kX86InstOpMem) == 0) + goto _IllegalInstruction; + _emitMmu(id->_opCode[0] | prefix, rexw, + reinterpret_cast(*o0).getRegCode(), reinterpret_cast(*o1), 0); _FINISHED(); } // (X)MM <- Imm (opcode1+opcodeR) if (o1->isImm()) { - if ((id->oflags[1] & InstructionDescription::O_IMM) == 0) - goto illegalInstruction; - _emitMmu(id->opCode[1] | prefix, rexw, - (uint8_t)id->opCodeR, - reinterpret_cast(*o0), 1); + if ((id->_opFlags[1] & kX86InstOpImm) == 0) + goto _IllegalInstruction; + _emitMmu(id->_opCode[1] | prefix, rexw, + (uint8_t)id->_opCodeR, + reinterpret_cast(*o0), 1); _FINISHED_IMMEDIATE(o1, 1); } break; } - case InstructionDescription::G_MMU_RM_IMM8: + case kX86InstGroupMmuRmImm8: { - ASMJIT_ASSERT(id->oflags[0] != 0); - ASMJIT_ASSERT(id->oflags[1] != 0); + ASMJIT_ASSERT(id->_opFlags[0] != 0); + ASMJIT_ASSERT(id->_opFlags[1] != 0); // Check parameters (X)MM|GP32_64 <- (X)MM|GP32_64|Mem|Imm if (!o0->isReg() || - (o0->isRegType(REG_TYPE_MM ) && (id->oflags[0] & InstructionDescription::O_MM ) == 0) || - (o0->isRegType(REG_TYPE_XMM) && (id->oflags[0] & InstructionDescription::O_XMM) == 0) || - (o0->isRegType(REG_TYPE_GPD) && (id->oflags[0] & InstructionDescription::O_GD ) == 0) || - (o0->isRegType(REG_TYPE_GPQ) && (id->oflags[0] & InstructionDescription::O_GQ ) == 0) || - (o1->isRegType(REG_TYPE_MM ) && (id->oflags[1] & InstructionDescription::O_MM ) == 0) || - (o1->isRegType(REG_TYPE_XMM) && (id->oflags[1] & InstructionDescription::O_XMM) == 0) || - (o1->isRegType(REG_TYPE_GPD) && (id->oflags[1] & InstructionDescription::O_GD ) == 0) || - (o1->isRegType(REG_TYPE_GPQ) && (id->oflags[1] & InstructionDescription::O_GQ ) == 0) || - (o1->isMem() && (id->oflags[1] & InstructionDescription::O_MEM) == 0) || + (o0->isRegType(kX86RegTypeMm ) && (id->_opFlags[0] & kX86InstOpMm ) == 0) || + (o0->isRegType(kX86RegTypeXmm) && (id->_opFlags[0] & kX86InstOpXmm) == 0) || + (o0->isRegType(kX86RegTypeGpd) && (id->_opFlags[0] & kX86InstOpGd ) == 0) || + (o0->isRegType(kX86RegTypeGpq) && (id->_opFlags[0] & kX86InstOpGq ) == 0) || + (o1->isRegType(kX86RegTypeMm ) && (id->_opFlags[1] & kX86InstOpMm ) == 0) || + (o1->isRegType(kX86RegTypeXmm) && (id->_opFlags[1] & kX86InstOpXmm) == 0) || + (o1->isRegType(kX86RegTypeGpd) && (id->_opFlags[1] & kX86InstOpGd ) == 0) || + (o1->isRegType(kX86RegTypeGpq) && (id->_opFlags[1] & kX86InstOpGq ) == 0) || + (o1->isMem() && (id->_opFlags[1] & kX86InstOpMem) == 0) || !o2->isImm()) { - goto illegalInstruction; + goto _IllegalInstruction; } uint32_t prefix = - ((id->oflags[0] & InstructionDescription::O_MM_XMM) == InstructionDescription::O_MM_XMM && o0->isRegType(REG_TYPE_XMM)) || - ((id->oflags[1] & InstructionDescription::O_MM_XMM) == InstructionDescription::O_MM_XMM && o1->isRegType(REG_TYPE_XMM)) + ((id->_opFlags[0] & kX86InstOpMmXmm) == kX86InstOpMmXmm && o0->isRegType(kX86RegTypeXmm)) || + ((id->_opFlags[1] & kX86InstOpMmXmm) == kX86InstOpMmXmm && o1->isRegType(kX86RegTypeXmm)) ? 0x66000000 : 0x00000000; - uint8_t rexw = ((id->oflags[0]|id->oflags[1]) & InstructionDescription::O_NOREX) + uint8_t rexw = ((id->_opFlags[0]|id->_opFlags[1]) & kX86InstOpNoRex) ? 0 - : o0->isRegType(REG_TYPE_GPQ) | o1->isRegType(REG_TYPE_GPQ); + : o0->isRegType(kX86RegTypeGpq) | o1->isRegType(kX86RegTypeGpq); // (X)MM <- (X)MM (opcode0) if (o1->isReg()) { - if ((id->oflags[1] & (InstructionDescription::O_MM_XMM | InstructionDescription::O_GQD)) == 0) -goto illegalInstruction; - _emitMmu(id->opCode[0] | prefix, rexw, - reinterpret_cast(*o0).getRegCode(), - reinterpret_cast(*o1), 1); + if ((id->_opFlags[1] & (kX86InstOpMmXmm | kX86InstOpGqd)) == 0) +goto _IllegalInstruction; + _emitMmu(id->_opCode[0] | prefix, rexw, + reinterpret_cast(*o0).getRegCode(), + reinterpret_cast(*o1), 1); _FINISHED_IMMEDIATE(o2, 1); } // (X)MM <- Mem (opcode0) if (o1->isMem()) { - if ((id->oflags[1] & InstructionDescription::O_MEM) == 0) - goto illegalInstruction; - _emitMmu(id->opCode[0] | prefix, rexw, - reinterpret_cast(*o0).getRegCode(), + if ((id->_opFlags[1] & kX86InstOpMem) == 0) + goto _IllegalInstruction; + _emitMmu(id->_opCode[0] | prefix, rexw, + reinterpret_cast(*o0).getRegCode(), reinterpret_cast(*o1), 1); _FINISHED_IMMEDIATE(o2, 1); } @@ -2509,14 +2511,14 @@ goto illegalInstruction; break; } - case InstructionDescription::G_MMU_RM_3DNOW: + case kX86InstGroupMmuRm3dNow: { - if (o0->isRegType(REG_TYPE_MM) && (o1->isRegType(REG_TYPE_MM) || o1->isMem())) + if (o0->isRegType(kX86RegTypeMm) && (o1->isRegType(kX86RegTypeMm) || o1->isMem())) { - _emitMmu(id->opCode[0], 0, - reinterpret_cast(*o0).getRegCode(), + _emitMmu(id->_opCode[0], 0, + reinterpret_cast(*o0).getRegCode(), reinterpret_cast(*o1), 1); - _emitByte((uint8_t)id->opCode[1]); + _emitByte((uint8_t)id->_opCode[1]); _FINISHED(); } @@ -2524,17 +2526,17 @@ goto illegalInstruction; } } -illegalInstruction: +_IllegalInstruction: // Set an error. If we run in release mode assertion will be not used, so we // must inform about invalid state. - setError(ERROR_ILLEGAL_INSTRUCTION); + setError(kErrorIllegalInstruction); #if defined(ASMJIT_DEBUG) assertIllegal = true; #endif // ASMJIT_DEBUG - goto end; + goto _End; -emitImmediate: +_EmitImmediate: { sysint_t value = immOperand->getValue(); switch (immSize) @@ -2549,7 +2551,7 @@ emitImmediate: } } -end: +_End: if (_logger #if defined(ASMJIT_DEBUG) || assertIllegal @@ -2561,6 +2563,7 @@ end: // Detect truncated operand. Imm immTemporary(0); + uint32_t loggerFlags = 0; // Use the original operands, because BYTE some of them were replaced. if (bLoHiUsed) @@ -2577,14 +2580,14 @@ end: switch (immSize) { - case 1: if ( isUnsigned && !Util::isUInt8 (value)) { immTemporary.setValue((uint8_t)(sysuint_t)value, true ); break; } - if (!isUnsigned && !Util::isInt8 (value)) { immTemporary.setValue((uint8_t)(sysuint_t)value, false); break; } + case 1: if ( isUnsigned && !IntUtil::isUInt8 (value)) { immTemporary.setValue((uint8_t)(sysuint_t)value, true ); break; } + if (!isUnsigned && !IntUtil::isInt8 (value)) { immTemporary.setValue((uint8_t)(sysuint_t)value, false); break; } break; - case 2: if ( isUnsigned && !Util::isUInt16(value)) { immTemporary.setValue((uint16_t)(sysuint_t)value, true ); break; } - if (!isUnsigned && !Util::isInt16 (value)) { immTemporary.setValue((uint16_t)(sysuint_t)value, false); break; } + case 2: if ( isUnsigned && !IntUtil::isUInt16(value)) { immTemporary.setValue((uint16_t)(sysuint_t)value, true ); break; } + if (!isUnsigned && !IntUtil::isInt16 (value)) { immTemporary.setValue((uint16_t)(sysuint_t)value, false); break; } break; - case 4: if ( isUnsigned && !Util::isUInt32(value)) { immTemporary.setValue((uint32_t)(sysuint_t)value, true ); break; } - if (!isUnsigned && !Util::isInt32 (value)) { immTemporary.setValue((uint32_t)(sysuint_t)value, false); break; } + case 4: if ( isUnsigned && !IntUtil::isUInt32(value)) { immTemporary.setValue((uint32_t)(sysuint_t)value, true ); break; } + if (!isUnsigned && !IntUtil::isInt32 (value)) { immTemporary.setValue((uint32_t)(sysuint_t)value, false); break; } break; } @@ -2596,18 +2599,24 @@ end: } } - buf = dumpInstruction(buf, code, _emitOptions, o0, o1, o2, memRegType); + if (_logger) + { + buf = StringUtil::copy(buf, _logger->getInstructionPrefix()); + loggerFlags = _logger->getFlags(); + } - if (_logger->getLogBinary()) - buf = dumpComment(buf, (sysuint_t)(buf - bufStorage), getCode() + beginOffset, getOffset() - beginOffset, _comment); + buf = X86Assembler_dumpInstruction(buf, code, _emitOptions, o0, o1, o2, memRegType, loggerFlags); + + if ((loggerFlags & kLoggerOutputBinary) != 0) + buf = X86Assembler_dumpComment(buf, (size_t)(buf - bufStorage), getCode() + beginOffset, getOffset() - beginOffset, _inlineComment); else - buf = dumpComment(buf, (sysuint_t)(buf - bufStorage), NULL, 0, _comment); + buf = X86Assembler_dumpComment(buf, (size_t)(buf - bufStorage), NULL, 0, _inlineComment); // We don't need to NULL terminate the resulting string. #if defined(ASMJIT_DEBUG) if (_logger) #endif // ASMJIT_DEBUG - _logger->logString(bufStorage, (sysuint_t)(buf - bufStorage)); + _logger->logString(bufStorage, (size_t)(buf - bufStorage)); #if defined(ASMJIT_DEBUG) if (assertIllegal) @@ -2621,35 +2630,35 @@ end: #endif // ASMJIT_DEBUG } -cleanup: - _comment = NULL; +_Cleanup: + _inlineComment = NULL; _emitOptions = 0; } -void AssemblerCore::_emitJcc(uint32_t code, const Label* label, uint32_t hint) ASMJIT_NOTHROW +void X86Assembler::_emitJcc(uint32_t code, const Label* label, uint32_t hint) { - if (!hint) + if (hint == kCondHintNone) { - _emitInstruction(code, label, NULL, NULL); + _emitInstruction(code, label); } else { Imm imm(hint); - _emitInstruction(code, label, &imm, NULL); + _emitInstruction(code, label, &imm); } } // ============================================================================ -// [AsmJit::AssemblerCore - Relocation helpers] +// [AsmJit::Assembler - Relocation helpers] // ============================================================================ -sysuint_t AssemblerCore::relocCode(void* _dst, sysuint_t addressBase) const ASMJIT_NOTHROW +size_t X86Assembler::relocCode(void* _dst, sysuint_t addressBase) const { // Copy code to virtual memory (this is a given _dst pointer). uint8_t* dst = reinterpret_cast(_dst); - sysint_t coff = _buffer.getOffset(); - sysint_t csize = getCodeSize(); + size_t coff = _buffer.getOffset(); + size_t csize = getCodeSize(); // We are copying the exact size of the generated code. Extra code for trampolines // is generated on-the-fly by relocator (this code doesn't exist at the moment). @@ -2661,8 +2670,8 @@ sysuint_t AssemblerCore::relocCode(void* _dst, sysuint_t addressBase) const ASMJ #endif // ASMJIT_X64 // Relocate all recorded locations. - sysint_t i; - sysint_t len = _relocData.getLength(); + size_t i; + size_t len = _relocData.getLength(); for (i = 0; i < len; i++) { @@ -2671,29 +2680,29 @@ sysuint_t AssemblerCore::relocCode(void* _dst, sysuint_t addressBase) const ASMJ #if defined(ASMJIT_X64) // Whether to use trampoline, can be only used if relocation type is - // ABSOLUTE_TO_RELATIVE_TRAMPOLINE. + // kRelocAbsToRel. bool useTrampoline = false; #endif // ASMJIT_X64 // Be sure that reloc data structure is correct. - ASMJIT_ASSERT((sysint_t)(r.offset + r.size) <= csize); + ASMJIT_ASSERT((size_t)(r.offset + r.size) <= csize); switch (r.type) { - case RelocData::ABSOLUTE_TO_ABSOLUTE: + case kRelocAbsToAbs: val = (sysint_t)(r.address); break; - case RelocData::RELATIVE_TO_ABSOLUTE: + case kRelocRelToAbs: val = (sysint_t)(addressBase + r.destination); break; - case RelocData::ABSOLUTE_TO_RELATIVE: - case RelocData::ABSOLUTE_TO_RELATIVE_TRAMPOLINE: + case kRelocAbsToRel: + case kRelocTrampoline: val = (sysint_t)( (sysuint_t)r.address - (addressBase + (sysuint_t)r.offset + 4) ); #if defined(ASMJIT_X64) - if (r.type == RelocData::ABSOLUTE_TO_RELATIVE_TRAMPOLINE && !Util::isInt32(val)) + if (r.type == kRelocTrampoline && !IntUtil::isInt32(val)) { val = (sysint_t)( (sysuint_t)tramp - ((sysuint_t)_dst + (sysuint_t)r.offset + 4) ); useTrampoline = true; @@ -2708,11 +2717,11 @@ sysuint_t AssemblerCore::relocCode(void* _dst, sysuint_t addressBase) const ASMJ switch (r.size) { case 4: - *reinterpret_cast(dst + r.offset) = (int32_t)val; + *reinterpret_cast(dst + r.offset) = static_cast(val); break; case 8: - *reinterpret_cast(dst + r.offset) = (int64_t)val; + *reinterpret_cast(dst + r.offset) = static_cast(val); break; default: @@ -2727,69 +2736,37 @@ sysuint_t AssemblerCore::relocCode(void* _dst, sysuint_t addressBase) const ASMJ getLogger()->logFormat("; Trampoline from %p -> %p\n", (int8_t*)addressBase + r.offset, r.address); } - TrampolineWriter::writeTrampoline(tramp, r.address); - tramp += TrampolineWriter::TRAMPOLINE_SIZE; + X64TrampolineWriter::writeTrampoline(tramp, (uint64_t)r.address); + tramp += X64TrampolineWriter::kSizeTotal; } #endif // ASMJIT_X64 } #if defined(ASMJIT_X64) - return (sysuint_t)(tramp - dst); + return (size_t)(tramp - dst); #else - return (sysuint_t)coff; + return (size_t)(coff); #endif // ASMJIT_X64 } // ============================================================================ -// [AsmJit::AssemblerCore - Embed] +// [AsmJit::Assembler - EmbedLabel] // ============================================================================ -void AssemblerCore::embed(const void* data, sysuint_t size) ASMJIT_NOTHROW +void X86Assembler::embedLabel(const Label& label) { + ASMJIT_ASSERT(label.getId() != kInvalidValue); if (!canEmit()) return; - if (_logger) - { - sysuint_t i, j; - sysuint_t max; - char buf[128]; - char dot[] = ".data "; - char* p; - - memcpy(buf, dot, ASMJIT_ARRAY_SIZE(dot) - 1); - - for (i = 0; i < size; i += 16) - { - max = (size - i < 16) ? size - i : 16; - p = buf + ASMJIT_ARRAY_SIZE(dot) - 1; - - for (j = 0; j < max; j++) - p += sprintf(p, "%0.2X", reinterpret_cast(data)[i+j]); - - *p++ = '\n'; - *p = '\0'; - - _logger->logString(buf); - } - } - - _buffer.emitData(data, size); -} - -void AssemblerCore::embedLabel(const Label& label) ASMJIT_NOTHROW -{ - ASMJIT_ASSERT(label.getId() != INVALID_VALUE); - if (!canEmit()) return; - - LabelData& l_data = _labelData[label.getId() & OPERAND_ID_VALUE_MASK]; + LabelData& l_data = _labels[label.getId() & kOperandIdValueMask]; RelocData r_data; if (_logger) { - _logger->logFormat(sizeof(sysint_t) == 4 ? ".dd L.%u\n" : ".dq L.%u\n", (uint32_t)label.getId() & OPERAND_ID_VALUE_MASK); + _logger->logFormat(sizeof(sysint_t) == 4 ? ".dd L.%u\n" : ".dq L.%u\n", (uint32_t)label.getId() & kOperandIdValueMask); } - r_data.type = RelocData::RELATIVE_TO_ABSOLUTE; + r_data.type = kRelocRelToAbs; r_data.size = sizeof(sysint_t); r_data.offset = getOffset(); r_data.destination = 0; @@ -2814,18 +2791,21 @@ void AssemblerCore::embedLabel(const Label& label) ASMJIT_NOTHROW _relocData.append(r_data); - // Emit dummy sysint (4 or 8 bytes that depends on address size). - _emitSysInt(0); + // Emit dummy intptr_t (4 or 8 bytes that depends on address size). + _emitIntPtrT(0); } // ============================================================================ -// [AsmJit::AssemblerCore - Align] +// [AsmJit::Assembler - Align] // ============================================================================ -void AssemblerCore::align(uint32_t m) ASMJIT_NOTHROW +void X86Assembler::align(uint32_t m) { - if (!canEmit()) return; - if (_logger) _logger->logFormat(".align %u", (uint)m); + if (!canEmit()) + return; + + if (_logger) + _logger->logFormat("%s.align %u\n", _logger->getInstructionPrefix(), (uint)m); if (!m) return; @@ -2838,9 +2818,9 @@ void AssemblerCore::align(uint32_t m) ASMJIT_NOTHROW sysint_t i = m - (getOffset() % m); if (i == m) return; - if (_properties & (1 << PROPERTY_OPTIMIZE_ALIGN)) + if (_properties & (1 << kX86PropertyOptimizedAlign)) { - const CpuInfo* ci = getCpuInfo(); + const X86CpuInfo* ci = X86CpuInfo::getGlobal(); // NOPs optimized for Intel: // Intel 64 and IA-32 Architectures Software Developer's Manual @@ -2870,10 +2850,7 @@ void AssemblerCore::align(uint32_t m) ASMJIT_NOTHROW const uint8_t* p; sysint_t n; - if (ci->vendorId == CPU_VENDOR_INTEL && - ((ci->family & 0x0F) == 6 || - (ci->family & 0x0F) == 15) - ) + if (ci->getVendorId() == kCpuIntel && ((ci->getFamily() & 0x0F) == 6 || (ci->getFamily() & 0x0F) == 15)) { do { switch (i) @@ -2896,8 +2873,7 @@ void AssemblerCore::align(uint32_t m) ASMJIT_NOTHROW return; } - if (ci->vendorId == CPU_VENDOR_AMD && - ci->family >= 0x0F) + if (ci->getVendorId() == kCpuAmd && ci->getFamily() >= 0x0F) { do { switch (i) @@ -2922,7 +2898,7 @@ void AssemblerCore::align(uint32_t m) ASMJIT_NOTHROW return; } #if defined(ASMJIT_X86) - // legacy NOPs, 0x90 with 0x66 prefix. + // Legacy NOPs, 0x90 with 0x66 prefix. do { switch (i) { @@ -2935,55 +2911,55 @@ void AssemblerCore::align(uint32_t m) ASMJIT_NOTHROW #endif } - // legacy NOPs, only 0x90 - // In 64-bit mode, we can't use 0x66 prefix + // Legacy NOPs, only 0x90. In 64-bit mode, we can't use 0x66 prefix. do { _emitByte(0x90); } while(--i); } // ============================================================================ -// [AsmJit::AssemblerCore - Label] +// [AsmJit::Assembler - Label] // ============================================================================ -Label AssemblerCore::newLabel() ASMJIT_NOTHROW +Label X86Assembler::newLabel() { Label label; - label._base.id = (uint32_t)_labelData.getLength() | OPERAND_ID_TYPE_LABEL; + label._base.id = (uint32_t)_labels.getLength() | kOperandIdTypeLabel; LabelData l_data; l_data.offset = -1; l_data.links = NULL; - _labelData.append(l_data); + _labels.append(l_data); return label; } -void AssemblerCore::registerLabels(sysuint_t count) ASMJIT_NOTHROW +void X86Assembler::registerLabels(size_t count) { // Duplicated newLabel() code, but we are not creating Label instances. LabelData l_data; l_data.offset = -1; l_data.links = NULL; - for (sysuint_t i = 0; i < count; i++) _labelData.append(l_data); + for (size_t i = 0; i < count; i++) + _labels.append(l_data); } -void AssemblerCore::bind(const Label& label) ASMJIT_NOTHROW +void X86Assembler::bind(const Label& label) { // Only labels created by newLabel() can be used by Assembler. - ASMJIT_ASSERT(label.getId() != INVALID_VALUE); + ASMJIT_ASSERT(label.getId() != kInvalidValue); // Never go out of bounds. - ASMJIT_ASSERT((label.getId() & OPERAND_ID_VALUE_MASK) < _labelData.getLength()); + ASMJIT_ASSERT((label.getId() & kOperandIdValueMask) < _labels.getLength()); // Get label data based on label id. - LabelData& l_data = _labelData[label.getId() & OPERAND_ID_VALUE_MASK]; + LabelData& l_data = _labels[label.getId() & kOperandIdValueMask]; // Label can be bound only once. ASMJIT_ASSERT(l_data.offset == -1); // Log. - if (_logger) _logger->logFormat("L.%u:\n", (uint32_t)label.getId() & OPERAND_ID_VALUE_MASK); + if (_logger) _logger->logFormat("L.%u:\n", (uint32_t)label.getId() & kOperandIdValueMask); sysint_t pos = getOffset(); @@ -3016,14 +2992,14 @@ void AssemblerCore::bind(const Label& label) ASMJIT_NOTHROW } else // if (size == 1) { - if (Util::isInt8(patchedValue)) + if (IntUtil::isInt8(patchedValue)) { setByteAt(offset, (uint8_t)(int8_t)patchedValue); } else { // Fatal error. - setError(ERROR_ILLEGAL_SHORT_JUMP); + setError(kErrorIllegalShortJump); } } } @@ -3048,61 +3024,21 @@ void AssemblerCore::bind(const Label& label) ASMJIT_NOTHROW } // ============================================================================ -// [AsmJit::AssemblerCore - Make] +// [AsmJit::Assembler - Make] // ============================================================================ -void* AssemblerCore::make() ASMJIT_NOTHROW +void* X86Assembler::make() { // Do nothing on error state or when no instruction was emitted. if (_error || getCodeSize() == 0) return NULL; void* p; - _error = _codeGenerator->generate(&p, reinterpret_cast(this)); + _error = _context->generate(&p, this); return p; } -// ============================================================================ -// [AsmJit::AssemblerCore - Links] -// ============================================================================ - -AssemblerCore::LabelLink* AssemblerCore::_newLabelLink() ASMJIT_NOTHROW -{ - LabelLink* link = _unusedLinks; - - if (link) - { - _unusedLinks = link->prev; - } - else - { - link = (LabelLink*)_zone.zalloc(sizeof(LabelLink)); - if (link == NULL) return NULL; - } - - // clean link - link->prev = NULL; - link->offset = 0; - link->displacement = 0; - link->relocId = -1; - - return link; -} - -// ============================================================================ -// [AsmJit::Assembler - Construction / Destruction] -// ============================================================================ - -Assembler::Assembler(CodeGenerator* codeGenerator) ASMJIT_NOTHROW : - AssemblerIntrinsics(codeGenerator) -{ -} - -Assembler::~Assembler() ASMJIT_NOTHROW -{ -} - } // AsmJit namespace // [Api-End] -#include "ApiEnd.h" +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/x86/x86assembler.h b/desmume/src/utils/AsmJit/x86/x86assembler.h new file mode 100644 index 000000000..442f13bf7 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86assembler.h @@ -0,0 +1,5449 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_X86_X86ASSEMBLER_H +#define _ASMJIT_X86_X86ASSEMBLER_H + +// [Dependencies - AsmJit] +#include "../core/assembler.h" + +#include "../x86/x86defs.h" +#include "../x86/x86operand.h" +#include "../x86/x86util.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_X86 +//! @{ + +// ============================================================================ +// [AsmJit::X86Assembler] +// ============================================================================ + +//! @brief X86Assembler - low level x86/x64 code generation. +//! +//! @ref X86Assembler is the main class in AsmJit for generating low level +//! x86/x64 binary stream. It creates internal buffer where opcodes are stored +//! and contains methods that mimics x86/x64 assembler instructions. Code +//! generation should be safe, because basic type-checks are done by the C++ +//! compiler. It's nearly impossible to create invalid instruction (for example +//! mov [eax], [eax] that will not be detected at compile time by +//! C++ compiler. +//! +//! Each call to assembler intrinsics directly emits instruction to internal +//! binary stream. Instruction emitting also contains runtime checks so it +//! should be impossible to create an instruction that is not valid (except +//! there is bug in AsmJit). +//! +//! @ref X86Assembler contains internal buffer where all emitted instructions +//! are stored. Look at @ref Buffer for an implementation. To generate and +//! allocate memory for function use @ref X86Assembler::make() method that will +//! allocate memory using the provided memory manager (see @ref MemoryManager) +//! and relocates the output code to the provided address. If you want to create +//! your function manually, you should look at @ref VirtualMemory interface and +//! use @ref X86Assembler::relocCode() method to relocate emitted code into +//! provided memory location. You can also take the emitted buffer by @ref +//! X86Assembler::take() to do something else with it. If you take buffer, you +//! must free it manually by using @ref ASMJIT_FREE() macro. +//! +//! @section AsmJit_Assembler_CodeGeneration Code Generation +//! +//! To generate code is only needed to create instance of @c AsmJit::Assembler +//! and to use intrinsics. See example how to do that: +//! +//! @code +//! // Use AsmJit namespace. +//! using namespace AsmJit; +//! +//! // Create Assembler instance. +//! Assembler a; +//! +//! // Prolog. +//! a.push(ebp); +//! a.mov(ebp, esp); +//! +//! // Mov 1024 to EAX, EAX is also return value. +//! a.mov(eax, imm(1024)); +//! +//! // Epilog. +//! a.mov(esp, ebp); +//! a.pop(ebp); +//! +//! // Return. +//! a.ret(); +//! @endcode +//! +//! You can see that syntax is very close to Intel one. Only difference is that +//! you are calling functions that emits the binary code for you. All registers +//! are in @c AsmJit namespace, so it's very comfortable to use it (look at +//! first line). There is also used method @c AsmJit::imm() to create an +//! immediate value. Use @c AsmJit::uimm() to create unsigned immediate value. +//! +//! There is also possibility to use memory addresses and immediates. To build +//! memory address use @c ptr(), @c byte_ptr(), @c word_ptr(), @c dword_ptr() +//! or other friend methods. In most cases you needs only @c ptr() method, but +//! there are instructions where you must specify address size, +//! +//! for example (a is @c AsmJit::Assembler instance): +//! +//! @code +//! a.mov(ptr(eax), imm(0)); // mov ptr [eax], 0 +//! a.mov(ptr(eax), edx); // mov ptr [eax], edx +//! @endcode +//! +//! But it's also possible to create complex addresses: +//! +//! @code +//! // eax + ecx*x addresses +//! a.mov(ptr(eax, ecx, kScaleNone), imm(0)); // mov ptr [eax + ecx], 0 +//! a.mov(ptr(eax, ecx, kScale2Times), imm(0)); // mov ptr [eax + ecx * 2], 0 +//! a.mov(ptr(eax, ecx, kScale4Times), imm(0)); // mov ptr [eax + ecx * 4], 0 +//! a.mov(ptr(eax, ecx, kScale8Times), imm(0)); // mov ptr [eax + ecx * 8], 0 +//! // eax + ecx*x + disp addresses +//! a.mov(ptr(eax, ecx, kScaleNone, 4), imm(0)); // mov ptr [eax + ecx + 4], 0 +//! a.mov(ptr(eax, ecx, kScale2Times, 8), imm(0)); // mov ptr [eax + ecx * 2 + 8], 0 +//! a.mov(ptr(eax, ecx, kScale4Times, 12), imm(0)); // mov ptr [eax + ecx * 4 + 12], 0 +//! a.mov(ptr(eax, ecx, kScale8Times, 16), imm(0)); // mov ptr [eax + ecx * 8 + 16], 0 +//! @endcode +//! +//! All addresses shown are using @c AsmJit::ptr() to make memory operand. +//! Some assembler instructions (single operand ones) needs to specify memory +//! operand size. For example calling a.inc(ptr(eax)) can't be +//! used. @c AsmJit::Assembler::inc(), @c AsmJit::Assembler::dec() and similar +//! instructions can't be serialized without specifying how bytes they are +//! operating on. See next code how assembler works: +//! +//! @code +//! // [byte] address +//! a.inc(byte_ptr(eax)); // inc byte ptr [eax] +//! a.dec(byte_ptr(eax)); // dec byte ptr [eax] +//! // [word] address +//! a.inc(word_ptr(eax)); // inc word ptr [eax] +//! a.dec(word_ptr(eax)); // dec word ptr [eax] +//! // [dword] address +//! a.inc(dword_ptr(eax)); // inc dword ptr [eax] +//! a.dec(dword_ptr(eax)); // dec dword ptr [eax] +//! @endcode +//! +//! @section AsmJit_Assembler_CallingJitCode Calling JIT Code +//! +//! While you are over from emitting instructions, you can make your function +//! using @c AsmJit::Assembler::make() method. This method will use memory +//! manager to allocate virtual memory and relocates generated code to it. For +//! memory allocation is used global memory manager by default and memory is +//! freeable, but of course this default behavior can be overridden specifying +//! your memory manager and allocation type. If you want to do with code +//! something else you can always override make() method and do what you want. +//! +//! You can get size of generated code by @c getCodeSize() or @c getOffset() +//! methods. These methods returns you code size (or more precisely current code +//! offset) in bytes. Use takeCode() to take internal buffer (all pointers in +//! @c AsmJit::Assembler instance will be zeroed and current buffer returned) +//! to use it. If you don't take it, @c AsmJit::Assembler destructor will +//! free it automatically. To alloc and run code manually don't use +//! @c malloc()'ed memory, but instead use @c AsmJit::VirtualMemory::alloc() +//! to get memory for executing (specify @c canExecute to @c true) or +//! @c AsmJit::MemoryManager that provides more effective and comfortable way +//! to allocate virtual memory. +//! +//! See next example how to allocate memory where you can execute code created +//! by @c AsmJit::Assembler: +//! +//! @code +//! using namespace AsmJit; +//! +//! Assembler a; +//! +//! // ... your code generation +//! +//! // your function prototype +//! typedef void (*MyFn)(); +//! +//! // make your function +//! MyFn fn = asmjit_cast(a.make()); +//! +//! // call your function +//! fn(); +//! +//! // If you don't need your function again, free it. +//! MemoryManager::getGlobal()->free(fn); +//! @endcode +//! +//! There is also low level alternative how to allocate virtual memory and +//! relocate code to it: +//! +//! @code +//! using namespace AsmJit; +//! +//! Assembler a; +//! // Your code generation ... +//! +//! // Your function prototype. +//! typedef void (*MyFn)(); +//! +//! // Alloc memory for your function. +//! MyFn fn = asmjit_cast( +//! MemoryManager::getGlobal()->alloc(a.getCodeSize()); +//! +//! // Relocate the code (will make the function). +//! a.relocCode(fn); +//! +//! // Call the generated function. +//! fn(); +//! +//! // If you don't need your function anymore, it should be freed. +//! MemoryManager::getGlobal()->free(fn); +//! @endcode +//! +//! @c note This was very primitive example how to call generated code. +//! In real production code you will never alloc and free code for one run, +//! you will usually use generated code many times. +//! +//! @section AsmJit_Assembler_Labels Labels +//! +//! While generating assembler code, you will usually need to create complex +//! code with labels. Labels are fully supported and you can call @c jmp or +//! @c je (and similar) instructions to initialized or yet uninitialized label. +//! Each label expects to be bound into offset. To bind label to specific +//! offset, use @c bind() method. +//! +//! See next example that contains complete code that creates simple memory +//! copy function (in DWORD entities). +//! +//! @code +//! // Example: Usage of Label (32-bit code). +//! // +//! // Create simple DWORD memory copy function: +//! // ASMJIT_STDCALL void copy32(uint32_t* dst, const uint32_t* src, size_t count); +//! using namespace AsmJit; +//! +//! // Assembler instance. +//! Assembler a; +//! +//! // Constants. +//! const int arg_offset = 8; // Arguments offset (STDCALL EBP). +//! const int arg_size = 12; // Arguments size. +//! +//! // Labels. +//! Label L_Loop = a.newLabel(); +//! +//! // Prolog. +//! a.push(ebp); +//! a.mov(ebp, esp); +//! a.push(esi); +//! a.push(edi); +//! +//! // Fetch arguments +//! a.mov(esi, dword_ptr(ebp, arg_offset + 0)); // Get dst. +//! a.mov(edi, dword_ptr(ebp, arg_offset + 4)); // Get src. +//! a.mov(ecx, dword_ptr(ebp, arg_offset + 8)); // Get count. +//! +//! // Bind L_Loop label to here. +//! a.bind(L_Loop); +//! +//! Copy 4 bytes. +//! a.mov(eax, dword_ptr(esi)); +//! a.mov(dword_ptr(edi), eax); +//! +//! // Increment pointers. +//! a.add(esi, 4); +//! a.add(edi, 4); +//! +//! // Repeat loop until (--ecx != 0). +//! a.dec(ecx); +//! a.jz(L_Loop); +//! +//! // Epilog. +//! a.pop(edi); +//! a.pop(esi); +//! a.mov(esp, ebp); +//! a.pop(ebp); +//! +//! // Return: STDCALL convention is to pop stack in called function. +//! a.ret(arg_size); +//! @endcode +//! +//! If you need more abstraction for generating assembler code and you want +//! to hide calling conventions between 32-bit and 64-bit operating systems, +//! look at @c Compiler class that is designed for higher level code +//! generation. +//! +//! @section AsmJit_Assembler_AdvancedCodeGeneration Advanced Code Generation +//! +//! This section describes some advanced generation features of @c Assembler +//! class which can be simply overlooked. The first thing that is very likely +//! needed is generic register support. In previous example the named registers +//! were used. AsmJit contains functions which can convert register index into +//! operand and back. +//! +//! Let's define function which can be used to generate some abstract code: +//! +//! @code +//! // Simple function that generates dword copy. +//! void genCopyDWord( +//! Assembler& a, +//! const GpReg& dst, const GpReg& src, const GpReg& tmp) +//! { +//! a.mov(tmp, dword_ptr(src)); +//! a.mov(dword_ptr(dst), tmp); +//! } +//! @endcode +//! +//! This function can be called like genCopyDWord(a, edi, esi, ebx) +//! or by using existing @ref GpReg instances. This abstraction allows to join +//! more code sections together without rewriting each to use specific registers. +//! You need to take care only about implicit registers which may be used by +//! several instructions (like mul, imul, div, idiv, shifting, etc...). +//! +//! Next, more advanced, but often needed technique is that you can build your +//! own registers allocator. X86 architecture contains 8 general purpose registers, +//! 8 MMX (MM) registers and 8 SSE (XMM) registers. The X64 (AMD64) architecture +//! extends count of general purpose registers and SSE2 registers to 16. Use the +//! @c kX86RegNumBase constant to get count of GP or XMM registers or @c kX86RegNumGp, +//! @c kX86RegNumMm and @c kX86RegNumXmm constants individually. +//! +//! To build register from index (value from 0 inclusive to kRegNumXXX +//! exclusive) use @ref gpd(), @ref gpq() or @ref gpz() functions. To create +//! a 8 or 16-bit register use @ref gpw(), @ref gpb_lo() or @ref gpb_hi(). +//! To create other registers there are similar methods like @ref mm(), @ref xmm() +//! and @ref st(). +//! +//! So our function call to genCopyDWord can be also used like this: +//! +//! @code +//! genCopyDWord(a, gpd(kX86RegIndexEdi), gpd(kX86RegIndexEsi), gpd(kX86RegIndexEbx)); +//! @endcode +//! +//! kX86RegIndexXXX are constants defined by @ref kX86RegIndex enum. You can use your +//! own register allocator (or register slot manager) to alloc / free registers +//! so kX86RegIndexXXX values can be replaced by your variables (0 to kRegNumXXX-1). +//! +//! @sa @ref X86Compiler. +struct X86Assembler : public Assembler +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_API X86Assembler(Context* context = JitContext::getGlobal()); + ASMJIT_API virtual ~X86Assembler(); + + // -------------------------------------------------------------------------- + // [Buffer - Setters (X86-Extensions)] + // -------------------------------------------------------------------------- + + //! @brief Set custom variable @a i at position @a pos. + //! + //! @note This function is used to patch existing code. + ASMJIT_API void setVarAt(size_t pos, sysint_t i, uint8_t isUnsigned, uint32_t size); + + // -------------------------------------------------------------------------- + // [Emit] + // + // These functions are not protected against buffer overrun. Each place of + // code which calls these functions ensures that there is some space using + // canEmit() method. Emitters are internally protected in AsmJit::Buffer, + // but only in debug builds. + // -------------------------------------------------------------------------- + + //! @brief Emit single @a opCode without operands. + inline void _emitOpCode(uint32_t opCode) + { + // Instruction prefix. + if (opCode & 0xFF000000) _emitByte(static_cast((opCode >> 24) & 0xFF)); + + // Instruction opcodes. + if (opCode & 0x00FF0000) _emitByte(static_cast((opCode >> 16) & 0xFF)); + if (opCode & 0x0000FF00) _emitByte(static_cast((opCode >> 8) & 0xFF)); + + // Last opcode is always emitted (can be also 0x00). + _emitByte(static_cast(opCode & 0xFF)); + } + + //! @brief Emit MODR/M byte. + inline void _emitMod(uint8_t m, uint8_t o, uint8_t r) + { _emitByte(((m & 0x03) << 6) | ((o & 0x07) << 3) | (r & 0x07)); } + + //! @brief Emit SIB byte. + inline void _emitSib(uint8_t s, uint8_t i, uint8_t b) + { _emitByte(((s & 0x03) << 6) | ((i & 0x07) << 3) | (b & 0x07)); } + + //! @brief Emit REX prefix (64-bit mode only). + inline void _emitRexR(uint8_t w, uint8_t opReg, uint8_t regCode, bool forceRexPrefix) + { +#if defined(ASMJIT_X64) + uint32_t rex; + + // w - Default operand size(0=Default, 1=64-bit). + // r - Register field (1=high bit extension of the ModR/M REG field). + // x - Index field not used in RexR + // b - Base field (1=high bit extension of the ModR/M or SIB Base field). + rex = (static_cast(forceRexPrefix != 0)) << 6; // Rex prefix code. + rex += (static_cast(w ) ) << 3; // Rex.W (w << 3). + rex += (static_cast(opReg ) & 0x08 ) >> 1; // Rex.R (r << 2). + rex += (static_cast(regCode) & 0x08 ) >> 3; // Rex.B (b << 0). + + if (rex) _emitByte(static_cast(rex | 0x40)); +#else + ASMJIT_UNUSED(w); + ASMJIT_UNUSED(opReg); + ASMJIT_UNUSED(regCode); + ASMJIT_UNUSED(forceRexPrefix); +#endif // ASMJIT_X64 + } + + //! @brief Emit REX prefix (64-bit mode only). + inline void _emitRexRM(uint8_t w, uint8_t opReg, const Operand& rm, bool forceRexPrefix) + { +#if defined(ASMJIT_X64) + uint32_t rex; + + // w - Default operand size(0=Default, 1=64-bit). + // r - Register field (1=high bit extension of the ModR/M REG field). + // x - Index field (1=high bit extension of the SIB Index field). + // b - Base field (1=high bit extension of the ModR/M or SIB Base field). + + rex = (static_cast(forceRexPrefix != 0)) << 6; // Rex prefix code. + rex += (static_cast(w ) ) << 3; // Rex.W (w << 3). + rex += (static_cast(opReg ) & 0x08 ) >> 1; // Rex.R (r << 2). + + uint32_t b = 0; + uint32_t x = 0; + + if (rm.isReg()) + { + b = (static_cast(rm).getRegCode() & 0x08) != 0; + } + else if (rm.isMem()) + { + b = ((static_cast(rm).getBase() & 0x8) != 0) & (static_cast(rm).getBase() != kInvalidValue); + x = ((static_cast(rm).getIndex() & 0x8) != 0) & (static_cast(rm).getIndex() != kInvalidValue); + } + + rex += static_cast(x) << 1; // Rex.R (x << 1). + rex += static_cast(b) ; // Rex.B (b << 0). + + if (rex) _emitByte(static_cast(rex | 0x40)); +#else + ASMJIT_UNUSED(w); + ASMJIT_UNUSED(opReg); + ASMJIT_UNUSED(rm); +#endif // ASMJIT_X64 + } + + //! @brief Emit Register / Register - calls _emitMod(3, opReg, r) + inline void _emitModR(uint8_t opReg, uint8_t r) + { _emitMod(3, opReg, r); } + + //! @brief Emit Register / Register - calls _emitMod(3, opReg, r.code()) + inline void _emitModR(uint8_t opReg, const Reg& r) + { _emitMod(3, opReg, r.getRegCode()); } + + //! @brief Emit register / memory address combination to buffer. + //! + //! This method can hangle addresses from simple to complex ones with + //! index and displacement. + ASMJIT_API void _emitModM(uint8_t opReg, const Mem& mem, sysint_t immSize); + + //! @brief Emit Reg<-Reg or Reg<-Reg|Mem ModRM (can be followed by SIB + //! and displacement) to buffer. + //! + //! This function internally calls @c _emitModM() or _emitModR() that depends + //! to @a op type. + //! + //! @note @a opReg is usually real register ID (see @c R) but some instructions + //! have specific format and in that cases @a opReg is part of opcode. + ASMJIT_API void _emitModRM(uint8_t opReg, const Operand& op, sysint_t immSize); + + //! @brief Emit CS (code segmend) prefix. + //! + //! Behavior of this function is to emit code prefix only if memory operand + //! address uses code segment. Code segment is used through memory operand + //! with attached @c AsmJit::Label. + ASMJIT_API void _emitSegmentPrefix(const Operand& rm); + + //! @brief Emit instruction where register is inlined to opcode. + ASMJIT_API void _emitX86Inl(uint32_t opCode, uint8_t i16bit, uint8_t rexw, uint8_t reg, bool forceRexPrefix); + + //! @brief Emit instruction with reg/memory operand. + ASMJIT_API void _emitX86RM(uint32_t opCode, uint8_t i16bit, uint8_t rexw, uint8_t o, + const Operand& op, sysint_t immSize, bool forceRexPrefix); + + //! @brief Emit FPU instruction with no operands. + ASMJIT_API void _emitFpu(uint32_t opCode); + + //! @brief Emit FPU instruction with one operand @a sti (index of FPU register). + ASMJIT_API void _emitFpuSTI(uint32_t opCode, uint32_t sti); + + //! @brief Emit FPU instruction with one operand @a opReg and memory operand @a mem. + ASMJIT_API void _emitFpuMEM(uint32_t opCode, uint8_t opReg, const Mem& mem); + + //! @brief Emit MMX/SSE instruction. + ASMJIT_API void _emitMmu(uint32_t opCode, uint8_t rexw, uint8_t opReg, const Operand& src, sysint_t immSize); + + //! @brief Emit displacement. + ASMJIT_API LabelLink* _emitDisplacement(LabelData& l_data, sysint_t inlinedDisplacement, int size); + + //! @brief Emit relative relocation to absolute pointer @a target. It's needed + //! to add what instruction is emitting this, because in x64 mode the relative + //! displacement can be impossible to calculate and in this case the trampoline + //! is used. + ASMJIT_API void _emitJmpOrCallReloc(uint32_t instruction, void* target); + + // Helpers to decrease binary code size. These four emit methods are just + // helpers thats used by assembler. They call emitX86() adding NULLs + // to first, second and third operand, if needed. + + //! @brief Emit X86/FPU or MM/XMM instruction. + ASMJIT_API void _emitInstruction(uint32_t code); + + //! @brief Emit X86/FPU or MM/XMM instruction. + ASMJIT_API void _emitInstruction(uint32_t code, const Operand* o0); + + //! @brief Emit X86/FPU or MM/XMM instruction. + ASMJIT_API void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1); + + //! @brief Emit X86/FPU or MM/XMM instruction. + //! + //! Operands @a o1, @a o2 or @a o3 can be @c NULL if they are not used. + //! + //! Hint: Use @c emitX86() helpers to emit instructions. + ASMJIT_API void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2); + + //! @brief Private method for emitting jcc. + ASMJIT_API void _emitJcc(uint32_t code, const Label* label, uint32_t hint); + + //! @brief Private method for emitting short jcc. + inline void _emitShortJcc(uint32_t code, const Label* label, uint32_t hint) + { + _emitOptions |= kX86EmitOptionShortJump; + _emitJcc(code, label, hint); + } + + // -------------------------------------------------------------------------- + // [EmbedLabel] + // -------------------------------------------------------------------------- + + //! @brief Embed absolute label pointer (4 or 8 bytes). + ASMJIT_API void embedLabel(const Label& label); + + // -------------------------------------------------------------------------- + // [Align] + // -------------------------------------------------------------------------- + + //! @brief Align target buffer to @a m bytes. + //! + //! Typical usage of this is to align labels at start of the inner loops. + //! + //! Inserts @c nop() instructions or CPU optimized NOPs. + ASMJIT_API void align(uint32_t m); + + // -------------------------------------------------------------------------- + // [Label] + // -------------------------------------------------------------------------- + + //! @brief Create and return new label. + ASMJIT_API Label newLabel(); + + //! @brief Register labels (used by @c Compiler). + ASMJIT_API void registerLabels(size_t count); + + //! @brief Bind label to the current offset. + //! + //! @note Label can be bound only once! + ASMJIT_API void bind(const Label& label); + + // -------------------------------------------------------------------------- + // [Reloc] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual size_t relocCode(void* dst, sysuint_t addressBase) const; + + // -------------------------------------------------------------------------- + // [Make] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void* make(); + + // -------------------------------------------------------------------------- + // [Embed] + // -------------------------------------------------------------------------- + + //! @brief Add 8-bit integer data to the instuction stream. + inline void db(uint8_t x) { embed(&x, 1); } + //! @brief Add 16-bit integer data to the instuction stream. + inline void dw(uint16_t x) { embed(&x, 2); } + //! @brief Add 32-bit integer data to the instuction stream. + inline void dd(uint32_t x) { embed(&x, 4); } + //! @brief Add 64-bit integer data to the instuction stream. + inline void dq(uint64_t x) { embed(&x, 8); } + + //! @brief Add 8-bit integer data to the instuction stream. + inline void dint8(int8_t x) { embed(&x, sizeof(int8_t)); } + //! @brief Add 8-bit integer data to the instuction stream. + inline void duint8(uint8_t x) { embed(&x, sizeof(uint8_t)); } + + //! @brief Add 16-bit integer data to the instuction stream. + inline void dint16(int16_t x) { embed(&x, sizeof(int16_t)); } + //! @brief Add 16-bit integer data to the instuction stream. + inline void duint16(uint16_t x) { embed(&x, sizeof(uint16_t)); } + + //! @brief Add 32-bit integer data to the instuction stream. + inline void dint32(int32_t x) { embed(&x, sizeof(int32_t)); } + //! @brief Add 32-bit integer data to the instuction stream. + inline void duint32(uint32_t x) { embed(&x, sizeof(uint32_t)); } + + //! @brief Add 64-bit integer data to the instuction stream. + inline void dint64(int64_t x) { embed(&x, sizeof(int64_t)); } + //! @brief Add 64-bit integer data to the instuction stream. + inline void duint64(uint64_t x) { embed(&x, sizeof(uint64_t)); } + + //! @brief Add system-integer data to the instuction stream. + inline void dintptr(intptr_t x) { embed(&x, sizeof(intptr_t)); } + //! @brief Add system-integer data to the instuction stream. + inline void duintptr(uintptr_t x) { embed(&x, sizeof(uintptr_t)); } + + //! @brief Add float data to the instuction stream. + inline void dfloat(float x) { embed(&x, sizeof(float)); } + //! @brief Add double data to the instuction stream. + inline void ddouble(double x) { embed(&x, sizeof(double)); } + + //! @brief Add pointer data to the instuction stream. + inline void dptr(void* x) { embed(&x, sizeof(void*)); } + + //! @brief Add MM data to the instuction stream. + inline void dmm(const MmData& x) { embed(&x, sizeof(MmData)); } + //! @brief Add XMM data to the instuction stream. + inline void dxmm(const XmmData& x) { embed(&x, sizeof(XmmData)); } + + //! @brief Add data to the instuction stream. + inline void data(const void* data, size_t size) { embed(data, size); } + + //! @brief Add data in a given structure instance to the instuction stream. + template + inline void dstruct(const T& x) { embed(&x, sizeof(T)); } + + // -------------------------------------------------------------------------- + // [X86 Instructions] + // -------------------------------------------------------------------------- + + //! @brief Add with Carry. + inline void adc(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstAdc, &dst, &src); } + //! @brief Add with Carry. + inline void adc(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstAdc, &dst, &src); } + //! @brief Add with Carry. + inline void adc(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstAdc, &dst, &src); } + //! @brief Add with Carry. + inline void adc(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstAdc, &dst, &src); } + //! @brief Add with Carry. + inline void adc(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstAdc, &dst, &src); } + + //! @brief Add. + inline void add(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstAdd, &dst, &src); } + //! @brief Add. + inline void add(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstAdd, &dst, &src); } + //! @brief Add. + inline void add(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstAdd, &dst, &src); } + //! @brief Add. + inline void add(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstAdd, &dst, &src); } + //! @brief Add. + inline void add(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstAdd, &dst, &src); } + + //! @brief Logical And. + inline void and_(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstAnd, &dst, &src); } + //! @brief Logical And. + inline void and_(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstAnd, &dst, &src); } + //! @brief Logical And. + inline void and_(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstAnd, &dst, &src); } + //! @brief Logical And. + inline void and_(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstAnd, &dst, &src); } + //! @brief Logical And. + inline void and_(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstAnd, &dst, &src); } + + //! @brief Bit Scan Forward. + inline void bsf(const GpReg& dst, const GpReg& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + _emitInstruction(kX86InstBsf, &dst, &src); + } + //! @brief Bit Scan Forward. + inline void bsf(const GpReg& dst, const Mem& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + _emitInstruction(kX86InstBsf, &dst, &src); + } + + //! @brief Bit Scan Reverse. + inline void bsr(const GpReg& dst, const GpReg& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + _emitInstruction(kX86InstBsr, &dst, &src); + } + //! @brief Bit Scan Reverse. + inline void bsr(const GpReg& dst, const Mem& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + _emitInstruction(kX86InstBsr, &dst, &src); + } + + //! @brief Byte swap (32-bit or 64-bit registers only) (i486). + inline void bswap(const GpReg& dst) + { + ASMJIT_ASSERT(dst.getRegType() == kX86RegTypeGpd || dst.getRegType() == kX86RegTypeGpq); + _emitInstruction(kX86InstBSwap, &dst); + } + + //! @brief Bit test. + inline void bt(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstBt, &dst, &src); } + //! @brief Bit test. + inline void bt(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstBt, &dst, &src); } + //! @brief Bit test. + inline void bt(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstBt, &dst, &src); } + //! @brief Bit test. + inline void bt(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstBt, &dst, &src); } + + //! @brief Bit test and complement. + inline void btc(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstBtc, &dst, &src); } + //! @brief Bit test and complement. + inline void btc(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstBtc, &dst, &src); } + //! @brief Bit test and complement. + inline void btc(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstBtc, &dst, &src); } + //! @brief Bit test and complement. + inline void btc(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstBtc, &dst, &src); } + + //! @brief Bit test and reset. + inline void btr(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstBtr, &dst, &src); } + //! @brief Bit test and reset. + inline void btr(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstBtr, &dst, &src); } + //! @brief Bit test and reset. + inline void btr(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstBtr, &dst, &src); } + //! @brief Bit test and reset. + inline void btr(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstBtr, &dst, &src); } + + //! @brief Bit test and set. + inline void bts(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstBts, &dst, &src); } + //! @brief Bit test and set. + inline void bts(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstBts, &dst, &src); } + //! @brief Bit test and set. + inline void bts(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstBts, &dst, &src); } + //! @brief Bit test and set. + inline void bts(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstBts, &dst, &src); } + + //! @brief Call Procedure. + inline void call(const GpReg& dst) + { + ASMJIT_ASSERT(dst.isRegType(kX86RegTypeGpz)); + _emitInstruction(kX86InstCall, &dst); + } + //! @brief Call Procedure. + inline void call(const Mem& dst) + { _emitInstruction(kX86InstCall, &dst); } + //! @brief Call Procedure. + inline void call(const Imm& dst) + { _emitInstruction(kX86InstCall, &dst); } + //! @brief Call Procedure. + //! @overload + inline void call(void* dst) + { + Imm imm((sysint_t)dst); + _emitInstruction(kX86InstCall, &imm); + } + + //! @brief Call Procedure. + inline void call(const Label& label) + { _emitInstruction(kX86InstCall, &label); } + + //! @brief Convert Byte to Word (Sign Extend). + //! + //! AX <- Sign Extend AL + inline void cbw() + { _emitInstruction(kX86InstCbw); } + + //! @brief Convert Word to DWord (Sign Extend). + //! + //! DX:AX <- Sign Extend AX + inline void cwd() + { _emitInstruction(kX86InstCwd); } + + //! @brief Convert Word to DWord (Sign Extend). + //! + //! EAX <- Sign Extend AX + inline void cwde() + { _emitInstruction(kX86InstCwde); } + + //! @brief Convert DWord to QWord (Sign Extend). + //! + //! EDX:EAX <- Sign Extend EAX + inline void cdq() + { _emitInstruction(kX86InstCdq); } + +#if defined(ASMJIT_X64) + //! @brief Convert DWord to QWord (Sign Extend). + //! + //! RAX <- Sign Extend EAX + inline void cdqe() + { _emitInstruction(kX86InstCdqe); } +#endif // ASMJIT_X64 + + //! @brief Clear Carry flag + //! + //! This instruction clears the CF flag in the EFLAGS register. + inline void clc() + { _emitInstruction(kX86InstClc); } + + //! @brief Clear Direction flag + //! + //! This instruction clears the DF flag in the EFLAGS register. + inline void cld() + { _emitInstruction(kX86InstCld); } + + //! @brief Complement Carry Flag. + //! + //! This instruction complements the CF flag in the EFLAGS register. + //! (CF = NOT CF) + inline void cmc() + { _emitInstruction(kX86InstCmc); } + + //! @brief Conditional Move. + inline void cmov(kX86Cond cc, const GpReg& dst, const GpReg& src) + { _emitInstruction(X86Util::getCMovccInstFromCond(cc), &dst, &src); } + + //! @brief Conditional Move. + inline void cmov(kX86Cond cc, const GpReg& dst, const Mem& src) + { _emitInstruction(X86Util::getCMovccInstFromCond(cc), &dst, &src); } + + //! @brief Conditional Move. + inline void cmova (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovA , &dst, &src); } + //! @brief Conditional Move. + inline void cmova (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovA , &dst, &src); } + //! @brief Conditional Move. + inline void cmovae (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovAE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovae (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovAE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovb (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovb (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovbe (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovBE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovbe (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovBE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovc (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovC , &dst, &src); } + //! @brief Conditional Move. + inline void cmovc (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovC , &dst, &src); } + //! @brief Conditional Move. + inline void cmove (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovE , &dst, &src); } + //! @brief Conditional Move. + inline void cmove (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovg (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovg (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovge (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovGE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovge (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovGE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovl (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovl (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovle (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovLE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovle (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovLE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovna (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNA , &dst, &src); } + //! @brief Conditional Move. + inline void cmovna (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNA , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnae(const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNAE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnae(const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNAE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnb (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnb (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnbe(const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNBE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnbe(const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNBE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnc (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNC , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnc (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNC , &dst, &src); } + //! @brief Conditional Move. + inline void cmovne (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovne (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovng (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovng (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnge(const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNGE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnge(const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNGE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnl (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnl (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnle(const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNLE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnle(const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNLE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovno (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovno (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnp (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnp (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovns (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovns (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnz (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovNZ , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnz (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovNZ , &dst, &src); } + //! @brief Conditional Move. + inline void cmovo (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovo (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovp (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovp (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpe (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovPE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpe (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovPE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpo (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovPO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpo (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovPO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovs (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovs (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovz (const GpReg& dst, const GpReg& src) { _emitInstruction(kX86InstCMovZ , &dst, &src); } + //! @brief Conditional Move. + inline void cmovz (const GpReg& dst, const Mem& src) { _emitInstruction(kX86InstCMovZ , &dst, &src); } + + //! @brief Compare Two Operands. + inline void cmp(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstCmp, &dst, &src); } + //! @brief Compare Two Operands. + inline void cmp(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstCmp, &dst, &src); } + //! @brief Compare Two Operands. + inline void cmp(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstCmp, &dst, &src); } + //! @brief Compare Two Operands. + inline void cmp(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstCmp, &dst, &src); } + //! @brief Compare Two Operands. + inline void cmp(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstCmp, &dst, &src); } + + //! @brief Compare and Exchange (i486). + inline void cmpxchg(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstCmpXCHG, &dst, &src); } + //! @brief Compare and Exchange (i486). + inline void cmpxchg(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstCmpXCHG, &dst, &src); } + + //! @brief Compares the 64-bit value in EDX:EAX with the memory operand (Pentium). + //! + //! If the values are equal, then this instruction stores the 64-bit value + //! in ECX:EBX into the memory operand and sets the zero flag. Otherwise, + //! this instruction copies the 64-bit memory operand into the EDX:EAX + //! registers and clears the zero flag. + inline void cmpxchg8b(const Mem& dst) + { _emitInstruction(kX86InstCmpXCHG8B, &dst); } + +#if defined(ASMJIT_X64) + //! @brief Compares the 128-bit value in RDX:RAX with the memory operand (X64). + //! + //! If the values are equal, then this instruction stores the 128-bit value + //! in RCX:RBX into the memory operand and sets the zero flag. Otherwise, + //! this instruction copies the 128-bit memory operand into the RDX:RAX + //! registers and clears the zero flag. + inline void cmpxchg16b(const Mem& dst) + { _emitInstruction(kX86InstCmpXCHG16B, &dst); } +#endif // ASMJIT_X64 + + //! @brief CPU Identification (i486). + inline void cpuid() + { _emitInstruction(kX86InstCpuId); } + +#if defined(ASMJIT_X64) + //! @brief Convert QWord to DQWord (Sign Extend). + //! + //! RDX:RAX <- Sign Extend RAX + inline void cqo() + { _emitInstruction(kX86InstCqo); } +#endif // ASMJIT_X64 + +#if defined(ASMJIT_X86) + //! @brief Decimal adjust AL after addition + //! + //! This instruction adjusts the sum of two packed BCD values to create + //! a packed BCD result. + //! + //! @note This instruction is only available in 32-bit mode. + inline void daa() + { _emitInstruction(kX86InstDaa); } +#endif // ASMJIT_X86 + +#if defined(ASMJIT_X86) + //! @brief Decimal adjust AL after subtraction + //! + //! This instruction adjusts the result of the subtraction of two packed + //! BCD values to create a packed BCD result. + //! + //! @note This instruction is only available in 32-bit mode. + inline void das() + { _emitInstruction(kX86InstDas); } +#endif // ASMJIT_X86 + + //! @brief Decrement by 1. + //! @note This instruction can be slower than sub(dst, 1) + inline void dec(const GpReg& dst) + { _emitInstruction(kX86InstDec, &dst); } + //! @brief Decrement by 1. + //! @note This instruction can be slower than sub(dst, 1) + inline void dec(const Mem& dst) + { _emitInstruction(kX86InstDec, &dst); } + + //! @brief Unsigned divide. + //! + //! This instruction divides (unsigned) the value in the AL, AX, or EAX + //! register by the source operand and stores the result in the AX, + //! DX:AX, or EDX:EAX registers. + inline void div(const GpReg& src) + { _emitInstruction(kX86InstDiv, &src); } + //! @brief Unsigned divide. + //! @overload + inline void div(const Mem& src) + { _emitInstruction(kX86InstDiv, &src); } + + //! @brief Make Stack Frame for Procedure Parameters. + inline void enter(const Imm& imm16, const Imm& imm8) + { _emitInstruction(kX86InstEnter, &imm16, &imm8); } + + //! @brief Signed divide. + //! + //! This instruction divides (signed) the value in the AL, AX, or EAX + //! register by the source operand and stores the result in the AX, + //! DX:AX, or EDX:EAX registers. + inline void idiv(const GpReg& src) + { _emitInstruction(kX86InstIDiv, &src); } + //! @brief Signed divide. + //! @overload + inline void idiv(const Mem& src) + { _emitInstruction(kX86InstIDiv, &src); } + + //! @brief Signed multiply. + //! + //! Source operand (in a general-purpose register or memory location) + //! is multiplied by the value in the AL, AX, or EAX register (depending + //! on the operand size) and the product is stored in the AX, DX:AX, or + //! EDX:EAX registers, respectively. + inline void imul(const GpReg& src) + { _emitInstruction(kX86InstIMul, &src); } + //! @overload + inline void imul(const Mem& src) + { _emitInstruction(kX86InstIMul, &src); } + + //! @brief Signed multiply. + //! + //! Destination operand (the first operand) is multiplied by the source + //! operand (second operand). The destination operand is a general-purpose + //! register and the source operand is an immediate value, a general-purpose + //! register, or a memory location. The product is then stored in the + //! destination operand location. + inline void imul(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstIMul, &dst, &src); } + //! @brief Signed multiply. + //! @overload + inline void imul(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstIMul, &dst, &src); } + //! @brief Signed multiply. + //! @overload + inline void imul(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstIMul, &dst, &src); } + + //! @brief Signed multiply. + //! + //! source operand (which can be a general-purpose register or a memory + //! location) is multiplied by the second source operand (an immediate + //! value). The product is then stored in the destination operand + //! (a general-purpose register). + inline void imul(const GpReg& dst, const GpReg& src, const Imm& imm) + { _emitInstruction(kX86InstIMul, &dst, &src, &imm); } + //! @overload + inline void imul(const GpReg& dst, const Mem& src, const Imm& imm) + { _emitInstruction(kX86InstIMul, &dst, &src, &imm); } + + //! @brief Increment by 1. + //! @note This instruction can be slower than add(dst, 1) + inline void inc(const GpReg& dst) + { _emitInstruction(kX86InstInc, &dst); } + //! @brief Increment by 1. + //! @note This instruction can be slower than add(dst, 1) + inline void inc(const Mem& dst) + { _emitInstruction(kX86InstInc, &dst); } + + //! @brief Interrupt 3 - trap to debugger. + inline void int3() + { _emitInstruction(kX86InstInt3); } + + //! @brief Jump to label @a label if condition @a cc is met. + //! + //! This instruction checks the state of one or more of the status flags in + //! the EFLAGS register (CF, OF, PF, SF, and ZF) and, if the flags are in the + //! specified state (condition), performs a jump to the target instruction + //! specified by the destination operand. A condition code (cc) is associated + //! with each instruction to indicate the condition being tested for. If the + //! condition is not satisfied, the jump is not performed and execution + //! continues with the instruction following the Jcc instruction. + inline void j(kX86Cond cc, const Label& label, uint32_t hint = kCondHintNone) + { + _emitJcc(X86Util::getJccInstFromCond(cc), &label, hint); + } + + //! @brief Jump to label @a label if condition is met. + inline void ja (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJA , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jae (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJAE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jb (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJB , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jbe (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJBE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jc (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJC , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void je (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jg (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJG , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jge (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJGE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jl (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJL , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jle (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJLE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jna (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNA , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnae(const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNAE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnb (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNB , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnbe(const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNBE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnc (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNC , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jne (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jng (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNG , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnge(const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNGE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnl (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNL , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnle(const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNLE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jno (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNO , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnp (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNP , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jns (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNS , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnz (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNZ , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jo (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJO , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jp (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJP , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jpe (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJPE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jpo (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJPO , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void js (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJS , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jz (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJZ , &label, hint); } + + //! @brief Short jump to label @a label if condition @a cc is met. + //! @sa j() + inline void short_j(kX86Cond cc, const Label& label, uint32_t hint = kCondHintNone) + { + _emitOptions |= kX86EmitOptionShortJump; + j(cc, label, hint); + } + + //! @brief Short jump to label @a label if condition is met. + inline void short_ja (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJA , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jae (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJAE , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jb (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJB , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jbe (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJBE , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jc (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJC , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_je (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJE , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jg (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJG , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jge (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJGE , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jl (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJL , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jle (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJLE , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jna (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNA , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jnae(const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNAE, &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jnb (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNB , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jnbe(const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNBE, &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jnc (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNC , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jne (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNE , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jng (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNG , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jnge(const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNGE, &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jnl (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNL , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jnle(const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNLE, &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jno (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNO , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jnp (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNP , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jns (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNS , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jnz (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJNZ , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jo (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJO , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jp (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJP , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jpe (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJPE , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jpo (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJPO , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_js (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJS , &label, hint); } + //! @brief Short jump to label @a label if condition is met. + inline void short_jz (const Label& label, uint32_t hint = kCondHintNone) { _emitShortJcc(kX86InstJZ , &label, hint); } + + //! @brief Jump. + //! @overload + inline void jmp(const GpReg& dst) + { _emitInstruction(kX86InstJmp, &dst); } + //! @brief Jump. + //! @overload + inline void jmp(const Mem& dst) + { _emitInstruction(kX86InstJmp, &dst); } + //! @brief Jump. + //! @overload + inline void jmp(const Imm& dst) + { _emitInstruction(kX86InstJmp, &dst); } + + //! @brief Jump. + //! @overload + inline void jmp(void* dst) + { + Imm imm((sysint_t)dst); + _emitInstruction(kX86InstJmp, &imm); + } + + //! @brief Jump. + //! + //! This instruction transfers program control to a different point + //! in the instruction stream without recording return information. + //! The destination (target) operand specifies the label of the + //! instruction being jumped to. + inline void jmp(const Label& label) + { _emitInstruction(kX86InstJmp, &label); } + + //! @brief Short jump. + //! @sa jmp() + inline void short_jmp(const Label& label) + { + _emitOptions |= kX86EmitOptionShortJump; + _emitInstruction(kX86InstJmp, &label); + } + + //! @brief Load Effective Address + //! + //! This instruction computes the effective address of the second + //! operand (the source operand) and stores it in the first operand + //! (destination operand). The source operand is a memory address + //! (offset part) specified with one of the processors addressing modes. + //! The destination operand is a general-purpose register. + inline void lea(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstLea, &dst, &src); } + + //! @brief High Level Procedure Exit. + inline void leave() + { _emitInstruction(kX86InstLeave); } + + //! @brief Move. + //! + //! This instruction copies the second operand (source operand) to the first + //! operand (destination operand). The source operand can be an immediate + //! value, general-purpose register, segment register, or memory location. + //! The destination register can be a general-purpose register, segment + //! register, or memory location. Both operands must be the same size, which + //! can be a byte, a word, or a DWORD. + //! + //! @note To move MMX or SSE registers to/from GP registers or memory, use + //! corresponding functions: @c movd(), @c movq(), etc. Passing MMX or SSE + //! registers to @c mov() is illegal. + inline void mov(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + //! @brief Move. + //! @overload + inline void mov(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + //! @brief Move. + //! @overload + inline void mov(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + //! @brief Move. + //! @overload + inline void mov(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + //! @brief Move. + //! @overload + inline void mov(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move from segment register. + //! @overload. + inline void mov(const GpReg& dst, const SegmentReg& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move from segment register. + //! @overload. + inline void mov(const Mem& dst, const SegmentReg& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move to segment register. + //! @overload. + inline void mov(const SegmentReg& dst, const GpReg& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move to segment register. + //! @overload. + inline void mov(const SegmentReg& dst, const Mem& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move byte, word, dword or qword from absolute address @a src to + //! AL, AX, EAX or RAX register. + inline void mov_ptr(const GpReg& dst, void* src) + { + ASMJIT_ASSERT(dst.getRegIndex() == 0); + Imm imm((sysint_t)src); + _emitInstruction(kX86InstMovPtr, &dst, &imm); + } + + //! @brief Move byte, word, dword or qword from AL, AX, EAX or RAX register + //! to absolute address @a dst. + inline void mov_ptr(void* dst, const GpReg& src) + { + ASMJIT_ASSERT(src.getRegIndex() == 0); + Imm imm((sysint_t)dst); + _emitInstruction(kX86InstMovPtr, &imm, &src); + } + + //! @brief Move with Sign-Extension. + //! + //! This instruction copies the contents of the source operand (register + //! or memory location) to the destination operand (register) and sign + //! extends the value to 16, 32 or 64-bits. + //! + //! @sa movsxd(). + void movsx(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstMovSX, &dst, &src); } + //! @brief Move with Sign-Extension. + //! @overload + void movsx(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovSX, &dst, &src); } + +#if defined(ASMJIT_X64) + //! @brief Move DWord to QWord with sign-extension. + inline void movsxd(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstMovSXD, &dst, &src); } + //! @brief Move DWord to QWord with sign-extension. + //! @overload + inline void movsxd(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovSXD, &dst, &src); } +#endif // ASMJIT_X64 + + //! @brief Move with Zero-Extend. + //! + //! This instruction copies the contents of the source operand (register + //! or memory location) to the destination operand (register) and zero + //! extends the value to 16 or 32-bits. The size of the converted value + //! depends on the operand-size attribute. + inline void movzx(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstMovZX, &dst, &src); } + //! @brief Move with Zero-Extend. + //! @brief Overload + inline void movzx(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovZX, &dst, &src); } + + //! @brief Unsigned multiply. + //! + //! Source operand (in a general-purpose register or memory location) + //! is multiplied by the value in the AL, AX, or EAX register (depending + //! on the operand size) and the product is stored in the AX, DX:AX, or + //! EDX:EAX registers, respectively. + inline void mul(const GpReg& src) + { _emitInstruction(kX86InstMul, &src); } + //! @brief Unsigned multiply. + //! @overload + inline void mul(const Mem& src) + { _emitInstruction(kX86InstMul, &src); } + + //! @brief Two's Complement Negation. + inline void neg(const GpReg& dst) + { _emitInstruction(kX86InstNeg, &dst); } + //! @brief Two's Complement Negation. + inline void neg(const Mem& dst) + { _emitInstruction(kX86InstNeg, &dst); } + + //! @brief No Operation. + //! + //! This instruction performs no operation. This instruction is a one-byte + //! instruction that takes up space in the instruction stream but does not + //! affect the machine context, except the EIP register. The NOP instruction + //! is an alias mnemonic for the XCHG (E)AX, (E)AX instruction. + inline void nop() + { _emitInstruction(kX86InstNop); } + + //! @brief One's Complement Negation. + inline void not_(const GpReg& dst) + { _emitInstruction(kX86InstNot, &dst); } + //! @brief One's Complement Negation. + inline void not_(const Mem& dst) + { _emitInstruction(kX86InstNot, &dst); } + + //! @brief Logical Inclusive OR. + inline void or_(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstOr, &dst, &src); } + //! @brief Logical Inclusive OR. + inline void or_(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstOr, &dst, &src); } + //! @brief Logical Inclusive OR. + inline void or_(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstOr, &dst, &src); } + //! @brief Logical Inclusive OR. + inline void or_(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstOr, &dst, &src); } + //! @brief Logical Inclusive OR. + inline void or_(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstOr, &dst, &src); } + + //! @brief Pop a Value from the Stack. + //! + //! This instruction loads the value from the top of the stack to the location + //! specified with the destination operand and then increments the stack pointer. + //! The destination operand can be a general purpose register, memory location, + //! or segment register. + inline void pop(const GpReg& dst) + { + ASMJIT_ASSERT(dst.isRegType(kX86RegTypeGpw) || dst.isRegType(kX86RegTypeGpz)); + _emitInstruction(kX86InstPop, &dst); + } + //! @brief Pop a Segment Register from the Stack. + //! + //! @note There is no instruction to pop a cs segment register. + inline void pop(const SegmentReg& dst) + { + ASMJIT_ASSERT(dst.getRegIndex() != kX86SegCs); + _emitInstruction(kX86InstPop, &dst); + } + + inline void pop(const Mem& dst) + { + ASMJIT_ASSERT(dst.getSize() == 2 || dst.getSize() == sizeof(sysint_t)); + _emitInstruction(kX86InstPop, &dst); + } + +#if defined(ASMJIT_X86) + //! @brief Pop All General-Purpose Registers. + //! + //! Pop EDI, ESI, EBP, EBX, EDX, ECX, and EAX. + inline void popad() + { _emitInstruction(kX86InstPopAD); } +#endif // ASMJIT_X86 + + //! @brief Pop Stack into EFLAGS Register (32-bit or 64-bit). + inline void popf() + { +#if defined(ASMJIT_X86) + popfd(); +#else + popfq(); +#endif + } + +#if defined(ASMJIT_X86) + //! @brief Pop Stack into EFLAGS Register (32-bit). + inline void popfd() { _emitInstruction(kX86InstPopFD); } +#else + //! @brief Pop Stack into EFLAGS Register (64-bit). + inline void popfq() { _emitInstruction(kX86InstPopFQ); } +#endif + + //! @brief Push WORD/DWORD/QWORD Onto the Stack. + //! + //! @note 32-bit architecture pushed DWORD while 64-bit + //! pushes QWORD. 64-bit mode not provides instruction to + //! push 32-bit register/memory. + inline void push(const GpReg& src) + { + ASMJIT_ASSERT(src.isRegType(kX86RegTypeGpw) || src.isRegType(kX86RegTypeGpz)); + _emitInstruction(kX86InstPush, &src); + } + //! @brief Push Segment Register Onto the Stack. + inline void push(const SegmentReg& src) + { _emitInstruction(kX86InstPush, &src); } + //! @brief Push WORD/DWORD/QWORD Onto the Stack. + inline void push(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == sizeof(sysint_t)); + _emitInstruction(kX86InstPush, &src); + } + //! @brief Push WORD/DWORD/QWORD Onto the Stack. + inline void push(const Imm& src) + { _emitInstruction(kX86InstPush, &src); } + +#if defined(ASMJIT_X86) + //! @brief Push All General-Purpose Registers. + //! + //! Push EAX, ECX, EDX, EBX, original ESP, EBP, ESI, and EDI. + inline void pushad() + { _emitInstruction(kX86InstPushAD); } +#endif // ASMJIT_X86 + + //! @brief Push EFLAGS Register (32-bit or 64-bit) onto the Stack. + inline void pushf() + { +#if defined(ASMJIT_X86) + pushfd(); +#else + pushfq(); +#endif + } + +#if defined(ASMJIT_X86) + //! @brief Push EFLAGS Register (32-bit) onto the Stack. + inline void pushfd() { _emitInstruction(kX86InstPushFD); } +#else + //! @brief Push EFLAGS Register (64-bit) onto the Stack. + inline void pushfq() { _emitInstruction(kX86InstPushFQ); } +#endif // ASMJIT_X86 + + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rcl(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstRcl, &dst, &src); } + //! @brief Rotate Bits Left. + inline void rcl(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstRcl, &dst, &src); } + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rcl(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstRcl, &dst, &src); } + //! @brief Rotate Bits Left. + inline void rcl(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstRcl, &dst, &src); } + + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void rcr(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstRcr, &dst, &src); } + //! @brief Rotate Bits Right. + inline void rcr(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstRcr, &dst, &src); } + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void rcr(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstRcr, &dst, &src); } + //! @brief Rotate Bits Right. + inline void rcr(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstRcr, &dst, &src); } + + //! @brief Read Time-Stamp Counter (Pentium). + inline void rdtsc() + { _emitInstruction(kX86InstRdtsc); } + + //! @brief Read Time-Stamp Counter and Processor ID (New). + inline void rdtscp() + { _emitInstruction(kX86InstRdtscP); } + + //! @brief Load ECX/RCX BYTEs from DS:[ESI/RSI] to AL. + inline void rep_lodsb() + { _emitInstruction(kX86InstRepLodSB); } + + //! @brief Load ECX/RCX DWORDs from DS:[ESI/RSI] to EAX. + inline void rep_lodsd() + { _emitInstruction(kX86InstRepLodSD); } + +#if defined(ASMJIT_X64) + //! @brief Load ECX/RCX QWORDs from DS:[ESI/RSI] to RAX. + inline void rep_lodsq() + { _emitInstruction(kX86InstRepLodSQ); } +#endif // ASMJIT_X64 + + //! @brief Load ECX/RCX WORDs from DS:[ESI/RSI] to AX. + inline void rep_lodsw() + { _emitInstruction(kX86InstRepLodSW); } + + //! @brief Move ECX/RCX BYTEs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsb() + { _emitInstruction(kX86InstRepMovSB); } + + //! @brief Move ECX/RCX DWORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsd() + { _emitInstruction(kX86InstRepMovSD); } + +#if defined(ASMJIT_X64) + //! @brief Move ECX/RCX QWORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsq() + { _emitInstruction(kX86InstRepMovSQ); } +#endif // ASMJIT_X64 + + //! @brief Move ECX/RCX WORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsw() + { _emitInstruction(kX86InstRepMovSW); } + + //! @brief Fill ECX/RCX BYTEs at ES:[EDI/RDI] with AL. + inline void rep_stosb() + { _emitInstruction(kX86InstRepStoSB); } + + //! @brief Fill ECX/RCX DWORDs at ES:[EDI/RDI] with EAX. + inline void rep_stosd() + { _emitInstruction(kX86InstRepStoSD); } + +#if defined(ASMJIT_X64) + //! @brief Fill ECX/RCX QWORDs at ES:[EDI/RDI] with RAX. + inline void rep_stosq() + { _emitInstruction(kX86InstRepStoSQ); } +#endif // ASMJIT_X64 + + //! @brief Fill ECX/RCX WORDs at ES:[EDI/RDI] with AX. + inline void rep_stosw() + { _emitInstruction(kX86InstRepStoSW); } + + //! @brief Repeated find nonmatching BYTEs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsb() + { _emitInstruction(kX86InstRepECmpSB); } + + //! @brief Repeated find nonmatching DWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsd() + { _emitInstruction(kX86InstRepECmpSD); } + +#if defined(ASMJIT_X64) + //! @brief Repeated find nonmatching QWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsq() + { _emitInstruction(kX86InstRepECmpSQ); } +#endif // ASMJIT_X64 + + //! @brief Repeated find nonmatching WORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsw() + { _emitInstruction(kX86InstRepECmpSW); } + + //! @brief Find non-AL BYTE starting at ES:[EDI/RDI]. + inline void repe_scasb() + { _emitInstruction(kX86InstRepEScaSB); } + + //! @brief Find non-EAX DWORD starting at ES:[EDI/RDI]. + inline void repe_scasd() + { _emitInstruction(kX86InstRepEScaSD); } + +#if defined(ASMJIT_X64) + //! @brief Find non-RAX QWORD starting at ES:[EDI/RDI]. + inline void repe_scasq() + { _emitInstruction(kX86InstRepEScaSQ); } +#endif // ASMJIT_X64 + + //! @brief Find non-AX WORD starting at ES:[EDI/RDI]. + inline void repe_scasw() + { _emitInstruction(kX86InstRepEScaSW); } + + //! @brief Repeated find nonmatching BYTEs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repne_cmpsb() + { _emitInstruction(kX86InstRepNECmpSB); } + + //! @brief Repeated find nonmatching DWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repne_cmpsd() + { _emitInstruction(kX86InstRepNECmpSD); } + +#if defined(ASMJIT_X64) + //! @brief Repeated find nonmatching QWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repne_cmpsq() + { _emitInstruction(kX86InstRepNECmpSQ); } +#endif // ASMJIT_X64 + + //! @brief Repeated find nonmatching WORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repne_cmpsw() + { _emitInstruction(kX86InstRepNECmpSW); } + + //! @brief Find AL, starting at ES:[EDI/RDI]. + inline void repne_scasb() + { _emitInstruction(kX86InstRepNEScaSB); } + + //! @brief Find EAX, starting at ES:[EDI/RDI]. + inline void repne_scasd() + { _emitInstruction(kX86InstRepNEScaSD); } + +#if defined(ASMJIT_X64) + //! @brief Find RAX, starting at ES:[EDI/RDI]. + inline void repne_scasq() + { _emitInstruction(kX86InstRepNEScaSQ); } +#endif // ASMJIT_X64 + + //! @brief Find AX, starting at ES:[EDI/RDI]. + inline void repne_scasw() + { _emitInstruction(kX86InstRepNEScaSW); } + + //! @brief Return from Procedure. + inline void ret() + { _emitInstruction(kX86InstRet); } + + //! @brief Return from Procedure. + inline void ret(const Imm& imm16) + { _emitInstruction(kX86InstRet, &imm16); } + + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rol(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstRol, &dst, &src); } + //! @brief Rotate Bits Left. + inline void rol(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstRol, &dst, &src); } + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rol(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstRol, &dst, &src); } + //! @brief Rotate Bits Left. + inline void rol(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstRol, &dst, &src); } + + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void ror(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstRor, &dst, &src); } + //! @brief Rotate Bits Right. + inline void ror(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstRor, &dst, &src); } + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void ror(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstRor, &dst, &src); } + //! @brief Rotate Bits Right. + inline void ror(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstRor, &dst, &src); } + +#if defined(ASMJIT_X86) + //! @brief Store AH into Flags. + inline void sahf() + { _emitInstruction(kX86InstSahf); } +#endif // ASMJIT_X86 + + //! @brief Integer subtraction with borrow. + inline void sbb(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstSbb, &dst, &src); } + //! @brief Integer subtraction with borrow. + inline void sbb(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstSbb, &dst, &src); } + //! @brief Integer subtraction with borrow. + inline void sbb(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstSbb, &dst, &src); } + //! @brief Integer subtraction with borrow. + inline void sbb(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstSbb, &dst, &src); } + //! @brief Integer subtraction with borrow. + inline void sbb(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstSbb, &dst, &src); } + + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void sal(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstSal, &dst, &src); } + //! @brief Shift Bits Left. + inline void sal(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstSal, &dst, &src); } + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void sal(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstSal, &dst, &src); } + //! @brief Shift Bits Left. + inline void sal(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstSal, &dst, &src); } + + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void sar(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstSar, &dst, &src); } + //! @brief Shift Bits Right. + inline void sar(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstSar, &dst, &src); } + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void sar(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstSar, &dst, &src); } + //! @brief Shift Bits Right. + inline void sar(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstSar, &dst, &src); } + + //! @brief Set Byte on Condition. + inline void set(kX86Cond cc, const GpReg& dst) + { + ASMJIT_ASSERT(dst.getSize() == 1); + _emitInstruction(X86Util::getSetccInstFromCond(cc), &dst); + } + + //! @brief Set Byte on Condition. + inline void set(kX86Cond cc, const Mem& dst) + { + ASMJIT_ASSERT(dst.getSize() <= 1); + _emitInstruction(X86Util::getSetccInstFromCond(cc), &dst); + } + + //! @brief Set Byte on Condition. + inline void seta (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetA , &dst); } + //! @brief Set Byte on Condition. + inline void seta (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetA , &dst); } + //! @brief Set Byte on Condition. + inline void setae (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetAE , &dst); } + //! @brief Set Byte on Condition. + inline void setae (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetAE , &dst); } + //! @brief Set Byte on Condition. + inline void setb (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetB , &dst); } + //! @brief Set Byte on Condition. + inline void setb (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetB , &dst); } + //! @brief Set Byte on Condition. + inline void setbe (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetBE , &dst); } + //! @brief Set Byte on Condition. + inline void setbe (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetBE , &dst); } + //! @brief Set Byte on Condition. + inline void setc (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetC , &dst); } + //! @brief Set Byte on Condition. + inline void setc (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetC , &dst); } + //! @brief Set Byte on Condition. + inline void sete (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetE , &dst); } + //! @brief Set Byte on Condition. + inline void sete (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetE , &dst); } + //! @brief Set Byte on Condition. + inline void setg (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetG , &dst); } + //! @brief Set Byte on Condition. + inline void setg (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetG , &dst); } + //! @brief Set Byte on Condition. + inline void setge (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetGE , &dst); } + //! @brief Set Byte on Condition. + inline void setge (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetGE , &dst); } + //! @brief Set Byte on Condition. + inline void setl (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetL , &dst); } + //! @brief Set Byte on Condition. + inline void setl (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetL , &dst); } + //! @brief Set Byte on Condition. + inline void setle (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetLE , &dst); } + //! @brief Set Byte on Condition. + inline void setle (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetLE , &dst); } + //! @brief Set Byte on Condition. + inline void setna (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNA , &dst); } + //! @brief Set Byte on Condition. + inline void setna (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNA , &dst); } + //! @brief Set Byte on Condition. + inline void setnae(const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNAE, &dst); } + //! @brief Set Byte on Condition. + inline void setnae(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNAE, &dst); } + //! @brief Set Byte on Condition. + inline void setnb (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNB , &dst); } + //! @brief Set Byte on Condition. + inline void setnb (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNB , &dst); } + //! @brief Set Byte on Condition. + inline void setnbe(const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNBE, &dst); } + //! @brief Set Byte on Condition. + inline void setnbe(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNBE, &dst); } + //! @brief Set Byte on Condition. + inline void setnc (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNC , &dst); } + //! @brief Set Byte on Condition. + inline void setnc (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNC , &dst); } + //! @brief Set Byte on Condition. + inline void setne (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNE , &dst); } + //! @brief Set Byte on Condition. + inline void setne (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNE , &dst); } + //! @brief Set Byte on Condition. + inline void setng (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNG , &dst); } + //! @brief Set Byte on Condition. + inline void setng (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNG , &dst); } + //! @brief Set Byte on Condition. + inline void setnge(const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNGE, &dst); } + //! @brief Set Byte on Condition. + inline void setnge(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNGE, &dst); } + //! @brief Set Byte on Condition. + inline void setnl (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNL , &dst); } + //! @brief Set Byte on Condition. + inline void setnl (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNL , &dst); } + //! @brief Set Byte on Condition. + inline void setnle(const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNLE, &dst); } + //! @brief Set Byte on Condition. + inline void setnle(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNLE, &dst); } + //! @brief Set Byte on Condition. + inline void setno (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNO , &dst); } + //! @brief Set Byte on Condition. + inline void setno (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNO , &dst); } + //! @brief Set Byte on Condition. + inline void setnp (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNP , &dst); } + //! @brief Set Byte on Condition. + inline void setnp (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNP , &dst); } + //! @brief Set Byte on Condition. + inline void setns (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNS , &dst); } + //! @brief Set Byte on Condition. + inline void setns (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNS , &dst); } + //! @brief Set Byte on Condition. + inline void setnz (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNZ , &dst); } + //! @brief Set Byte on Condition. + inline void setnz (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNZ , &dst); } + //! @brief Set Byte on Condition. + inline void seto (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetO , &dst); } + //! @brief Set Byte on Condition. + inline void seto (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetO , &dst); } + //! @brief Set Byte on Condition. + inline void setp (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetP , &dst); } + //! @brief Set Byte on Condition. + inline void setp (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetP , &dst); } + //! @brief Set Byte on Condition. + inline void setpe (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetPE , &dst); } + //! @brief Set Byte on Condition. + inline void setpe (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetPE , &dst); } + //! @brief Set Byte on Condition. + inline void setpo (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetPO , &dst); } + //! @brief Set Byte on Condition. + inline void setpo (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetPO , &dst); } + //! @brief Set Byte on Condition. + inline void sets (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetS , &dst); } + //! @brief Set Byte on Condition. + inline void sets (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetS , &dst); } + //! @brief Set Byte on Condition. + inline void setz (const GpReg& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetZ , &dst); } + //! @brief Set Byte on Condition. + inline void setz (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetZ , &dst); } + + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void shl(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstShl, &dst, &src); } + //! @brief Shift Bits Left. + inline void shl(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstShl, &dst, &src); } + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void shl(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstShl, &dst, &src); } + //! @brief Shift Bits Left. + inline void shl(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstShl, &dst, &src); } + + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void shr(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstShr, &dst, &src); } + //! @brief Shift Bits Right. + inline void shr(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstShr, &dst, &src); } + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void shr(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstShr, &dst, &src); } + //! @brief Shift Bits Right. + inline void shr(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstShr, &dst, &src); } + + //! @brief Double Precision Shift Left. + //! @note src2 register can be only @c cl register. + inline void shld(const GpReg& dst, const GpReg& src1, const GpReg& src2) + { _emitInstruction(kX86InstShld, &dst, &src1, &src2); } + //! @brief Double Precision Shift Left. + inline void shld(const GpReg& dst, const GpReg& src1, const Imm& src2) + { _emitInstruction(kX86InstShld, &dst, &src1, &src2); } + //! @brief Double Precision Shift Left. + //! @note src2 register can be only @c cl register. + inline void shld(const Mem& dst, const GpReg& src1, const GpReg& src2) + { _emitInstruction(kX86InstShld, &dst, &src1, &src2); } + //! @brief Double Precision Shift Left. + inline void shld(const Mem& dst, const GpReg& src1, const Imm& src2) + { _emitInstruction(kX86InstShld, &dst, &src1, &src2); } + + //! @brief Double Precision Shift Right. + //! @note src2 register can be only @c cl register. + inline void shrd(const GpReg& dst, const GpReg& src1, const GpReg& src2) + { _emitInstruction(kX86InstShrd, &dst, &src1, &src2); } + //! @brief Double Precision Shift Right. + inline void shrd(const GpReg& dst, const GpReg& src1, const Imm& src2) + { _emitInstruction(kX86InstShrd, &dst, &src1, &src2); } + //! @brief Double Precision Shift Right. + //! @note src2 register can be only @c cl register. + inline void shrd(const Mem& dst, const GpReg& src1, const GpReg& src2) + { _emitInstruction(kX86InstShrd, &dst, &src1, &src2); } + //! @brief Double Precision Shift Right. + inline void shrd(const Mem& dst, const GpReg& src1, const Imm& src2) + { _emitInstruction(kX86InstShrd, &dst, &src1, &src2); } + + //! @brief Set Carry Flag to 1. + inline void stc() + { _emitInstruction(kX86InstStc); } + + //! @brief Set Direction Flag to 1. + inline void std() + { _emitInstruction(kX86InstStd); } + + //! @brief Subtract. + inline void sub(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstSub, &dst, &src); } + //! @brief Subtract. + inline void sub(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstSub, &dst, &src); } + //! @brief Subtract. + inline void sub(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstSub, &dst, &src); } + //! @brief Subtract. + inline void sub(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstSub, &dst, &src); } + //! @brief Subtract. + inline void sub(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstSub, &dst, &src); } + + //! @brief Logical Compare. + inline void test(const GpReg& op1, const GpReg& op2) + { _emitInstruction(kX86InstTest, &op1, &op2); } + //! @brief Logical Compare. + inline void test(const GpReg& op1, const Imm& op2) + { _emitInstruction(kX86InstTest, &op1, &op2); } + //! @brief Logical Compare. + inline void test(const Mem& op1, const GpReg& op2) + { _emitInstruction(kX86InstTest, &op1, &op2); } + //! @brief Logical Compare. + inline void test(const Mem& op1, const Imm& op2) + { _emitInstruction(kX86InstTest, &op1, &op2); } + + //! @brief Undefined instruction - Raise invalid opcode exception. + inline void ud2() + { _emitInstruction(kX86InstUd2); } + + //! @brief Exchange and Add. + inline void xadd(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstXadd, &dst, &src); } + //! @brief Exchange and Add. + inline void xadd(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstXadd, &dst, &src); } + + //! @brief Exchange Register/Memory with Register. + inline void xchg(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstXchg, &dst, &src); } + //! @brief Exchange Register/Memory with Register. + inline void xchg(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstXchg, &dst, &src); } + //! @brief Exchange Register/Memory with Register. + inline void xchg(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstXchg, &src, &dst); } + + //! @brief Exchange Register/Memory with Register. + inline void xor_(const GpReg& dst, const GpReg& src) + { _emitInstruction(kX86InstXor, &dst, &src); } + //! @brief Exchange Register/Memory with Register. + inline void xor_(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstXor, &dst, &src); } + //! @brief Exchange Register/Memory with Register. + inline void xor_(const GpReg& dst, const Imm& src) + { _emitInstruction(kX86InstXor, &dst, &src); } + //! @brief Exchange Register/Memory with Register. + inline void xor_(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstXor, &dst, &src); } + //! @brief Exchange Register/Memory with Register. + inline void xor_(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstXor, &dst, &src); } + + // -------------------------------------------------------------------------- + // [X87 Instructions (FPU)] + // -------------------------------------------------------------------------- + + //! @brief Compute 2^x - 1 (FPU). + inline void f2xm1() + { _emitInstruction(kX86InstF2XM1); } + + //! @brief Absolute Value of st(0) (FPU). + inline void fabs() + { _emitInstruction(kX86InstFAbs); } + + //! @brief Add @a src to @a dst and store result in @a dst (FPU). + //! + //! @note One of dst or src must be st(0). + inline void fadd(const X87Reg& dst, const X87Reg& src) + { + ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); + _emitInstruction(kX86InstFAdd, &dst, &src); + } + + //! @brief Add @a src to st(0) and store result in st(0) (FPU). + //! + //! @note SP-FP or DP-FP determined by @a adr size. + inline void fadd(const Mem& src) + { _emitInstruction(kX86InstFAdd, &src); } + + //! @brief Add st(0) to @a dst and POP register stack (FPU). + inline void faddp(const X87Reg& dst = st(1)) + { _emitInstruction(kX86InstFAddP, &dst); } + + //! @brief Load Binary Coded Decimal (FPU). + inline void fbld(const Mem& src) + { _emitInstruction(kX86InstFBLd, &src); } + + //! @brief Store BCD Integer and Pop (FPU). + inline void fbstp(const Mem& dst) + { _emitInstruction(kX86InstFBStP, &dst); } + + //! @brief Change st(0) Sign (FPU). + inline void fchs() + { _emitInstruction(kX86InstFCHS); } + + //! @brief Clear Exceptions (FPU). + //! + //! Clear floating-point exception flags after checking for pending unmasked + //! floating-point exceptions. + //! + //! Clears the floating-point exception flags (PE, UE, OE, ZE, DE, and IE), + //! the exception summary status flag (ES), the stack fault flag (SF), and + //! the busy flag (B) in the FPU status word. The FCLEX instruction checks + //! for and handles any pending unmasked floating-point exceptions before + //! clearing the exception flags. + inline void fclex() + { _emitInstruction(kX86InstFClex); } + + //! @brief FP Conditional Move (FPU). + inline void fcmovb(const X87Reg& src) + { _emitInstruction(kX86InstFCMovB, &src); } + //! @brief FP Conditional Move (FPU). + inline void fcmovbe(const X87Reg& src) + { _emitInstruction(kX86InstFCMovBE, &src); } + //! @brief FP Conditional Move (FPU). + inline void fcmove(const X87Reg& src) + { _emitInstruction(kX86InstFCMovE, &src); } + //! @brief FP Conditional Move (FPU). + inline void fcmovnb(const X87Reg& src) + { _emitInstruction(kX86InstFCMovNB, &src); } + //! @brief FP Conditional Move (FPU). + inline void fcmovnbe(const X87Reg& src) + { _emitInstruction(kX86InstFCMovNBE, &src); } + //! @brief FP Conditional Move (FPU). + inline void fcmovne(const X87Reg& src) + { _emitInstruction(kX86InstFCMovNE, &src); } + //! @brief FP Conditional Move (FPU). + inline void fcmovnu(const X87Reg& src) + { _emitInstruction(kX86InstFCMovNU, &src); } + //! @brief FP Conditional Move (FPU). + inline void fcmovu(const X87Reg& src) + { _emitInstruction(kX86InstFCMovU, &src); } + + //! @brief Compare st(0) with @a reg (FPU). + inline void fcom(const X87Reg& reg = st(1)) + { _emitInstruction(kX86InstFCom, ®); } + //! @brief Compare st(0) with 4-byte or 8-byte FP at @a src (FPU). + inline void fcom(const Mem& src) + { _emitInstruction(kX86InstFCom, &src); } + + //! @brief Compare st(0) with @a reg and pop the stack (FPU). + inline void fcomp(const X87Reg& reg = st(1)) + { _emitInstruction(kX86InstFComP, ®); } + //! @brief Compare st(0) with 4-byte or 8-byte FP at @a adr and pop the + //! stack (FPU). + inline void fcomp(const Mem& mem) + { _emitInstruction(kX86InstFComP, &mem); } + + //! @brief Compare st(0) with st(1) and pop register stack twice (FPU). + inline void fcompp() + { _emitInstruction(kX86InstFComPP); } + + //! @brief Compare st(0) and @a reg and Set EFLAGS (FPU). + inline void fcomi(const X87Reg& reg) + { _emitInstruction(kX86InstFComI, ®); } + + //! @brief Compare st(0) and @a reg and Set EFLAGS and pop the stack (FPU). + inline void fcomip(const X87Reg& reg) + { _emitInstruction(kX86InstFComIP, ®); } + + //! @brief Cosine (FPU). + //! + //! This instruction calculates the cosine of the source operand in + //! register st(0) and stores the result in st(0). + inline void fcos() + { _emitInstruction(kX86InstFCos); } + + //! @brief Decrement Stack-Top Pointer (FPU). + //! + //! Subtracts one from the TOP field of the FPU status word (decrements + //! the top-ofstack pointer). If the TOP field contains a 0, it is set + //! to 7. The effect of this instruction is to rotate the stack by one + //! position. The contents of the FPU data registers and tag register + //! are not affected. + inline void fdecstp() + { _emitInstruction(kX86InstFDecStP); } + + //! @brief Divide @a dst by @a src (FPU). + //! + //! @note One of @a dst or @a src register must be st(0). + inline void fdiv(const X87Reg& dst, const X87Reg& src) + { + ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); + _emitInstruction(kX86InstFDiv, &dst, &src); + } + //! @brief Divide st(0) by 32-bit or 64-bit FP value (FPU). + inline void fdiv(const Mem& src) + { _emitInstruction(kX86InstFDiv, &src); } + + //! @brief Divide @a reg by st(0) (FPU). + inline void fdivp(const X87Reg& reg = st(1)) + { _emitInstruction(kX86InstFDivP, ®); } + + //! @brief Reverse Divide @a dst by @a src (FPU). + //! + //! @note One of @a dst or @a src register must be st(0). + inline void fdivr(const X87Reg& dst, const X87Reg& src) + { + ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); + _emitInstruction(kX86InstFDivR, &dst, &src); + } + //! @brief Reverse Divide st(0) by 32-bit or 64-bit FP value (FPU). + inline void fdivr(const Mem& src) + { _emitInstruction(kX86InstFDivR, &src); } + + //! @brief Reverse Divide @a reg by st(0) (FPU). + inline void fdivrp(const X87Reg& reg = st(1)) + { _emitInstruction(kX86InstFDivRP, ®); } + + //! @brief Free Floating-Point Register (FPU). + //! + //! Sets the tag in the FPU tag register associated with register @a reg + //! to empty (11B). The contents of @a reg and the FPU stack-top pointer + //! (TOP) are not affected. + inline void ffree(const X87Reg& reg) + { _emitInstruction(kX86InstFFree, ®); } + + //! @brief Add 16-bit or 32-bit integer to st(0) (FPU). + inline void fiadd(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); + _emitInstruction(kX86InstFIAdd, &src); + } + + //! @brief Compare st(0) with 16-bit or 32-bit Integer (FPU). + inline void ficom(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); + _emitInstruction(kX86InstFICom, &src); + } + + //! @brief Compare st(0) with 16-bit or 32-bit Integer and pop the stack (FPU). + inline void ficomp(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); + _emitInstruction(kX86InstFIComP, &src); + } + + //! @brief Divide st(0) by 32-bit or 16-bit integer (@a src) (FPU). + inline void fidiv(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); + _emitInstruction(kX86InstFIDiv, &src); + } + + //! @brief Reverse Divide st(0) by 32-bit or 16-bit integer (@a src) (FPU). + inline void fidivr(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); + _emitInstruction(kX86InstFIDivR, &src); + } + + //! @brief Load 16-bit, 32-bit or 64-bit Integer and push it to the stack (FPU). + //! + //! Converts the signed-integer source operand into double extended-precision + //! floating point format and pushes the value onto the FPU register stack. + //! The source operand can be a word, doubleword, or quadword integer. It is + //! loaded without rounding errors. The sign of the source operand is + //! preserved. + inline void fild(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4 || src.getSize() == 8); + _emitInstruction(kX86InstFILd, &src); + } + + //! @brief Multiply st(0) by 16-bit or 32-bit integer and store it + //! to st(0) (FPU). + inline void fimul(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); + _emitInstruction(kX86InstFIMul, &src); + } + + //! @brief Increment Stack-Top Pointer (FPU). + //! + //! Adds one to the TOP field of the FPU status word (increments the + //! top-of-stack pointer). If the TOP field contains a 7, it is set to 0. + //! The effect of this instruction is to rotate the stack by one position. + //! The contents of the FPU data registers and tag register are not affected. + //! This operation is not equivalent to popping the stack, because the tag + //! for the previous top-of-stack register is not marked empty. + inline void fincstp() + { _emitInstruction(kX86InstFIncStP); } + + //! @brief Initialize Floating-Point Unit (FPU). + //! + //! Initialize FPU after checking for pending unmasked floating-point + //! exceptions. + inline void finit() + { _emitInstruction(kX86InstFInit); } + + //! @brief Subtract 16-bit or 32-bit integer from st(0) and store result to + //! st(0) (FPU). + inline void fisub(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); + _emitInstruction(kX86InstFISub, &src); + } + + //! @brief Reverse Subtract 16-bit or 32-bit integer from st(0) and + //! store result to st(0) (FPU). + inline void fisubr(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == 4); + _emitInstruction(kX86InstFISubR, &src); + } + + //! @brief Initialize Floating-Point Unit (FPU). + //! + //! Initialize FPU without checking for pending unmasked floating-point + //! exceptions. + inline void fninit() + { _emitInstruction(kX86InstFNInit); } + + //! @brief Store st(0) as 16-bit or 32-bit Integer to @a dst (FPU). + inline void fist(const Mem& dst) + { + ASMJIT_ASSERT(dst.getSize() == 2 || dst.getSize() == 4); + _emitInstruction(kX86InstFISt, &dst); + } + + //! @brief Store st(0) as 16-bit, 32-bit or 64-bit Integer to @a dst and pop + //! stack (FPU). + inline void fistp(const Mem& dst) + { + ASMJIT_ASSERT(dst.getSize() == 2 || dst.getSize() == 4 || dst.getSize() == 8); + _emitInstruction(kX86InstFIStP, &dst); + } + + //! @brief Push 32-bit, 64-bit or 80-bit Floating Point Value onto the FPU + //! register stack (FPU). + inline void fld(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 4 || src.getSize() == 8 || src.getSize() == 10); + _emitInstruction(kX86InstFLd, &src); + } + + //! @brief Push @a reg onto the FPU register stack (FPU). + inline void fld(const X87Reg& reg) + { _emitInstruction(kX86InstFLd, ®); } + + //! @brief Push +1.0 onto the FPU register stack (FPU). + inline void fld1() + { _emitInstruction(kX86InstFLd1); } + + //! @brief Push log2(10) onto the FPU register stack (FPU). + inline void fldl2t() + { _emitInstruction(kX86InstFLdL2T); } + + //! @brief Push log2(e) onto the FPU register stack (FPU). + inline void fldl2e() + { _emitInstruction(kX86InstFLdL2E); } + + //! @brief Push pi onto the FPU register stack (FPU). + inline void fldpi() + { _emitInstruction(kX86InstFLdPi); } + + //! @brief Push log10(2) onto the FPU register stack (FPU). + inline void fldlg2() + { _emitInstruction(kX86InstFLdLg2); } + + //! @brief Push ln(2) onto the FPU register stack (FPU). + inline void fldln2() + { _emitInstruction(kX86InstFLdLn2); } + + //! @brief Push +0.0 onto the FPU register stack (FPU). + inline void fldz() + { _emitInstruction(kX86InstFLdZ); } + + //! @brief Load x87 FPU Control Word (2 bytes) (FPU). + inline void fldcw(const Mem& src) + { _emitInstruction(kX86InstFLdCw, &src); } + + //! @brief Load x87 FPU Environment (14 or 28 bytes) (FPU). + inline void fldenv(const Mem& src) + { _emitInstruction(kX86InstFLdEnv, &src); } + + //! @brief Multiply @a dst by @a src and store result in @a dst (FPU). + //! + //! @note One of dst or src must be st(0). + inline void fmul(const X87Reg& dst, const X87Reg& src) + { + ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); + _emitInstruction(kX86InstFMul, &dst, &src); + } + //! @brief Multiply st(0) by @a src and store result in st(0) (FPU). + //! + //! @note SP-FP or DP-FP determined by @a adr size. + inline void fmul(const Mem& src) + { _emitInstruction(kX86InstFMul, &src); } + + //! @brief Multiply st(0) by @a dst and POP register stack (FPU). + inline void fmulp(const X87Reg& dst = st(1)) + { _emitInstruction(kX86InstFMulP, &dst); } + + //! @brief Clear Exceptions (FPU). + //! + //! Clear floating-point exception flags without checking for pending + //! unmasked floating-point exceptions. + //! + //! Clears the floating-point exception flags (PE, UE, OE, ZE, DE, and IE), + //! the exception summary status flag (ES), the stack fault flag (SF), and + //! the busy flag (B) in the FPU status word. The FCLEX instruction does + //! not checks for and handles any pending unmasked floating-point exceptions + //! before clearing the exception flags. + inline void fnclex() + { _emitInstruction(kX86InstFNClex); } + + //! @brief No Operation (FPU). + inline void fnop() + { _emitInstruction(kX86InstFNop); } + + //! @brief Save FPU State (FPU). + //! + //! Store FPU environment to m94byte or m108byte without + //! checking for pending unmasked FP exceptions. + //! Then re-initialize the FPU. + inline void fnsave(const Mem& dst) + { _emitInstruction(kX86InstFNSave, &dst); } + + //! @brief Store x87 FPU Environment (FPU). + //! + //! Store FPU environment to @a dst (14 or 28 Bytes) without checking for + //! pending unmasked floating-point exceptions. Then mask all floating + //! point exceptions. + inline void fnstenv(const Mem& dst) + { _emitInstruction(kX86InstFNStEnv, &dst); } + + //! @brief Store x87 FPU Control Word (FPU). + //! + //! Store FPU control word to @a dst (2 Bytes) without checking for pending + //! unmasked floating-point exceptions. + inline void fnstcw(const Mem& dst) + { _emitInstruction(kX86InstFNStCw, &dst); } + + //! @brief Store x87 FPU Status Word (2 Bytes) (FPU). + inline void fnstsw(const GpReg& dst) + { + ASMJIT_ASSERT(dst.isRegCode(kX86RegAx)); + _emitInstruction(kX86InstFNStSw, &dst); + } + //! @brief Store x87 FPU Status Word (2 Bytes) (FPU). + inline void fnstsw(const Mem& dst) + { _emitInstruction(kX86InstFNStSw, &dst); } + + //! @brief Partial Arctangent (FPU). + //! + //! Replace st(1) with arctan(st(1)/st(0)) and pop the register stack. + inline void fpatan() + { _emitInstruction(kX86InstFPAtan); } + + //! @brief Partial Remainder (FPU). + //! + //! Replace st(0) with the remainder obtained from dividing st(0) by st(1). + inline void fprem() + { _emitInstruction(kX86InstFPRem); } + + //! @brief Partial Remainder (FPU). + //! + //! Replace st(0) with the IEEE remainder obtained from dividing st(0) by + //! st(1). + inline void fprem1() + { _emitInstruction(kX86InstFPRem1); } + + //! @brief Partial Tangent (FPU). + //! + //! Replace st(0) with its tangent and push 1 onto the FPU stack. + inline void fptan() + { _emitInstruction(kX86InstFPTan); } + + //! @brief Round to Integer (FPU). + //! + //! Rount st(0) to an Integer. + inline void frndint() + { _emitInstruction(kX86InstFRndInt); } + + //! @brief Restore FPU State (FPU). + //! + //! Load FPU state from src (94 or 108 bytes). + inline void frstor(const Mem& src) + { _emitInstruction(kX86InstFRstor, &src); } + + //! @brief Save FPU State (FPU). + //! + //! Store FPU state to 94 or 108-bytes after checking for + //! pending unmasked FP exceptions. Then reinitialize + //! the FPU. + inline void fsave(const Mem& dst) + { _emitInstruction(kX86InstFSave, &dst); } + + //! @brief Scale (FPU). + //! + //! Scale st(0) by st(1). + inline void fscale() + { _emitInstruction(kX86InstFScale); } + + //! @brief Sine (FPU). + //! + //! This instruction calculates the sine of the source operand in + //! register st(0) and stores the result in st(0). + inline void fsin() + { _emitInstruction(kX86InstFSin); } + + //! @brief Sine and Cosine (FPU). + //! + //! Compute the sine and cosine of st(0); replace st(0) with + //! the sine, and push the cosine onto the register stack. + inline void fsincos() + { _emitInstruction(kX86InstFSinCos); } + + //! @brief Square Root (FPU). + //! + //! Calculates square root of st(0) and stores the result in st(0). + inline void fsqrt() + { _emitInstruction(kX86InstFSqrt); } + + //! @brief Store Floating Point Value (FPU). + //! + //! Store st(0) as 32-bit or 64-bit floating point value to @a dst. + inline void fst(const Mem& dst) + { + ASMJIT_ASSERT(dst.getSize() == 4 || dst.getSize() == 8); + _emitInstruction(kX86InstFSt, &dst); + } + + //! @brief Store Floating Point Value (FPU). + //! + //! Store st(0) to @a reg. + inline void fst(const X87Reg& reg) + { _emitInstruction(kX86InstFSt, ®); } + + //! @brief Store Floating Point Value and Pop Register Stack (FPU). + //! + //! Store st(0) as 32-bit or 64-bit floating point value to @a dst + //! and pop register stack. + inline void fstp(const Mem& dst) + { + ASMJIT_ASSERT(dst.getSize() == 4 || dst.getSize() == 8 || dst.getSize() == 10); + _emitInstruction(kX86InstFStP, &dst); + } + + //! @brief Store Floating Point Value and Pop Register Stack (FPU). + //! + //! Store st(0) to @a reg and pop register stack. + inline void fstp(const X87Reg& reg) + { _emitInstruction(kX86InstFStP, ®); } + + //! @brief Store x87 FPU Control Word (FPU). + //! + //! Store FPU control word to @a dst (2 Bytes) after checking for pending + //! unmasked floating-point exceptions. + inline void fstcw(const Mem& dst) + { _emitInstruction(kX86InstFStCw, &dst); } + + //! @brief Store x87 FPU Environment (FPU). + //! + //! Store FPU environment to @a dst (14 or 28 Bytes) after checking for + //! pending unmasked floating-point exceptions. Then mask all floating + //! point exceptions. + inline void fstenv(const Mem& dst) + { _emitInstruction(kX86InstFStEnv, &dst); } + + //! @brief Store x87 FPU Status Word (2 Bytes) (FPU). + inline void fstsw(const GpReg& dst) + { + ASMJIT_ASSERT(dst.isRegCode(kX86RegAx)); + _emitInstruction(kX86InstFStSw, &dst); + } + //! @brief Store x87 FPU Status Word (2 Bytes) (FPU). + inline void fstsw(const Mem& dst) + { _emitInstruction(kX86InstFStSw, &dst); } + + //! @brief Subtract @a src from @a dst and store result in @a dst (FPU). + //! + //! @note One of dst or src must be st(0). + inline void fsub(const X87Reg& dst, const X87Reg& src) + { + ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); + _emitInstruction(kX86InstFSub, &dst, &src); + } + //! @brief Subtract @a src from st(0) and store result in st(0) (FPU). + //! + //! @note SP-FP or DP-FP determined by @a adr size. + inline void fsub(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 4 || src.getSize() == 8); + _emitInstruction(kX86InstFSub, &src); + } + + //! @brief Subtract st(0) from @a dst and POP register stack (FPU). + inline void fsubp(const X87Reg& dst = st(1)) + { _emitInstruction(kX86InstFSubP, &dst); } + + //! @brief Reverse Subtract @a src from @a dst and store result in @a dst (FPU). + //! + //! @note One of dst or src must be st(0). + inline void fsubr(const X87Reg& dst, const X87Reg& src) + { + ASMJIT_ASSERT(dst.getRegIndex() == 0 || src.getRegIndex() == 0); + _emitInstruction(kX86InstFSubR, &dst, &src); + } + + //! @brief Reverse Subtract @a src from st(0) and store result in st(0) (FPU). + //! + //! @note SP-FP or DP-FP determined by @a adr size. + inline void fsubr(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 4 || src.getSize() == 8); + _emitInstruction(kX86InstFSubR, &src); + } + + //! @brief Reverse Subtract st(0) from @a dst and POP register stack (FPU). + inline void fsubrp(const X87Reg& dst = st(1)) + { _emitInstruction(kX86InstFSubRP, &dst); } + + //! @brief Floating point test - Compare st(0) with 0.0. (FPU). + inline void ftst() + { _emitInstruction(kX86InstFTst); } + + //! @brief Unordered Compare st(0) with @a reg (FPU). + inline void fucom(const X87Reg& reg = st(1)) + { _emitInstruction(kX86InstFUCom, ®); } + + //! @brief Unordered Compare st(0) and @a reg, check for ordered values + //! and Set EFLAGS (FPU). + inline void fucomi(const X87Reg& reg) + { _emitInstruction(kX86InstFUComI, ®); } + + //! @brief UnorderedCompare st(0) and @a reg, Check for ordered values + //! and Set EFLAGS and pop the stack (FPU). + inline void fucomip(const X87Reg& reg = st(1)) + { _emitInstruction(kX86InstFUComIP, ®); } + + //! @brief Unordered Compare st(0) with @a reg and pop register stack (FPU). + inline void fucomp(const X87Reg& reg = st(1)) + { _emitInstruction(kX86InstFUComP, ®); } + + //! @brief Unordered compare st(0) with st(1) and pop register stack twice + //! (FPU). + inline void fucompp() + { _emitInstruction(kX86InstFUComPP); } + + inline void fwait() + { _emitInstruction(kX86InstFWait); } + + //! @brief Examine st(0) (FPU). + //! + //! Examines the contents of the ST(0) register and sets the condition code + //! flags C0, C2, and C3 in the FPU status word to indicate the class of + //! value or number in the register. + inline void fxam() + { _emitInstruction(kX86InstFXam); } + + //! @brief Exchange Register Contents (FPU). + //! + //! Exchange content of st(0) with @a reg. + inline void fxch(const X87Reg& reg = st(1)) + { _emitInstruction(kX86InstFXch, ®); } + + //! @brief Restore FP And MMX(tm) State And Streaming SIMD Extension State + //! (FPU, MMX, SSE). + //! + //! Load FP and MMX(tm) technology and Streaming SIMD Extension state from + //! src (512 bytes). + inline void fxrstor(const Mem& src) + { _emitInstruction(kX86InstFXRstor, &src); } + + //! @brief Store FP and MMX(tm) State and Streaming SIMD Extension State + //! (FPU, MMX, SSE). + //! + //! Store FP and MMX(tm) technology state and Streaming SIMD Extension state + //! to dst (512 bytes). + inline void fxsave(const Mem& dst) + { _emitInstruction(kX86InstFXSave, &dst); } + + //! @brief Extract Exponent and Significand (FPU). + //! + //! Separate value in st(0) into exponent and significand, store exponent + //! in st(0), and push the significand onto the register stack. + inline void fxtract() + { _emitInstruction(kX86InstFXtract); } + + //! @brief Compute y * log2(x). + //! + //! Replace st(1) with (st(1) * log2st(0)) and pop the register stack. + inline void fyl2x() + { _emitInstruction(kX86InstFYL2X); } + + //! @brief Compute y * log_2(x+1). + //! + //! Replace st(1) with (st(1) * (log2st(0) + 1.0)) and pop the register stack. + inline void fyl2xp1() + { _emitInstruction(kX86InstFYL2XP1); } + + // -------------------------------------------------------------------------- + // [MMX] + // -------------------------------------------------------------------------- + + //! @brief Empty MMX state. + inline void emms() + { _emitInstruction(kX86InstEmms); } + + //! @brief Move DWord (MMX). + inline void movd(const Mem& dst, const MmReg& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + //! @brief Move DWord (MMX). + inline void movd(const GpReg& dst, const MmReg& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + //! @brief Move DWord (MMX). + inline void movd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + //! @brief Move DWord (MMX). + inline void movd(const MmReg& dst, const GpReg& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + + //! @brief Move QWord (MMX). + inline void movq(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } + //! @brief Move QWord (MMX). + inline void movq(const Mem& dst, const MmReg& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#if defined(ASMJIT_X64) + //! @brief Move QWord (MMX). + inline void movq(const GpReg& dst, const MmReg& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#endif + //! @brief Move QWord (MMX). + inline void movq(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#if defined(ASMJIT_X64) + //! @brief Move QWord (MMX). + inline void movq(const MmReg& dst, const GpReg& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#endif + + //! @brief Pack with Signed Saturation (MMX). + inline void packsswb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPackSSWB, &dst, &src); } + //! @brief Pack with Signed Saturation (MMX). + inline void packsswb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPackSSWB, &dst, &src); } + + //! @brief Pack with Signed Saturation (MMX). + inline void packssdw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPackSSDW, &dst, &src); } + //! @brief Pack with Signed Saturation (MMX). + inline void packssdw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPackSSDW, &dst, &src); } + + //! @brief Pack with Unsigned Saturation (MMX). + inline void packuswb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPackUSWB, &dst, &src); } + //! @brief Pack with Unsigned Saturation (MMX). + inline void packuswb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPackUSWB, &dst, &src); } + + //! @brief Packed BYTE Add (MMX). + inline void paddb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAddB, &dst, &src); } + //! @brief Packed BYTE Add (MMX). + inline void paddb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddB, &dst, &src); } + + //! @brief Packed WORD Add (MMX). + inline void paddw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAddW, &dst, &src); } + //! @brief Packed WORD Add (MMX). + inline void paddw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddW, &dst, &src); } + + //! @brief Packed DWORD Add (MMX). + inline void paddd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAddD, &dst, &src); } + //! @brief Packed DWORD Add (MMX). + inline void paddd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddD, &dst, &src); } + + //! @brief Packed Add with Saturation (MMX). + inline void paddsb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAddSB, &dst, &src); } + //! @brief Packed Add with Saturation (MMX). + inline void paddsb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddSB, &dst, &src); } + + //! @brief Packed Add with Saturation (MMX). + inline void paddsw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAddSW, &dst, &src); } + //! @brief Packed Add with Saturation (MMX). + inline void paddsw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddSW, &dst, &src); } + + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAddUSB, &dst, &src); } + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddUSB, &dst, &src); } + + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAddUSW, &dst, &src); } + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddUSW, &dst, &src); } + + //! @brief Logical AND (MMX). + inline void pand(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAnd, &dst, &src); } + //! @brief Logical AND (MMX). + inline void pand(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAnd, &dst, &src); } + + //! @brief Logical AND Not (MMX). + inline void pandn(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAndN, &dst, &src); } + //! @brief Logical AND Not (MMX). + inline void pandn(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAndN, &dst, &src); } + + //! @brief Packed Compare for Equal (BYTES) (MMX). + inline void pcmpeqb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPCmpEqB, &dst, &src); } + //! @brief Packed Compare for Equal (BYTES) (MMX). + inline void pcmpeqb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqB, &dst, &src); } + + //! @brief Packed Compare for Equal (WORDS) (MMX). + inline void pcmpeqw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPCmpEqW, &dst, &src); } + //! @brief Packed Compare for Equal (WORDS) (MMX). + inline void pcmpeqw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqW, &dst, &src); } + + //! @brief Packed Compare for Equal (DWORDS) (MMX). + inline void pcmpeqd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPCmpEqD, &dst, &src); } + //! @brief Packed Compare for Equal (DWORDS) (MMX). + inline void pcmpeqd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqD, &dst, &src); } + + //! @brief Packed Compare for Greater Than (BYTES) (MMX). + inline void pcmpgtb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPCmpGtB, &dst, &src); } + //! @brief Packed Compare for Greater Than (BYTES) (MMX). + inline void pcmpgtb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtB, &dst, &src); } + + //! @brief Packed Compare for Greater Than (WORDS) (MMX). + inline void pcmpgtw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPCmpGtW, &dst, &src); } + //! @brief Packed Compare for Greater Than (WORDS) (MMX). + inline void pcmpgtw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtW, &dst, &src); } + + //! @brief Packed Compare for Greater Than (DWORDS) (MMX). + inline void pcmpgtd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPCmpGtD, &dst, &src); } + //! @brief Packed Compare for Greater Than (DWORDS) (MMX). + inline void pcmpgtd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtD, &dst, &src); } + + //! @brief Packed Multiply High (MMX). + inline void pmulhw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMulHW, &dst, &src); } + //! @brief Packed Multiply High (MMX). + inline void pmulhw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHW, &dst, &src); } + + //! @brief Packed Multiply Low (MMX). + inline void pmullw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMulLW, &dst, &src); } + //! @brief Packed Multiply Low (MMX). + inline void pmullw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulLW, &dst, &src); } + + //! @brief Bitwise Logical OR (MMX). + inline void por(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPOr, &dst, &src); } + //! @brief Bitwise Logical OR (MMX). + inline void por(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPOr, &dst, &src); } + + //! @brief Packed Multiply and Add (MMX). + inline void pmaddwd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMAddWD, &dst, &src); } + //! @brief Packed Multiply and Add (MMX). + inline void pmaddwd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMAddWD, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void pslld(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + //! @brief Packed Shift Left Logical (MMX). + inline void pslld(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + //! @brief Packed Shift Left Logical (MMX). + inline void pslld(const MmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void psllq(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + //! @brief Packed Shift Left Logical (MMX). + inline void psllq(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + //! @brief Packed Shift Left Logical (MMX). + inline void psllq(const MmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void psllw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + //! @brief Packed Shift Left Logical (MMX). + inline void psllw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + //! @brief Packed Shift Left Logical (MMX). + inline void psllw(const MmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psrad(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSraD, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psrad(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSraD, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psrad(const MmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSraD, &dst, &src); } + + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psraw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psraw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psraw(const MmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrld(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + //! @brief Packed Shift Right Logical (MMX). + inline void psrld(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + //! @brief Packed Shift Right Logical (MMX). + inline void psrld(const MmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrlq(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + //! @brief Packed Shift Right Logical (MMX). + inline void psrlq(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + //! @brief Packed Shift Right Logical (MMX). + inline void psrlq(const MmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrlw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + //! @brief Packed Shift Right Logical (MMX). + inline void psrlw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + //! @brief Packed Shift Right Logical (MMX). + inline void psrlw(const MmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + + //! @brief Packed Subtract (MMX). + inline void psubb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSubB, &dst, &src); } + //! @brief Packed Subtract (MMX). + inline void psubb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubB, &dst, &src); } + + //! @brief Packed Subtract (MMX). + inline void psubw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSubW, &dst, &src); } + //! @brief Packed Subtract (MMX). + inline void psubw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubW, &dst, &src); } + + //! @brief Packed Subtract (MMX). + inline void psubd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSubD, &dst, &src); } + //! @brief Packed Subtract (MMX). + inline void psubd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubD, &dst, &src); } + + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSubSB, &dst, &src); } + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubSB, &dst, &src); } + + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSubSW, &dst, &src); } + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubSW, &dst, &src); } + + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSubUSB, &dst, &src); } + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubUSB, &dst, &src); } + + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSubUSW, &dst, &src); } + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubUSW, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhbw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPunpckHBW, &dst, &src); } + //! @brief Unpack High Packed Data (MMX). + inline void punpckhbw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHBW, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhwd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPunpckHWD, &dst, &src); } + //! @brief Unpack High Packed Data (MMX). + inline void punpckhwd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHWD, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhdq(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPunpckHDQ, &dst, &src); } + //! @brief Unpack High Packed Data (MMX). + inline void punpckhdq(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHDQ, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpcklbw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPunpckLBW, &dst, &src); } + //! @brief Unpack High Packed Data (MMX). + inline void punpcklbw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLBW, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpcklwd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPunpckLWD, &dst, &src); } + //! @brief Unpack High Packed Data (MMX). + inline void punpcklwd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLWD, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckldq(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPunpckLDQ, &dst, &src); } + //! @brief Unpack High Packed Data (MMX). + inline void punpckldq(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLDQ, &dst, &src); } + + //! @brief Bitwise Exclusive OR (MMX). + inline void pxor(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPXor, &dst, &src); } + //! @brief Bitwise Exclusive OR (MMX). + inline void pxor(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPXor, &dst, &src); } + + // ------------------------------------------------------------------------- + // [3dNow] + // ------------------------------------------------------------------------- + + //! @brief Faster EMMS (3dNow!). + //! + //! @note Use only for early AMD processors where is only 3dNow! or SSE. If + //! CPU contains SSE2, it's better to use @c emms() ( @c femms() is mapped + //! to @c emms() ). + inline void femms() + { _emitInstruction(kX86InstFEmms); } + + //! @brief Packed SP-FP to Integer Convert (3dNow!). + inline void pf2id(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPF2ID, &dst, &src); } + //! @brief Packed SP-FP to Integer Convert (3dNow!). + inline void pf2id(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPF2ID, &dst, &src); } + + //! @brief Packed SP-FP to Integer Word Convert (3dNow!). + inline void pf2iw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPF2IW, &dst, &src); } + //! @brief Packed SP-FP to Integer Word Convert (3dNow!). + inline void pf2iw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPF2IW, &dst, &src); } + + //! @brief Packed SP-FP Accumulate (3dNow!). + inline void pfacc(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFAcc, &dst, &src); } + //! @brief Packed SP-FP Accumulate (3dNow!). + inline void pfacc(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFAcc, &dst, &src); } + + //! @brief Packed SP-FP Addition (3dNow!). + inline void pfadd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFAdd, &dst, &src); } + //! @brief Packed SP-FP Addition (3dNow!). + inline void pfadd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFAdd, &dst, &src); } + + //! @brief Packed SP-FP Compare - dst == src (3dNow!). + inline void pfcmpeq(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFCmpEQ, &dst, &src); } + //! @brief Packed SP-FP Compare - dst == src (3dNow!). + inline void pfcmpeq(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFCmpEQ, &dst, &src); } + + //! @brief Packed SP-FP Compare - dst >= src (3dNow!). + inline void pfcmpge(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFCmpGE, &dst, &src); } + //! @brief Packed SP-FP Compare - dst >= src (3dNow!). + inline void pfcmpge(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFCmpGE, &dst, &src); } + + //! @brief Packed SP-FP Compare - dst > src (3dNow!). + inline void pfcmpgt(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFCmpGT, &dst, &src); } + //! @brief Packed SP-FP Compare - dst > src (3dNow!). + inline void pfcmpgt(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFCmpGT, &dst, &src); } + + //! @brief Packed SP-FP Maximum (3dNow!). + inline void pfmax(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFMax, &dst, &src); } + //! @brief Packed SP-FP Maximum (3dNow!). + inline void pfmax(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFMax, &dst, &src); } + + //! @brief Packed SP-FP Minimum (3dNow!). + inline void pfmin(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFMin, &dst, &src); } + //! @brief Packed SP-FP Minimum (3dNow!). + inline void pfmin(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFMin, &dst, &src); } + + //! @brief Packed SP-FP Multiply (3dNow!). + inline void pfmul(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFMul, &dst, &src); } + //! @brief Packed SP-FP Multiply (3dNow!). + inline void pfmul(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFMul, &dst, &src); } + + //! @brief Packed SP-FP Negative Accumulate (3dNow!). + inline void pfnacc(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFNAcc, &dst, &src); } + //! @brief Packed SP-FP Negative Accumulate (3dNow!). + inline void pfnacc(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFNAcc, &dst, &src); } + + //! @brief Packed SP-FP Mixed Accumulate (3dNow!). + inline void pfpnacc(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFPNAcc, &dst, &src); } + //! @brief Packed SP-FP Mixed Accumulate (3dNow!). + inline void pfpnacc(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFPNAcc, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal Approximation (3dNow!). + inline void pfrcp(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFRcp, &dst, &src); } + //! @brief Packed SP-FP Reciprocal Approximation (3dNow!). + inline void pfrcp(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFRcp, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal, First Iteration Step (3dNow!). + inline void pfrcpit1(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFRcpIt1, &dst, &src); } + //! @brief Packed SP-FP Reciprocal, First Iteration Step (3dNow!). + inline void pfrcpit1(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFRcpIt1, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal, Second Iteration Step (3dNow!). + inline void pfrcpit2(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFRcpIt2, &dst, &src); } + //! @brief Packed SP-FP Reciprocal, Second Iteration Step (3dNow!). + inline void pfrcpit2(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFRcpIt2, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal Square Root, First Iteration Step (3dNow!). + inline void pfrsqit1(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFRSqIt1, &dst, &src); } + //! @brief Packed SP-FP Reciprocal Square Root, First Iteration Step (3dNow!). + inline void pfrsqit1(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFRSqIt1, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal Square Root Approximation (3dNow!). + inline void pfrsqrt(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFRSqrt, &dst, &src); } + //! @brief Packed SP-FP Reciprocal Square Root Approximation (3dNow!). + inline void pfrsqrt(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFRSqrt, &dst, &src); } + + //! @brief Packed SP-FP Subtract (3dNow!). + inline void pfsub(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFSub, &dst, &src); } + //! @brief Packed SP-FP Subtract (3dNow!). + inline void pfsub(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFSub, &dst, &src); } + + //! @brief Packed SP-FP Reverse Subtract (3dNow!). + inline void pfsubr(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPFSubR, &dst, &src); } + //! @brief Packed SP-FP Reverse Subtract (3dNow!). + inline void pfsubr(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPFSubR, &dst, &src); } + + //! @brief Packed DWords to SP-FP (3dNow!). + inline void pi2fd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPI2FD, &dst, &src); } + //! @brief Packed DWords to SP-FP (3dNow!). + inline void pi2fd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPI2FD, &dst, &src); } + + //! @brief Packed Words to SP-FP (3dNow!). + inline void pi2fw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPI2FW, &dst, &src); } + //! @brief Packed Words to SP-FP (3dNow!). + inline void pi2fw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPI2FW, &dst, &src); } + + //! @brief Packed swap DWord (3dNow!) + inline void pswapd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSwapD, &dst, &src); } + //! @brief Packed swap DWord (3dNow!) + inline void pswapd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSwapD, &dst, &src); } + + // -------------------------------------------------------------------------- + // [SSE] + // -------------------------------------------------------------------------- + + //! @brief Packed SP-FP Add (SSE). + inline void addps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstAddPS, &dst, &src); } + //! @brief Packed SP-FP Add (SSE). + inline void addps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstAddPS, &dst, &src); } + + //! @brief Scalar SP-FP Add (SSE). + inline void addss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstAddSS, &dst, &src); } + //! @brief Scalar SP-FP Add (SSE). + inline void addss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstAddSS, &dst, &src); } + + //! @brief Bit-wise Logical And Not For SP-FP (SSE). + inline void andnps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstAndnPS, &dst, &src); } + //! @brief Bit-wise Logical And Not For SP-FP (SSE). + inline void andnps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstAndnPS, &dst, &src); } + + //! @brief Bit-wise Logical And For SP-FP (SSE). + inline void andps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstAndPS, &dst, &src); } + //! @brief Bit-wise Logical And For SP-FP (SSE). + inline void andps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstAndPS, &dst, &src); } + + //! @brief Packed SP-FP Compare (SSE). + inline void cmpps(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpPS, &dst, &src, &imm8); } + //! @brief Packed SP-FP Compare (SSE). + inline void cmpps(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpPS, &dst, &src, &imm8); } + + //! @brief Compare Scalar SP-FP Values (SSE). + inline void cmpss(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpSS, &dst, &src, &imm8); } + //! @brief Compare Scalar SP-FP Values (SSE). + inline void cmpss(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpSS, &dst, &src, &imm8); } + + //! @brief Scalar Ordered SP-FP Compare and Set EFLAGS (SSE). + inline void comiss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstComISS, &dst, &src); } + //! @brief Scalar Ordered SP-FP Compare and Set EFLAGS (SSE). + inline void comiss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstComISS, &dst, &src); } + + //! @brief Packed Signed INT32 to Packed SP-FP Conversion (SSE). + inline void cvtpi2ps(const XmmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstCvtPI2PS, &dst, &src); } + //! @brief Packed Signed INT32 to Packed SP-FP Conversion (SSE). + inline void cvtpi2ps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPI2PS, &dst, &src); } + + //! @brief Packed SP-FP to Packed INT32 Conversion (SSE). + inline void cvtps2pi(const MmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtPS2PI, &dst, &src); } + //! @brief Packed SP-FP to Packed INT32 Conversion (SSE). + inline void cvtps2pi(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPS2PI, &dst, &src); } + + //! @brief Scalar Signed INT32 to SP-FP Conversion (SSE). + inline void cvtsi2ss(const XmmReg& dst, const GpReg& src) + { _emitInstruction(kX86InstCvtSI2SS, &dst, &src); } + //! @brief Scalar Signed INT32 to SP-FP Conversion (SSE). + inline void cvtsi2ss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSI2SS, &dst, &src); } + + //! @brief Scalar SP-FP to Signed INT32 Conversion (SSE). + inline void cvtss2si(const GpReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtSS2SI, &dst, &src); } + //! @brief Scalar SP-FP to Signed INT32 Conversion (SSE). + inline void cvtss2si(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSS2SI, &dst, &src); } + + //! @brief Packed SP-FP to Packed INT32 Conversion (truncate) (SSE). + inline void cvttps2pi(const MmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvttPS2PI, &dst, &src); } + //! @brief Packed SP-FP to Packed INT32 Conversion (truncate) (SSE). + inline void cvttps2pi(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvttPS2PI, &dst, &src); } + + //! @brief Scalar SP-FP to Signed INT32 Conversion (truncate) (SSE). + inline void cvttss2si(const GpReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvttSS2SI, &dst, &src); } + //! @brief Scalar SP-FP to Signed INT32 Conversion (truncate) (SSE). + inline void cvttss2si(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvttSS2SI, &dst, &src); } + + //! @brief Packed SP-FP Divide (SSE). + inline void divps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstDivPS, &dst, &src); } + //! @brief Packed SP-FP Divide (SSE). + inline void divps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstDivPS, &dst, &src); } + + //! @brief Scalar SP-FP Divide (SSE). + inline void divss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstDivSS, &dst, &src); } + //! @brief Scalar SP-FP Divide (SSE). + inline void divss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstDivSS, &dst, &src); } + + //! @brief Load Streaming SIMD Extension Control/Status (SSE). + inline void ldmxcsr(const Mem& src) + { _emitInstruction(kX86InstLdMXCSR, &src); } + + //! @brief Byte Mask Write (SSE). + //! + //! @note The default memory location is specified by DS:EDI. + inline void maskmovq(const MmReg& data, const MmReg& mask) + { _emitInstruction(kX86InstMaskMovQ, &data, &mask); } + + //! @brief Packed SP-FP Maximum (SSE). + inline void maxps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMaxPS, &dst, &src); } + //! @brief Packed SP-FP Maximum (SSE). + inline void maxps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMaxPS, &dst, &src); } + + //! @brief Scalar SP-FP Maximum (SSE). + inline void maxss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMaxSS, &dst, &src); } + //! @brief Scalar SP-FP Maximum (SSE). + inline void maxss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMaxSS, &dst, &src); } + + //! @brief Packed SP-FP Minimum (SSE). + inline void minps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMinPS, &dst, &src); } + //! @brief Packed SP-FP Minimum (SSE). + inline void minps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMinPS, &dst, &src); } + + //! @brief Scalar SP-FP Minimum (SSE). + inline void minss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMinSS, &dst, &src); } + //! @brief Scalar SP-FP Minimum (SSE). + inline void minss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMinSS, &dst, &src); } + + //! @brief Move Aligned Packed SP-FP Values (SSE). + inline void movaps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovAPS, &dst, &src); } + //! @brief Move Aligned Packed SP-FP Values (SSE). + inline void movaps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovAPS, &dst, &src); } + + //! @brief Move Aligned Packed SP-FP Values (SSE). + inline void movaps(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovAPS, &dst, &src); } + + //! @brief Move DWord. + inline void movd(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + //! @brief Move DWord. + inline void movd(const GpReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + //! @brief Move DWord. + inline void movd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + //! @brief Move DWord. + inline void movd(const XmmReg& dst, const GpReg& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + + //! @brief Move QWord (SSE). + inline void movq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } + //! @brief Move QWord (SSE). + inline void movq(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#if defined(ASMJIT_X64) + //! @brief Move QWord (SSE). + inline void movq(const GpReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#endif // ASMJIT_X64 + //! @brief Move QWord (SSE). + inline void movq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#if defined(ASMJIT_X64) + //! @brief Move QWord (SSE). + inline void movq(const XmmReg& dst, const GpReg& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#endif // ASMJIT_X64 + + //! @brief Move 64 Bits Non Temporal (SSE). + inline void movntq(const Mem& dst, const MmReg& src) + { _emitInstruction(kX86InstMovNTQ, &dst, &src); } + + //! @brief High to Low Packed SP-FP (SSE). + inline void movhlps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovHLPS, &dst, &src); } + + //! @brief Move High Packed SP-FP (SSE). + inline void movhps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovHPS, &dst, &src); } + + //! @brief Move High Packed SP-FP (SSE). + inline void movhps(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovHPS, &dst, &src); } + + //! @brief Move Low to High Packed SP-FP (SSE). + inline void movlhps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovLHPS, &dst, &src); } + + //! @brief Move Low Packed SP-FP (SSE). + inline void movlps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovLPS, &dst, &src); } + + //! @brief Move Low Packed SP-FP (SSE). + inline void movlps(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovLPS, &dst, &src); } + + //! @brief Move Aligned Four Packed SP-FP Non Temporal (SSE). + inline void movntps(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovNTPS, &dst, &src); } + + //! @brief Move Scalar SP-FP (SSE). + inline void movss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovSS, &dst, &src); } + + //! @brief Move Scalar SP-FP (SSE). + inline void movss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovSS, &dst, &src); } + + //! @brief Move Scalar SP-FP (SSE). + inline void movss(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovSS, &dst, &src); } + + //! @brief Move Unaligned Packed SP-FP Values (SSE). + inline void movups(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovUPS, &dst, &src); } + //! @brief Move Unaligned Packed SP-FP Values (SSE). + inline void movups(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovUPS, &dst, &src); } + + //! @brief Move Unaligned Packed SP-FP Values (SSE). + inline void movups(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovUPS, &dst, &src); } + + //! @brief Packed SP-FP Multiply (SSE). + inline void mulps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMulPS, &dst, &src); } + //! @brief Packed SP-FP Multiply (SSE). + inline void mulps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMulPS, &dst, &src); } + + //! @brief Scalar SP-FP Multiply (SSE). + inline void mulss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMulSS, &dst, &src); } + //! @brief Scalar SP-FP Multiply (SSE). + inline void mulss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMulSS, &dst, &src); } + + //! @brief Bit-wise Logical OR for SP-FP Data (SSE). + inline void orps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstOrPS, &dst, &src); } + //! @brief Bit-wise Logical OR for SP-FP Data (SSE). + inline void orps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstOrPS, &dst, &src); } + + //! @brief Packed Average (SSE). + inline void pavgb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAvgB, &dst, &src); } + //! @brief Packed Average (SSE). + inline void pavgb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAvgB, &dst, &src); } + + //! @brief Packed Average (SSE). + inline void pavgw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAvgW, &dst, &src); } + //! @brief Packed Average (SSE). + inline void pavgw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAvgW, &dst, &src); } + + //! @brief Extract Word (SSE). + inline void pextrw(const GpReg& dst, const MmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrW, &dst, &src, &imm8); } + + //! @brief Insert Word (SSE). + inline void pinsrw(const MmReg& dst, const GpReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRW, &dst, &src, &imm8); } + //! @brief Insert Word (SSE). + inline void pinsrw(const MmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRW, &dst, &src, &imm8); } + + //! @brief Packed Signed Integer Word Maximum (SSE). + inline void pmaxsw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMaxSW, &dst, &src); } + //! @brief Packed Signed Integer Word Maximum (SSE). + inline void pmaxsw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxSW, &dst, &src); } + + //! @brief Packed Unsigned Integer Byte Maximum (SSE). + inline void pmaxub(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMaxUB, &dst, &src); } + //! @brief Packed Unsigned Integer Byte Maximum (SSE). + inline void pmaxub(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxUB, &dst, &src); } + + //! @brief Packed Signed Integer Word Minimum (SSE). + inline void pminsw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMinSW, &dst, &src); } + //! @brief Packed Signed Integer Word Minimum (SSE). + inline void pminsw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMinSW, &dst, &src); } + + //! @brief Packed Unsigned Integer Byte Minimum (SSE). + inline void pminub(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMinUB, &dst, &src); } + //! @brief Packed Unsigned Integer Byte Minimum (SSE). + inline void pminub(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMinUB, &dst, &src); } + + //! @brief Move Byte Mask To Integer (SSE). + inline void pmovmskb(const GpReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMovMskB, &dst, &src); } + + //! @brief Packed Multiply High Unsigned (SSE). + inline void pmulhuw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMulHUW, &dst, &src); } + //! @brief Packed Multiply High Unsigned (SSE). + inline void pmulhuw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHUW, &dst, &src); } + + //! @brief Packed Sum of Absolute Differences (SSE). + inline void psadbw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSADBW, &dst, &src); } + //! @brief Packed Sum of Absolute Differences (SSE). + inline void psadbw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSADBW, &dst, &src); } + + //! @brief Packed Shuffle word (SSE). + inline void pshufw(const MmReg& dst, const MmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufW, &dst, &src, &imm8); } + //! @brief Packed Shuffle word (SSE). + inline void pshufw(const MmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufW, &dst, &src, &imm8); } + + //! @brief Packed SP-FP Reciprocal (SSE). + inline void rcpps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstRcpPS, &dst, &src); } + //! @brief Packed SP-FP Reciprocal (SSE). + inline void rcpps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstRcpPS, &dst, &src); } + + //! @brief Scalar SP-FP Reciprocal (SSE). + inline void rcpss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstRcpSS, &dst, &src); } + //! @brief Scalar SP-FP Reciprocal (SSE). + inline void rcpss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstRcpSS, &dst, &src); } + + //! @brief Prefetch (SSE). + inline void prefetch(const Mem& mem, const Imm& hint) + { _emitInstruction(kX86InstPrefetch, &mem, &hint); } + + //! @brief Compute Sum of Absolute Differences (SSE). + inline void psadbw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSADBW, &dst, &src); } + //! @brief Compute Sum of Absolute Differences (SSE). + inline void psadbw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSADBW, &dst, &src); } + + //! @brief Packed SP-FP Square Root Reciprocal (SSE). + inline void rsqrtps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstSqrtPS, &dst, &src); } + //! @brief Packed SP-FP Square Root Reciprocal (SSE). + inline void rsqrtps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtPS, &dst, &src); } + + //! @brief Scalar SP-FP Square Root Reciprocal (SSE). + inline void rsqrtss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstSqrtSS, &dst, &src); } + //! @brief Scalar SP-FP Square Root Reciprocal (SSE). + inline void rsqrtss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtSS, &dst, &src); } + + //! @brief Store fence (SSE). + inline void sfence() + { _emitInstruction(kX86InstSFence); } + + //! @brief Shuffle SP-FP (SSE). + inline void shufps(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstShufPS, &dst, &src, &imm8); } + //! @brief Shuffle SP-FP (SSE). + inline void shufps(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstShufPS, &dst, &src, &imm8); } + + //! @brief Packed SP-FP Square Root (SSE). + inline void sqrtps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstSqrtPS, &dst, &src); } + //! @brief Packed SP-FP Square Root (SSE). + inline void sqrtps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtPS, &dst, &src); } + + //! @brief Scalar SP-FP Square Root (SSE). + inline void sqrtss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstSqrtSS, &dst, &src); } + //! @brief Scalar SP-FP Square Root (SSE). + inline void sqrtss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtSS, &dst, &src); } + + //! @brief Store Streaming SIMD Extension Control/Status (SSE). + inline void stmxcsr(const Mem& dst) + { _emitInstruction(kX86InstStMXCSR, &dst); } + + //! @brief Packed SP-FP Subtract (SSE). + inline void subps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstSubPS, &dst, &src); } + //! @brief Packed SP-FP Subtract (SSE). + inline void subps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstSubPS, &dst, &src); } + + //! @brief Scalar SP-FP Subtract (SSE). + inline void subss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstSubSS, &dst, &src); } + //! @brief Scalar SP-FP Subtract (SSE). + inline void subss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstSubSS, &dst, &src); } + + //! @brief Unordered Scalar SP-FP compare and set EFLAGS (SSE). + inline void ucomiss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstUComISS, &dst, &src); } + //! @brief Unordered Scalar SP-FP compare and set EFLAGS (SSE). + inline void ucomiss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstUComISS, &dst, &src); } + + //! @brief Unpack High Packed SP-FP Data (SSE). + inline void unpckhps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstUnpckHPS, &dst, &src); } + //! @brief Unpack High Packed SP-FP Data (SSE). + inline void unpckhps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstUnpckHPS, &dst, &src); } + + //! @brief Unpack Low Packed SP-FP Data (SSE). + inline void unpcklps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstUnpckLPS, &dst, &src); } + //! @brief Unpack Low Packed SP-FP Data (SSE). + inline void unpcklps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstUnpckLPS, &dst, &src); } + + //! @brief Bit-wise Logical Xor for SP-FP Data (SSE). + inline void xorps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstXorPS, &dst, &src); } + //! @brief Bit-wise Logical Xor for SP-FP Data (SSE). + inline void xorps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstXorPS, &dst, &src); } + + // -------------------------------------------------------------------------- + // [SSE2] + // -------------------------------------------------------------------------- + + //! @brief Packed DP-FP Add (SSE2). + inline void addpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstAddPD, &dst, &src); } + //! @brief Packed DP-FP Add (SSE2). + inline void addpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstAddPD, &dst, &src); } + + //! @brief Scalar DP-FP Add (SSE2). + inline void addsd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstAddSD, &dst, &src); } + //! @brief Scalar DP-FP Add (SSE2). + inline void addsd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstAddSD, &dst, &src); } + + //! @brief Bit-wise Logical And Not For DP-FP (SSE2). + inline void andnpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstAndnPD, &dst, &src); } + //! @brief Bit-wise Logical And Not For DP-FP (SSE2). + inline void andnpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstAndnPD, &dst, &src); } + + //! @brief Bit-wise Logical And For DP-FP (SSE2). + inline void andpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstAndPD, &dst, &src); } + //! @brief Bit-wise Logical And For DP-FP (SSE2). + inline void andpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstAndPD, &dst, &src); } + + //! @brief Flush Cache Line (SSE2). + inline void clflush(const Mem& mem) + { _emitInstruction(kX86InstClFlush, &mem); } + + //! @brief Packed DP-FP Compare (SSE2). + inline void cmppd(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpPD, &dst, &src, &imm8); } + //! @brief Packed DP-FP Compare (SSE2). + inline void cmppd(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpPD, &dst, &src, &imm8); } + + //! @brief Compare Scalar SP-FP Values (SSE2). + inline void cmpsd(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpSD, &dst, &src, &imm8); } + //! @brief Compare Scalar SP-FP Values (SSE2). + inline void cmpsd(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpSD, &dst, &src, &imm8); } + + //! @brief Scalar Ordered DP-FP Compare and Set EFLAGS (SSE2). + inline void comisd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstComISD, &dst, &src); } + //! @brief Scalar Ordered DP-FP Compare and Set EFLAGS (SSE2). + inline void comisd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstComISD, &dst, &src); } + + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtdq2pd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtDQ2PD, &dst, &src); } + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtdq2pd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtDQ2PD, &dst, &src); } + + //! @brief Convert Packed Dword Integers to Packed SP-FP Values (SSE2). + inline void cvtdq2ps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtDQ2PS, &dst, &src); } + //! @brief Convert Packed Dword Integers to Packed SP-FP Values (SSE2). + inline void cvtdq2ps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtDQ2PS, &dst, &src); } + + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2dq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtPD2DQ, &dst, &src); } + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2dq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPD2DQ, &dst, &src); } + + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2pi(const MmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtPD2PI, &dst, &src); } + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2pi(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPD2PI, &dst, &src); } + + //! @brief Convert Packed DP-FP Values to Packed SP-FP Values (SSE2). + inline void cvtpd2ps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtPD2PS, &dst, &src); } + //! @brief Convert Packed DP-FP Values to Packed SP-FP Values (SSE2). + inline void cvtpd2ps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPD2PS, &dst, &src); } + + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtpi2pd(const XmmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstCvtPI2PD, &dst, &src); } + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtpi2pd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPI2PD, &dst, &src); } + + //! @brief Convert Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvtps2dq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtPS2DQ, &dst, &src); } + //! @brief Convert Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvtps2dq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPS2DQ, &dst, &src); } + + //! @brief Convert Packed SP-FP Values to Packed DP-FP Values (SSE2). + inline void cvtps2pd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtPS2PD, &dst, &src); } + //! @brief Convert Packed SP-FP Values to Packed DP-FP Values (SSE2). + inline void cvtps2pd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPS2PD, &dst, &src); } + + //! @brief Convert Scalar DP-FP Value to Dword Integer (SSE2). + inline void cvtsd2si(const GpReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtSD2SI, &dst, &src); } + //! @brief Convert Scalar DP-FP Value to Dword Integer (SSE2). + inline void cvtsd2si(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSD2SI, &dst, &src); } + + //! @brief Convert Scalar DP-FP Value to Scalar SP-FP Value (SSE2). + inline void cvtsd2ss(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtSD2SS, &dst, &src); } + //! @brief Convert Scalar DP-FP Value to Scalar SP-FP Value (SSE2). + inline void cvtsd2ss(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSD2SS, &dst, &src); } + + //! @brief Convert Dword Integer to Scalar DP-FP Value (SSE2). + inline void cvtsi2sd(const XmmReg& dst, const GpReg& src) + { _emitInstruction(kX86InstCvtSI2SD, &dst, &src); } + //! @brief Convert Dword Integer to Scalar DP-FP Value (SSE2). + inline void cvtsi2sd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSI2SD, &dst, &src); } + + //! @brief Convert Scalar SP-FP Value to Scalar DP-FP Value (SSE2). + inline void cvtss2sd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvtSS2SD, &dst, &src); } + //! @brief Convert Scalar SP-FP Value to Scalar DP-FP Value (SSE2). + inline void cvtss2sd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSS2SD, &dst, &src); } + + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2pi(const MmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvttPD2PI, &dst, &src); } + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2pi(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvttPD2PI, &dst, &src); } + + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2dq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvttPD2DQ, &dst, &src); } + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2dq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvttPD2DQ, &dst, &src); } + + //! @brief Convert with Truncation Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvttps2dq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvttPS2DQ, &dst, &src); } + //! @brief Convert with Truncation Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvttps2dq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvttPS2DQ, &dst, &src); } + + //! @brief Convert with Truncation Scalar DP-FP Value to Signed Dword Integer (SSE2). + inline void cvttsd2si(const GpReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstCvttSD2SI, &dst, &src); } + //! @brief Convert with Truncation Scalar DP-FP Value to Signed Dword Integer (SSE2). + inline void cvttsd2si(const GpReg& dst, const Mem& src) + { _emitInstruction(kX86InstCvttSD2SI, &dst, &src); } + + //! @brief Packed DP-FP Divide (SSE2). + inline void divpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstDivPD, &dst, &src); } + //! @brief Packed DP-FP Divide (SSE2). + inline void divpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstDivPD, &dst, &src); } + + //! @brief Scalar DP-FP Divide (SSE2). + inline void divsd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstDivSD, &dst, &src); } + //! @brief Scalar DP-FP Divide (SSE2). + inline void divsd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstDivSD, &dst, &src); } + + //! @brief Load Fence (SSE2). + inline void lfence() + { _emitInstruction(kX86InstLFence); } + + //! @brief Store Selected Bytes of Double Quadword (SSE2). + //! + //! @note Target is DS:EDI. + inline void maskmovdqu(const XmmReg& src, const XmmReg& mask) + { _emitInstruction(kX86InstMaskMovDQU, &src, &mask); } + + //! @brief Return Maximum Packed Double-Precision FP Values (SSE2). + inline void maxpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMaxPD, &dst, &src); } + //! @brief Return Maximum Packed Double-Precision FP Values (SSE2). + inline void maxpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMaxPD, &dst, &src); } + + //! @brief Return Maximum Scalar Double-Precision FP Value (SSE2). + inline void maxsd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMaxSD, &dst, &src); } + //! @brief Return Maximum Scalar Double-Precision FP Value (SSE2). + inline void maxsd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMaxSD, &dst, &src); } + + //! @brief Memory Fence (SSE2). + inline void mfence() + { _emitInstruction(kX86InstMFence); } + + //! @brief Return Minimum Packed DP-FP Values (SSE2). + inline void minpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMinPD, &dst, &src); } + //! @brief Return Minimum Packed DP-FP Values (SSE2). + inline void minpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMinPD, &dst, &src); } + + //! @brief Return Minimum Scalar DP-FP Value (SSE2). + inline void minsd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMinSD, &dst, &src); } + //! @brief Return Minimum Scalar DP-FP Value (SSE2). + inline void minsd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMinSD, &dst, &src); } + + //! @brief Move Aligned DQWord (SSE2). + inline void movdqa(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovDQA, &dst, &src); } + //! @brief Move Aligned DQWord (SSE2). + inline void movdqa(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovDQA, &dst, &src); } + + //! @brief Move Aligned DQWord (SSE2). + inline void movdqa(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovDQA, &dst, &src); } + + //! @brief Move Unaligned Double Quadword (SSE2). + inline void movdqu(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovDQU, &dst, &src); } + //! @brief Move Unaligned Double Quadword (SSE2). + inline void movdqu(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovDQU, &dst, &src); } + + //! @brief Move Unaligned Double Quadword (SSE2). + inline void movdqu(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovDQU, &dst, &src); } + + //! @brief Extract Packed SP-FP Sign Mask (SSE2). + inline void movmskps(const GpReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovMskPS, &dst, &src); } + + //! @brief Extract Packed DP-FP Sign Mask (SSE2). + inline void movmskpd(const GpReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovMskPD, &dst, &src); } + + //! @brief Move Scalar Double-Precision FP Value (SSE2). + inline void movsd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovSD, &dst, &src); } + //! @brief Move Scalar Double-Precision FP Value (SSE2). + inline void movsd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovSD, &dst, &src); } + + //! @brief Move Scalar Double-Precision FP Value (SSE2). + inline void movsd(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovSD, &dst, &src); } + + //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). + inline void movapd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovAPD, &dst, &src); } + + //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). + inline void movapd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovAPD, &dst, &src); } + + //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). + inline void movapd(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovAPD, &dst, &src); } + + //! @brief Move Quadword from XMM to MMX Technology Register (SSE2). + inline void movdq2q(const MmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovDQ2Q, &dst, &src); } + + //! @brief Move Quadword from MMX Technology to XMM Register (SSE2). + inline void movq2dq(const XmmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstMovQ2DQ, &dst, &src); } + + //! @brief Move High Packed Double-Precision FP Value (SSE2). + inline void movhpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovHPD, &dst, &src); } + + //! @brief Move High Packed Double-Precision FP Value (SSE2). + inline void movhpd(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovHPD, &dst, &src); } + + //! @brief Move Low Packed Double-Precision FP Value (SSE2). + inline void movlpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovLPD, &dst, &src); } + + //! @brief Move Low Packed Double-Precision FP Value (SSE2). + inline void movlpd(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovLPD, &dst, &src); } + + //! @brief Store Double Quadword Using Non-Temporal Hint (SSE2). + inline void movntdq(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovNTDQ, &dst, &src); } + + //! @brief Store Store DWORD Using Non-Temporal Hint (SSE2). + inline void movnti(const Mem& dst, const GpReg& src) + { _emitInstruction(kX86InstMovNTI, &dst, &src); } + + //! @brief Store Packed Double-Precision FP Values Using Non-Temporal Hint (SSE2). + inline void movntpd(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovNTPD, &dst, &src); } + + //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). + inline void movupd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovUPD, &dst, &src); } + + //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). + inline void movupd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovUPD, &dst, &src); } + + //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). + inline void movupd(const Mem& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovUPD, &dst, &src); } + + //! @brief Packed DP-FP Multiply (SSE2). + inline void mulpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMulPD, &dst, &src); } + //! @brief Packed DP-FP Multiply (SSE2). + inline void mulpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMulPD, &dst, &src); } + + //! @brief Scalar DP-FP Multiply (SSE2). + inline void mulsd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMulSD, &dst, &src); } + //! @brief Scalar DP-FP Multiply (SSE2). + inline void mulsd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMulSD, &dst, &src); } + + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void orpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstOrPD, &dst, &src); } + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void orpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstOrPD, &dst, &src); } + + //! @brief Pack with Signed Saturation (SSE2). + inline void packsswb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPackSSWB, &dst, &src); } + //! @brief Pack with Signed Saturation (SSE2). + inline void packsswb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPackSSWB, &dst, &src); } + + //! @brief Pack with Signed Saturation (SSE2). + inline void packssdw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPackSSDW, &dst, &src); } + //! @brief Pack with Signed Saturation (SSE2). + inline void packssdw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPackSSDW, &dst, &src); } + + //! @brief Pack with Unsigned Saturation (SSE2). + inline void packuswb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPackUSWB, &dst, &src); } + //! @brief Pack with Unsigned Saturation (SSE2). + inline void packuswb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPackUSWB, &dst, &src); } + + //! @brief Packed BYTE Add (SSE2). + inline void paddb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAddB, &dst, &src); } + //! @brief Packed BYTE Add (SSE2). + inline void paddb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddB, &dst, &src); } + + //! @brief Packed WORD Add (SSE2). + inline void paddw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAddW, &dst, &src); } + //! @brief Packed WORD Add (SSE2). + inline void paddw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddW, &dst, &src); } + + //! @brief Packed DWORD Add (SSE2). + inline void paddd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAddD, &dst, &src); } + //! @brief Packed DWORD Add (SSE2). + inline void paddd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddD, &dst, &src); } + + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAddQ, &dst, &src); } + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddQ, &dst, &src); } + + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAddQ, &dst, &src); } + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddQ, &dst, &src); } + + //! @brief Packed Add with Saturation (SSE2). + inline void paddsb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAddSB, &dst, &src); } + //! @brief Packed Add with Saturation (SSE2). + inline void paddsb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddSB, &dst, &src); } + + //! @brief Packed Add with Saturation (SSE2). + inline void paddsw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAddSW, &dst, &src); } + //! @brief Packed Add with Saturation (SSE2). + inline void paddsw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddSW, &dst, &src); } + + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAddUSB, &dst, &src); } + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddUSB, &dst, &src); } + + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAddUSW, &dst, &src); } + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAddUSW, &dst, &src); } + + //! @brief Logical AND (SSE2). + inline void pand(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAnd, &dst, &src); } + //! @brief Logical AND (SSE2). + inline void pand(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAnd, &dst, &src); } + + //! @brief Logical AND Not (SSE2). + inline void pandn(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAndN, &dst, &src); } + //! @brief Logical AND Not (SSE2). + inline void pandn(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAndN, &dst, &src); } + + //! @brief Spin Loop Hint (SSE2). + inline void pause() + { _emitInstruction(kX86InstPause); } + + //! @brief Packed Average (SSE2). + inline void pavgb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAvgB, &dst, &src); } + //! @brief Packed Average (SSE2). + inline void pavgb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAvgB, &dst, &src); } + + //! @brief Packed Average (SSE2). + inline void pavgw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAvgW, &dst, &src); } + //! @brief Packed Average (SSE2). + inline void pavgw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAvgW, &dst, &src); } + + //! @brief Packed Compare for Equal (BYTES) (SSE2). + inline void pcmpeqb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPCmpEqB, &dst, &src); } + //! @brief Packed Compare for Equal (BYTES) (SSE2). + inline void pcmpeqb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqB, &dst, &src); } + + //! @brief Packed Compare for Equal (WORDS) (SSE2). + inline void pcmpeqw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPCmpEqW, &dst, &src); } + //! @brief Packed Compare for Equal (WORDS) (SSE2). + inline void pcmpeqw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqW, &dst, &src); } + + //! @brief Packed Compare for Equal (DWORDS) (SSE2). + inline void pcmpeqd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPCmpEqD, &dst, &src); } + //! @brief Packed Compare for Equal (DWORDS) (SSE2). + inline void pcmpeqd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqD, &dst, &src); } + + //! @brief Packed Compare for Greater Than (BYTES) (SSE2). + inline void pcmpgtb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPCmpGtB, &dst, &src); } + //! @brief Packed Compare for Greater Than (BYTES) (SSE2). + inline void pcmpgtb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtB, &dst, &src); } + + //! @brief Packed Compare for Greater Than (WORDS) (SSE2). + inline void pcmpgtw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPCmpGtW, &dst, &src); } + //! @brief Packed Compare for Greater Than (WORDS) (SSE2). + inline void pcmpgtw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtW, &dst, &src); } + + //! @brief Packed Compare for Greater Than (DWORDS) (SSE2). + inline void pcmpgtd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPCmpGtD, &dst, &src); } + //! @brief Packed Compare for Greater Than (DWORDS) (SSE2). + inline void pcmpgtd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtD, &dst, &src); } + + //! @brief Packed Signed Integer Word Maximum (SSE2). + inline void pmaxsw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMaxSW, &dst, &src); } + //! @brief Packed Signed Integer Word Maximum (SSE2). + inline void pmaxsw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxSW, &dst, &src); } + + //! @brief Packed Unsigned Integer Byte Maximum (SSE2). + inline void pmaxub(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMaxUB, &dst, &src); } + //! @brief Packed Unsigned Integer Byte Maximum (SSE2). + inline void pmaxub(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxUB, &dst, &src); } + + //! @brief Packed Signed Integer Word Minimum (SSE2). + inline void pminsw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMinSW, &dst, &src); } + //! @brief Packed Signed Integer Word Minimum (SSE2). + inline void pminsw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMinSW, &dst, &src); } + + //! @brief Packed Unsigned Integer Byte Minimum (SSE2). + inline void pminub(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMinUB, &dst, &src); } + //! @brief Packed Unsigned Integer Byte Minimum (SSE2). + inline void pminub(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMinUB, &dst, &src); } + + //! @brief Move Byte Mask (SSE2). + inline void pmovmskb(const GpReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovMskB, &dst, &src); } + + //! @brief Packed Multiply High (SSE2). + inline void pmulhw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMulHW, &dst, &src); } + //! @brief Packed Multiply High (SSE2). + inline void pmulhw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHW, &dst, &src); } + + //! @brief Packed Multiply High Unsigned (SSE2). + inline void pmulhuw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMulHUW, &dst, &src); } + //! @brief Packed Multiply High Unsigned (SSE2). + inline void pmulhuw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHUW, &dst, &src); } + + //! @brief Packed Multiply Low (SSE2). + inline void pmullw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMulLW, &dst, &src); } + //! @brief Packed Multiply Low (SSE2). + inline void pmullw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulLW, &dst, &src); } + + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMulUDQ, &dst, &src); } + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulUDQ, &dst, &src); } + + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMulUDQ, &dst, &src); } + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulUDQ, &dst, &src); } + + //! @brief Bitwise Logical OR (SSE2). + inline void por(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPOr, &dst, &src); } + //! @brief Bitwise Logical OR (SSE2). + inline void por(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPOr, &dst, &src); } + + //! @brief Packed Shift Left Logical (SSE2). + inline void pslld(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void pslld(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void pslld(const XmmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + + //! @brief Packed Shift Left Logical (SSE2). + inline void psllq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllq(const XmmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + + //! @brief Packed Shift Left Logical (SSE2). + inline void psllw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllw(const XmmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + + //! @brief Packed Shift Left Logical (SSE2). + inline void pslldq(const XmmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSllDQ, &dst, &src); } + + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psrad(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSraD, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psrad(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSraD, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psrad(const XmmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSraD, &dst, &src); } + + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psraw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psraw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psraw(const XmmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + + //! @brief Packed Subtract (SSE2). + inline void psubb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSubB, &dst, &src); } + //! @brief Packed Subtract (SSE2). + inline void psubb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubB, &dst, &src); } + + //! @brief Packed Subtract (SSE2). + inline void psubw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSubW, &dst, &src); } + //! @brief Packed Subtract (SSE2). + inline void psubw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubW, &dst, &src); } + + //! @brief Packed Subtract (SSE2). + inline void psubd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSubD, &dst, &src); } + //! @brief Packed Subtract (SSE2). + inline void psubd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubD, &dst, &src); } + + //! @brief Packed Subtract (SSE2). + inline void psubq(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSubQ, &dst, &src); } + //! @brief Packed Subtract (SSE2). + inline void psubq(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubQ, &dst, &src); } + + //! @brief Packed Subtract (SSE2). + inline void psubq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSubQ, &dst, &src); } + //! @brief Packed Subtract (SSE2). + inline void psubq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubQ, &dst, &src); } + + //! @brief Packed Multiply and Add (SSE2). + inline void pmaddwd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMAddWD, &dst, &src); } + //! @brief Packed Multiply and Add (SSE2). + inline void pmaddwd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMAddWD, &dst, &src); } + + //! @brief Shuffle Packed DWORDs (SSE2). + inline void pshufd(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufD, &dst, &src, &imm8); } + //! @brief Shuffle Packed DWORDs (SSE2). + inline void pshufd(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufD, &dst, &src, &imm8); } + + //! @brief Shuffle Packed High Words (SSE2). + inline void pshufhw(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufHW, &dst, &src, &imm8); } + //! @brief Shuffle Packed High Words (SSE2). + inline void pshufhw(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufHW, &dst, &src, &imm8); } + + //! @brief Shuffle Packed Low Words (SSE2). + inline void pshuflw(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufLW, &dst, &src, &imm8); } + //! @brief Shuffle Packed Low Words (SSE2). + inline void pshuflw(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufLW, &dst, &src, &imm8); } + + //! @brief Packed Shift Right Logical (SSE2). + inline void psrld(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrld(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrld(const XmmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlq(const XmmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + + //! @brief DQWord Shift Right Logical (MMX). + inline void psrldq(const XmmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlDQ, &dst, &src); } + + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlw(const XmmReg& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSubSB, &dst, &src); } + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubSB, &dst, &src); } + + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSubSW, &dst, &src); } + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubSW, &dst, &src); } + + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSubUSB, &dst, &src); } + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubUSB, &dst, &src); } + + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSubUSW, &dst, &src); } + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSubUSW, &dst, &src); } + + //! @brief Unpack High Data (SSE2). + inline void punpckhbw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPunpckHBW, &dst, &src); } + //! @brief Unpack High Data (SSE2). + inline void punpckhbw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHBW, &dst, &src); } + + //! @brief Unpack High Data (SSE2). + inline void punpckhwd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPunpckHWD, &dst, &src); } + //! @brief Unpack High Data (SSE2). + inline void punpckhwd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHWD, &dst, &src); } + + //! @brief Unpack High Data (SSE2). + inline void punpckhdq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPunpckHDQ, &dst, &src); } + //! @brief Unpack High Data (SSE2). + inline void punpckhdq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHDQ, &dst, &src); } + + //! @brief Unpack High Data (SSE2). + inline void punpckhqdq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPunpckHQDQ, &dst, &src); } + //! @brief Unpack High Data (SSE2). + inline void punpckhqdq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHQDQ, &dst, &src); } + + //! @brief Unpack Low Data (SSE2). + inline void punpcklbw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPunpckLBW, &dst, &src); } + //! @brief Unpack Low Data (SSE2). + inline void punpcklbw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLBW, &dst, &src); } + + //! @brief Unpack Low Data (SSE2). + inline void punpcklwd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPunpckLWD, &dst, &src); } + //! @brief Unpack Low Data (SSE2). + inline void punpcklwd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLWD, &dst, &src); } + + //! @brief Unpack Low Data (SSE2). + inline void punpckldq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPunpckLDQ, &dst, &src); } + //! @brief Unpack Low Data (SSE2). + inline void punpckldq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLDQ, &dst, &src); } + + //! @brief Unpack Low Data (SSE2). + inline void punpcklqdq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPunpckLQDQ, &dst, &src); } + //! @brief Unpack Low Data (SSE2). + inline void punpcklqdq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLQDQ, &dst, &src); } + + //! @brief Bitwise Exclusive OR (SSE2). + inline void pxor(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPXor, &dst, &src); } + //! @brief Bitwise Exclusive OR (SSE2). + inline void pxor(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPXor, &dst, &src); } + + //! @brief Shuffle DP-FP (SSE2). + inline void shufpd(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstShufPD, &dst, &src, &imm8); } + //! @brief Shuffle DP-FP (SSE2). + inline void shufpd(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstShufPD, &dst, &src, &imm8); } + + //! @brief Compute Square Roots of Packed DP-FP Values (SSE2). + inline void sqrtpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstSqrtPD, &dst, &src); } + //! @brief Compute Square Roots of Packed DP-FP Values (SSE2). + inline void sqrtpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtPD, &dst, &src); } + + //! @brief Compute Square Root of Scalar DP-FP Value (SSE2). + inline void sqrtsd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstSqrtSD, &dst, &src); } + //! @brief Compute Square Root of Scalar DP-FP Value (SSE2). + inline void sqrtsd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtSD, &dst, &src); } + + //! @brief Packed DP-FP Subtract (SSE2). + inline void subpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstSubPD, &dst, &src); } + //! @brief Packed DP-FP Subtract (SSE2). + inline void subpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstSubPD, &dst, &src); } + + //! @brief Scalar DP-FP Subtract (SSE2). + inline void subsd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstSubSD, &dst, &src); } + //! @brief Scalar DP-FP Subtract (SSE2). + inline void subsd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstSubSD, &dst, &src); } + + //! @brief Scalar Unordered DP-FP Compare and Set EFLAGS (SSE2). + inline void ucomisd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstUComISD, &dst, &src); } + //! @brief Scalar Unordered DP-FP Compare and Set EFLAGS (SSE2). + inline void ucomisd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstUComISD, &dst, &src); } + + //! @brief Unpack and Interleave High Packed Double-Precision FP Values (SSE2). + inline void unpckhpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstUnpckHPD, &dst, &src); } + //! @brief Unpack and Interleave High Packed Double-Precision FP Values (SSE2). + inline void unpckhpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstUnpckHPD, &dst, &src); } + + //! @brief Unpack and Interleave Low Packed Double-Precision FP Values (SSE2). + inline void unpcklpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstUnpckLPD, &dst, &src); } + //! @brief Unpack and Interleave Low Packed Double-Precision FP Values (SSE2). + inline void unpcklpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstUnpckLPD, &dst, &src); } + + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void xorpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstXorPD, &dst, &src); } + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void xorpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstXorPD, &dst, &src); } + + // -------------------------------------------------------------------------- + // [SSE3] + // -------------------------------------------------------------------------- + + //! @brief Packed DP-FP Add/Subtract (SSE3). + inline void addsubpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstAddSubPD, &dst, &src); } + //! @brief Packed DP-FP Add/Subtract (SSE3). + inline void addsubpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstAddSubPD, &dst, &src); } + + //! @brief Packed SP-FP Add/Subtract (SSE3). + inline void addsubps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstAddSubPS, &dst, &src); } + //! @brief Packed SP-FP Add/Subtract (SSE3). + inline void addsubps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstAddSubPS, &dst, &src); } + + //! @brief Store Integer with Truncation (SSE3). + inline void fisttp(const Mem& dst) + { _emitInstruction(kX86InstFISttP, &dst); } + + //! @brief Packed DP-FP Horizontal Add (SSE3). + inline void haddpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstHAddPD, &dst, &src); } + //! @brief Packed DP-FP Horizontal Add (SSE3). + inline void haddpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstHAddPD, &dst, &src); } + + //! @brief Packed SP-FP Horizontal Add (SSE3). + inline void haddps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstHAddPS, &dst, &src); } + //! @brief Packed SP-FP Horizontal Add (SSE3). + inline void haddps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstHAddPS, &dst, &src); } + + //! @brief Packed DP-FP Horizontal Subtract (SSE3). + inline void hsubpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstHSubPD, &dst, &src); } + //! @brief Packed DP-FP Horizontal Subtract (SSE3). + inline void hsubpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstHSubPD, &dst, &src); } + + //! @brief Packed SP-FP Horizontal Subtract (SSE3). + inline void hsubps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstHSubPS, &dst, &src); } + //! @brief Packed SP-FP Horizontal Subtract (SSE3). + inline void hsubps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstHSubPS, &dst, &src); } + + //! @brief Load Unaligned Integer 128 Bits (SSE3). + inline void lddqu(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstLdDQU, &dst, &src); } + + //! @brief Set Up Monitor Address (SSE3). + inline void monitor() + { _emitInstruction(kX86InstMonitor); } + + //! @brief Move One DP-FP and Duplicate (SSE3). + inline void movddup(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovDDup, &dst, &src); } + //! @brief Move One DP-FP and Duplicate (SSE3). + inline void movddup(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovDDup, &dst, &src); } + + //! @brief Move Packed SP-FP High and Duplicate (SSE3). + inline void movshdup(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovSHDup, &dst, &src); } + //! @brief Move Packed SP-FP High and Duplicate (SSE3). + inline void movshdup(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovSHDup, &dst, &src); } + + //! @brief Move Packed SP-FP Low and Duplicate (SSE3). + inline void movsldup(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstMovSLDup, &dst, &src); } + //! @brief Move Packed SP-FP Low and Duplicate (SSE3). + inline void movsldup(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovSLDup, &dst, &src); } + + //! @brief Monitor Wait (SSE3). + inline void mwait() + { _emitInstruction(kX86InstMWait); } + + // -------------------------------------------------------------------------- + // [SSSE3] + // -------------------------------------------------------------------------- + + //! @brief Packed SIGN (SSSE3). + inline void psignb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSignB, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSignB, &dst, &src); } + + //! @brief Packed SIGN (SSSE3). + inline void psignb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSignB, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSignB, &dst, &src); } + + //! @brief Packed SIGN (SSSE3). + inline void psignw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSignW, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSignW, &dst, &src); } + + //! @brief Packed SIGN (SSSE3). + inline void psignw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSignW, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSignW, &dst, &src); } + + //! @brief Packed SIGN (SSSE3). + inline void psignd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPSignD, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSignD, &dst, &src); } + + //! @brief Packed SIGN (SSSE3). + inline void psignd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPSignD, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPSignD, &dst, &src); } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPHAddW, &dst, &src); } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddW, &dst, &src); } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPHAddW, &dst, &src); } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddW, &dst, &src); } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPHAddD, &dst, &src); } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddD, &dst, &src); } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPHAddD, &dst, &src); } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddD, &dst, &src); } + + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPHAddSW, &dst, &src); } + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddSW, &dst, &src); } + + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPHAddSW, &dst, &src); } + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddSW, &dst, &src); } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPHSubW, &dst, &src); } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubW, &dst, &src); } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPHSubW, &dst, &src); } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubW, &dst, &src); } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPHSubD, &dst, &src); } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubD, &dst, &src); } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPHSubD, &dst, &src); } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubD, &dst, &src); } + + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPHSubSW, &dst, &src); } + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubSW, &dst, &src); } + + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPHSubSW, &dst, &src); } + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubSW, &dst, &src); } + + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMAddUBSW, &dst, &src); } + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMAddUBSW, &dst, &src); } + + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMAddUBSW, &dst, &src); } + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMAddUBSW, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAbsB, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsB, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAbsB, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsB, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAbsW, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsW, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAbsW, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsW, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPAbsD, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsD, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPAbsD, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsD, &dst, &src); } + + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPMulHRSW, &dst, &src); } + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHRSW, &dst, &src); } + + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMulHRSW, &dst, &src); } + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHRSW, &dst, &src); } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const MmReg& dst, const MmReg& src) + { _emitInstruction(kX86InstPShufB, &dst, &src); } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const MmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPShufB, &dst, &src); } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPShufB, &dst, &src); } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPShufB, &dst, &src); } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const MmReg& dst, const MmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPAlignR, &dst, &src, &imm8); } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const MmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPAlignR, &dst, &src, &imm8); } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPAlignR, &dst, &src, &imm8); } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPAlignR, &dst, &src, &imm8); } + + // -------------------------------------------------------------------------- + // [SSE4.1] + // -------------------------------------------------------------------------- + + //! @brief Blend Packed DP-FP Values (SSE4.1). + inline void blendpd(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstBlendPD, &dst, &src, &imm8); } + //! @brief Blend Packed DP-FP Values (SSE4.1). + inline void blendpd(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstBlendPD, &dst, &src, &imm8); } + + //! @brief Blend Packed SP-FP Values (SSE4.1). + inline void blendps(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstBlendPS, &dst, &src, &imm8); } + //! @brief Blend Packed SP-FP Values (SSE4.1). + inline void blendps(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstBlendPS, &dst, &src, &imm8); } + + //! @brief Variable Blend Packed DP-FP Values (SSE4.1). + inline void blendvpd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstBlendVPD, &dst, &src); } + //! @brief Variable Blend Packed DP-FP Values (SSE4.1). + inline void blendvpd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstBlendVPD, &dst, &src); } + + //! @brief Variable Blend Packed SP-FP Values (SSE4.1). + inline void blendvps(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstBlendVPS, &dst, &src); } + //! @brief Variable Blend Packed SP-FP Values (SSE4.1). + inline void blendvps(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstBlendVPS, &dst, &src); } + + //! @brief Dot Product of Packed DP-FP Values (SSE4.1). + inline void dppd(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstDpPD, &dst, &src, &imm8); } + //! @brief Dot Product of Packed DP-FP Values (SSE4.1). + inline void dppd(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstDpPD, &dst, &src, &imm8); } + + //! @brief Dot Product of Packed SP-FP Values (SSE4.1). + inline void dpps(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstDpPS, &dst, &src, &imm8); } + //! @brief Dot Product of Packed SP-FP Values (SSE4.1). + inline void dpps(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstDpPS, &dst, &src, &imm8); } + + //! @brief Extract Packed SP-FP Value (SSE4.1). + inline void extractps(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstExtractPS, &dst, &src, &imm8); } + //! @brief Extract Packed SP-FP Value (SSE4.1). + inline void extractps(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstExtractPS, &dst, &src, &imm8); } + + //! @brief Load Double Quadword Non-Temporal Aligned Hint (SSE4.1). + inline void movntdqa(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstMovNTDQA, &dst, &src); } + + //! @brief Compute Multiple Packed Sums of Absolute Difference (SSE4.1). + inline void mpsadbw(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstMPSADBW, &dst, &src, &imm8); } + //! @brief Compute Multiple Packed Sums of Absolute Difference (SSE4.1). + inline void mpsadbw(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstMPSADBW, &dst, &src, &imm8); } + + //! @brief Pack with Unsigned Saturation (SSE4.1). + inline void packusdw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPackUSDW, &dst, &src); } + //! @brief Pack with Unsigned Saturation (SSE4.1). + inline void packusdw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPackUSDW, &dst, &src); } + + //! @brief Variable Blend Packed Bytes (SSE4.1). + inline void pblendvb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPBlendVB, &dst, &src); } + //! @brief Variable Blend Packed Bytes (SSE4.1). + inline void pblendvb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPBlendVB, &dst, &src); } + + //! @brief Blend Packed Words (SSE4.1). + inline void pblendw(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPBlendW, &dst, &src, &imm8); } + //! @brief Blend Packed Words (SSE4.1). + inline void pblendw(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPBlendW, &dst, &src, &imm8); } + + //! @brief Compare Packed Qword Data for Equal (SSE4.1). + inline void pcmpeqq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPCmpEqQ, &dst, &src); } + //! @brief Compare Packed Qword Data for Equal (SSE4.1). + inline void pcmpeqq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqQ, &dst, &src); } + + //! @brief Extract Byte (SSE4.1). + inline void pextrb(const GpReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrB, &dst, &src, &imm8); } + //! @brief Extract Byte (SSE4.1). + inline void pextrb(const Mem& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrB, &dst, &src, &imm8); } + + //! @brief Extract Dword (SSE4.1). + inline void pextrd(const GpReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrD, &dst, &src, &imm8); } + //! @brief Extract Dword (SSE4.1). + inline void pextrd(const Mem& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrD, &dst, &src, &imm8); } + + //! @brief Extract Dword (SSE4.1). + inline void pextrq(const GpReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrQ, &dst, &src, &imm8); } + //! @brief Extract Dword (SSE4.1). + inline void pextrq(const Mem& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrQ, &dst, &src, &imm8); } + + //! @brief Extract Word (SSE4.1). + inline void pextrw(const GpReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrW, &dst, &src, &imm8); } + //! @brief Extract Word (SSE4.1). + inline void pextrw(const Mem& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrW, &dst, &src, &imm8); } + + //! @brief Packed Horizontal Word Minimum (SSE4.1). + inline void phminposuw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPHMinPOSUW, &dst, &src); } + //! @brief Packed Horizontal Word Minimum (SSE4.1). + inline void phminposuw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPHMinPOSUW, &dst, &src); } + + //! @brief Insert Byte (SSE4.1). + inline void pinsrb(const XmmReg& dst, const GpReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRB, &dst, &src, &imm8); } + //! @brief Insert Byte (SSE4.1). + inline void pinsrb(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRB, &dst, &src, &imm8); } + + //! @brief Insert Dword (SSE4.1). + inline void pinsrd(const XmmReg& dst, const GpReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRD, &dst, &src, &imm8); } + //! @brief Insert Dword (SSE4.1). + inline void pinsrd(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRD, &dst, &src, &imm8); } + + //! @brief Insert Dword (SSE4.1). + inline void pinsrq(const XmmReg& dst, const GpReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRQ, &dst, &src, &imm8); } + //! @brief Insert Dword (SSE4.1). + inline void pinsrq(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRQ, &dst, &src, &imm8); } + + //! @brief Insert Word (SSE2). + inline void pinsrw(const XmmReg& dst, const GpReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRW, &dst, &src, &imm8); } + //! @brief Insert Word (SSE2). + inline void pinsrw(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRW, &dst, &src, &imm8); } + + //! @brief Maximum of Packed Word Integers (SSE4.1). + inline void pmaxuw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMaxUW, &dst, &src); } + //! @brief Maximum of Packed Word Integers (SSE4.1). + inline void pmaxuw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxUW, &dst, &src); } + + //! @brief Maximum of Packed Signed Byte Integers (SSE4.1). + inline void pmaxsb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMaxSB, &dst, &src); } + //! @brief Maximum of Packed Signed Byte Integers (SSE4.1). + inline void pmaxsb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxSB, &dst, &src); } + + //! @brief Maximum of Packed Signed Dword Integers (SSE4.1). + inline void pmaxsd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMaxSD, &dst, &src); } + //! @brief Maximum of Packed Signed Dword Integers (SSE4.1). + inline void pmaxsd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxSD, &dst, &src); } + + //! @brief Maximum of Packed Unsigned Dword Integers (SSE4.1). + inline void pmaxud(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMaxUD, &dst, &src); } + //! @brief Maximum of Packed Unsigned Dword Integers (SSE4.1). + inline void pmaxud(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxUD, &dst, &src); } + + //! @brief Minimum of Packed Signed Byte Integers (SSE4.1). + inline void pminsb(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMinSB, &dst, &src); } + //! @brief Minimum of Packed Signed Byte Integers (SSE4.1). + inline void pminsb(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMinSB, &dst, &src); } + + //! @brief Minimum of Packed Word Integers (SSE4.1). + inline void pminuw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMinUW, &dst, &src); } + //! @brief Minimum of Packed Word Integers (SSE4.1). + inline void pminuw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMinUW, &dst, &src); } + + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminud(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMinUD, &dst, &src); } + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminud(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMinUD, &dst, &src); } + + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminsd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMinSD, &dst, &src); } + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminsd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMinSD, &dst, &src); } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovSXBW, &dst, &src); } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXBW, &dst, &src); } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovSXBD, &dst, &src); } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXBD, &dst, &src); } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovSXBQ, &dst, &src); } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXBQ, &dst, &src); } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxwd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovSXWD, &dst, &src); } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxwd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXWD, &dst, &src); } + + //! @brief (SSE4.1). + inline void pmovsxwq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovSXWQ, &dst, &src); } + //! @brief (SSE4.1). + inline void pmovsxwq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXWQ, &dst, &src); } + + //! @brief (SSE4.1). + inline void pmovsxdq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovSXDQ, &dst, &src); } + //! @brief (SSE4.1). + inline void pmovsxdq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXDQ, &dst, &src); } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbw(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovZXBW, &dst, &src); } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbw(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXBW, &dst, &src); } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovZXBD, &dst, &src); } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXBD, &dst, &src); } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovZXBQ, &dst, &src); } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXBQ, &dst, &src); } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxwd(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovZXWD, &dst, &src); } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxwd(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXWD, &dst, &src); } + + //! @brief (SSE4.1). + inline void pmovzxwq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovZXWQ, &dst, &src); } + //! @brief (SSE4.1). + inline void pmovzxwq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXWQ, &dst, &src); } + + //! @brief (SSE4.1). + inline void pmovzxdq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMovZXDQ, &dst, &src); } + //! @brief (SSE4.1). + inline void pmovzxdq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXDQ, &dst, &src); } + + //! @brief Multiply Packed Signed Dword Integers (SSE4.1). + inline void pmuldq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMulDQ, &dst, &src); } + //! @brief Multiply Packed Signed Dword Integers (SSE4.1). + inline void pmuldq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulDQ, &dst, &src); } + + //! @brief Multiply Packed Signed Integers and Store Low Result (SSE4.1). + inline void pmulld(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPMulLD, &dst, &src); } + //! @brief Multiply Packed Signed Integers and Store Low Result (SSE4.1). + inline void pmulld(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPMulLD, &dst, &src); } + + //! @brief Logical Compare (SSE4.1). + inline void ptest(const XmmReg& op1, const XmmReg& op2) + { _emitInstruction(kX86InstPTest, &op1, &op2); } + //! @brief Logical Compare (SSE4.1). + inline void ptest(const XmmReg& op1, const Mem& op2) + { _emitInstruction(kX86InstPTest, &op1, &op2); } + + //! Round Packed SP-FP Values @brief (SSE4.1). + inline void roundps(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundPS, &dst, &src, &imm8); } + //! Round Packed SP-FP Values @brief (SSE4.1). + inline void roundps(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundPS, &dst, &src, &imm8); } + + //! @brief Round Scalar SP-FP Values (SSE4.1). + inline void roundss(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundSS, &dst, &src, &imm8); } + //! @brief Round Scalar SP-FP Values (SSE4.1). + inline void roundss(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundSS, &dst, &src, &imm8); } + + //! @brief Round Packed DP-FP Values (SSE4.1). + inline void roundpd(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundPD, &dst, &src, &imm8); } + //! @brief Round Packed DP-FP Values (SSE4.1). + inline void roundpd(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundPD, &dst, &src, &imm8); } + + //! @brief Round Scalar DP-FP Values (SSE4.1). + inline void roundsd(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundSD, &dst, &src, &imm8); } + //! @brief Round Scalar DP-FP Values (SSE4.1). + inline void roundsd(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundSD, &dst, &src, &imm8); } + + // -------------------------------------------------------------------------- + // [SSE4.2] + // -------------------------------------------------------------------------- + + //! @brief Accumulate CRC32 Value (polynomial 0x11EDC6F41) (SSE4.2). + inline void crc32(const GpReg& dst, const GpReg& src) + { + ASMJIT_ASSERT(dst.isRegType(kX86RegTypeGpd) || dst.isRegType(kX86RegTypeGpq)); + _emitInstruction(kX86InstCrc32, &dst, &src); + } + //! @brief Accumulate CRC32 Value (polynomial 0x11EDC6F41) (SSE4.2). + inline void crc32(const GpReg& dst, const Mem& src) + { + ASMJIT_ASSERT(dst.isRegType(kX86RegTypeGpd) || dst.isRegType(kX86RegTypeGpq)); + _emitInstruction(kX86InstCrc32, &dst, &src); + } + + //! @brief Packed Compare Explicit Length Strings, Return Index (SSE4.2). + inline void pcmpestri(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpEStrI, &dst, &src, &imm8); } + //! @brief Packed Compare Explicit Length Strings, Return Index (SSE4.2). + inline void pcmpestri(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpEStrI, &dst, &src, &imm8); } + + //! @brief Packed Compare Explicit Length Strings, Return Mask (SSE4.2). + inline void pcmpestrm(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpEStrM, &dst, &src, &imm8); } + //! @brief Packed Compare Explicit Length Strings, Return Mask (SSE4.2). + inline void pcmpestrm(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpEStrM, &dst, &src, &imm8); } + + //! @brief Packed Compare Implicit Length Strings, Return Index (SSE4.2). + inline void pcmpistri(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpIStrI, &dst, &src, &imm8); } + //! @brief Packed Compare Implicit Length Strings, Return Index (SSE4.2). + inline void pcmpistri(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpIStrI, &dst, &src, &imm8); } + + //! @brief Packed Compare Implicit Length Strings, Return Mask (SSE4.2). + inline void pcmpistrm(const XmmReg& dst, const XmmReg& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpIStrM, &dst, &src, &imm8); } + //! @brief Packed Compare Implicit Length Strings, Return Mask (SSE4.2). + inline void pcmpistrm(const XmmReg& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpIStrM, &dst, &src, &imm8); } + + //! @brief Compare Packed Data for Greater Than (SSE4.2). + inline void pcmpgtq(const XmmReg& dst, const XmmReg& src) + { _emitInstruction(kX86InstPCmpGtQ, &dst, &src); } + //! @brief Compare Packed Data for Greater Than (SSE4.2). + inline void pcmpgtq(const XmmReg& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtQ, &dst, &src); } + + //! @brief Return the Count of Number of Bits Set to 1 (SSE4.2). + inline void popcnt(const GpReg& dst, const GpReg& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + ASMJIT_ASSERT(src.getRegType() == dst.getRegType()); + _emitInstruction(kX86InstPopCnt, &dst, &src); + } + //! @brief Return the Count of Number of Bits Set to 1 (SSE4.2). + inline void popcnt(const GpReg& dst, const Mem& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + _emitInstruction(kX86InstPopCnt, &dst, &src); + } + + // ------------------------------------------------------------------------- + // [AMD only] + // ------------------------------------------------------------------------- + + //! @brief Prefetch (3dNow - Amd). + //! + //! Loads the entire 64-byte aligned memory sequence containing the + //! specified memory address into the L1 data cache. The position of + //! the specified memory address within the 64-byte cache line is + //! irrelevant. If a cache hit occurs, or if a memory fault is detected, + //! no bus cycle is initiated and the instruction is treated as a NOP. + inline void amd_prefetch(const Mem& mem) + { _emitInstruction(kX86InstAmdPrefetch, &mem); } + + //! @brief Prefetch and set cache to modified (3dNow - Amd). + //! + //! The PREFETCHW instruction loads the prefetched line and sets the + //! cache-line state to Modified, in anticipation of subsequent data + //! writes to the line. The PREFETCH instruction, by contrast, typically + //! sets the cache-line state to Exclusive (depending on the hardware + //! implementation). + inline void amd_prefetchw(const Mem& mem) + { _emitInstruction(kX86InstAmdPrefetchW, &mem); } + + // ------------------------------------------------------------------------- + // [Intel only] + // ------------------------------------------------------------------------- + + //! @brief Move Data After Swapping Bytes (SSE3 - Intel Atom). + inline void movbe(const GpReg& dst, const Mem& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + _emitInstruction(kX86InstMovBE, &dst, &src); + } + + //! @brief Move Data After Swapping Bytes (SSE3 - Intel Atom). + inline void movbe(const Mem& dst, const GpReg& src) + { + ASMJIT_ASSERT(!src.isGpb()); + _emitInstruction(kX86InstMovBE, &dst, &src); + } + + // ------------------------------------------------------------------------- + // [Emit Options] + // ------------------------------------------------------------------------- + + //! @brief Assert LOCK# Signal Prefix. + //! + //! This instruction causes the processor's LOCK# signal to be asserted + //! during execution of the accompanying instruction (turns the + //! instruction into an atomic instruction). In a multiprocessor environment, + //! the LOCK# signal insures that the processor has exclusive use of any shared + //! memory while the signal is asserted. + //! + //! The LOCK prefix can be prepended only to the following instructions and + //! to those forms of the instructions that use a memory operand: ADD, ADC, + //! AND, BTC, BTR, BTS, CMPXCHG, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, + //! and XCHG. An undefined opcode exception will be generated if the LOCK + //! prefix is used with any other instruction. The XCHG instruction always + //! asserts the LOCK# signal regardless of the presence or absence of the LOCK + //! prefix. + //! + //! @sa @c kX86EmitOptionLock. + inline void lock() + { _emitOptions |= kX86EmitOptionLock; } + + //! @brief Force REX prefix to be emitted. + //! + //! This option should be used carefully, because there are unencodable + //! combinations. If you want to access ah, bh, ch or dh registers then you + //! can't emit REX prefix and it will cause an illegal instruction error. + //! + //! @note REX prefix is only valid for X64/AMD64 platform. + //! + //! @sa @c kX86EmitOptionRex. + inline void rex() + { _emitOptions |= kX86EmitOptionRex; } +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_X86_X86ASSEMBLER_H diff --git a/desmume/src/utils/AsmJit/x86/x86compiler.cpp b/desmume/src/utils/AsmJit/x86/x86compiler.cpp new file mode 100644 index 000000000..6d9aee374 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86compiler.cpp @@ -0,0 +1,877 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/intutil.h" +#include "../core/stringutil.h" + +#include "../x86/x86assembler.h" +#include "../x86/x86compiler.h" +#include "../x86/x86compilercontext.h" +#include "../x86/x86compilerfunc.h" +#include "../x86/x86compileritem.h" +#include "../x86/x86util.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::CompilerUtil] +// ============================================================================ + +bool CompilerUtil::isStack16ByteAligned() +{ + // Stack is always aligned to 16-bytes when using 64-bit OS. + bool result = (sizeof(uintptr_t) == 8); + + // Modern Linux, APPLE and UNIX guarantees stack alignment to 16 bytes by + // default. I'm really not sure about all UNIX operating systems, because + // 16-byte alignment is an addition to an older specification. +#if (defined(__linux__) || \ + defined(__linux) || \ + defined(linux) || \ + defined(__unix__) || \ + defined(__FreeBSD__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) || \ + defined(__DARWIN__) || \ + defined(__APPLE__) ) + result = true; +#endif // __linux__ + + return result; +} + +// ============================================================================ +// [AsmJit::X86Compiler - Construction / Destruction] +// ============================================================================ + +X86Compiler::X86Compiler(Context* context) : + Compiler(context) +{ + _properties |= IntUtil::maskFromIndex(kX86PropertyOptimizedAlign); +} + +X86Compiler::~X86Compiler() +{ +} + +// ============================================================================ +// [AsmJit::Compiler - Function Builder] +// ============================================================================ + +X86CompilerFuncDecl* X86Compiler::newFunc_(uint32_t convention, uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount) +{ + ASMJIT_ASSERT(_func == NULL); + + X86CompilerFuncDecl* func = Compiler_newItem(this); + + _func = func; + _varNameId = 0; + + func->setPrototype(convention, returnType, arguments, argumentsCount); + addItem(func); + + bind(func->_entryLabel); + func->_createVariables(); + + return func; +} + +X86CompilerFuncDecl* X86Compiler::endFunc() +{ + X86CompilerFuncDecl* func = getFunc(); + ASMJIT_ASSERT(func != NULL); + + bind(func->_exitLabel); + addItem(func->_end); + + func->setFuncFlag(kFuncFlagIsFinished); + _func = NULL; + + return func; +} + +// ============================================================================ +// [AsmJit::Compiler - EmitInstruction] +// ============================================================================ + +static inline X86CompilerInst* X86Compiler_newInstruction(X86Compiler* self, uint32_t code, Operand* opData, uint32_t opCount) +{ + if (code >= _kX86InstJBegin && code <= _kX86InstJEnd) + { + void* p = self->_zoneMemory.alloc(sizeof(X86CompilerJmpInst)); + return new(p) X86CompilerJmpInst(self, code, opData, opCount); + } + else + { + void* p = self->_zoneMemory.alloc(sizeof(X86CompilerInst) + opCount * sizeof(Operand)); + return new(p) X86CompilerInst(self, code, opData, opCount); + } +} + +void X86Compiler::_emitInstruction(uint32_t code) +{ + X86CompilerInst* inst = X86Compiler_newInstruction(this, code, NULL, 0); + + if (inst == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + addItem(inst); + + if (_cc != NULL) + { + inst->_offset = _cc->_currentOffset; + inst->prepare(*_cc); + } +} + +void X86Compiler::_emitInstruction(uint32_t code, const Operand* o0) +{ + Operand* operands = reinterpret_cast(_zoneMemory.alloc(1 * sizeof(Operand))); + + if (operands == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + operands[0] = *o0; + X86CompilerInst* inst = X86Compiler_newInstruction(this, code, operands, 1); + + if (inst == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + addItem(inst); + + if (_cc != NULL) + { + inst->_offset = _cc->_currentOffset; + inst->prepare(*_cc); + } +} + +void X86Compiler::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1) +{ + Operand* operands = reinterpret_cast(_zoneMemory.alloc(2 * sizeof(Operand))); + + if (operands == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + operands[0] = *o0; + operands[1] = *o1; + X86CompilerInst* inst = X86Compiler_newInstruction(this, code, operands, 2); + + if (inst == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + addItem(inst); + + if (_cc) + { + inst->_offset = _cc->_currentOffset; + inst->prepare(*_cc); + } +} + +void X86Compiler::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2) +{ + Operand* operands = reinterpret_cast(_zoneMemory.alloc(3 * sizeof(Operand))); + + if (operands == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + operands[0] = *o0; + operands[1] = *o1; + operands[2] = *o2; + X86CompilerInst* inst = X86Compiler_newInstruction(this, code, operands, 3); + + if (inst == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + addItem(inst); + + if (_cc != NULL) + { + inst->_offset = _cc->_currentOffset; + inst->prepare(*_cc); + } +} + +void X86Compiler::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3) +{ + Operand* operands = reinterpret_cast(_zoneMemory.alloc(4 * sizeof(Operand))); + + if (operands == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + operands[0] = *o0; + operands[1] = *o1; + operands[2] = *o2; + operands[3] = *o3; + X86CompilerInst* inst = X86Compiler_newInstruction(this, code, operands, 4); + + if (inst == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + addItem(inst); + + if (_cc != NULL) + { + inst->_offset = _cc->_currentOffset; + inst->prepare(*_cc); + } +} + +void X86Compiler::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3, const Operand* o4) +{ + Operand* operands = reinterpret_cast(_zoneMemory.alloc(5 * sizeof(Operand))); + + if (operands == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + operands[0] = *o0; + operands[1] = *o1; + operands[2] = *o2; + operands[3] = *o3; + operands[4] = *o4; + X86CompilerInst* inst = X86Compiler_newInstruction(this, code, operands, 5); + + if (inst == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + addItem(inst); + + if (_cc != NULL) + { + inst->_offset = _cc->_currentOffset; + inst->prepare(*_cc); + } +} + +void X86Compiler::_emitJcc(uint32_t code, const Label* label, uint32_t hint) +{ + if (hint == kCondHintNone) + { + _emitInstruction(code, label); + } + else + { + Imm imm(hint); + _emitInstruction(code, label, &imm); + } +} + +X86CompilerFuncCall* X86Compiler::_emitCall(const Operand* o0) +{ + X86CompilerFuncDecl* func = getFunc(); + + if (func == NULL) + { + setError(kErrorNoFunction); + return NULL; + } + + X86CompilerFuncCall* call = Compiler_newItem(this, func, o0); + if (call == NULL) + { + setError(kErrorNoHeapMemory); + return NULL; + } + + addItem(call); + return call; +} + +void X86Compiler::_emitReturn(const Operand* first, const Operand* second) +{ + X86CompilerFuncDecl* func = getFunc(); + + if (func == NULL) + { + setError(kErrorNoFunction); + return; + } + + X86CompilerFuncRet* ret = Compiler_newItem(this, func, first, second); + + if (ret == NULL) + { + setError(kErrorNoHeapMemory); + return; + } + + addItem(ret); +} + +// ============================================================================ +// [AsmJit::Compiler - Align] +// ============================================================================ + +void X86Compiler::align(uint32_t m) +{ + addItem(Compiler_newItem(this, m)); +} + +// ============================================================================ +// [AsmJit::Compiler - Label] +// ============================================================================ + +Label X86Compiler::newLabel() +{ + Label label; + label._base.id = static_cast(_targets.getLength()) | kOperandIdTypeLabel; + + CompilerTarget* target = Compiler_newItem(this, label); + _targets.append(target); + + return label; +} + +void X86Compiler::bind(const Label& label) +{ + uint32_t id = label.getId() & kOperandIdValueMask; + + ASMJIT_ASSERT(id != kInvalidValue); + ASMJIT_ASSERT(id < _targets.getLength()); + + addItem(_targets[id]); +} + +// ============================================================================ +// [AsmJit::Compiler - Variables] +// ============================================================================ + +X86CompilerVar* X86Compiler::_newVar(const char* name, uint32_t type, uint32_t size) +{ + X86CompilerVar* var = reinterpret_cast(_zoneMemory.alloc(sizeof(X86CompilerVar))); + if (var == NULL) return NULL; + + char nameBuffer[32]; + if (name == NULL) + { + sprintf(nameBuffer, "var_%d", _varNameId); + name = nameBuffer; + _varNameId++; + } + + var->_name = _zoneMemory.sdup(name); + var->_id = static_cast(_vars.getLength()) | kOperandIdTypeVar; + + var->_type = static_cast(type); + var->_class = x86VarInfo[type].getClass(); + var->_priority = 10; + + var->_isRegArgument = false; + var->_isMemArgument = false; + var->_isCalculated = false; + var->_unused = 0; + + var->_size = size; + + var->firstItem = NULL; + var->lastItem = NULL; + var->funcScope = getFunc(); + var->funcCall = NULL; + + var->homeRegisterIndex = kRegIndexInvalid; + var->prefRegisterMask = 0; + + var->homeMemoryOffset = 0; + var->homeMemoryData = NULL; + + var->regIndex = kRegIndexInvalid; + var->workOffset = kInvalidValue; + + var->nextActive = NULL; + var->prevActive = NULL; + + var->state = kVarStateUnused; + var->changed = false; + var->saveOnUnuse = false; + + var->regReadCount = 0; + var->regWriteCount = 0; + var->regRwCount = 0; + + var->regGpbLoCount = 0; + var->regGpbHiCount = 0; + + var->memReadCount = 0; + var->memWriteCount = 0; + var->memRwCount = 0; + + var->tPtr = NULL; + + _vars.append(var); + return var; +} + +GpVar X86Compiler::newGpVar(uint32_t varType, const char* name) +{ + ASMJIT_ASSERT((varType < kX86VarTypeCount) && (x86VarInfo[varType].getClass() & kX86VarClassGp) != 0); + +#if defined(ASMJIT_X86) + if (x86VarInfo[varType].getSize() > 4) + { + varType = kX86VarTypeGpd; + if (_logger) + _logger->logString("*** COMPILER WARNING: QWORD variable translated to DWORD, FIX YOUR CODE! ***\n"); + } +#endif // ASMJIT_X86 + + X86CompilerVar* var = _newVar(name, varType, x86VarInfo[varType].getSize()); + return var->asGpVar(); +} + +GpVar X86Compiler::getGpArg(uint32_t argIndex) +{ + X86CompilerFuncDecl* func = getFunc(); + GpVar var; + + if (func != NULL) + { + X86FuncDecl* decl = func->getDecl(); + + if (argIndex < decl->getArgumentsCount()) + { + X86CompilerVar* cv = func->getVar(argIndex); + + var._var.id = cv->getId(); + var._var.size = cv->getSize(); + var._var.regCode = x86VarInfo[cv->getType()].getCode(); + var._var.varType = cv->getType(); + } + } + + return var; +} + +MmVar X86Compiler::newMmVar(uint32_t varType, const char* name) +{ + ASMJIT_ASSERT((varType < kX86VarTypeCount) && (x86VarInfo[varType].getClass() & kX86VarClassMm) != 0); + + X86CompilerVar* var = _newVar(name, varType, 8); + return var->asMmVar(); +} + +MmVar X86Compiler::getMmArg(uint32_t argIndex) +{ + X86CompilerFuncDecl* func = getFunc(); + MmVar var; + + if (func != NULL) + { + const X86FuncDecl* decl = func->getDecl(); + + if (argIndex < decl->getArgumentsCount()) + { + X86CompilerVar* cv = func->getVar(argIndex); + + var._var.id = cv->getId(); + var._var.size = cv->getSize(); + var._var.regCode = x86VarInfo[cv->getType()].getCode(); + var._var.varType = cv->getType(); + } + } + + return var; +} + +XmmVar X86Compiler::newXmmVar(uint32_t varType, const char* name) +{ + ASMJIT_ASSERT((varType < kX86VarTypeCount) && (x86VarInfo[varType].getClass() & kX86VarClassXmm) != 0); + + X86CompilerVar* var = _newVar(name, varType, 16); + return var->asXmmVar(); +} + +XmmVar X86Compiler::getXmmArg(uint32_t argIndex) +{ + X86CompilerFuncDecl* func = getFunc(); + XmmVar var; + + if (func != NULL) + { + const X86FuncDecl* decl = func->getDecl(); + + if (argIndex < decl->getArgumentsCount()) + { + X86CompilerVar* cv = func->getVar(argIndex); + + var._var.id = cv->getId(); + var._var.size = cv->getSize(); + var._var.regCode = x86VarInfo[cv->getType()].getCode(); + var._var.varType = cv->getType(); + } + } + + return var; +} + +void X86Compiler::_vhint(Var& var, uint32_t hintId, uint32_t hintValue) +{ + if (var.getId() == kInvalidValue) + return; + + X86CompilerVar* cv = _getVar(var.getId()); + ASMJIT_ASSERT(cv != NULL); + + X86CompilerHint* item = Compiler_newItem(this, cv, hintId, hintValue); + addItem(item); +} + +void X86Compiler::alloc(Var& var) +{ + _vhint(var, kVarHintAlloc, kInvalidValue); +} + +void X86Compiler::alloc(Var& var, uint32_t regIndex) +{ + if (regIndex > 31) + return; + + _vhint(var, kVarHintAlloc, IntUtil::maskFromIndex(regIndex)); +} + +void X86Compiler::alloc(Var& var, const Reg& reg) +{ + _vhint(var, kVarHintAlloc, IntUtil::maskFromIndex(reg.getRegIndex())); +} + +void X86Compiler::save(Var& var) +{ + _vhint(var, kVarHintSave, kInvalidValue); +} + +void X86Compiler::spill(Var& var) +{ + _vhint(var, kVarHintSpill, kInvalidValue); +} + +void X86Compiler::unuse(Var& var) +{ + _vhint(var, kVarHintUnuse, kInvalidValue); +} + +uint32_t X86Compiler::getPriority(Var& var) const +{ + if (var.getId() == kInvalidValue) + return kInvalidValue; + + X86CompilerVar* vdata = _getVar(var.getId()); + ASMJIT_ASSERT(vdata != NULL); + + return vdata->getPriority(); +} + +void X86Compiler::setPriority(Var& var, uint32_t priority) +{ + if (var.getId() == kInvalidValue) + return; + + X86CompilerVar* vdata = _getVar(var.getId()); + ASMJIT_ASSERT(vdata != NULL); + + if (priority > 100) priority = 100; + vdata->_priority = static_cast(priority); +} + +bool X86Compiler::getSaveOnUnuse(Var& var) const +{ + if (var.getId() == kInvalidValue) + return false; + + X86CompilerVar* vdata = _getVar(var.getId()); + ASMJIT_ASSERT(vdata != NULL); + + return (bool)vdata->saveOnUnuse; +} + +void X86Compiler::setSaveOnUnuse(Var& var, bool value) +{ + if (var.getId() == kInvalidValue) + return; + + X86CompilerVar* vdata = _getVar(var.getId()); + ASMJIT_ASSERT(vdata != NULL); + + vdata->saveOnUnuse = value; +} + +void X86Compiler::rename(Var& var, const char* name) +{ + if (var.getId() == kInvalidValue) + return; + + X86CompilerVar* vdata = _getVar(var.getId()); + ASMJIT_ASSERT(vdata != NULL); + + vdata->_name = _zoneMemory.sdup(name); +} + +// ============================================================================ +// [AsmJit::Compiler - State] +// ============================================================================ + +X86CompilerState* X86Compiler::_newState(uint32_t memVarsCount) +{ + X86CompilerState* state = reinterpret_cast(_zoneMemory.alloc( + sizeof(X86CompilerState) + memVarsCount * sizeof(void*))); + return state; +} + +// ============================================================================ +// [AsmJit::Compiler - Make] +// ============================================================================ + +void* X86Compiler::make() +{ + X86Assembler x86Asm(_context); + + x86Asm._properties = _properties; + x86Asm.setLogger(_logger); + + serialize(x86Asm); + + if (this->getError()) + return NULL; + + if (x86Asm.getError()) + { + setError(x86Asm.getError()); + return NULL; + } + + void* result = x86Asm.make(); + + if (_logger) + { + _logger->logFormat("*** COMPILER SUCCESS - Wrote %u bytes, code: %u, trampolines: %u.\n\n", + (unsigned int)x86Asm.getCodeSize(), + (unsigned int)x86Asm.getOffset(), + (unsigned int)x86Asm.getTrampolineSize()); + } + + return result; +} + +void X86Compiler::serialize(Assembler& a) +{ + X86CompilerContext x86Context(this); + X86Assembler& x86Asm = static_cast(a); + + CompilerItem* start = _first; + CompilerItem* stop = NULL; + + // Register all labels. + x86Asm.registerLabels(_targets.getLength()); + + // Make code. + for (;;) + { + _cc = NULL; + + // ------------------------------------------------------------------------ + // [Find Function] + // ------------------------------------------------------------------------ + + for (;;) + { + if (start == NULL) + return; + + if (start->getType() == kCompilerItemFuncDecl) + break; + + start->emit(x86Asm); + start = start->getNext(); + } + + // ------------------------------------------------------------------------ + // [Setup CompilerContext] + // ------------------------------------------------------------------------ + + stop = static_cast(start)->getEnd(); + + x86Context._func = static_cast(start); + x86Context._start = start; + x86Context._stop = stop; + x86Context._extraBlock = stop->getPrev(); + + // Detect whether the function generation was finished. + if (!x86Context._func->isFinished() || x86Context._func->getEnd()->getPrev() == NULL) + { + setError(kErrorIncompleteFunction); + return; + } + + // ------------------------------------------------------------------------ + // Step 1: + // - Assign/increment offset of each item. + // - Extract variables from instructions. + // - Prepare variables for register allocator: + // - Update read(r) / write(w) / read/write(x) statistics. + // - Update register / memory usage statistics. + // - Find scope (first / last item) of variables. + // ------------------------------------------------------------------------ + + CompilerItem* cur; + for (cur = start; ; cur = cur->getNext()) + { + cur->prepare(x86Context); + if (cur == stop) + break; + } + + // We set compiler context also to Compiler so newly emitted instructions + // can call CompilerItem::prepare() on itself. + _cc = &x86Context; + + // ------------------------------------------------------------------------ + // Step 2: + // - Translate special instructions (imul, cmpxchg8b, ...). + // - Alloc registers. + // - Translate forward jumps. + // - Alloc memory operands (variables related). + // - Emit function prolog. + // - Emit function epilog. + // - Patch memory operands (variables related). + // - Dump function prototype and variable statistics (if enabled). + // ------------------------------------------------------------------------ + + // Translate special instructions and run alloc registers. + cur = start; + + do { + do { + // Assign current offset of each item back to CompilerContext. + x86Context._currentOffset = cur->_offset; + // Assign previous item to compiler so each variable spill/alloc will + // be emitted before. + _current = cur->getPrev(); + + cur = cur->translate(x86Context); + } while (cur); + + x86Context._isUnreachable = true; + + size_t len = x86Context._backCode.getLength(); + while (x86Context._backPos < len) + { + cur = x86Context._backCode[x86Context._backPos++]->getNext(); + if (!cur->isTranslated()) break; + + cur = NULL; + } + } while (cur); + + // Translate forward jumps. + { + ForwardJumpData* j = x86Context._forwardJumps; + while (j != NULL) + { + x86Context._assignState(j->state); + _current = j->inst->getPrev(); + j->inst->doJump(x86Context); + j = j->next; + } + } + + // Alloc memory operands (variables related). + x86Context._allocMemoryOperands(); + + // Emit function prolog / epilog. + x86Context.getFunc()->_preparePrologEpilog(x86Context); + + _current = x86Context._func->getEntryTarget(); + x86Context.getFunc()->_emitProlog(x86Context); + + _current = x86Context._func->getExitTarget(); + x86Context.getFunc()->_emitEpilog(x86Context); + + // Patch memory operands (variables related). + _current = _last; + x86Context._patchMemoryOperands(start, stop); + + // Dump function prototype and variable statistics (if enabled). + if (_logger) + x86Context.getFunc()->_dumpFunction(x86Context); + + // ------------------------------------------------------------------------ + // Hack: need to register labels that was created by the Step 2. + // ------------------------------------------------------------------------ + + if (x86Asm._labels.getLength() < _targets.getLength()) + x86Asm.registerLabels(_targets.getLength() - x86Asm._labels.getLength()); + + CompilerItem* extraBlock = x86Context._extraBlock; + + // ------------------------------------------------------------------------ + // Step 3: + // - Emit instructions to Assembler stream. + // ------------------------------------------------------------------------ + + for (cur = start; ; cur = cur->getNext()) + { + cur->emit(x86Asm); + if (cur == extraBlock) break; + } + + // ------------------------------------------------------------------------ + // Step 4: + // - Emit everything else (post action). + // ------------------------------------------------------------------------ + + for (cur = start; ; cur = cur->getNext()) + { + cur->post(x86Asm); + if (cur == extraBlock) break; + } + + start = extraBlock->getNext(); + x86Context._clear(); + } +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/x86/x86compiler.h b/desmume/src/utils/AsmJit/x86/x86compiler.h new file mode 100644 index 000000000..8141c7005 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86compiler.h @@ -0,0 +1,5829 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_X86_X86COMPILER_H +#define _ASMJIT_X86_X86COMPILER_H + +// [Dependencies - AsmJit] +#include "../core/build.h" +#include "../core/compiler.h" +#include "../core/compilercontext.h" +#include "../core/compilerfunc.h" +#include "../core/compileritem.h" + +#include "../x86/x86assembler.h" +#include "../x86/x86defs.h" +#include "../x86/x86func.h" +#include "../x86/x86util.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +//! @internal +//! +//! @brief Mark methods not supported by @ref Compiler. These methods are +//! usually used only in function prologs/epilogs or to manage stack. +#define ASMJIT_NOT_SUPPORTED_BY_COMPILER 0 + +namespace AsmJit { + +//! @addtogroup AsmJit_X86 +//! @{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +struct X86Compiler; +struct X86CompilerAlign; +struct X86CompilerContext; +struct X86CompilerFuncCall; +struct X86CompilerFuncDecl; +struct X86CompilerFuncEnd; +struct X86CompilerInst; +struct X86CompilerJmpInst; +struct X86CompilerState; +struct X86CompilerTarget; +struct X86CompilerVar; + +// ============================================================================ +// [AsmJit::X86CompilerVar] +// ============================================================================ + +//! @brief @ref X86Compiler variable. +struct X86CompilerVar : public CompilerVar +{ + // -------------------------------------------------------------------------- + // [AsVar] + // -------------------------------------------------------------------------- + + inline GpVar asGpVar() const + { + GpVar var; + var._var.id = _id; + var._var.size = _size; + var._var.regCode = x86VarInfo[_type].getCode(); + var._var.varType = _type; + return var; + } + + inline MmVar asMmVar() const + { + MmVar var; + var._var.id = _id; + var._var.size = _size; + var._var.regCode = x86VarInfo[_type].getCode(); + var._var.varType = _type; + return var; + } + + inline XmmVar asXmmVar() const + { + XmmVar var; + var._var.id = _id; + var._var.size = _size; + var._var.regCode = x86VarInfo[_type].getCode(); + var._var.varType = _type; + return var; + } + + // -------------------------------------------------------------------------- + // [Members - Scope] + // -------------------------------------------------------------------------- + + //! @brief The first item where the variable is accessed. + //! @note If this member is @c NULL then variable isn't used. + CompilerItem* firstItem; + //! @brief The last item where the variable is accessed. + CompilerItem* lastItem; + + //! @brief Scope (NULL if variable is global). + X86CompilerFuncDecl* funcScope; + //! @brief The first call which is after the @c firstItem. + X86CompilerFuncCall* funcCall; + + // -------------------------------------------------------------------------- + // [Members - Home] + // -------------------------------------------------------------------------- + + //! @brief Home register index or @c kRegIndexInvalid (used by register allocator). + uint32_t homeRegisterIndex; + //! @brief Preferred registers mask. + uint32_t prefRegisterMask; + + //! @brief Home memory address offset. + int32_t homeMemoryOffset; + //! @brief Used by @c CompilerContext, do not touch (initially NULL). + void* homeMemoryData; + + // -------------------------------------------------------------------------- + // [Members - Actual] + // -------------------------------------------------------------------------- + + //! @brief Actual register index (connected with actual @c X86CompilerState). + uint32_t regIndex; + //! @brief Actual working offset. This member is set before register allocator + //! is called. If workOffset is same as CompilerContext::_currentOffset then + //! this variable is probably used in next instruction and can't be spilled. + uint32_t workOffset; + + //! @brief Next active variable in circular double-linked list. + X86CompilerVar* nextActive; + //! @brief Previous active variable in circular double-linked list. + X86CompilerVar* prevActive; + + // -------------------------------------------------------------------------- + // [Members - Flags] + // -------------------------------------------------------------------------- + + //! @brief Variable state (connected with actual @c X86CompilerState). + uint8_t state; + //! @brief Whether variable was changed (connected with actual @c X86CompilerState). + uint8_t changed; + //! @brief Save on unuse (at end of the variable scope). + uint8_t saveOnUnuse; + + // -------------------------------------------------------------------------- + // [Members - Statistics] + // -------------------------------------------------------------------------- + + //! @brief Register read access statistics. + uint32_t regReadCount; + //! @brief Register write access statistics. + uint32_t regWriteCount; + //! @brief Register read/write access statistics (related to a single instruction). + uint32_t regRwCount; + + //! @brief Register GpbLo access statistics. + uint32_t regGpbLoCount; + //! @brief Register GpbHi access statistics. + uint32_t regGpbHiCount; + + //! @brief Memory read statistics. + uint32_t memReadCount; + //! @brief Memory write statistics. + uint32_t memWriteCount; + //! @brief Memory read+write statistics. + uint32_t memRwCount; + + // -------------------------------------------------------------------------- + // [Members - Temporary] + // -------------------------------------------------------------------------- + + //! @brief Temporary data that can be used in prepare/translate stage. + //! + //! Initial value is NULL and it's expected that after use it's set back to + //! NULL. + //! + //! The temporary data is designed to be used by algorithms that need to + //! set some state into variables, do something and then clean-up. See + //! state switch and function call for details. + union + { + void* tPtr; + intptr_t tInt; + }; +}; + +// ============================================================================ +// [AsmJit::X86CompilerState] +// ============================================================================ + +//! @brief @ref X86Compiler state. +struct X86CompilerState : CompilerState +{ + enum + { + //! @brief Base for Gp registers. + kStateRegGpBase = 0, + //! @brief Base for Mm registers. + kStateRegMmBase = 16, + //! @brief Base for Xmm registers. + kStateRegXmmBase = 24, + + //! @brief Count of all registers in @ref X86CompilerState. + kStateRegCount = 16 + 8 + 16 + }; + + // -------------------------------------------------------------------------- + // [Clear] + // -------------------------------------------------------------------------- + + inline void clear() + { memset(this, 0, sizeof(*this)); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + union + { + //! @brief All allocated variables in one array. + X86CompilerVar* regs[kStateRegCount]; + + struct + { + //! @brief Allocated GP registers. + X86CompilerVar* gp[16]; + //! @brief Allocated MM registers. + X86CompilerVar* mm[8]; + //! @brief Allocated XMM registers. + X86CompilerVar* xmm[16]; + }; + }; + + //! @brief Used GP registers bit-mask. + uint32_t usedGP; + //! @brief Used MM registers bit-mask. + uint32_t usedMM; + //! @brief Used XMM registers bit-mask. + uint32_t usedXMM; + + //! @brief Changed GP registers bit-mask. + uint32_t changedGP; + //! @brief Changed MM registers bit-mask. + uint32_t changedMM; + //! @brief Changed XMM registers bit-mask. + uint32_t changedXMM; + + //! @brief Count of variables in @c memVarsData. + uint32_t memVarsCount; + //! @brief Variables stored in memory (@c kVarStateMem). + //! + //! When saving / restoring state it's important to keep registers which are + //! still in memory. Register is always unused when it is going out-of-scope. + //! All variables which are not here are unused (@c kVarStateUnused). + X86CompilerVar* memVarsData[1]; +}; + +// ============================================================================ +// [AsmJit::VarMemBlock] +// ============================================================================ + +struct VarMemBlock +{ + int32_t offset; + uint32_t size; + + VarMemBlock* nextUsed; + VarMemBlock* nextFree; +}; + +// ============================================================================ +// [AsmJit::VarAllocRecord] +// ============================================================================ + +//! @brief Variable alloc record (for each instruction that uses variables). +//! +//! Variable record contains pointer to variable data and register allocation +//! flags. These flags are important to determine the best alloc instruction. +struct VarAllocRecord +{ + //! @brief Variable data (the structure owned by @c Compiler). + X86CompilerVar* vdata; + //! @brief Variable alloc flags, see @c kVarAllocFlags. + uint32_t vflags; + //! @brief Register mask (default is 0). + uint32_t regMask; +}; + +// ============================================================================ +// [AsmJit::VarCallRecord] +// ============================================================================ + +//! @brief Variable call-fn record (for each callable that uses variables). +//! +//! This record contains variables that are used to call a function (using +//! @c X86CompilerFuncCall item). Each variable contains the registers where +//! it must be and registers where the value will be returned. +struct VarCallRecord +{ + //! @brief Variable data (the structure owned by @c Compiler). + X86CompilerVar* vdata; + uint32_t flags; + + uint8_t inCount; + uint8_t inDone; + + uint8_t outCount; + uint8_t outDone; + + enum FLAGS + { + kFlagInGp = 0x0001, + kFlagInMm = 0x0002, + kFlagInXmm = 0x0004, + kFlagInStack = 0x0008, + + kFlagOutEax = 0x0010, + kFlagOutEdx = 0x0020, + kFlagOutSt0 = 0x0040, + kFlagOutSt1 = 0x0080, + kFlagOutMm0 = 0x0100, + kFlagOutXmm0 = 0x0400, + kFlagOutXmm1 = 0x0800, + + kFlagInMemPtr = 0x1000, + kFlagCallReg = 0x2000, + kFlagCallMem = 0x4000, + kFlagUnuseAfterUse = 0x8000 + }; +}; + +// ============================================================================ +// [AsmJit::VarHintRecord] +// ============================================================================ + +struct VarHintRecord +{ + X86CompilerVar* vdata; + uint32_t hint; +}; + +// ============================================================================ +// [AsmJit::ForwardJumpData] +// ============================================================================ + +struct ForwardJumpData +{ + X86CompilerJmpInst* inst; + X86CompilerState* state; + ForwardJumpData* next; +}; + +// ============================================================================ +// [AsmJit::CompilerUtil] +// ============================================================================ + +//! @brief Static class that contains utility methods. +struct CompilerUtil +{ + ASMJIT_API static bool isStack16ByteAligned(); +}; + +// ============================================================================ +// [AsmJit::X86Compiler] +// ============================================================================ + +//! @brief Compiler - high level code generation. +//! +//! This class is used to store instruction stream and allows to modify +//! it on the fly. It uses different concept than @c AsmJit::Assembler class +//! and in fact @c AsmJit::Assembler is only used as a backend. Compiler never +//! emits machine code and each instruction you use is stored to instruction +//! array instead. This allows to modify instruction stream later and for +//! example to reorder instructions to make better performance. +//! +//! Using @c AsmJit::Compiler moves code generation to higher level. Higher +//! level constructs allows to write more abstract and extensible code that +//! is not possible with pure @c AsmJit::Assembler class. Because +//! @c AsmJit::Compiler needs to create many objects and lifetime of these +//! objects is small (same as @c AsmJit::Compiler lifetime itself) it uses +//! very fast memory management model. This model allows to create object +//! instances in nearly zero time (compared to @c malloc() or @c new() +//! operators) so overhead by creating machine code by @c AsmJit::Compiler +//! is minimized. +//! +//! @section AsmJit_Compiler_TheStory The Story +//! +//! Before telling you how Compiler works I'd like to write a story. I'd like +//! to cover reasons why this class was created and why I'm recommending to use +//! it. When I released the first version of AsmJit (0.1) it was a toy. The +//! first function I wrote was function which is still available as testjit and +//! which simply returns 1024. The reason why function works for both 32-bit/ +//! 64-bit mode and for Windows/Unix specific calling conventions is luck, no +//! arguments usage and no registers usage except returning value in EAX/RAX. +//! +//! Then I started a project called BlitJit which was targetted to generating +//! JIT code for computer graphics. After writing some lines I decided that I +//! can't join pieces of code together without abstraction, should be +//! pixels source pointer in ESI/RSI or EDI/RDI or it's completelly +//! irrellevant? What about destination pointer and SSE2 register for reading +//! input pixels? The simple answer might be "just pick some one and use it". +//! +//! Another reason for abstraction is function calling-conventions. It's really +//! not easy to write assembler code for 32-bit and 64-bit platform supporting +//! three calling conventions (32-bit is similar between Windows and Unix, but +//! 64-bit calling conventions are different). +//! +//! At this time I realized that I can't write code which uses named registers, +//! I need to abstract it. In most cases you don't need specific register, you +//! need to emit instruction that does something with 'virtual' register(s), +//! memory, immediate or label. +//! +//! The first version of AsmJit with Compiler was 0.5 (or 0.6?, can't remember). +//! There was support for 32-bit and 64-bit mode, function calling conventions, +//! but when emitting instructions the developer needed to decide which +//! registers are changed, which are only read or completely overwritten. This +//! model helped a lot when generating code, especially when joining more +//! code-sections together, but there was also small possibility for mistakes. +//! Simply the first version of Compiler was great improvement over low-level +//! Assembler class, but the API design wasn't perfect. +//! +//! The second version of Compiler, completelly rewritten and based on +//! different goals, is part of AsmJit starting at version 1.0. This version +//! was designed after the first one and it contains serious improvements over +//! the old one. The first improvement is that you just use instructions with +//! virtual registers - called variables. When using compiler there is no way +//! to use native registers, there are variables instead. AsmJit is smarter +//! than before and it knows which register is needed only for read (r), +//! read/write (w) or overwrite (x). Supported are also instructions which +//! are using some registers in implicit way (these registers are not part of +//! instruction definition in string form). For example to use CPUID instruction +//! you must give it four variables which will be automatically allocated to +//! input/output registers (EAX, EBX, ECX, EDX). +//! +//! Another improvement is algorithm used by a register allocator. In first +//! version the registers were allocated when creating instruction stream. In +//! new version registers are allocated after calling @c Compiler::make(). This +//! means that register allocator has information about scope of all variables +//! and their usage statistics. The algorithm to allocate registers is very +//! simple and it's always called as a 'linear scan register allocator'. When +//! you get out of registers the all possible variables are scored and the worst +//! is spilled. Of course algorithm ignores the variables used for current +//! instruction. +//! +//! In addition, because registers are allocated after the code stream is +//! generated, the state switches between jumps are handled by Compiler too. +//! You don't need to worry about jumps, compiler always do this dirty work +//! for you. +//! +//! The nearly last thing I'd like to present is calling other functions from +//! the generated code. AsmJit uses a @c FunctionPrototype class to hold +//! the function parameters, their position in stack (or register index) and +//! function return value. This class is used internally, but it can be +//! used to create your own function calling-convention. All standard function +//! calling conventions are implemented. +//! +//! Please enjoy the new version of Compiler, it was created for writing a +//! low-level code using high-level API, leaving developer to concentrate to +//! real problems and not to solving a register puzzle. +//! +//! @section AsmJit_Compiler_CodeGeneration Code Generation +//! +//! First that is needed to know about compiler is that compiler never emits +//! machine code. It's used as a middleware between @c AsmJit::Assembler and +//! your code. There is also convenience method @c make() that allows to +//! generate machine code directly without creating @c AsmJit::Assembler +//! instance. +//! +//! Comparison of generating machine code through @c Assembler and directly +//! by @c Compiler: +//! +//! @code +//! // Assembler instance is low level code generation class that emits +//! // machine code. +//! X86Assembler a; +//! +//! // Compiler instance is high level code generation class that stores all +//! // instructions in internal representation. +//! X86Compiler c; +//! +//! // ... put your code here ... +//! +//! // Final step - generate code. AsmJit::Compiler::serialize() will serialize +//! // all instructions into Assembler and this ensures generating real machine +//! // code. +//! c.serialize(a); +//! +//! // Your function +//! void* fn = a.make(); +//! @endcode +//! +//! Example how to generate machine code using only @c Compiler (preferred): +//! +//! @code +//! // Compiler instance is enough. +//! X86Compiler c; +//! +//! // ... put your code here ... +//! +//! // Your function +//! void* fn = c.make(); +//! @endcode +//! +//! You can see that there is @c AsmJit::Compiler::serialize() function that +//! emits instructions into @c AsmJit::Assembler(). This layered architecture +//! means that each class is used for something different and there is no code +//! duplication. For convenience there is also @c AsmJit::Compiler::make() +//! method that can create your function using @c AsmJit::Assembler, but +//! internally (this is preffered bahavior when using @c AsmJit::Compiler). +//! +//! The @c make() method allocates memory using @c Context instance passed +//! into the @c X86Compiler constructor. If code generator is used to create JIT +//! function then virtual memory allocated by @c MemoryManager is used. To get +//! global memory manager use @c MemoryManager::getGlobal(). +//! +//! @code +//! // Compiler instance is enough. +//! X86Compiler c; +//! +//! // ... put your code using Compiler instance ... +//! +//! // Your function +//! void* fn = c.make(); +//! +//! // Free it if you don't want it anymore +//! // (using global memory manager instance) +//! MemoryManager::getGlobal()->free(fn); +//! @endcode +//! +//! @section AsmJit_Compiler_Functions Functions +//! +//! To build functions with @c Compiler, see @c AsmJit::Compiler::newFunc() +//! method. +//! +//! @section AsmJit_Compiler_Variables Variables +//! +//! Compiler is able to manage variables and function arguments. Internally +//! there is no difference between function argument and variable declared +//! inside. To get function argument you use @c getGpArg() method and to declare +//! variable use @c newGpVar(), @c newMmVar() and @c newXmmVar() methods. The @c newXXX() +//! methods accept also parameter describing the variable type. For example +//! the @c newGpVar() method always creates variable which size matches the target +//! architecture size (for 32-bit target the 32-bit variable is created, for +//! 64-bit target the variable size is 64-bit). To override this behavior the +//! variable type must be specified. +//! +//! @code +//! // Compiler and function declaration - void f(int*); +//! X86Compiler c; +//! c.newFunc(kX86FuncConvDefault, BuildFunction1()); +//! +//! // Get argument variable (it's pointer). +//! GpVar a1(c.getGpArg(0)); +//! +//! // Create your variables. +//! GpVar x1(c.newGpVar(kX86VarTypeGpd)); +//! GpVar x2(c.newGpVar(kX86VarTypeGpd)); +//! +//! // Init your variables. +//! c.mov(x1, 1); +//! c.mov(x2, 2); +//! +//! // ... your code ... +//! c.add(x1, x2); +//! // ... your code ... +//! +//! // Store result to a given pointer in first argument +//! c.mov(dword_ptr(a1), x1); +//! +//! // End of function body. +//! c.endFunc(); +//! +//! // Make the function. +//! typedef void (*MyFn)(int*); +//! MyFn fn = asmjit_cast(c.make()); +//! @endcode +//! +//! This code snipped needs to be explained. You can see that there are more +//! variable types that can be used by @c Compiler. Most useful variables can +//! be allocated using general purpose registers (@c GpVar), MMX registers +//! (@c MmVar) or SSE registers (@c XmmVar). +//! +//! X86/X64 variable types: +//! +//! - @c kX86VarTypeGpd - 32-bit general purpose register (EAX, EBX, ...). +//! - @c kX86VarTypeGpq - 64-bit general purpose register (RAX, RBX, ...). +//! - @c kX86VarTypeGpz - 32-bit or 64-bit general purpose register, depends +//! to target architecture. Mapped to @c kX86VarTypeGpd or @c kX86VarTypeGpq. +//! +//! - @c kX86VarTypeX87 - 80-bit floating point stack register st(0 to 7). +//! - @c kX86VarTypeX87SS - 32-bit floating point stack register st(0 to 7). +//! - @c kX86VarTypeX87SD - 64-bit floating point stack register st(0 to 7). +//! +//! - @c VARIALBE_TYPE_MM - 64-bit MMX register. +//! +//! - @c kX86VarTypeXmm - 128-bit SSE register. +//! - @c kX86VarTypeXmmSS - 128-bit SSE register which contains +//! scalar 32-bit single precision floating point. +//! - @c kX86VarTypeXmmSD - 128-bit SSE register which contains +//! scalar 64-bit double precision floating point. +//! - @c kX86VarTypeXmmPS - 128-bit SSE register which contains +//! 4 packed 32-bit single precision floating points. +//! - @c kX86VarTypeXmmPD - 128-bit SSE register which contains +//! 2 packed 64-bit double precision floating points. +//! +//! Unified variable types: +//! +//! - @c kX86VarTypeInt32 - 32-bit general purpose register. +//! - @c kX86VarTypeInt64 - 64-bit general purpose register. +//! - @c kX86VarTypeIntPtr - 32-bit or 64-bit general purpose register / pointer. +//! +//! - @c kX86VarTypeFloat - 32-bit single precision floating point. +//! - @c kX86VarTypeDouble - 64-bit double precision floating point. +//! +//! Variable states: +//! +//! - @c kVarStateUnused - State that is assigned to newly created +//! variables or to not used variables (dereferenced to zero). +//! - @c kVarStateReg - State that means that variable is currently +//! allocated in register. +//! - @c kVarStateMem - State that means that variable is currently +//! only in memory location. +//! +//! When you create new variable, initial state is always @c kVarStateUnused, +//! allocating it to register or spilling to memory changes this state to +//! @c kVarStateReg or @c kVarStateMem, respectively. +//! During variable lifetime it's usual that its state is changed multiple +//! times. To generate better code, you can control allocating and spilling +//! by using up to four types of methods that allows it (see next list). +//! +//! Explicit variable allocating / spilling methods: +//! +//! - @c Compiler::alloc() - Explicit method to alloc variable into +//! register. You can use this before loops or code blocks. +//! +//! - @c Compiler::spill() - Explicit method to spill variable. If variable +//! is in register and you call this method, it's moved to its home memory +//! location. If variable is not in register no operation is performed. +//! +//! - @c Compiler::unuse() - Unuse variable (you can use this to end the +//! variable scope or sub-scope). +//! +//! Please see AsmJit tutorials (testcompiler.cpp and testvariables.cpp) for +//! more complete examples. +//! +//! @section AsmJit_Compiler_MemoryManagement Memory Management +//! +//! @c Compiler Memory management follows these rules: +//! - Everything created by @c Compiler is always freed by @c Compiler. +//! - To get decent performance, compiler always uses larger memory buffer +//! for objects to allocate and when compiler instance is destroyed, this +//! buffer is freed. Destructors of active objects are called when +//! destroying compiler instance. Destructors of abadonded compiler +//! objects are called immediately after abadonding them. +//! - This type of memory management is called 'zone memory management'. +//! +//! This means that you can't use any @c Compiler object after destructing it, +//! it also means that each object like @c Label, @c Var and others are created +//! and managed by @c Compiler itself. These objects contain ID which is used +//! internally by Compiler to store additional information about these objects. +//! +//! @section AsmJit_Compiler_StateManagement Control-Flow and State Management. +//! +//! The @c Compiler automatically manages state of the variables when using +//! control flow instructions like jumps, conditional jumps and calls. There +//! is minimal heuristics for choosing the method how state is saved or restored. +//! +//! Generally the state can be changed only when using jump or conditional jump +//! instruction. When using non-conditional jump then state change is embedded +//! into the instruction stream before the jump. When using conditional jump +//! the @c Compiler decides whether to restore state before the jump or whether +//! to use another block where state is restored. The last case is that no-code +//! have to be emitted and there is no state change (this is of course ideal). +//! +//! Choosing whether to embed 'restore-state' section before conditional jump +//! is quite simple. If jump is likely to be 'taken' then code is embedded, if +//! jump is unlikely to be taken then the small code section for state-switch +//! will be generated instead. +//! +//! Next example is the situation where the extended code block is used to +//! do state-change: +//! +//! @code +//! X86Compiler c; +//! +//! c.newFunc(kX86FuncConvDefault, FuncBuilder0()); +//! c.getFunc()->setHint(kFuncHintNaked, true); +//! +//! // Labels. +//! Label L0 = c.newLabel(); +//! +//! // Variables. +//! GpVar var0 = c.newGpVar(); +//! GpVar var1 = c.newGpVar(); +//! +//! // Cleanup. After these two lines, the var0 and var1 will be always stored +//! // in registers. Our example is very small, but in larger code the var0 can +//! // be spilled by xor(var1, var1). +//! c.xor_(var0, var0); +//! c.xor_(var1, var1); +//! c.cmp(var0, var1); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! // We manually spill these variables. +//! c.spill(var0); +//! c.spill(var1); +//! // State: +//! // var0 - memory. +//! // var1 - memory. +//! +//! // Conditional jump to L0. It will be always taken, but compiler thinks that +//! // it is unlikely taken so it will embed state change code somewhere. +//! c.je(L0); +//! +//! // Do something. The variables var0 and var1 will be allocated again. +//! c.add(var0, 1); +//! c.add(var1, 2); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! // Bind label here, the state is not changed. +//! c.bind(L0); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! // We need to use var0 and var1, because if compiler detects that variables +//! // are out of scope then it optimizes the state-change. +//! c.sub(var0, var1); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! c.endFunc(); +//! @endcode +//! +//! The output: +//! +//! @verbatim +//! xor eax, eax ; xor var_0, var_0 +//! xor ecx, ecx ; xor var_1, var_1 +//! cmp eax, ecx ; cmp var_0, var_1 +//! mov [esp - 24], eax ; spill var_0 +//! mov [esp - 28], ecx ; spill var_1 +//! je L0_Switch +//! mov eax, [esp - 24] ; alloc var_0 +//! add eax, 1 ; add var_0, 1 +//! mov ecx, [esp - 28] ; alloc var_1 +//! add ecx, 2 ; add var_1, 2 +//! L0: +//! sub eax, ecx ; sub var_0, var_1 +//! ret +//! +//! ; state-switch begin +//! L0_Switch0: +//! mov eax, [esp - 24] ; alloc var_0 +//! mov ecx, [esp - 28] ; alloc var_1 +//! jmp short L0 +//! ; state-switch end +//! @endverbatim +//! +//! You can see that the state-switch section was generated (see L0_Switch0). +//! The compiler is unable to restore state immediately when emitting the +//! forward jump (the code is generated from first to last instruction and +//! the target state is simply not known at this time). +//! +//! To tell @c Compiler that you want to embed state-switch code before jump +//! it's needed to create backward jump (where also processor expects that it +//! will be taken). To demonstrate the possibility to embed state-switch before +//! jump we use slightly modified code: +//! +//! @code +//! X86Compiler c; +//! +//! c.newFunc(kX86FuncConvDefault, FuncBuilder0()); +//! c.getFunc()->setHint(kFuncHintNaked, true); +//! +//! // Labels. +//! Label L0 = c.newLabel(); +//! +//! // Variables. +//! GpVar var0 = c.newGpVar(); +//! GpVar var1 = c.newGpVar(); +//! +//! // Cleanup. After these two lines, the var0 and var1 will be always stored +//! // in registers. Our example is very small, but in larger code the var0 can +//! // be spilled by xor(var1, var1). +//! c.xor_(var0, var0); +//! c.xor_(var1, var1); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! // We manually spill these variables. +//! c.spill(var0); +//! c.spill(var1); +//! // State: +//! // var0 - memory. +//! // var1 - memory. +//! +//! // Bind our label here. +//! c.bind(L0); +//! +//! // Do something, the variables will be allocated again. +//! c.add(var0, 1); +//! c.add(var1, 2); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! // Backward conditional jump to L0. The default behavior is that it is taken +//! // so state-change code will be embedded here. +//! c.je(L0); +//! +//! c.endFunc(); +//! @endcode +//! +//! The output: +//! +//! @verbatim +//! xor ecx, ecx ; xor var_0, var_0 +//! xor edx, edx ; xor var_1, var_1 +//! mov [esp - 24], ecx ; spill var_0 +//! mov [esp - 28], edx ; spill var_1 +//! L.2: +//! mov ecx, [esp - 24] ; alloc var_0 +//! add ecx, 1 ; add var_0, 1 +//! mov edx, [esp - 28] ; alloc var_1 +//! add edx, 2 ; add var_1, 2 +//! +//! ; state-switch begin +//! mov [esp - 24], ecx ; spill var_0 +//! mov [esp - 28], edx ; spill var_1 +//! ; state-switch end +//! +//! je short L.2 +//! ret +//! @endverbatim +//! +//! Please notice where the state-switch section is located. The @c Compiler +//! decided that jump is likely to be taken so the state change is embedded +//! before the conditional jump. To change this behavior into the previous +//! case it's needed to add a hint (@c kCondHintLikely or @c kCondHintUnlikely). +//! +//! Replacing the c.je(L0) by c.je(L0, kCondHintUnlikely) +//! will generate code like this: +//! +//! @verbatim +//! xor ecx, ecx ; xor var_0, var_0 +//! xor edx, edx ; xor var_1, var_1 +//! mov [esp - 24], ecx ; spill var_0 +//! mov [esp - 28], edx ; spill var_1 +//! L0: +//! mov ecx, [esp - 24] ; alloc var_0 +//! add ecx, 1 ; add var_0, a +//! mov edx, [esp - 28] ; alloc var_1 +//! add edx, 2 ; add var_1, 2 +//! je L0_Switch, 2 +//! ret +//! +//! ; state-switch begin +//! L0_Switch: +//! mov [esp - 24], ecx ; spill var_0 +//! mov [esp - 28], edx ; spill var_1 +//! jmp short L0 +//! ; state-switch end +//! @endverbatim +//! +//! This section provided information about how state-change works. The +//! behavior is deterministic and it can be overridden. +//! +//! @section AsmJit_Compiler_AdvancedCodeGeneration Advanced Code Generation +//! +//! This section describes advanced method of code generation available to +//! @c Compiler (but also to @c Assembler). When emitting code to instruction +//! stream the methods like @c mov(), @c add(), @c sub() can be called directly +//! (advantage is static-type control performed also by C++ compiler) or +//! indirectly using @c emit() method. The @c emit() method needs only +//! instruction code and operands. +//! +//! Example of code generating by standard type-safe API: +//! +//! @code +//! X86Compiler c; +//! GpVar var0 = c.newGpVar(); +//! GpVar var1 = c.newGpVar(); +//! +//! ... +//! +//! c.mov(var0, imm(0)); +//! c.add(var0, var1); +//! c.sub(var0, var1); +//! @endcode +//! +//! The code above can be rewritten as: +//! +//! @code +//! X86Compiler c; +//! GpVar var0 = c.newGpVar(); +//! GpVar var1 = c.newGpVar(); +//! +//! ... +//! +//! c.emit(kX86InstMov, var0, imm(0)); +//! c.emit(kX86InstAdd, var0, var1); +//! c.emit(kX86InstSub, var0, var1); +//! @endcode +//! +//! The advantage of first snippet is very friendly API and type-safe control +//! that is controlled by the C++ compiler. The advantage of second snippet is +//! availability to replace or generate instruction code in different places. +//! See the next example how the @c emit() method can be used to generate +//! abstract code. +//! +//! Use case: +//! +//! @code +//! bool emitArithmetic(Compiler& c, XmmVar& var0, XmmVar& var1, const char* op) +//! { +//! uint code = kInstNone; +//! +//! if (strcmp(op, "ADD") == 0) +//! code = kX86InstAddSS; +//! else if (strcmp(op, "SUBTRACT") == 0) +//! code = kX86InstSubSS; +//! else if (strcmp(op, "MULTIPLY") == 0) +//! code = kX86InstMulSS; +//! else if (strcmp(op, "DIVIDE") == 0) +//! code = kX86InstDivSS; +//! else +//! // Invalid parameter? +//! return false; +//! +//! c.emit(code, var0, var1); +//! } +//! @endcode +//! +//! Other use cases are waiting for you! Be sure that instruction you are +//! emitting is correct and encodable, because if not, Assembler will set +//! error code to @c kErrorUnknownInstruction. +//! +//! @section AsmJit_Compiler_CompilerDetails Compiler Details +//! +//! This section is here for people interested in the compiling process. There +//! are few steps that must be done for each compiled function (or your code). +//! +//! When your @c Compiler instance is ready, you can create function and add +//! compiler-items using intrinsics or higher level methods implemented by the +//! @c AsmJit::Compiler. When you are done (all instructions serialized) you +//! should call @c AsmJit::Compiler::make() method which will analyze your code, +//! allocate registers and memory for local variables and serialize all items +//! to @c AsmJit::Assembler instance. Next steps shows what's done internally +//! before code is serialized into @c AsmJit::Assembler +//! (implemented in @c AsmJit::Compiler::serialize() method). +//! +//! 1. Compiler try to match function and end-function items (these items +//! define function body and blocks). +//! +//! 2. For all items inside the function-body the virtual functions +//! are called in this order: +//! - CompilerItem::prepare() +//! - CompilerItem::translate() +//! - CompilerItem::emit() +//! - CompilerItem::post() +//! +//! There is some extra work when emitting function prolog / epilog and +//! register allocator. +//! +//! 3. Emit jump tables data. +//! +//! When everything here ends, @c AsmJit::Assembler contains binary stream +//! that needs only relocation to be callable by C/C++ code. +//! +//! @section AsmJit_Compiler_Differences Summary of Differences between @c Assembler and @c Compiler +//! +//! - Instructions are not translated to machine code immediately, they are +//! stored as emmitables, see @c AsmJit::CompilerItem. +//! - Contains function builder and ability to call other functions. +//! - Contains register allocator and variable management. +//! - Contains a lot of helper methods to simplify the code generation not +//! available/possible in @c AsmJit::Assembler. +//! - Ability to pre-process or post-process the code which is being generated. +struct X86Compiler : public Compiler +{ + // Special X86 instructions: + // - cpuid, + // - cbw, cwd, cwde, cdq, cdqe, cqo + // - cmpxchg + // - cmpxchg8b, cmpxchg16b, + // - daa, das, + // - imul, mul, idiv, div, + // - mov_ptr + // - lahf, sahf + // - maskmovq, maskmovdqu + // - enter, leave + // - ret + // - monitor, mwait + // - pop, popad, popfd, popfq, + // - push, pushad, pushfd, pushfq + // - rcl, rcr, rol, ror, sal, sar, shl, shr + // - shld, shrd + // - rdtsc. rdtscp + // - lodsb, lodsd, lodsq, lodsw + // - movsb, movsd, movsq, movsw + // - stosb, stosd, stosq, stosw + // - cmpsb, cmpsd, cmpsq, cmpsw + // - scasb, scasd, scasq, scasw + // + // Special X87 instructions: + // - fisttp + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a @ref X86Compiler instance. + ASMJIT_API X86Compiler(Context* context = JitContext::getGlobal()); + //! @brief Destroy the @ref X86Compiler instance. + ASMJIT_API ~X86Compiler(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get current function as @ref X86CompilerFuncDecl. + //! + //! This method can be called within @c newFunc() and @c endFunc() + //! block to get current function you are working with. It's recommended + //! to store @c AsmJit::Function pointer returned by @c newFunc<> method, + //! because this allows you in future implement function sections outside of + //! function itself (yeah, this is possible!). + inline X86CompilerFuncDecl* getFunc() const + { return reinterpret_cast(_func); } + + // -------------------------------------------------------------------------- + // [Function Builder] + // -------------------------------------------------------------------------- + + //! @brief Create a new function. + //! + //! @param cconv Calling convention to use (see @c kX86FuncConv enum) + //! @param params Function arguments prototype. + //! + //! This method is usually used as a first step when generating functions + //! by @c Compiler. First parameter @a cconv specifies function calling + //! convention to use. Second parameter @a params specifies function + //! arguments. To create function arguments are used templates + //! @c BuildFunction0<>, @c BuildFunction1<...>, @c BuildFunction2<...>, + //! etc... + //! + //! Templates with BuildFunction prefix are used to generate argument IDs + //! based on real C++ types. See next example how to generate function with + //! two 32-bit integer arguments. + //! + //! @code + //! // Building function using AsmJit::Compiler example. + //! + //! // Compiler instance + //! X86Compiler c; + //! + //! // Begin of function (also emits function @c Prolog) + //! c.newFunc( + //! // Default calling convention (32-bit cdecl or 64-bit for host OS) + //! kX86FuncConvDefault, + //! // Using function builder to generate arguments list + //! BuildFunction2()); + //! + //! // End of function (also emits function @c Epilog) + //! c.endFunc(); + //! @endcode + //! + //! You can see that building functions is really easy. Previous code snipped + //! will generate code for function with two 32-bit integer arguments. You + //! can access arguments by @c AsmJit::Function::argument() method. Arguments + //! are indexed from 0 (like everything in C). + //! + //! @code + //! // Accessing function arguments through AsmJit::Function example. + //! + //! // Compiler instance + //! X86Compiler c; + //! + //! // Begin of function (also emits function @c Prolog) + //! c.newFunc( + //! // Default calling convention (32-bit cdecl or 64-bit for host OS) + //! kX86FuncConvDefault, + //! // Using function builder to generate arguments list + //! BuildFunction2()); + //! + //! // Arguments are like other variables, you need to reference them by + //! // variable operands: + //! GpVar a0 = c.getGpArg(0); + //! GpVar a1 = c.getGpArg(1); + //! + //! // Use them. + //! c.add(a0, a1); + //! + //! // End of function (emits function epilog and return) + //! c.endFunc(); + //! @endcode + //! + //! Arguments are like variables. How to manipulate with variables is + //! documented in @c AsmJit::Compiler, variables section. + //! + //! @note To get current function use @c currentFunction() method or save + //! pointer to @c AsmJit::Function returned by @c AsmJit::Compiler::newFunc<> + //! method. Recommended is to save the pointer. + //! + //! @sa @c BuildFunction0, @c BuildFunction1, @c BuildFunction2, ... + inline X86CompilerFuncDecl* newFunc(uint32_t convention, const FuncPrototype& func) + { return newFunc_(convention, func.getReturnType(), func.getArguments(), func.getArgumentsCount()); } + + //! @brief Create a new function (low level version). + //! + //! @param cconv Function calling convention (see @c AsmJit::kX86FuncConv). + //! @param args Function arguments (see @c AsmJit::kX86VarType). + //! @param count Arguments count. + //! + //! This method is internally called from @c newFunc() method and + //! contains arguments thats used internally by @c AsmJit::Compiler. + //! + //! @note To get current function use @c currentFunction() method. + ASMJIT_API X86CompilerFuncDecl* newFunc_(uint32_t convenion, uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount); + + //! @brief End of current function scope and all variables. + ASMJIT_API X86CompilerFuncDecl* endFunc(); + + // -------------------------------------------------------------------------- + // [Emit] + // -------------------------------------------------------------------------- + + //! @brief Emit instruction with no operand. + ASMJIT_API void _emitInstruction(uint32_t code); + + //! @brief Emit instruction with one operand. + ASMJIT_API void _emitInstruction(uint32_t code, const Operand* o0); + + //! @brief Emit instruction with two operands. + ASMJIT_API void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1); + + //! @brief Emit instruction with three operands. + ASMJIT_API void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2); + + //! @brief Emit instruction with four operands (Special instructions). + ASMJIT_API void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3); + + //! @brief Emit instruction with five operands (Special instructions). + ASMJIT_API void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3, const Operand* o4); + + //! @brief Private method for emitting jcc. + ASMJIT_API void _emitJcc(uint32_t code, const Label* label, uint32_t hint); + + //! @brief Private method for emitting function call. + ASMJIT_API X86CompilerFuncCall* _emitCall(const Operand* o0); + + //! @brief Private method for returning a value from the function. + ASMJIT_API void _emitReturn(const Operand* first, const Operand* second); + + // -------------------------------------------------------------------------- + // [Align] + // -------------------------------------------------------------------------- + + //! @brief Align target buffer to @a m bytes. + //! + //! Typical usage of this is to align labels at start of the inner loops. + //! + //! Inserts @c nop() instructions or CPU optimized NOPs. + ASMJIT_API void align(uint32_t m); + + // -------------------------------------------------------------------------- + // [Label] + // -------------------------------------------------------------------------- + + //! @brief Create and return new label. + ASMJIT_API Label newLabel(); + + //! @brief Bind label to the current offset. + //! + //! @note Label can be bound only once! + ASMJIT_API void bind(const Label& label); + + // -------------------------------------------------------------------------- + // [Variables] + // -------------------------------------------------------------------------- + + //! @brief Get compiler variable at @a id. + inline X86CompilerVar* _getVar(uint32_t id) const + { + ASMJIT_ASSERT(id != kInvalidValue); + return reinterpret_cast(_vars[id & kOperandIdValueMask]); + } + + //! @internal + //! + //! @brief Create a new variable data. + ASMJIT_API X86CompilerVar* _newVar(const char* name, uint32_t type, uint32_t size); + + //! @brief Create a new general-purpose variable. + ASMJIT_API GpVar newGpVar(uint32_t varType = kX86VarTypeGpz, const char* name = NULL); + //! @brief Get argument as general-purpose variable. + ASMJIT_API GpVar getGpArg(uint32_t argIndex); + + //! @brief Create a new MM variable. + ASMJIT_API MmVar newMmVar(uint32_t varType = kX86VarTypeMm, const char* name = NULL); + //! @brief Get argument as MM variable. + ASMJIT_API MmVar getMmArg(uint32_t argIndex); + + //! @brief Create a new XMM variable. + ASMJIT_API XmmVar newXmmVar(uint32_t varType = kX86VarTypeXmm, const char* name = NULL); + //! @brief Get argument as XMM variable. + ASMJIT_API XmmVar getXmmArg(uint32_t argIndex); + + //! @internal + //! + //! @brief Serialize variable hint. + ASMJIT_API void _vhint(Var& var, uint32_t hintId, uint32_t hintValue); + + //! @brief Alloc variable @a var. + ASMJIT_API void alloc(Var& var); + //! @brief Alloc variable @a var using @a regIndex as a register index. + ASMJIT_API void alloc(Var& var, uint32_t regIndex); + //! @brief Alloc variable @a var using @a reg as a demanded register. + ASMJIT_API void alloc(Var& var, const Reg& reg); + //! @brief Spill variable @a var. + ASMJIT_API void spill(Var& var); + //! @brief Save variable @a var if modified. + ASMJIT_API void save(Var& var); + //! @brief Unuse variable @a var. + ASMJIT_API void unuse(Var& var); + + //! @brief Get memory home of variable @a var. + ASMJIT_API void getMemoryHome(Var& var, GpVar* home, int* displacement = NULL); + + //! @brief Set memory home of variable @a var. + //! + //! Default memory home location is on stack (ESP/RSP), but when needed the + //! bebahior can be changed by this method. + //! + //! It is an error to chaining memory home locations. For example the given + //! code is invalid: + //! + //! @code + //! X86Compiler c; + //! + //! ... + //! GpVar v0 = c.newGpVar(); + //! GpVar v1 = c.newGpVar(); + //! GpVar v2 = c.newGpVar(); + //! GpVar v3 = c.newGpVar(); + //! + //! c.setMemoryHome(v1, v0, 0); // Allowed, [v0] is memory home for v1. + //! c.setMemoryHome(v2, v0, 4); // Allowed, [v0+4] is memory home for v2. + //! c.setMemoryHome(v3, v2); // CHAINING, NOT ALLOWED! + //! @endcode + ASMJIT_API void setMemoryHome(Var& var, const GpVar& home, int displacement = 0); + + //! @brief Get priority of variable @a var. + ASMJIT_API uint32_t getPriority(Var& var) const; + //! @brief Set priority of variable @a var to @a priority. + ASMJIT_API void setPriority(Var& var, uint32_t priority); + + //! @brief Get save-on-unuse @a var property. + ASMJIT_API bool getSaveOnUnuse(Var& var) const; + //! @brief Set save-on-unuse @a var property to @a value. + ASMJIT_API void setSaveOnUnuse(Var& var, bool value); + + //! @brief Rename variable @a var to @a name. + //! + //! @note Only new name will appear in the logger. + ASMJIT_API void rename(Var& var, const char* name); + + // -------------------------------------------------------------------------- + // [State] + // -------------------------------------------------------------------------- + + //! @internal + //! + //! @brief Create a new @ref X86CompilerState. + ASMJIT_API X86CompilerState* _newState(uint32_t memVarsCount); + + // -------------------------------------------------------------------------- + // [Make] + // -------------------------------------------------------------------------- + + //! @brief Make is convenience method to make currently serialized code and + //! return pointer to generated function. + //! + //! What you need is only to cast this pointer to your function type and call + //! it. Note that if there was an error and calling @c getError() method doesn't + //! return @c kErrorOk (zero) then this function always returns @c NULL and + //! error value remains the same. + ASMJIT_API virtual void* make(); + + //! @brief Method that will emit everything to @c Assembler instance @a a. + ASMJIT_API virtual void serialize(Assembler& a); + + // -------------------------------------------------------------------------- + // [Data] + // -------------------------------------------------------------------------- + + //! @brief Get target from label @a id. + inline X86CompilerTarget* _getTarget(uint32_t id) + { + ASMJIT_ASSERT((id & kOperandIdTypeMask) == kOperandIdTypeLabel); + return reinterpret_cast(_targets[id & kOperandIdValueMask]); + } + + // -------------------------------------------------------------------------- + // [Embed] + // -------------------------------------------------------------------------- + + //! @brief Add 8-bit integer data to the instuction stream. + inline void db(uint8_t x) { embed(&x, 1); } + //! @brief Add 16-bit integer data to the instuction stream. + inline void dw(uint16_t x) { embed(&x, 2); } + //! @brief Add 32-bit integer data to the instuction stream. + inline void dd(uint32_t x) { embed(&x, 4); } + //! @brief Add 64-bit integer data to the instuction stream. + inline void dq(uint64_t x) { embed(&x, 8); } + + //! @brief Add 8-bit integer data to the instuction stream. + inline void dint8(int8_t x) { embed(&x, sizeof(int8_t)); } + //! @brief Add 8-bit integer data to the instuction stream. + inline void duint8(uint8_t x) { embed(&x, sizeof(uint8_t)); } + + //! @brief Add 16-bit integer data to the instuction stream. + inline void dint16(int16_t x) { embed(&x, sizeof(int16_t)); } + //! @brief Add 16-bit integer data to the instuction stream. + inline void duint16(uint16_t x) { embed(&x, sizeof(uint16_t)); } + + //! @brief Add 32-bit integer data to the instuction stream. + inline void dint32(int32_t x) { embed(&x, sizeof(int32_t)); } + //! @brief Add 32-bit integer data to the instuction stream. + inline void duint32(uint32_t x) { embed(&x, sizeof(uint32_t)); } + + //! @brief Add 64-bit integer data to the instuction stream. + inline void dint64(int64_t x) { embed(&x, sizeof(int64_t)); } + //! @brief Add 64-bit integer data to the instuction stream. + inline void duint64(uint64_t x) { embed(&x, sizeof(uint64_t)); } + + //! @brief Add system-integer data to the instuction stream. + inline void dintptr(intptr_t x) { embed(&x, sizeof(intptr_t)); } + //! @brief Add system-integer data to the instuction stream. + inline void duintptr(uintptr_t x) { embed(&x, sizeof(uintptr_t)); } + + //! @brief Add float data to the instuction stream. + inline void dfloat(float x) { embed(&x, sizeof(float)); } + //! @brief Add double data to the instuction stream. + inline void ddouble(double x) { embed(&x, sizeof(double)); } + + //! @brief Add pointer data to the instuction stream. + inline void dptr(void* x) { embed(&x, sizeof(void*)); } + + //! @brief Add MM data to the instuction stream. + inline void dmm(const MmData& x) { embed(&x, sizeof(MmData)); } + //! @brief Add XMM data to the instuction stream. + inline void dxmm(const XmmData& x) { embed(&x, sizeof(XmmData)); } + + //! @brief Add data to the instuction stream. + inline void data(const void* data, size_t size) { embed(data, size); } + + //! @brief Add data in a given structure instance to the instuction stream. + template + inline void dstruct(const T& x) { embed(&x, sizeof(T)); } + + // -------------------------------------------------------------------------- + // [Custom Instructions] + // -------------------------------------------------------------------------- + + // These emitters are used by custom compiler code (register alloc / spill, + // prolog / epilog generator, ...). + + inline void emit(uint32_t code) + { _emitInstruction(code); } + + inline void emit(uint32_t code, const Operand& o0) + { _emitInstruction(code, &o0); } + + inline void emit(uint32_t code, const Operand& o0, const Operand& o1) + { _emitInstruction(code, &o0, &o1); } + + inline void emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) + { _emitInstruction(code, &o0, &o1, &o2); } + + // -------------------------------------------------------------------------- + // [X86 Instructions] + // -------------------------------------------------------------------------- + + //! @brief Add with Carry. + inline void adc(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstAdc, &dst, &src); } + + //! @brief Add with Carry. + inline void adc(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstAdc, &dst, &src); } + + //! @brief Add with Carry. + inline void adc(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstAdc, &dst, &src); } + + //! @brief Add with Carry. + inline void adc(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstAdc, &dst, &src); } + + //! @brief Add with Carry. + inline void adc(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstAdc, &dst, &src); } + + //! @brief Add. + inline void add(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstAdd, &dst, &src); } + + //! @brief Add. + inline void add(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstAdd, &dst, &src); } + + //! @brief Add. + inline void add(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstAdd, &dst, &src); } + + //! @brief Add. + inline void add(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstAdd, &dst, &src); } + + //! @brief Add. + inline void add(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstAdd, &dst, &src); } + + //! @brief Logical And. + inline void and_(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstAnd, &dst, &src); } + + //! @brief Logical And. + inline void and_(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstAnd, &dst, &src); } + + //! @brief Logical And. + inline void and_(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstAnd, &dst, &src); } + + //! @brief Logical And. + inline void and_(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstAnd, &dst, &src); } + + //! @brief Logical And. + inline void and_(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstAnd, &dst, &src); } + + //! @brief Bit Scan Forward. + inline void bsf(const GpVar& dst, const GpVar& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + _emitInstruction(kX86InstBsf, &dst, &src); + } + + //! @brief Bit Scan Forward. + inline void bsf(const GpVar& dst, const Mem& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + _emitInstruction(kX86InstBsf, &dst, &src); + } + + //! @brief Bit Scan Reverse. + inline void bsr(const GpVar& dst, const GpVar& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + _emitInstruction(kX86InstBsr, &dst, &src); + } + + //! @brief Bit Scan Reverse. + inline void bsr(const GpVar& dst, const Mem& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + _emitInstruction(kX86InstBsr, &dst, &src); + } + + //! @brief Byte swap (32-bit or 64-bit registers only) (i486). + inline void bswap(const GpVar& dst) + { + // ASMJIT_ASSERT(dst.getRegType() == kX86RegGPD || dst.getRegType() == kX86RegGPQ); + _emitInstruction(kX86InstBSwap, &dst); + } + + //! @brief Bit test. + inline void bt(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstBt, &dst, &src); } + + //! @brief Bit test. + inline void bt(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstBt, &dst, &src); } + + //! @brief Bit test. + inline void bt(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstBt, &dst, &src); } + + //! @brief Bit test. + inline void bt(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstBt, &dst, &src); } + + //! @brief Bit test and complement. + inline void btc(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstBtc, &dst, &src); } + + //! @brief Bit test and complement. + inline void btc(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstBtc, &dst, &src); } + + //! @brief Bit test and complement. + inline void btc(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstBtc, &dst, &src); } + + //! @brief Bit test and complement. + inline void btc(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstBtc, &dst, &src); } + + //! @brief Bit test and reset. + inline void btr(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstBtr, &dst, &src); } + + //! @brief Bit test and reset. + inline void btr(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstBtr, &dst, &src); } + + //! @brief Bit test and reset. + inline void btr(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstBtr, &dst, &src); } + + //! @brief Bit test and reset. + inline void btr(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstBtr, &dst, &src); } + + //! @brief Bit test and set. + inline void bts(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstBts, &dst, &src); } + + //! @brief Bit test and set. + inline void bts(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstBts, &dst, &src); } + + //! @brief Bit test and set. + inline void bts(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstBts, &dst, &src); } + + //! @brief Bit test and set. + inline void bts(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstBts, &dst, &src); } + + //! @brief Call Procedure. + inline X86CompilerFuncCall* call(const GpVar& dst) + { return _emitCall(&dst); } + + //! @brief Call Procedure. + inline X86CompilerFuncCall* call(const Mem& dst) + { return _emitCall(&dst); } + + //! @brief Call Procedure. + inline X86CompilerFuncCall* call(const Imm& dst) + { return _emitCall(&dst); } + + //! @brief Call Procedure. + //! @overload + inline X86CompilerFuncCall* call(void* dst) + { + Imm imm((sysint_t)dst); + return _emitCall(&imm); + } + + //! @brief Call Procedure. + inline X86CompilerFuncCall* call(const Label& label) + { return _emitCall(&label); } + + //! @brief Convert Byte to Word (Sign Extend). + inline void cbw(const GpVar& dst) + { _emitInstruction(kX86InstCbw, &dst); } + + //! @brief Convert Word to DWord (Sign Extend). + inline void cwd(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstCwd, &dst, &src); } + + //! @brief Convert Word to DWord (Sign Extend). + inline void cwde(const GpVar& dst) + { _emitInstruction(kX86InstCwde, &dst); } + + //! @brief Convert Word to DWord (Sign Extend). + inline void cdq(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstCdq, &dst, &src); } + +#if defined(ASMJIT_X64) + //! @brief Convert DWord to QWord (Sign Extend). + inline void cdqe(const GpVar& dst) + { _emitInstruction(kX86InstCdqe, &dst); } +#endif // ASMJIT_X64 + +#if defined(ASMJIT_X64) + //! @brief Convert QWord to DQWord (Sign Extend). + inline void cqo(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstCqo, &dst, &src); } +#endif // ASMJIT_X64 + + //! @brief Clear Carry flag + //! + //! This instruction clears the CF flag in the EFLAGS register. + inline void clc() + { _emitInstruction(kX86InstClc); } + + //! @brief Clear Direction flag + //! + //! This instruction clears the DF flag in the EFLAGS register. + inline void cld() + { _emitInstruction(kX86InstCld); } + + //! @brief Complement Carry Flag. + //! + //! This instruction complements the CF flag in the EFLAGS register. + //! (CF = NOT CF) + inline void cmc() + { _emitInstruction(kX86InstCmc); } + + //! @brief Conditional Move. + inline void cmov(kX86Cond cc, const GpVar& dst, const GpVar& src) + { _emitInstruction(X86Util::getCMovccInstFromCond(cc), &dst, &src); } + + //! @brief Conditional Move. + inline void cmov(kX86Cond cc, const GpVar& dst, const Mem& src) + { _emitInstruction(X86Util::getCMovccInstFromCond(cc), &dst, &src); } + + //! @brief Conditional Move. + inline void cmova (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovA , &dst, &src); } + //! @brief Conditional Move. + inline void cmova (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovA , &dst, &src); } + //! @brief Conditional Move. + inline void cmovae (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovAE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovae (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovAE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovb (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovb (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovbe (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovBE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovbe (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovBE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovc (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovC , &dst, &src); } + //! @brief Conditional Move. + inline void cmovc (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovC , &dst, &src); } + //! @brief Conditional Move. + inline void cmove (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovE , &dst, &src); } + //! @brief Conditional Move. + inline void cmove (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovg (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovg (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovge (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovGE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovge (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovGE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovl (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovl (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovle (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovLE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovle (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovLE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovna (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNA , &dst, &src); } + //! @brief Conditional Move. + inline void cmovna (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNA , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnae(const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNAE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnae(const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNAE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnb (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnb (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnbe(const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNBE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnbe(const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNBE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnc (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNC , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnc (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNC , &dst, &src); } + //! @brief Conditional Move. + inline void cmovne (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovne (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovng (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovng (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnge(const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNGE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnge(const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNGE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnl (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnl (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnle(const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNLE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnle(const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNLE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovno (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovno (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnp (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnp (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovns (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovns (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnz (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovNZ , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnz (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovNZ , &dst, &src); } + //! @brief Conditional Move. + inline void cmovo (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovo (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovp (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovp (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpe (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovPE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpe (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovPE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpo (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovPO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpo (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovPO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovs (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovs (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovz (const GpVar& dst, const GpVar& src) { _emitInstruction(kX86InstCMovZ , &dst, &src); } + //! @brief Conditional Move. + inline void cmovz (const GpVar& dst, const Mem& src) { _emitInstruction(kX86InstCMovZ , &dst, &src); } + + //! @brief Compare Two Operands. + inline void cmp(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstCmp, &dst, &src); } + + //! @brief Compare Two Operands. + inline void cmp(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstCmp, &dst, &src); } + + //! @brief Compare Two Operands. + inline void cmp(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstCmp, &dst, &src); } + + //! @brief Compare Two Operands. + inline void cmp(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstCmp, &dst, &src); } + + //! @brief Compare Two Operands. + inline void cmp(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstCmp, &dst, &src); } + + //! @brief Compare and Exchange (i486). + inline void cmpxchg(const GpVar cmp_1_eax, const GpVar& cmp_2, const GpVar& src) + { + ASMJIT_ASSERT(cmp_1_eax.getId() != src.getId()); + _emitInstruction(kX86InstCmpXCHG, &cmp_1_eax, &cmp_2, &src); + } + + //! @brief Compare and Exchange (i486). + inline void cmpxchg(const GpVar cmp_1_eax, const Mem& cmp_2, const GpVar& src) + { + ASMJIT_ASSERT(cmp_1_eax.getId() != src.getId()); + _emitInstruction(kX86InstCmpXCHG, &cmp_1_eax, &cmp_2, &src); + } + + //! @brief Compares the 64-bit value in EDX:EAX with the memory operand (Pentium). + //! + //! If the values are equal, then this instruction stores the 64-bit value + //! in ECX:EBX into the memory operand and sets the zero flag. Otherwise, + //! this instruction copies the 64-bit memory operand into the EDX:EAX + //! registers and clears the zero flag. + inline void cmpxchg8b( + const GpVar& cmp_edx, const GpVar& cmp_eax, + const GpVar& cmp_ecx, const GpVar& cmp_ebx, + const Mem& dst) + { + ASMJIT_ASSERT(cmp_edx.getId() != cmp_eax.getId() && + cmp_eax.getId() != cmp_ecx.getId() && + cmp_ecx.getId() != cmp_ebx.getId()); + + _emitInstruction(kX86InstCmpXCHG8B, &cmp_edx, &cmp_eax, &cmp_ecx, &cmp_ebx, &dst); + } + +#if defined(ASMJIT_X64) + //! @brief Compares the 128-bit value in RDX:RAX with the memory operand (X64). + //! + //! If the values are equal, then this instruction stores the 128-bit value + //! in RCX:RBX into the memory operand and sets the zero flag. Otherwise, + //! this instruction copies the 128-bit memory operand into the RDX:RAX + //! registers and clears the zero flag. + inline void cmpxchg16b( + const GpVar& cmp_edx, const GpVar& cmp_eax, + const GpVar& cmp_ecx, const GpVar& cmp_ebx, + const Mem& dst) + { + ASMJIT_ASSERT(cmp_edx.getId() != cmp_eax.getId() && + cmp_eax.getId() != cmp_ecx.getId() && + cmp_ecx.getId() != cmp_ebx.getId()); + + _emitInstruction(kX86InstCmpXCHG16B, &cmp_edx, &cmp_eax, &cmp_ecx, &cmp_ebx, &dst); + } +#endif // ASMJIT_X64 + + //! @brief CPU Identification (i486). + inline void cpuid( + const GpVar& inout_eax, + const GpVar& out_ebx, + const GpVar& out_ecx, + const GpVar& out_edx) + { + // Destination variables must be different. + ASMJIT_ASSERT(inout_eax.getId() != out_ebx.getId() && + out_ebx.getId() != out_ecx.getId() && + out_ecx.getId() != out_edx.getId()); + + _emitInstruction(kX86InstCpuId, &inout_eax, &out_ebx, &out_ecx, &out_edx); + } + +#if defined(ASMJIT_X86) + inline void daa(const GpVar& dst) + { _emitInstruction(kX86InstDaa, &dst); } +#endif // ASMJIT_X86 + +#if defined(ASMJIT_X86) + inline void das(const GpVar& dst) + { _emitInstruction(kX86InstDas, &dst); } +#endif // ASMJIT_X86 + + //! @brief Decrement by 1. + //! @note This instruction can be slower than sub(dst, 1) + inline void dec(const GpVar& dst) + { _emitInstruction(kX86InstDec, &dst); } + + //! @brief Decrement by 1. + //! @note This instruction can be slower than sub(dst, 1) + inline void dec(const Mem& dst) + { _emitInstruction(kX86InstDec, &dst); } + + //! @brief Unsigned divide. + //! + //! This instruction divides (unsigned) the value in the AL, AX, or EAX + //! register by the source operand and stores the result in the AX, + //! DX:AX, or EDX:EAX registers. + inline void div(const GpVar& dst_rem, const GpVar& dst_quot, const GpVar& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_rem.getId() != dst_quot.getId()); + _emitInstruction(kX86InstDiv, &dst_rem, &dst_quot, &src); + } + + //! @brief Unsigned divide. + //! @overload + inline void div(const GpVar& dst_rem, const GpVar& dst_quot, const Mem& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_rem.getId() != dst_quot.getId()); + _emitInstruction(kX86InstDiv, &dst_rem, &dst_quot, &src); + } + +#if ASMJIT_NOT_SUPPORTED_BY_COMPILER + //! @brief Make Stack Frame for Procedure Parameters. + inline void enter(const Imm& imm16, const Imm& imm8) + { _emitInstruction(kX86InstEnter, &imm16, &imm8); } +#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER + + //! @brief Signed divide. + //! + //! This instruction divides (signed) the value in the AL, AX, or EAX + //! register by the source operand and stores the result in the AX, + //! DX:AX, or EDX:EAX registers. + inline void idiv(const GpVar& dst_rem, const GpVar& dst_quot, const GpVar& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_rem.getId() != dst_quot.getId()); + _emitInstruction(kX86InstIDiv, &dst_rem, &dst_quot, &src); + } + + //! @brief Signed divide. + //! @overload + inline void idiv(const GpVar& dst_rem, const GpVar& dst_quot, const Mem& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_rem.getId() != dst_quot.getId()); + _emitInstruction(kX86InstIDiv, &dst_rem, &dst_quot, &src); + } + + //! @brief Signed multiply. + //! + //! [dst_lo:dst_hi] = dst_hi * src. + inline void imul(const GpVar& dst_hi, const GpVar& dst_lo, const GpVar& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_hi.getId() != dst_lo.getId()); + _emitInstruction(kX86InstIMul, &dst_hi, &dst_lo, &src); + } + + //! @overload + inline void imul(const GpVar& dst_hi, const GpVar& dst_lo, const Mem& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_hi.getId() != dst_lo.getId()); + _emitInstruction(kX86InstIMul, &dst_hi, &dst_lo, &src); + } + + //! @brief Signed multiply. + //! + //! Destination operand (the first operand) is multiplied by the source + //! operand (second operand). The destination operand is a general-purpose + //! register and the source operand is an immediate value, a general-purpose + //! register, or a memory location. The product is then stored in the + //! destination operand location. + inline void imul(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstIMul, &dst, &src); } + + //! @brief Signed multiply. + //! @overload + inline void imul(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstIMul, &dst, &src); } + + //! @brief Signed multiply. + //! @overload + inline void imul(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstIMul, &dst, &src); } + + //! @brief Signed multiply. + //! + //! source operand (which can be a general-purpose register or a memory + //! location) is multiplied by the second source operand (an immediate + //! value). The product is then stored in the destination operand + //! (a general-purpose register). + inline void imul(const GpVar& dst, const GpVar& src, const Imm& imm) + { _emitInstruction(kX86InstIMul, &dst, &src, &imm); } + + //! @overload + inline void imul(const GpVar& dst, const Mem& src, const Imm& imm) + { _emitInstruction(kX86InstIMul, &dst, &src, &imm); } + + //! @brief Increment by 1. + //! @note This instruction can be slower than add(dst, 1) + inline void inc(const GpVar& dst) + { _emitInstruction(kX86InstInc, &dst); } + + //! @brief Increment by 1. + //! @note This instruction can be slower than add(dst, 1) + inline void inc(const Mem& dst) + { _emitInstruction(kX86InstInc, &dst); } + + //! @brief Interrupt 3 - trap to debugger. + inline void int3() + { _emitInstruction(kX86InstInt3); } + + //! @brief Jump to label @a label if condition @a cc is met. + //! + //! This instruction checks the state of one or more of the status flags in + //! the EFLAGS register (CF, OF, PF, SF, and ZF) and, if the flags are in the + //! specified state (condition), performs a jump to the target instruction + //! specified by the destination operand. A condition code (cc) is associated + //! with each instruction to indicate the condition being tested for. If the + //! condition is not satisfied, the jump is not performed and execution + //! continues with the instruction following the Jcc instruction. + inline void j(kX86Cond cc, const Label& label, uint32_t hint = kCondHintNone) + { _emitJcc(X86Util::getJccInstFromCond(cc), &label, hint); } + + //! @brief Jump to label @a label if condition is met. + inline void ja (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJA , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jae (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJAE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jb (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJB , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jbe (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJBE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jc (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJC , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void je (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jg (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJG , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jge (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJGE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jl (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJL , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jle (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJLE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jna (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNA , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnae(const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNAE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnb (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNB , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnbe(const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNBE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnc (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNC , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jne (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jng (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNG , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnge(const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNGE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnl (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNL , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnle(const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNLE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jno (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNO , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnp (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNP , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jns (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNS , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnz (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJNZ , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jo (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJO , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jp (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJP , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jpe (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJPE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jpo (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJPO , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void js (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJS , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jz (const Label& label, uint32_t hint = kCondHintNone) { _emitJcc(kX86InstJZ , &label, hint); } + + //! @brief Jump. + //! @overload + inline void jmp(const GpVar& dst) + { _emitInstruction(kX86InstJmp, &dst); } + + //! @brief Jump. + //! @overload + inline void jmp(const Mem& dst) + { _emitInstruction(kX86InstJmp, &dst); } + + //! @brief Jump. + //! @overload + inline void jmp(const Imm& dst) + { _emitInstruction(kX86InstJmp, &dst); } + + //! @brief Jump. + //! @overload + inline void jmp(void* dst) + { + Imm imm((sysint_t)dst); + _emitInstruction(kX86InstJmp, &imm); + } + + //! @brief Jump. + //! + //! This instruction transfers program control to a different point + //! in the instruction stream without recording return information. + //! The destination (target) operand specifies the label of the + //! instruction being jumped to. + inline void jmp(const Label& label) + { _emitInstruction(kX86InstJmp, &label); } + + //! @brief Load Effective Address + //! + //! This instruction computes the effective address of the second + //! operand (the source operand) and stores it in the first operand + //! (destination operand). The source operand is a memory address + //! (offset part) specified with one of the processors addressing modes. + //! The destination operand is a general-purpose register. + inline void lea(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstLea, &dst, &src); } + +#if ASMJIT_NOT_SUPPORTED_BY_COMPILER + //! @brief High Level Procedure Exit. + inline void leave() + { _emitInstruction(kX86InstLeave); } +#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER + + //! @brief Move. + //! + //! This instruction copies the second operand (source operand) to the first + //! operand (destination operand). The source operand can be an immediate + //! value, general-purpose register, segment register, or memory location. + //! The destination register can be a general-purpose register, segment + //! register, or memory location. Both operands must be the same size, which + //! can be a byte, a word, or a DWORD. + //! + //! @note To move MMX or SSE registers to/from GP registers or memory, use + //! corresponding functions: @c movd(), @c movq(), etc. Passing MMX or SSE + //! registers to @c mov() is illegal. + inline void mov(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move. + //! @overload + inline void mov(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move. + //! @overload + inline void mov(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move. + //! @overload + inline void mov(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move. + //! @overload + inline void mov(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move from segment register. + //! @overload. + inline void mov(const GpVar& dst, const SegmentReg& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move from segment register. + //! @overload. + inline void mov(const Mem& dst, const SegmentReg& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move to segment register. + //! @overload. + inline void mov(const SegmentReg& dst, const GpVar& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move to segment register. + //! @overload. + inline void mov(const SegmentReg& dst, const Mem& src) + { _emitInstruction(kX86InstMov, &dst, &src); } + + //! @brief Move byte, word, dword or qword from absolute address @a src to + //! AL, AX, EAX or RAX register. + inline void mov_ptr(const GpVar& dst, void* src) + { + Imm imm((sysint_t)src); + _emitInstruction(kX86InstMovPtr, &dst, &imm); + } + + //! @brief Move byte, word, dword or qword from AL, AX, EAX or RAX register + //! to absolute address @a dst. + inline void mov_ptr(void* dst, const GpVar& src) + { + Imm imm((sysint_t)dst); + _emitInstruction(kX86InstMovPtr, &imm, &src); + } + + //! @brief Move with Sign-Extension. + //! + //! This instruction copies the contents of the source operand (register + //! or memory location) to the destination operand (register) and sign + //! extends the value to 16, 32 or 64-bits. + //! + //! @sa movsxd(). + void movsx(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstMovSX, &dst, &src); } + + //! @brief Move with Sign-Extension. + //! @overload + void movsx(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovSX, &dst, &src); } + +#if defined(ASMJIT_X64) + //! @brief Move DWord to QWord with sign-extension. + inline void movsxd(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstMovSXD, &dst, &src); } + + //! @brief Move DWord to QWord with sign-extension. + //! @overload + inline void movsxd(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovSXD, &dst, &src); } +#endif // ASMJIT_X64 + + //! @brief Move with Zero-Extend. + //! + //! This instruction copies the contents of the source operand (register + //! or memory location) to the destination operand (register) and zero + //! extends the value to 16 or 32-bits. The size of the converted value + //! depends on the operand-size attribute. + inline void movzx(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstMovZX, &dst, &src); } + + //! @brief Move with Zero-Extend. + //! @brief Overload + inline void movzx(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovZX, &dst, &src); } + + //! @brief Unsigned multiply. + //! + //! Source operand (in a general-purpose register or memory location) + //! is multiplied by the value in the AL, AX, or EAX register (depending + //! on the operand size) and the product is stored in the AX, DX:AX, or + //! EDX:EAX registers, respectively. + inline void mul(const GpVar& dst_hi, const GpVar& dst_lo, const GpVar& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_hi.getId() != dst_lo.getId()); + _emitInstruction(kX86InstMul, &dst_hi, &dst_lo, &src); + } + + //! @brief Unsigned multiply. + //! @overload + inline void mul(const GpVar& dst_hi, const GpVar& dst_lo, const Mem& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_hi.getId() != dst_lo.getId()); + _emitInstruction(kX86InstMul, &dst_hi, &dst_lo, &src); + } + + //! @brief Two's Complement Negation. + inline void neg(const GpVar& dst) + { _emitInstruction(kX86InstNeg, &dst); } + + //! @brief Two's Complement Negation. + inline void neg(const Mem& dst) + { _emitInstruction(kX86InstNeg, &dst); } + + //! @brief No Operation. + //! + //! This instruction performs no operation. This instruction is a one-byte + //! instruction that takes up space in the instruction stream but does not + //! affect the machine context, except the EIP register. The NOP instruction + //! is an alias mnemonic for the XCHG (E)AX, (E)AX instruction. + inline void nop() + { _emitInstruction(kX86InstNop); } + + //! @brief One's Complement Negation. + inline void not_(const GpVar& dst) + { _emitInstruction(kX86InstNot, &dst); } + + //! @brief One's Complement Negation. + inline void not_(const Mem& dst) + { _emitInstruction(kX86InstNot, &dst); } + + //! @brief Logical Inclusive OR. + inline void or_(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstOr, &dst, &src); } + + //! @brief Logical Inclusive OR. + inline void or_(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstOr, &dst, &src); } + + //! @brief Logical Inclusive OR. + inline void or_(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstOr, &dst, &src); } + + //! @brief Logical Inclusive OR. + inline void or_(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstOr, &dst, &src); } + + //! @brief Logical Inclusive OR. + inline void or_(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstOr, &dst, &src); } + + //! @brief Pop a Value from the Stack. + //! + //! This instruction loads the value from the top of the stack to the location + //! specified with the destination operand and then increments the stack pointer. + //! The destination operand can be a general purpose register, memory location, + //! or segment register. + inline void pop(const GpVar& dst) + { _emitInstruction(kX86InstPop, &dst); } + + inline void pop(const Mem& dst) + { + ASMJIT_ASSERT(dst.getSize() == 2 || dst.getSize() == sizeof(sysint_t)); + _emitInstruction(kX86InstPop, &dst); + } + +#if defined(ASMJIT_X86) + //! @brief Pop All General-Purpose Registers. + //! + //! Pop EDI, ESI, EBP, EBX, EDX, ECX, and EAX. + inline void popad() + { _emitInstruction(kX86InstPopAD); } +#endif // ASMJIT_X86 + + //! @brief Pop Stack into EFLAGS Register (32-bit or 64-bit). + inline void popf() + { +#if defined(ASMJIT_X86) + popfd(); +#else + popfq(); +#endif + } + +#if defined(ASMJIT_X86) + //! @brief Pop Stack into EFLAGS Register (32-bit). + inline void popfd() + { _emitInstruction(kX86InstPopFD); } +#else + //! @brief Pop Stack into EFLAGS Register (64-bit). + inline void popfq() + { _emitInstruction(kX86InstPopFQ); } +#endif + + //! @brief Push WORD/DWORD/QWORD Onto the Stack. + //! + //! @note 32-bit architecture pushed DWORD while 64-bit + //! pushes QWORD. 64-bit mode not provides instruction to + //! push 32-bit register/memory. + inline void push(const GpVar& src) + { _emitInstruction(kX86InstPush, &src); } + + //! @brief Push WORD/DWORD/QWORD Onto the Stack. + inline void push(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == sizeof(sysint_t)); + _emitInstruction(kX86InstPush, &src); + } + + //! @brief Push WORD/DWORD/QWORD Onto the Stack. + inline void push(const Imm& src) + { _emitInstruction(kX86InstPush, &src); } + +#if defined(ASMJIT_X86) + //! @brief Push All General-Purpose Registers. + //! + //! Push EAX, ECX, EDX, EBX, original ESP, EBP, ESI, and EDI. + inline void pushad() + { _emitInstruction(kX86InstPushAD); } +#endif // ASMJIT_X86 + + //! @brief Push EFLAGS Register (32-bit or 64-bit) onto the Stack. + inline void pushf() + { +#if defined(ASMJIT_X86) + pushfd(); +#else + pushfq(); +#endif + } + +#if defined(ASMJIT_X86) + //! @brief Push EFLAGS Register (32-bit) onto the Stack. + inline void pushfd() + { _emitInstruction(kX86InstPushFD); } +#else + //! @brief Push EFLAGS Register (64-bit) onto the Stack. + inline void pushfq() + { _emitInstruction(kX86InstPushFQ); } +#endif // ASMJIT_X86 + + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rcl(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstRcl, &dst, &src); } + + //! @brief Rotate Bits Left. + inline void rcl(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstRcl, &dst, &src); } + + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rcl(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstRcl, &dst, &src); } + + //! @brief Rotate Bits Left. + inline void rcl(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstRcl, &dst, &src); } + + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void rcr(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstRcr, &dst, &src); } + + //! @brief Rotate Bits Right. + inline void rcr(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstRcr, &dst, &src); } + + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void rcr(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstRcr, &dst, &src); } + + //! @brief Rotate Bits Right. + inline void rcr(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstRcr, &dst, &src); } + + //! @brief Read Time-Stamp Counter (Pentium). + inline void rdtsc(const GpVar& dst_edx, const GpVar& dst_eax) + { + // Destination registers must be different. + ASMJIT_ASSERT(dst_edx.getId() != dst_eax.getId()); + _emitInstruction(kX86InstRdtsc, &dst_edx, &dst_eax); + } + + //! @brief Read Time-Stamp Counter and Processor ID (New). + inline void rdtscp(const GpVar& dst_edx, const GpVar& dst_eax, const GpVar& dst_ecx) + { + // Destination registers must be different. + ASMJIT_ASSERT(dst_edx.getId() != dst_eax.getId() && dst_eax.getId() != dst_ecx.getId()); + _emitInstruction(kX86InstRdtscP, &dst_edx, &dst_eax, &dst_ecx); + } + + //! @brief Load ECX/RCX BYTEs from DS:[ESI/RSI] to AL. + inline void rep_lodsb(const GpVar& dst_val, const GpVar& src_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepLodSB, &dst_val, &src_addr, &cnt_ecx); + } + + //! @brief Load ECX/RCX DWORDs from DS:[ESI/RSI] to EAX. + inline void rep_lodsd(const GpVar& dst_val, const GpVar& src_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepLodSD, &dst_val, &src_addr, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Load ECX/RCX QWORDs from DS:[ESI/RSI] to RAX. + inline void rep_lodsq(const GpVar& dst_val, const GpVar& src_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepLodSQ, &dst_val, &src_addr, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Load ECX/RCX WORDs from DS:[ESI/RSI] to AX. + inline void rep_lodsw(const GpVar& dst_val, const GpVar& src_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepLodSW, &dst_val, &src_addr, &cnt_ecx); + } + + //! @brief Move ECX/RCX BYTEs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsb(const GpVar& dst_addr, const GpVar& src_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepMovSB, &dst_addr, &src_addr, &cnt_ecx); + } + + //! @brief Move ECX/RCX DWORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsd(const GpVar& dst_addr, const GpVar& src_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepMovSD, &dst_addr, &src_addr, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Move ECX/RCX QWORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsq(const GpVar& dst_addr, const GpVar& src_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepMovSQ, &dst_addr, &src_addr, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Move ECX/RCX WORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsw(const GpVar& dst_addr, const GpVar& src_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepMovSW, &dst_addr, &src_addr, &cnt_ecx); + } + + //! @brief Fill ECX/RCX BYTEs at ES:[EDI/RDI] with AL. + inline void rep_stosb(const GpVar& dst_addr, const GpVar& src_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepStoSB, &dst_addr, &src_val, &cnt_ecx); + } + + //! @brief Fill ECX/RCX DWORDs at ES:[EDI/RDI] with EAX. + inline void rep_stosd(const GpVar& dst_addr, const GpVar& src_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepStoSD, &dst_addr, &src_val, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Fill ECX/RCX QWORDs at ES:[EDI/RDI] with RAX. + inline void rep_stosq(const GpVar& dst_addr, const GpVar& src_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepStoSQ, &dst_addr, &src_val, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Fill ECX/RCX WORDs at ES:[EDI/RDI] with AX. + inline void rep_stosw(const GpVar& dst_addr, const GpVar& src_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepStoSW, &dst_addr, &src_val, &cnt_ecx); + } + + //! @brief Repeated find nonmatching BYTEs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsb(const GpVar& cmp1_addr, const GpVar& cmp2_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepECmpSB, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + + //! @brief Repeated find nonmatching DWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsd(const GpVar& cmp1_addr, const GpVar& cmp2_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepECmpSD, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Repeated find nonmatching QWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsq(const GpVar& cmp1_addr, const GpVar& cmp2_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepECmpSQ, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Repeated find nonmatching WORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsw(const GpVar& cmp1_addr, const GpVar& cmp2_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepECmpSW, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + + //! @brief Find non-AL BYTE starting at ES:[EDI/RDI]. + inline void repe_scasb(const GpVar& cmp1_addr, const GpVar& cmp2_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AL, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepEScaSB, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + + //! @brief Find non-EAX DWORD starting at ES:[EDI/RDI]. + inline void repe_scasd(const GpVar& cmp1_addr, const GpVar& cmp2_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=EAX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepEScaSD, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Find non-RAX QWORD starting at ES:[EDI/RDI]. + inline void repe_scasq(const GpVar& cmp1_addr, const GpVar& cmp2_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepEScaSQ, &cmp1_addr, &cmp2_val, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Find non-AX WORD starting at ES:[EDI/RDI]. + inline void repe_scasw(const GpVar& cmp1_addr, const GpVar& cmp2_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepEScaSW, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + + //! @brief Find matching BYTEs in [RDI] and [RSI]. + inline void repne_cmpsb(const GpVar& cmp1_addr, const GpVar& cmp2_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepNECmpSB, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + + //! @brief Find matching DWORDs in [RDI] and [RSI]. + inline void repne_cmpsd(const GpVar& cmp1_addr, const GpVar& cmp2_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepNECmpSD, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Find matching QWORDs in [RDI] and [RSI]. + inline void repne_cmpsq(const GpVar& cmp1_addr, const GpVar& cmp2_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepNECmpSQ, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Find matching WORDs in [RDI] and [RSI]. + inline void repne_cmpsw(const GpVar& cmp1_addr, const GpVar& cmp2_addr, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepNECmpSW, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + + //! @brief Find AL, starting at ES:[EDI/RDI]. + inline void repne_scasb(const GpVar& cmp1_addr, const GpVar& cmp2_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AL, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepNEScaSB, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + + //! @brief Find EAX, starting at ES:[EDI/RDI]. + inline void repne_scasd(const GpVar& cmp1_addr, const GpVar& cmp2_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=EAX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepNEScaSD, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Find RAX, starting at ES:[EDI/RDI]. + inline void repne_scasq(const GpVar& cmp1_addr, const GpVar& cmp2_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepNEScaSQ, &cmp1_addr, &cmp2_val, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Find AX, starting at ES:[EDI/RDI]. + inline void repne_scasw(const GpVar& cmp1_addr, const GpVar& cmp2_val, const GpVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + _emitInstruction(kX86InstRepNEScaSW, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + + //! @brief Return from Procedure. + inline void ret() + { _emitReturn(NULL, NULL); } + + //! @brief Return from Procedure. + inline void ret(const GpVar& first) + { _emitReturn(&first, NULL); } + + //! @brief Return from Procedure. + inline void ret(const GpVar& first, const GpVar& second) + { _emitReturn(&first, &second); } + + //! @brief Return from Procedure. + inline void ret(const XmmVar& first) + { _emitReturn(&first, NULL); } + + //! @brief Return from Procedure. + inline void ret(const XmmVar& first, const XmmVar& second) + { _emitReturn(&first, &second); } + + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rol(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstRol, &dst, &src); } + + //! @brief Rotate Bits Left. + inline void rol(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstRol, &dst, &src); } + + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rol(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstRol, &dst, &src); } + + //! @brief Rotate Bits Left. + inline void rol(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstRol, &dst, &src); } + + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void ror(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstRor, &dst, &src); } + + //! @brief Rotate Bits Right. + inline void ror(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstRor, &dst, &src); } + + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void ror(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstRor, &dst, &src); } + + //! @brief Rotate Bits Right. + inline void ror(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstRor, &dst, &src); } + +#if defined(ASMJIT_X86) + //! @brief Store @a var (allocated to AH/AX/EAX/RAX) into Flags. + inline void sahf(const GpVar& var) + { _emitInstruction(kX86InstSahf, &var); } +#endif // ASMJIT_X86 + + //! @brief Integer subtraction with borrow. + inline void sbb(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstSbb, &dst, &src); } + + //! @brief Integer subtraction with borrow. + inline void sbb(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstSbb, &dst, &src); } + + //! @brief Integer subtraction with borrow. + inline void sbb(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstSbb, &dst, &src); } + + //! @brief Integer subtraction with borrow. + inline void sbb(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstSbb, &dst, &src); } + + //! @brief Integer subtraction with borrow. + inline void sbb(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstSbb, &dst, &src); } + + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void sal(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstSal, &dst, &src); } + + //! @brief Shift Bits Left. + inline void sal(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstSal, &dst, &src); } + + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void sal(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstSal, &dst, &src); } + + //! @brief Shift Bits Left. + inline void sal(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstSal, &dst, &src); } + + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void sar(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstSar, &dst, &src); } + + //! @brief Shift Bits Right. + inline void sar(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstSar, &dst, &src); } + + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void sar(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstSar, &dst, &src); } + + //! @brief Shift Bits Right. + inline void sar(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstSar, &dst, &src); } + + //! @brief Set Byte on Condition. + inline void set(kX86Cond cc, const GpVar& dst) + { + ASMJIT_ASSERT(dst.getSize() == 1); + _emitInstruction(X86Util::getSetccInstFromCond(cc), &dst); + } + + //! @brief Set Byte on Condition. + inline void set(kX86Cond cc, const Mem& dst) + { + ASMJIT_ASSERT(dst.getSize() <= 1); + _emitInstruction(X86Util::getSetccInstFromCond(cc), &dst); + } + + //! @brief Set Byte on Condition. + inline void seta (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetA , &dst); } + //! @brief Set Byte on Condition. + inline void seta (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetA , &dst); } + //! @brief Set Byte on Condition. + inline void setae (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetAE , &dst); } + //! @brief Set Byte on Condition. + inline void setae (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetAE , &dst); } + //! @brief Set Byte on Condition. + inline void setb (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetB , &dst); } + //! @brief Set Byte on Condition. + inline void setb (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetB , &dst); } + //! @brief Set Byte on Condition. + inline void setbe (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetBE , &dst); } + //! @brief Set Byte on Condition. + inline void setbe (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetBE , &dst); } + //! @brief Set Byte on Condition. + inline void setc (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetC , &dst); } + //! @brief Set Byte on Condition. + inline void setc (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetC , &dst); } + //! @brief Set Byte on Condition. + inline void sete (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetE , &dst); } + //! @brief Set Byte on Condition. + inline void sete (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetE , &dst); } + //! @brief Set Byte on Condition. + inline void setg (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetG , &dst); } + //! @brief Set Byte on Condition. + inline void setg (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetG , &dst); } + //! @brief Set Byte on Condition. + inline void setge (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetGE , &dst); } + //! @brief Set Byte on Condition. + inline void setge (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetGE , &dst); } + //! @brief Set Byte on Condition. + inline void setl (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetL , &dst); } + //! @brief Set Byte on Condition. + inline void setl (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetL , &dst); } + //! @brief Set Byte on Condition. + inline void setle (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetLE , &dst); } + //! @brief Set Byte on Condition. + inline void setle (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetLE , &dst); } + //! @brief Set Byte on Condition. + inline void setna (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNA , &dst); } + //! @brief Set Byte on Condition. + inline void setna (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNA , &dst); } + //! @brief Set Byte on Condition. + inline void setnae(const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNAE, &dst); } + //! @brief Set Byte on Condition. + inline void setnae(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNAE, &dst); } + //! @brief Set Byte on Condition. + inline void setnb (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNB , &dst); } + //! @brief Set Byte on Condition. + inline void setnb (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNB , &dst); } + //! @brief Set Byte on Condition. + inline void setnbe(const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNBE, &dst); } + //! @brief Set Byte on Condition. + inline void setnbe(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNBE, &dst); } + //! @brief Set Byte on Condition. + inline void setnc (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNC , &dst); } + //! @brief Set Byte on Condition. + inline void setnc (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNC , &dst); } + //! @brief Set Byte on Condition. + inline void setne (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNE , &dst); } + //! @brief Set Byte on Condition. + inline void setne (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNE , &dst); } + //! @brief Set Byte on Condition. + inline void setng (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNG , &dst); } + //! @brief Set Byte on Condition. + inline void setng (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNG , &dst); } + //! @brief Set Byte on Condition. + inline void setnge(const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNGE, &dst); } + //! @brief Set Byte on Condition. + inline void setnge(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNGE, &dst); } + //! @brief Set Byte on Condition. + inline void setnl (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNL , &dst); } + //! @brief Set Byte on Condition. + inline void setnl (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNL , &dst); } + //! @brief Set Byte on Condition. + inline void setnle(const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNLE, &dst); } + //! @brief Set Byte on Condition. + inline void setnle(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNLE, &dst); } + //! @brief Set Byte on Condition. + inline void setno (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNO , &dst); } + //! @brief Set Byte on Condition. + inline void setno (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNO , &dst); } + //! @brief Set Byte on Condition. + inline void setnp (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNP , &dst); } + //! @brief Set Byte on Condition. + inline void setnp (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNP , &dst); } + //! @brief Set Byte on Condition. + inline void setns (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNS , &dst); } + //! @brief Set Byte on Condition. + inline void setns (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNS , &dst); } + //! @brief Set Byte on Condition. + inline void setnz (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetNZ , &dst); } + //! @brief Set Byte on Condition. + inline void setnz (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetNZ , &dst); } + //! @brief Set Byte on Condition. + inline void seto (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetO , &dst); } + //! @brief Set Byte on Condition. + inline void seto (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetO , &dst); } + //! @brief Set Byte on Condition. + inline void setp (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetP , &dst); } + //! @brief Set Byte on Condition. + inline void setp (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetP , &dst); } + //! @brief Set Byte on Condition. + inline void setpe (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetPE , &dst); } + //! @brief Set Byte on Condition. + inline void setpe (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetPE , &dst); } + //! @brief Set Byte on Condition. + inline void setpo (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetPO , &dst); } + //! @brief Set Byte on Condition. + inline void setpo (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetPO , &dst); } + //! @brief Set Byte on Condition. + inline void sets (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetS , &dst); } + //! @brief Set Byte on Condition. + inline void sets (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetS , &dst); } + //! @brief Set Byte on Condition. + inline void setz (const GpVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(kX86InstSetZ , &dst); } + //! @brief Set Byte on Condition. + inline void setz (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(kX86InstSetZ , &dst); } + + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void shl(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstShl, &dst, &src); } + + //! @brief Shift Bits Left. + inline void shl(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstShl, &dst, &src); } + + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void shl(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstShl, &dst, &src); } + + //! @brief Shift Bits Left. + inline void shl(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstShl, &dst, &src); } + + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void shr(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstShr, &dst, &src); } + + //! @brief Shift Bits Right. + inline void shr(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstShr, &dst, &src); } + + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void shr(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstShr, &dst, &src); } + + //! @brief Shift Bits Right. + inline void shr(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstShr, &dst, &src); } + + //! @brief Double Precision Shift Left. + //! @note src2 register can be only @c cl register. + inline void shld(const GpVar& dst, const GpVar& src1, const GpVar& src2) + { _emitInstruction(kX86InstShld, &dst, &src1, &src2); } + + //! @brief Double Precision Shift Left. + inline void shld(const GpVar& dst, const GpVar& src1, const Imm& src2) + { _emitInstruction(kX86InstShld, &dst, &src1, &src2); } + + //! @brief Double Precision Shift Left. + //! @note src2 register can be only @c cl register. + inline void shld(const Mem& dst, const GpVar& src1, const GpVar& src2) + { _emitInstruction(kX86InstShld, &dst, &src1, &src2); } + + //! @brief Double Precision Shift Left. + inline void shld(const Mem& dst, const GpVar& src1, const Imm& src2) + { _emitInstruction(kX86InstShld, &dst, &src1, &src2); } + + //! @brief Double Precision Shift Right. + //! @note src2 register can be only @c cl register. + inline void shrd(const GpVar& dst, const GpVar& src1, const GpVar& src2) + { _emitInstruction(kX86InstShrd, &dst, &src1, &src2); } + + //! @brief Double Precision Shift Right. + inline void shrd(const GpVar& dst, const GpVar& src1, const Imm& src2) + { _emitInstruction(kX86InstShrd, &dst, &src1, &src2); } + + //! @brief Double Precision Shift Right. + //! @note src2 register can be only @c cl register. + inline void shrd(const Mem& dst, const GpVar& src1, const GpVar& src2) + { _emitInstruction(kX86InstShrd, &dst, &src1, &src2); } + + //! @brief Double Precision Shift Right. + inline void shrd(const Mem& dst, const GpVar& src1, const Imm& src2) + { _emitInstruction(kX86InstShrd, &dst, &src1, &src2); } + + //! @brief Set Carry Flag to 1. + inline void stc() + { _emitInstruction(kX86InstStc); } + + //! @brief Set Direction Flag to 1. + inline void std() + { _emitInstruction(kX86InstStd); } + + //! @brief Subtract. + inline void sub(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstSub, &dst, &src); } + + //! @brief Subtract. + inline void sub(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstSub, &dst, &src); } + + //! @brief Subtract. + inline void sub(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstSub, &dst, &src); } + + //! @brief Subtract. + inline void sub(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstSub, &dst, &src); } + + //! @brief Subtract. + inline void sub(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstSub, &dst, &src); } + + //! @brief Logical Compare. + inline void test(const GpVar& op1, const GpVar& op2) + { _emitInstruction(kX86InstTest, &op1, &op2); } + + //! @brief Logical Compare. + inline void test(const GpVar& op1, const Imm& op2) + { _emitInstruction(kX86InstTest, &op1, &op2); } + + //! @brief Logical Compare. + inline void test(const Mem& op1, const GpVar& op2) + { _emitInstruction(kX86InstTest, &op1, &op2); } + + //! @brief Logical Compare. + inline void test(const Mem& op1, const Imm& op2) + { _emitInstruction(kX86InstTest, &op1, &op2); } + + //! @brief Undefined instruction - Raise invalid opcode exception. + inline void ud2() + { _emitInstruction(kX86InstUd2); } + + //! @brief Exchange and Add. + inline void xadd(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstXadd, &dst, &src); } + + //! @brief Exchange and Add. + inline void xadd(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstXadd, &dst, &src); } + + //! @brief Exchange Register/Memory with Register. + inline void xchg(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstXchg, &dst, &src); } + + //! @brief Exchange Register/Memory with Register. + inline void xchg(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstXchg, &dst, &src); } + + //! @brief Exchange Register/Memory with Register. + inline void xchg(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstXchg, &src, &dst); } + + //! @brief Exchange Register/Memory with Register. + inline void xor_(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstXor, &dst, &src); } + + //! @brief Exchange Register/Memory with Register. + inline void xor_(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstXor, &dst, &src); } + + //! @brief Exchange Register/Memory with Register. + inline void xor_(const GpVar& dst, const Imm& src) + { _emitInstruction(kX86InstXor, &dst, &src); } + + //! @brief Exchange Register/Memory with Register. + inline void xor_(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstXor, &dst, &src); } + + //! @brief Exchange Register/Memory with Register. + inline void xor_(const Mem& dst, const Imm& src) + { _emitInstruction(kX86InstXor, &dst, &src); } + + // -------------------------------------------------------------------------- + // [MMX] + // -------------------------------------------------------------------------- + + //! @brief Empty MMX state. + inline void emms() + { _emitInstruction(kX86InstEmms); } + + //! @brief Move DWord (MMX). + inline void movd(const Mem& dst, const MmVar& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + + //! @brief Move DWord (MMX). + inline void movd(const GpVar& dst, const MmVar& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + + //! @brief Move DWord (MMX). + inline void movd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + + //! @brief Move DWord (MMX). + inline void movd(const MmVar& dst, const GpVar& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + + //! @brief Move QWord (MMX). + inline void movq(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } + + //! @brief Move QWord (MMX). + inline void movq(const Mem& dst, const MmVar& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } + +#if defined(ASMJIT_X64) + //! @brief Move QWord (MMX). + inline void movq(const GpVar& dst, const MmVar& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#endif + + //! @brief Move QWord (MMX). + inline void movq(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } + +#if defined(ASMJIT_X64) + //! @brief Move QWord (MMX). + inline void movq(const MmVar& dst, const GpVar& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#endif + + //! @brief Pack with Signed Saturation (MMX). + inline void packsswb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPackSSWB, &dst, &src); } + + //! @brief Pack with Signed Saturation (MMX). + inline void packsswb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPackSSWB, &dst, &src); } + + //! @brief Pack with Signed Saturation (MMX). + inline void packssdw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPackSSDW, &dst, &src); } + + //! @brief Pack with Signed Saturation (MMX). + inline void packssdw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPackSSDW, &dst, &src); } + + //! @brief Pack with Unsigned Saturation (MMX). + inline void packuswb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPackUSWB, &dst, &src); } + + //! @brief Pack with Unsigned Saturation (MMX). + inline void packuswb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPackUSWB, &dst, &src); } + + //! @brief Packed BYTE Add (MMX). + inline void paddb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAddB, &dst, &src); } + + //! @brief Packed BYTE Add (MMX). + inline void paddb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddB, &dst, &src); } + + //! @brief Packed WORD Add (MMX). + inline void paddw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAddW, &dst, &src); } + + //! @brief Packed WORD Add (MMX). + inline void paddw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddW, &dst, &src); } + + //! @brief Packed DWORD Add (MMX). + inline void paddd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAddD, &dst, &src); } + + //! @brief Packed DWORD Add (MMX). + inline void paddd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddD, &dst, &src); } + + //! @brief Packed Add with Saturation (MMX). + inline void paddsb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAddSB, &dst, &src); } + + //! @brief Packed Add with Saturation (MMX). + inline void paddsb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddSB, &dst, &src); } + + //! @brief Packed Add with Saturation (MMX). + inline void paddsw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAddSW, &dst, &src); } + + //! @brief Packed Add with Saturation (MMX). + inline void paddsw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddSW, &dst, &src); } + + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAddUSB, &dst, &src); } + + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddUSB, &dst, &src); } + + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAddUSW, &dst, &src); } + + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddUSW, &dst, &src); } + + //! @brief Logical AND (MMX). + inline void pand(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAnd, &dst, &src); } + + //! @brief Logical AND (MMX). + inline void pand(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAnd, &dst, &src); } + + //! @brief Logical AND Not (MMX). + inline void pandn(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAndN, &dst, &src); } + + //! @brief Logical AND Not (MMX). + inline void pandn(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAndN, &dst, &src); } + + //! @brief Packed Compare for Equal (BYTES) (MMX). + inline void pcmpeqb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPCmpEqB, &dst, &src); } + + //! @brief Packed Compare for Equal (BYTES) (MMX). + inline void pcmpeqb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqB, &dst, &src); } + + //! @brief Packed Compare for Equal (WORDS) (MMX). + inline void pcmpeqw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPCmpEqW, &dst, &src); } + + //! @brief Packed Compare for Equal (WORDS) (MMX). + inline void pcmpeqw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqW, &dst, &src); } + + //! @brief Packed Compare for Equal (DWORDS) (MMX). + inline void pcmpeqd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPCmpEqD, &dst, &src); } + + //! @brief Packed Compare for Equal (DWORDS) (MMX). + inline void pcmpeqd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqD, &dst, &src); } + + //! @brief Packed Compare for Greater Than (BYTES) (MMX). + inline void pcmpgtb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPCmpGtB, &dst, &src); } + + //! @brief Packed Compare for Greater Than (BYTES) (MMX). + inline void pcmpgtb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtB, &dst, &src); } + + //! @brief Packed Compare for Greater Than (WORDS) (MMX). + inline void pcmpgtw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPCmpGtW, &dst, &src); } + + //! @brief Packed Compare for Greater Than (WORDS) (MMX). + inline void pcmpgtw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtW, &dst, &src); } + + //! @brief Packed Compare for Greater Than (DWORDS) (MMX). + inline void pcmpgtd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPCmpGtD, &dst, &src); } + + //! @brief Packed Compare for Greater Than (DWORDS) (MMX). + inline void pcmpgtd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtD, &dst, &src); } + + //! @brief Packed Multiply High (MMX). + inline void pmulhw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMulHW, &dst, &src); } + + //! @brief Packed Multiply High (MMX). + inline void pmulhw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHW, &dst, &src); } + + //! @brief Packed Multiply Low (MMX). + inline void pmullw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMulLW, &dst, &src); } + + //! @brief Packed Multiply Low (MMX). + inline void pmullw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulLW, &dst, &src); } + + //! @brief Bitwise Logical OR (MMX). + inline void por(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPOr, &dst, &src); } + + //! @brief Bitwise Logical OR (MMX). + inline void por(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPOr, &dst, &src); } + + //! @brief Packed Multiply and Add (MMX). + inline void pmaddwd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMAddWD, &dst, &src); } + + //! @brief Packed Multiply and Add (MMX). + inline void pmaddwd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMAddWD, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void pslld(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void pslld(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void pslld(const MmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void psllq(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void psllq(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void psllq(const MmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void psllw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void psllw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + + //! @brief Packed Shift Left Logical (MMX). + inline void psllw(const MmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psrad(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSraD, &dst, &src); } + + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psrad(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSraD, &dst, &src);} + + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psrad(const MmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSraD, &dst, &src); } + + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psraw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psraw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psraw(const MmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrld(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrld(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrld(const MmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrlq(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrlq(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrlq(const MmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrlw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrlw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrlw(const MmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + + //! @brief Packed Subtract (MMX). + inline void psubb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSubB, &dst, &src); } + + //! @brief Packed Subtract (MMX). + inline void psubb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubB, &dst, &src); } + + //! @brief Packed Subtract (MMX). + inline void psubw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSubW, &dst, &src); } + + //! @brief Packed Subtract (MMX). + inline void psubw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubW, &dst, &src); } + + //! @brief Packed Subtract (MMX). + inline void psubd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSubD, &dst, &src); } + + //! @brief Packed Subtract (MMX). + inline void psubd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubD, &dst, &src); } + + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSubSB, &dst, &src); } + + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubSB, &dst, &src); } + + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSubSW, &dst, &src); } + + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubSW, &dst, &src); } + + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSubUSB, &dst, &src); } + + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubUSB, &dst, &src); } + + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSubUSW, &dst, &src); } + + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubUSW, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhbw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPunpckHBW, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhbw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHBW, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhwd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPunpckHWD, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhwd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHWD, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhdq(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPunpckHDQ, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhdq(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHDQ, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpcklbw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPunpckLBW, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpcklbw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLBW, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpcklwd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPunpckLWD, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpcklwd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLWD, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckldq(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPunpckLDQ, &dst, &src); } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckldq(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLDQ, &dst, &src); } + + //! @brief Bitwise Exclusive OR (MMX). + inline void pxor(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPXor, &dst, &src); } + + //! @brief Bitwise Exclusive OR (MMX). + inline void pxor(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPXor, &dst, &src); } + + // -------------------------------------------------------------------------- + // [3dNow] + // -------------------------------------------------------------------------- + + //! @brief Faster EMMS (3dNow!). + //! + //! @note Use only for early AMD processors where is only 3dNow! or SSE. If + //! CPU contains SSE2, it's better to use @c emms() ( @c femms() is mapped + //! to @c emms() ). + inline void femms() + { _emitInstruction(kX86InstFEmms); } + + //! @brief Packed SP-FP to Integer Convert (3dNow!). + inline void pf2id(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPF2ID, &dst, &src); } + + //! @brief Packed SP-FP to Integer Convert (3dNow!). + inline void pf2id(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPF2ID, &dst, &src); } + + //! @brief Packed SP-FP to Integer Word Convert (3dNow!). + inline void pf2iw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPF2IW, &dst, &src); } + + //! @brief Packed SP-FP to Integer Word Convert (3dNow!). + inline void pf2iw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPF2IW, &dst, &src); } + + //! @brief Packed SP-FP Accumulate (3dNow!). + inline void pfacc(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFAcc, &dst, &src); } + + //! @brief Packed SP-FP Accumulate (3dNow!). + inline void pfacc(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFAcc, &dst, &src); } + + //! @brief Packed SP-FP Addition (3dNow!). + inline void pfadd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFAdd, &dst, &src); } + + //! @brief Packed SP-FP Addition (3dNow!). + inline void pfadd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFAdd, &dst, &src); } + + //! @brief Packed SP-FP Compare - dst == src (3dNow!). + inline void pfcmpeq(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFCmpEQ, &dst, &src); } + + //! @brief Packed SP-FP Compare - dst == src (3dNow!). + inline void pfcmpeq(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFCmpEQ, &dst, &src); } + + //! @brief Packed SP-FP Compare - dst >= src (3dNow!). + inline void pfcmpge(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFCmpGE, &dst, &src); } + + //! @brief Packed SP-FP Compare - dst >= src (3dNow!). + inline void pfcmpge(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFCmpGE, &dst, &src); } + + //! @brief Packed SP-FP Compare - dst > src (3dNow!). + inline void pfcmpgt(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFCmpGT, &dst, &src); } + + //! @brief Packed SP-FP Compare - dst > src (3dNow!). + inline void pfcmpgt(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFCmpGT, &dst, &src); } + + //! @brief Packed SP-FP Maximum (3dNow!). + inline void pfmax(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFMax, &dst, &src); } + + //! @brief Packed SP-FP Maximum (3dNow!). + inline void pfmax(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFMax, &dst, &src); } + + //! @brief Packed SP-FP Minimum (3dNow!). + inline void pfmin(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFMin, &dst, &src); } + + //! @brief Packed SP-FP Minimum (3dNow!). + inline void pfmin(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFMin, &dst, &src); } + + //! @brief Packed SP-FP Multiply (3dNow!). + inline void pfmul(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFMul, &dst, &src); } + + //! @brief Packed SP-FP Multiply (3dNow!). + inline void pfmul(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFMul, &dst, &src); } + + //! @brief Packed SP-FP Negative Accumulate (3dNow!). + inline void pfnacc(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFNAcc, &dst, &src); } + + //! @brief Packed SP-FP Negative Accumulate (3dNow!). + inline void pfnacc(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFNAcc, &dst, &src); } + + //! @brief Packed SP-FP Mixed Accumulate (3dNow!). + inline void pfpnacc(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFPNAcc, &dst, &src); } + + //! @brief Packed SP-FP Mixed Accumulate (3dNow!). + inline void pfpnacc(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFPNAcc, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal Approximation (3dNow!). + inline void pfrcp(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFRcp, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal Approximation (3dNow!). + inline void pfrcp(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFRcp, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal, First Iteration Step (3dNow!). + inline void pfrcpit1(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFRcpIt1, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal, First Iteration Step (3dNow!). + inline void pfrcpit1(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFRcpIt1, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal, Second Iteration Step (3dNow!). + inline void pfrcpit2(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFRcpIt2, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal, Second Iteration Step (3dNow!). + inline void pfrcpit2(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFRcpIt2, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal Square Root, First Iteration Step (3dNow!). + inline void pfrsqit1(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFRSqIt1, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal Square Root, First Iteration Step (3dNow!). + inline void pfrsqit1(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFRSqIt1, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal Square Root Approximation (3dNow!). + inline void pfrsqrt(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFRSqrt, &dst, &src); } + + //! @brief Packed SP-FP Reciprocal Square Root Approximation (3dNow!). + inline void pfrsqrt(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFRSqrt, &dst, &src); } + + //! @brief Packed SP-FP Subtract (3dNow!). + inline void pfsub(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFSub, &dst, &src); } + + //! @brief Packed SP-FP Subtract (3dNow!). + inline void pfsub(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFSub, &dst, &src); } + + //! @brief Packed SP-FP Reverse Subtract (3dNow!). + inline void pfsubr(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPFSubR, &dst, &src); } + + //! @brief Packed SP-FP Reverse Subtract (3dNow!). + inline void pfsubr(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPFSubR, &dst, &src); } + + //! @brief Packed DWords to SP-FP (3dNow!). + inline void pi2fd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPI2FD, &dst, &src); } + + //! @brief Packed DWords to SP-FP (3dNow!). + inline void pi2fd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPI2FD, &dst, &src); } + + //! @brief Packed Words to SP-FP (3dNow!). + inline void pi2fw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPI2FW, &dst, &src); } + + //! @brief Packed Words to SP-FP (3dNow!). + inline void pi2fw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPI2FW, &dst, &src); } + + //! @brief Packed swap DWord (3dNow!) + inline void pswapd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSwapD, &dst, &src); } + + //! @brief Packed swap DWord (3dNow!) + inline void pswapd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSwapD, &dst, &src); } + + // -------------------------------------------------------------------------- + // [SSE] + // -------------------------------------------------------------------------- + + //! @brief Packed SP-FP Add (SSE). + inline void addps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstAddPS, &dst, &src); } + //! @brief Packed SP-FP Add (SSE). + inline void addps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstAddPS, &dst, &src); } + + //! @brief Scalar SP-FP Add (SSE). + inline void addss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstAddSS, &dst, &src); } + //! @brief Scalar SP-FP Add (SSE). + inline void addss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstAddSS, &dst, &src); } + + //! @brief Bit-wise Logical And Not For SP-FP (SSE). + inline void andnps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstAndnPS, &dst, &src); } + //! @brief Bit-wise Logical And Not For SP-FP (SSE). + inline void andnps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstAndnPS, &dst, &src); } + + //! @brief Bit-wise Logical And For SP-FP (SSE). + inline void andps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstAndPS, &dst, &src); } + //! @brief Bit-wise Logical And For SP-FP (SSE). + inline void andps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstAndPS, &dst, &src); } + + //! @brief Packed SP-FP Compare (SSE). + inline void cmpps(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpPS, &dst, &src, &imm8); } + //! @brief Packed SP-FP Compare (SSE). + inline void cmpps(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpPS, &dst, &src, &imm8); } + + //! @brief Compare Scalar SP-FP Values (SSE). + inline void cmpss(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpSS, &dst, &src, &imm8); } + //! @brief Compare Scalar SP-FP Values (SSE). + inline void cmpss(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpSS, &dst, &src, &imm8); } + + //! @brief Scalar Ordered SP-FP Compare and Set EFLAGS (SSE). + inline void comiss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstComISS, &dst, &src); } + //! @brief Scalar Ordered SP-FP Compare and Set EFLAGS (SSE). + inline void comiss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstComISS, &dst, &src); } + + //! @brief Packed Signed INT32 to Packed SP-FP Conversion (SSE). + inline void cvtpi2ps(const XmmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstCvtPI2PS, &dst, &src); } + //! @brief Packed Signed INT32 to Packed SP-FP Conversion (SSE). + inline void cvtpi2ps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPI2PS, &dst, &src); } + + //! @brief Packed SP-FP to Packed INT32 Conversion (SSE). + inline void cvtps2pi(const MmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtPS2PI, &dst, &src); } + //! @brief Packed SP-FP to Packed INT32 Conversion (SSE). + inline void cvtps2pi(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPS2PI, &dst, &src); } + + //! @brief Scalar Signed INT32 to SP-FP Conversion (SSE). + inline void cvtsi2ss(const XmmVar& dst, const GpVar& src) + { _emitInstruction(kX86InstCvtSI2SS, &dst, &src); } + //! @brief Scalar Signed INT32 to SP-FP Conversion (SSE). + inline void cvtsi2ss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSI2SS, &dst, &src); } + + //! @brief Scalar SP-FP to Signed INT32 Conversion (SSE). + inline void cvtss2si(const GpVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtSS2SI, &dst, &src); } + //! @brief Scalar SP-FP to Signed INT32 Conversion (SSE). + inline void cvtss2si(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSS2SI, &dst, &src); } + + //! @brief Packed SP-FP to Packed INT32 Conversion (truncate) (SSE). + inline void cvttps2pi(const MmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvttPS2PI, &dst, &src); } + //! @brief Packed SP-FP to Packed INT32 Conversion (truncate) (SSE). + inline void cvttps2pi(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvttPS2PI, &dst, &src); } + + //! @brief Scalar SP-FP to Signed INT32 Conversion (truncate) (SSE). + inline void cvttss2si(const GpVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvttSS2SI, &dst, &src); } + //! @brief Scalar SP-FP to Signed INT32 Conversion (truncate) (SSE). + inline void cvttss2si(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvttSS2SI, &dst, &src); } + + //! @brief Packed SP-FP Divide (SSE). + inline void divps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstDivPS, &dst, &src); } + //! @brief Packed SP-FP Divide (SSE). + inline void divps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstDivPS, &dst, &src); } + + //! @brief Scalar SP-FP Divide (SSE). + inline void divss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstDivSS, &dst, &src); } + //! @brief Scalar SP-FP Divide (SSE). + inline void divss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstDivSS, &dst, &src); } + + //! @brief Load Streaming SIMD Extension Control/Status (SSE). + inline void ldmxcsr(const Mem& src) + { _emitInstruction(kX86InstLdMXCSR, &src); } + + //! @brief Byte Mask Write (SSE). + //! + //! @note The default memory location is specified by DS:EDI. + inline void maskmovq(const GpVar& dst_ptr, const MmVar& data, const MmVar& mask) + { _emitInstruction(kX86InstMaskMovQ, &dst_ptr, &data, &mask); } + + //! @brief Packed SP-FP Maximum (SSE). + inline void maxps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMaxPS, &dst, &src); } + //! @brief Packed SP-FP Maximum (SSE). + inline void maxps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMaxPS, &dst, &src); } + + //! @brief Scalar SP-FP Maximum (SSE). + inline void maxss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMaxSS, &dst, &src); } + //! @brief Scalar SP-FP Maximum (SSE). + inline void maxss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMaxSS, &dst, &src); } + + //! @brief Packed SP-FP Minimum (SSE). + inline void minps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMinPS, &dst, &src); } + //! @brief Packed SP-FP Minimum (SSE). + inline void minps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMinPS, &dst, &src); } + + //! @brief Scalar SP-FP Minimum (SSE). + inline void minss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMinSS, &dst, &src); } + //! @brief Scalar SP-FP Minimum (SSE). + inline void minss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMinSS, &dst, &src); } + + //! @brief Move Aligned Packed SP-FP Values (SSE). + inline void movaps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovAPS, &dst, &src); } + //! @brief Move Aligned Packed SP-FP Values (SSE). + inline void movaps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovAPS, &dst, &src); } + + //! @brief Move Aligned Packed SP-FP Values (SSE). + inline void movaps(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovAPS, &dst, &src); } + + //! @brief Move DWord. + inline void movd(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + //! @brief Move DWord. + inline void movd(const GpVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + //! @brief Move DWord. + inline void movd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + //! @brief Move DWord. + inline void movd(const XmmVar& dst, const GpVar& src) + { _emitInstruction(kX86InstMovD, &dst, &src); } + + //! @brief Move QWord (SSE). + inline void movq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } + //! @brief Move QWord (SSE). + inline void movq(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#if defined(ASMJIT_X64) + //! @brief Move QWord (SSE). + inline void movq(const GpVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#endif // ASMJIT_X64 + //! @brief Move QWord (SSE). + inline void movq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#if defined(ASMJIT_X64) + //! @brief Move QWord (SSE). + inline void movq(const XmmVar& dst, const GpVar& src) + { _emitInstruction(kX86InstMovQ, &dst, &src); } +#endif // ASMJIT_X64 + + //! @brief Move 64 Bits Non Temporal (SSE). + inline void movntq(const Mem& dst, const MmVar& src) + { _emitInstruction(kX86InstMovNTQ, &dst, &src); } + + //! @brief High to Low Packed SP-FP (SSE). + inline void movhlps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovHLPS, &dst, &src); } + + //! @brief Move High Packed SP-FP (SSE). + inline void movhps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovHPS, &dst, &src); } + + //! @brief Move High Packed SP-FP (SSE). + inline void movhps(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovHPS, &dst, &src); } + + //! @brief Move Low to High Packed SP-FP (SSE). + inline void movlhps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovLHPS, &dst, &src); } + + //! @brief Move Low Packed SP-FP (SSE). + inline void movlps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovLPS, &dst, &src); } + + //! @brief Move Low Packed SP-FP (SSE). + inline void movlps(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovLPS, &dst, &src); } + + //! @brief Move Aligned Four Packed SP-FP Non Temporal (SSE). + inline void movntps(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovNTPS, &dst, &src); } + + //! @brief Move Scalar SP-FP (SSE). + inline void movss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovSS, &dst, &src); } + + //! @brief Move Scalar SP-FP (SSE). + inline void movss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovSS, &dst, &src); } + + //! @brief Move Scalar SP-FP (SSE). + inline void movss(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovSS, &dst, &src); } + + //! @brief Move Unaligned Packed SP-FP Values (SSE). + inline void movups(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovUPS, &dst, &src); } + //! @brief Move Unaligned Packed SP-FP Values (SSE). + inline void movups(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovUPS, &dst, &src); } + + //! @brief Move Unaligned Packed SP-FP Values (SSE). + inline void movups(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovUPS, &dst, &src); } + + //! @brief Packed SP-FP Multiply (SSE). + inline void mulps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMulPS, &dst, &src); } + //! @brief Packed SP-FP Multiply (SSE). + inline void mulps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMulPS, &dst, &src); } + + //! @brief Scalar SP-FP Multiply (SSE). + inline void mulss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMulSS, &dst, &src); } + //! @brief Scalar SP-FP Multiply (SSE). + inline void mulss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMulSS, &dst, &src); } + + //! @brief Bit-wise Logical OR for SP-FP Data (SSE). + inline void orps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstOrPS, &dst, &src); } + //! @brief Bit-wise Logical OR for SP-FP Data (SSE). + inline void orps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstOrPS, &dst, &src); } + + //! @brief Packed Average (SSE). + inline void pavgb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAvgB, &dst, &src); } + //! @brief Packed Average (SSE). + inline void pavgb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAvgB, &dst, &src); } + + //! @brief Packed Average (SSE). + inline void pavgw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAvgW, &dst, &src); } + //! @brief Packed Average (SSE). + inline void pavgw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAvgW, &dst, &src); } + + //! @brief Extract Word (SSE). + inline void pextrw(const GpVar& dst, const MmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrW, &dst, &src, &imm8); } + + //! @brief Insert Word (SSE). + inline void pinsrw(const MmVar& dst, const GpVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRW, &dst, &src, &imm8); } + //! @brief Insert Word (SSE). + inline void pinsrw(const MmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRW, &dst, &src, &imm8); } + + //! @brief Packed Signed Integer Word Maximum (SSE). + inline void pmaxsw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMaxSW, &dst, &src); } + //! @brief Packed Signed Integer Word Maximum (SSE). + inline void pmaxsw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxSW, &dst, &src); } + + //! @brief Packed Unsigned Integer Byte Maximum (SSE). + inline void pmaxub(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMaxUB, &dst, &src); } + //! @brief Packed Unsigned Integer Byte Maximum (SSE). + inline void pmaxub(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxUB, &dst, &src); } + + //! @brief Packed Signed Integer Word Minimum (SSE). + inline void pminsw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMinSW, &dst, &src); } + //! @brief Packed Signed Integer Word Minimum (SSE). + inline void pminsw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMinSW, &dst, &src); } + + //! @brief Packed Unsigned Integer Byte Minimum (SSE). + inline void pminub(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMinUB, &dst, &src); } + //! @brief Packed Unsigned Integer Byte Minimum (SSE). + inline void pminub(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMinUB, &dst, &src); } + + //! @brief Move Byte Mask To Integer (SSE). + inline void pmovmskb(const GpVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMovMskB, &dst, &src); } + + //! @brief Packed Multiply High Unsigned (SSE). + inline void pmulhuw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMulHUW, &dst, &src); } + //! @brief Packed Multiply High Unsigned (SSE). + inline void pmulhuw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHUW, &dst, &src); } + + //! @brief Packed Sum of Absolute Differences (SSE). + inline void psadbw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSADBW, &dst, &src); } + //! @brief Packed Sum of Absolute Differences (SSE). + inline void psadbw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSADBW, &dst, &src); } + + //! @brief Packed Shuffle word (SSE). + inline void pshufw(const MmVar& dst, const MmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufW, &dst, &src, &imm8); } + //! @brief Packed Shuffle word (SSE). + inline void pshufw(const MmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufW, &dst, &src, &imm8); } + + //! @brief Packed SP-FP Reciprocal (SSE). + inline void rcpps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstRcpPS, &dst, &src); } + //! @brief Packed SP-FP Reciprocal (SSE). + inline void rcpps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstRcpPS, &dst, &src); } + + //! @brief Scalar SP-FP Reciprocal (SSE). + inline void rcpss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstRcpSS, &dst, &src); } + //! @brief Scalar SP-FP Reciprocal (SSE). + inline void rcpss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstRcpSS, &dst, &src); } + + //! @brief Prefetch (SSE). + inline void prefetch(const Mem& mem, const Imm& hint) + { _emitInstruction(kX86InstPrefetch, &mem, &hint); } + + //! @brief Compute Sum of Absolute Differences (SSE). + inline void psadbw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSADBW, &dst, &src); } + //! @brief Compute Sum of Absolute Differences (SSE). + inline void psadbw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSADBW, &dst, &src); } + + //! @brief Packed SP-FP Square Root Reciprocal (SSE). + inline void rsqrtps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstSqrtPS, &dst, &src); } + //! @brief Packed SP-FP Square Root Reciprocal (SSE). + inline void rsqrtps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtPS, &dst, &src); } + + //! @brief Scalar SP-FP Square Root Reciprocal (SSE). + inline void rsqrtss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstSqrtSS, &dst, &src); } + //! @brief Scalar SP-FP Square Root Reciprocal (SSE). + inline void rsqrtss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtSS, &dst, &src); } + + //! @brief Store fence (SSE). + inline void sfence() + { _emitInstruction(kX86InstSFence); } + + //! @brief Shuffle SP-FP (SSE). + inline void shufps(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstShufPS, &dst, &src, &imm8); } + //! @brief Shuffle SP-FP (SSE). + inline void shufps(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstShufPS, &dst, &src, &imm8); } + + //! @brief Packed SP-FP Square Root (SSE). + inline void sqrtps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstSqrtPS, &dst, &src); } + //! @brief Packed SP-FP Square Root (SSE). + inline void sqrtps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtPS, &dst, &src); } + + //! @brief Scalar SP-FP Square Root (SSE). + inline void sqrtss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstSqrtSS, &dst, &src); } + //! @brief Scalar SP-FP Square Root (SSE). + inline void sqrtss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtSS, &dst, &src); } + + //! @brief Store Streaming SIMD Extension Control/Status (SSE). + inline void stmxcsr(const Mem& dst) + { _emitInstruction(kX86InstStMXCSR, &dst); } + + //! @brief Packed SP-FP Subtract (SSE). + inline void subps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstSubPS, &dst, &src); } + //! @brief Packed SP-FP Subtract (SSE). + inline void subps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstSubPS, &dst, &src); } + + //! @brief Scalar SP-FP Subtract (SSE). + inline void subss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstSubSS, &dst, &src); } + //! @brief Scalar SP-FP Subtract (SSE). + inline void subss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstSubSS, &dst, &src); } + + //! @brief Unordered Scalar SP-FP compare and set EFLAGS (SSE). + inline void ucomiss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstUComISS, &dst, &src); } + //! @brief Unordered Scalar SP-FP compare and set EFLAGS (SSE). + inline void ucomiss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstUComISS, &dst, &src); } + + //! @brief Unpack High Packed SP-FP Data (SSE). + inline void unpckhps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstUnpckHPS, &dst, &src); } + //! @brief Unpack High Packed SP-FP Data (SSE). + inline void unpckhps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstUnpckHPS, &dst, &src); } + + //! @brief Unpack Low Packed SP-FP Data (SSE). + inline void unpcklps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstUnpckLPS, &dst, &src); } + //! @brief Unpack Low Packed SP-FP Data (SSE). + inline void unpcklps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstUnpckLPS, &dst, &src); } + + //! @brief Bit-wise Logical Xor for SP-FP Data (SSE). + inline void xorps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstXorPS, &dst, &src); } + //! @brief Bit-wise Logical Xor for SP-FP Data (SSE). + inline void xorps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstXorPS, &dst, &src); } + + // -------------------------------------------------------------------------- + // [SSE2] + // -------------------------------------------------------------------------- + + //! @brief Packed DP-FP Add (SSE2). + inline void addpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstAddPD, &dst, &src); } + //! @brief Packed DP-FP Add (SSE2). + inline void addpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstAddPD, &dst, &src); } + + //! @brief Scalar DP-FP Add (SSE2). + inline void addsd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstAddSD, &dst, &src); } + //! @brief Scalar DP-FP Add (SSE2). + inline void addsd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstAddSD, &dst, &src); } + + //! @brief Bit-wise Logical And Not For DP-FP (SSE2). + inline void andnpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstAndnPD, &dst, &src); } + //! @brief Bit-wise Logical And Not For DP-FP (SSE2). + inline void andnpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstAndnPD, &dst, &src); } + + //! @brief Bit-wise Logical And For DP-FP (SSE2). + inline void andpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstAndPD, &dst, &src); } + //! @brief Bit-wise Logical And For DP-FP (SSE2). + inline void andpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstAndPD, &dst, &src); } + + //! @brief Flush Cache Line (SSE2). + inline void clflush(const Mem& mem) + { _emitInstruction(kX86InstClFlush, &mem); } + + //! @brief Packed DP-FP Compare (SSE2). + inline void cmppd(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpPD, &dst, &src, &imm8); } + //! @brief Packed DP-FP Compare (SSE2). + inline void cmppd(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpPD, &dst, &src, &imm8); } + + //! @brief Compare Scalar SP-FP Values (SSE2). + inline void cmpsd(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpSD, &dst, &src, &imm8); } + //! @brief Compare Scalar SP-FP Values (SSE2). + inline void cmpsd(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstCmpSD, &dst, &src, &imm8); } + + //! @brief Scalar Ordered DP-FP Compare and Set EFLAGS (SSE2). + inline void comisd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstComISD, &dst, &src); } + //! @brief Scalar Ordered DP-FP Compare and Set EFLAGS (SSE2). + inline void comisd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstComISD, &dst, &src); } + + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtdq2pd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtDQ2PD, &dst, &src); } + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtdq2pd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtDQ2PD, &dst, &src); } + + //! @brief Convert Packed Dword Integers to Packed SP-FP Values (SSE2). + inline void cvtdq2ps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtDQ2PS, &dst, &src); } + //! @brief Convert Packed Dword Integers to Packed SP-FP Values (SSE2). + inline void cvtdq2ps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtDQ2PS, &dst, &src); } + + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2dq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtPD2DQ, &dst, &src); } + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2dq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPD2DQ, &dst, &src); } + + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2pi(const MmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtPD2PI, &dst, &src); } + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2pi(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPD2PI, &dst, &src); } + + //! @brief Convert Packed DP-FP Values to Packed SP-FP Values (SSE2). + inline void cvtpd2ps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtPD2PS, &dst, &src); } + //! @brief Convert Packed DP-FP Values to Packed SP-FP Values (SSE2). + inline void cvtpd2ps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPD2PS, &dst, &src); } + + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtpi2pd(const XmmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstCvtPI2PD, &dst, &src); } + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtpi2pd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPI2PD, &dst, &src); } + + //! @brief Convert Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvtps2dq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtPS2DQ, &dst, &src); } + //! @brief Convert Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvtps2dq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPS2DQ, &dst, &src); } + + //! @brief Convert Packed SP-FP Values to Packed DP-FP Values (SSE2). + inline void cvtps2pd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtPS2PD, &dst, &src); } + //! @brief Convert Packed SP-FP Values to Packed DP-FP Values (SSE2). + inline void cvtps2pd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtPS2PD, &dst, &src); } + + //! @brief Convert Scalar DP-FP Value to Dword Integer (SSE2). + inline void cvtsd2si(const GpVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtSD2SI, &dst, &src); } + //! @brief Convert Scalar DP-FP Value to Dword Integer (SSE2). + inline void cvtsd2si(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSD2SI, &dst, &src); } + + //! @brief Convert Scalar DP-FP Value to Scalar SP-FP Value (SSE2). + inline void cvtsd2ss(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtSD2SS, &dst, &src); } + //! @brief Convert Scalar DP-FP Value to Scalar SP-FP Value (SSE2). + inline void cvtsd2ss(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSD2SS, &dst, &src); } + + //! @brief Convert Dword Integer to Scalar DP-FP Value (SSE2). + inline void cvtsi2sd(const XmmVar& dst, const GpVar& src) + { _emitInstruction(kX86InstCvtSI2SD, &dst, &src); } + //! @brief Convert Dword Integer to Scalar DP-FP Value (SSE2). + inline void cvtsi2sd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSI2SD, &dst, &src); } + + //! @brief Convert Scalar SP-FP Value to Scalar DP-FP Value (SSE2). + inline void cvtss2sd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvtSS2SD, &dst, &src); } + //! @brief Convert Scalar SP-FP Value to Scalar DP-FP Value (SSE2). + inline void cvtss2sd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvtSS2SD, &dst, &src); } + + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2pi(const MmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvttPD2PI, &dst, &src); } + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2pi(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvttPD2PI, &dst, &src); } + + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2dq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvttPD2DQ, &dst, &src); } + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2dq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvttPD2DQ, &dst, &src); } + + //! @brief Convert with Truncation Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvttps2dq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvttPS2DQ, &dst, &src); } + //! @brief Convert with Truncation Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvttps2dq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvttPS2DQ, &dst, &src); } + + //! @brief Convert with Truncation Scalar DP-FP Value to Signed Dword Integer (SSE2). + inline void cvttsd2si(const GpVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstCvttSD2SI, &dst, &src); } + //! @brief Convert with Truncation Scalar DP-FP Value to Signed Dword Integer (SSE2). + inline void cvttsd2si(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstCvttSD2SI, &dst, &src); } + + //! @brief Packed DP-FP Divide (SSE2). + inline void divpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstDivPD, &dst, &src); } + //! @brief Packed DP-FP Divide (SSE2). + inline void divpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstDivPD, &dst, &src); } + + //! @brief Scalar DP-FP Divide (SSE2). + inline void divsd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstDivSD, &dst, &src); } + //! @brief Scalar DP-FP Divide (SSE2). + inline void divsd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstDivSD, &dst, &src); } + + //! @brief Load Fence (SSE2). + inline void lfence() + { _emitInstruction(kX86InstLFence); } + + //! @brief Store Selected Bytes of Double Quadword (SSE2). + //! + //! @note Target is DS:EDI. + inline void maskmovdqu(const GpVar& dst_ptr, const XmmVar& src, const XmmVar& mask) + { _emitInstruction(kX86InstMaskMovDQU, &dst_ptr, &src, &mask); } + + //! @brief Return Maximum Packed Double-Precision FP Values (SSE2). + inline void maxpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMaxPD, &dst, &src); } + //! @brief Return Maximum Packed Double-Precision FP Values (SSE2). + inline void maxpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMaxPD, &dst, &src); } + + //! @brief Return Maximum Scalar Double-Precision FP Value (SSE2). + inline void maxsd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMaxSD, &dst, &src); } + //! @brief Return Maximum Scalar Double-Precision FP Value (SSE2). + inline void maxsd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMaxSD, &dst, &src); } + + //! @brief Memory Fence (SSE2). + inline void mfence() + { _emitInstruction(kX86InstMFence); } + + //! @brief Return Minimum Packed DP-FP Values (SSE2). + inline void minpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMinPD, &dst, &src); } + //! @brief Return Minimum Packed DP-FP Values (SSE2). + inline void minpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMinPD, &dst, &src); } + + //! @brief Return Minimum Scalar DP-FP Value (SSE2). + inline void minsd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMinSD, &dst, &src); } + //! @brief Return Minimum Scalar DP-FP Value (SSE2). + inline void minsd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMinSD, &dst, &src); } + + //! @brief Move Aligned DQWord (SSE2). + inline void movdqa(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovDQA, &dst, &src); } + //! @brief Move Aligned DQWord (SSE2). + inline void movdqa(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovDQA, &dst, &src); } + + //! @brief Move Aligned DQWord (SSE2). + inline void movdqa(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovDQA, &dst, &src); } + + //! @brief Move Unaligned Double Quadword (SSE2). + inline void movdqu(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovDQU, &dst, &src); } + //! @brief Move Unaligned Double Quadword (SSE2). + inline void movdqu(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovDQU, &dst, &src); } + + //! @brief Move Unaligned Double Quadword (SSE2). + inline void movdqu(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovDQU, &dst, &src); } + + //! @brief Extract Packed SP-FP Sign Mask (SSE2). + inline void movmskps(const GpVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovMskPS, &dst, &src); } + + //! @brief Extract Packed DP-FP Sign Mask (SSE2). + inline void movmskpd(const GpVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovMskPD, &dst, &src); } + + //! @brief Move Scalar Double-Precision FP Value (SSE2). + inline void movsd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovSD, &dst, &src); } + //! @brief Move Scalar Double-Precision FP Value (SSE2). + inline void movsd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovSD, &dst, &src); } + + //! @brief Move Scalar Double-Precision FP Value (SSE2). + inline void movsd(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovSD, &dst, &src); } + + //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). + inline void movapd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovAPD, &dst, &src); } + + //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). + inline void movapd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovAPD, &dst, &src); } + + //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). + inline void movapd(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovAPD, &dst, &src); } + + //! @brief Move Quadword from XMM to MMX Technology Register (SSE2). + inline void movdq2q(const MmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovDQ2Q, &dst, &src); } + + //! @brief Move Quadword from MMX Technology to XMM Register (SSE2). + inline void movq2dq(const XmmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstMovQ2DQ, &dst, &src); } + + //! @brief Move High Packed Double-Precision FP Value (SSE2). + inline void movhpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovHPD, &dst, &src); } + + //! @brief Move High Packed Double-Precision FP Value (SSE2). + inline void movhpd(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovHPD, &dst, &src); } + + //! @brief Move Low Packed Double-Precision FP Value (SSE2). + inline void movlpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovLPD, &dst, &src); } + + //! @brief Move Low Packed Double-Precision FP Value (SSE2). + inline void movlpd(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovLPD, &dst, &src); } + + //! @brief Store Double Quadword Using Non-Temporal Hint (SSE2). + inline void movntdq(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovNTDQ, &dst, &src); } + + //! @brief Store Store DWORD Using Non-Temporal Hint (SSE2). + inline void movnti(const Mem& dst, const GpVar& src) + { _emitInstruction(kX86InstMovNTI, &dst, &src); } + + //! @brief Store Packed Double-Precision FP Values Using Non-Temporal Hint (SSE2). + inline void movntpd(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovNTPD, &dst, &src); } + + //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). + inline void movupd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovUPD, &dst, &src); } + + //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). + inline void movupd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovUPD, &dst, &src); } + + //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). + inline void movupd(const Mem& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovUPD, &dst, &src); } + + //! @brief Packed DP-FP Multiply (SSE2). + inline void mulpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMulPD, &dst, &src); } + //! @brief Packed DP-FP Multiply (SSE2). + inline void mulpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMulPD, &dst, &src); } + + //! @brief Scalar DP-FP Multiply (SSE2). + inline void mulsd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMulSD, &dst, &src); } + //! @brief Scalar DP-FP Multiply (SSE2). + inline void mulsd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMulSD, &dst, &src); } + + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void orpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstOrPD, &dst, &src); } + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void orpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstOrPD, &dst, &src); } + + //! @brief Pack with Signed Saturation (SSE2). + inline void packsswb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPackSSWB, &dst, &src); } + //! @brief Pack with Signed Saturation (SSE2). + inline void packsswb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPackSSWB, &dst, &src); } + + //! @brief Pack with Signed Saturation (SSE2). + inline void packssdw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPackSSDW, &dst, &src); } + //! @brief Pack with Signed Saturation (SSE2). + inline void packssdw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPackSSDW, &dst, &src); } + + //! @brief Pack with Unsigned Saturation (SSE2). + inline void packuswb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPackUSWB, &dst, &src); } + //! @brief Pack with Unsigned Saturation (SSE2). + inline void packuswb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPackUSWB, &dst, &src); } + + //! @brief Packed BYTE Add (SSE2). + inline void paddb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAddB, &dst, &src); } + //! @brief Packed BYTE Add (SSE2). + inline void paddb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddB, &dst, &src); } + + //! @brief Packed WORD Add (SSE2). + inline void paddw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAddW, &dst, &src); } + //! @brief Packed WORD Add (SSE2). + inline void paddw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddW, &dst, &src); } + + //! @brief Packed DWORD Add (SSE2). + inline void paddd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAddD, &dst, &src); } + //! @brief Packed DWORD Add (SSE2). + inline void paddd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddD, &dst, &src); } + + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAddQ, &dst, &src); } + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddQ, &dst, &src); } + + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAddQ, &dst, &src); } + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddQ, &dst, &src); } + + //! @brief Packed Add with Saturation (SSE2). + inline void paddsb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAddSB, &dst, &src); } + //! @brief Packed Add with Saturation (SSE2). + inline void paddsb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddSB, &dst, &src); } + + //! @brief Packed Add with Saturation (SSE2). + inline void paddsw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAddSW, &dst, &src); } + //! @brief Packed Add with Saturation (SSE2). + inline void paddsw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddSW, &dst, &src); } + + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAddUSB, &dst, &src); } + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddUSB, &dst, &src); } + + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAddUSW, &dst, &src); } + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAddUSW, &dst, &src); } + + //! @brief Logical AND (SSE2). + inline void pand(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAnd, &dst, &src); } + //! @brief Logical AND (SSE2). + inline void pand(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAnd, &dst, &src); } + + //! @brief Logical AND Not (SSE2). + inline void pandn(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAndN, &dst, &src); } + //! @brief Logical AND Not (SSE2). + inline void pandn(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAndN, &dst, &src); } + + //! @brief Spin Loop Hint (SSE2). + inline void pause() + { _emitInstruction(kX86InstPause); } + + //! @brief Packed Average (SSE2). + inline void pavgb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAvgB, &dst, &src); } + //! @brief Packed Average (SSE2). + inline void pavgb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAvgB, &dst, &src); } + + //! @brief Packed Average (SSE2). + inline void pavgw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAvgW, &dst, &src); } + //! @brief Packed Average (SSE2). + inline void pavgw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAvgW, &dst, &src); } + + //! @brief Packed Compare for Equal (BYTES) (SSE2). + inline void pcmpeqb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPCmpEqB, &dst, &src); } + //! @brief Packed Compare for Equal (BYTES) (SSE2). + inline void pcmpeqb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqB, &dst, &src); } + + //! @brief Packed Compare for Equal (WORDS) (SSE2). + inline void pcmpeqw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPCmpEqW, &dst, &src); } + //! @brief Packed Compare for Equal (WORDS) (SSE2). + inline void pcmpeqw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqW, &dst, &src); } + + //! @brief Packed Compare for Equal (DWORDS) (SSE2). + inline void pcmpeqd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPCmpEqD, &dst, &src); } + //! @brief Packed Compare for Equal (DWORDS) (SSE2). + inline void pcmpeqd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqD, &dst, &src); } + + //! @brief Packed Compare for Greater Than (BYTES) (SSE2). + inline void pcmpgtb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPCmpGtB, &dst, &src); } + //! @brief Packed Compare for Greater Than (BYTES) (SSE2). + inline void pcmpgtb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtB, &dst, &src); } + + //! @brief Packed Compare for Greater Than (WORDS) (SSE2). + inline void pcmpgtw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPCmpGtW, &dst, &src); } + //! @brief Packed Compare for Greater Than (WORDS) (SSE2). + inline void pcmpgtw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtW, &dst, &src); } + + //! @brief Packed Compare for Greater Than (DWORDS) (SSE2). + inline void pcmpgtd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPCmpGtD, &dst, &src); } + //! @brief Packed Compare for Greater Than (DWORDS) (SSE2). + inline void pcmpgtd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtD, &dst, &src); } + + //! @brief Extract Word (SSE2). + inline void pextrw(const GpVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrW, &dst, &src, &imm8); } + //! @brief Extract Word (SSE2). + inline void pextrw(const Mem& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrW, &dst, &src, &imm8); } + + //! @brief Packed Signed Integer Word Maximum (SSE2). + inline void pmaxsw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMaxSW, &dst, &src); } + //! @brief Packed Signed Integer Word Maximum (SSE2). + inline void pmaxsw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxSW, &dst, &src); } + + //! @brief Packed Unsigned Integer Byte Maximum (SSE2). + inline void pmaxub(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMaxUB, &dst, &src); } + //! @brief Packed Unsigned Integer Byte Maximum (SSE2). + inline void pmaxub(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxUB, &dst, &src); } + + //! @brief Packed Signed Integer Word Minimum (SSE2). + inline void pminsw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMinSW, &dst, &src); } + //! @brief Packed Signed Integer Word Minimum (SSE2). + inline void pminsw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMinSW, &dst, &src); } + + //! @brief Packed Unsigned Integer Byte Minimum (SSE2). + inline void pminub(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMinUB, &dst, &src); } + //! @brief Packed Unsigned Integer Byte Minimum (SSE2). + inline void pminub(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMinUB, &dst, &src); } + + //! @brief Move Byte Mask (SSE2). + inline void pmovmskb(const GpVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovMskB, &dst, &src); } + + //! @brief Packed Multiply High (SSE2). + inline void pmulhw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMulHW, &dst, &src); } + //! @brief Packed Multiply High (SSE2). + inline void pmulhw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHW, &dst, &src); } + + //! @brief Packed Multiply High Unsigned (SSE2). + inline void pmulhuw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMulHUW, &dst, &src); } + //! @brief Packed Multiply High Unsigned (SSE2). + inline void pmulhuw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHUW, &dst, &src); } + + //! @brief Packed Multiply Low (SSE2). + inline void pmullw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMulLW, &dst, &src); } + //! @brief Packed Multiply Low (SSE2). + inline void pmullw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulLW, &dst, &src); } + + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMulUDQ, &dst, &src); } + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulUDQ, &dst, &src); } + + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMulUDQ, &dst, &src); } + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulUDQ, &dst, &src); } + + //! @brief Bitwise Logical OR (SSE2). + inline void por(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPOr, &dst, &src); } + //! @brief Bitwise Logical OR (SSE2). + inline void por(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPOr, &dst, &src); } + + //! @brief Packed Shift Left Logical (SSE2). + inline void pslld(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void pslld(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void pslld(const XmmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSllD, &dst, &src); } + + //! @brief Packed Shift Left Logical (SSE2). + inline void psllq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllq(const XmmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSllQ, &dst, &src); } + + //! @brief Packed Shift Left Logical (SSE2). + inline void psllw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllw(const XmmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSllW, &dst, &src); } + + //! @brief Packed Shift Left Logical (SSE2). + inline void pslldq(const XmmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSllDQ, &dst, &src); } + + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psrad(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSraD, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psrad(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSraD, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psrad(const XmmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSraD, &dst, &src); } + + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psraw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psraw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psraw(const XmmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSraW, &dst, &src); } + + //! @brief Packed Subtract (SSE2). + inline void psubb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSubB, &dst, &src); } + //! @brief Packed Subtract (SSE2). + inline void psubb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubB, &dst, &src); } + + //! @brief Packed Subtract (SSE2). + inline void psubw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSubW, &dst, &src); } + //! @brief Packed Subtract (SSE2). + inline void psubw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubW, &dst, &src); } + + //! @brief Packed Subtract (SSE2). + inline void psubd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSubD, &dst, &src); } + //! @brief Packed Subtract (SSE2). + inline void psubd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubD, &dst, &src); } + + //! @brief Packed Subtract (SSE2). + inline void psubq(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSubQ, &dst, &src); } + //! @brief Packed Subtract (SSE2). + inline void psubq(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubQ, &dst, &src); } + + //! @brief Packed Subtract (SSE2). + inline void psubq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSubQ, &dst, &src); } + //! @brief Packed Subtract (SSE2). + inline void psubq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubQ, &dst, &src); } + + //! @brief Packed Multiply and Add (SSE2). + inline void pmaddwd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMAddWD, &dst, &src); } + //! @brief Packed Multiply and Add (SSE2). + inline void pmaddwd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMAddWD, &dst, &src); } + + //! @brief Shuffle Packed DWORDs (SSE2). + inline void pshufd(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufD, &dst, &src, &imm8); } + //! @brief Shuffle Packed DWORDs (SSE2). + inline void pshufd(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufD, &dst, &src, &imm8); } + + //! @brief Shuffle Packed High Words (SSE2). + inline void pshufhw(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufHW, &dst, &src, &imm8); } + //! @brief Shuffle Packed High Words (SSE2). + inline void pshufhw(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufHW, &dst, &src, &imm8); } + + //! @brief Shuffle Packed Low Words (SSE2). + inline void pshuflw(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufLW, &dst, &src, &imm8); } + //! @brief Shuffle Packed Low Words (SSE2). + inline void pshuflw(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPShufLW, &dst, &src, &imm8); } + + //! @brief Packed Shift Right Logical (SSE2). + inline void psrld(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrld(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrld(const XmmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlD, &dst, &src); } + + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlq(const XmmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlQ, &dst, &src); } + + //! @brief DQWord Shift Right Logical (MMX). + inline void psrldq(const XmmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlDQ, &dst, &src); } + + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlw(const XmmVar& dst, const Imm& src) + { _emitInstruction(kX86InstPSrlW, &dst, &src); } + + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSubSB, &dst, &src); } + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubSB, &dst, &src); } + + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSubSW, &dst, &src); } + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubSW, &dst, &src); } + + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSubUSB, &dst, &src); } + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubUSB, &dst, &src); } + + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSubUSW, &dst, &src); } + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSubUSW, &dst, &src); } + + //! @brief Unpack High Data (SSE2). + inline void punpckhbw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPunpckHBW, &dst, &src); } + //! @brief Unpack High Data (SSE2). + inline void punpckhbw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHBW, &dst, &src); } + + //! @brief Unpack High Data (SSE2). + inline void punpckhwd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPunpckHWD, &dst, &src); } + //! @brief Unpack High Data (SSE2). + inline void punpckhwd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHWD, &dst, &src); } + + //! @brief Unpack High Data (SSE2). + inline void punpckhdq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPunpckHDQ, &dst, &src); } + //! @brief Unpack High Data (SSE2). + inline void punpckhdq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHDQ, &dst, &src); } + + //! @brief Unpack High Data (SSE2). + inline void punpckhqdq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPunpckHQDQ, &dst, &src); } + //! @brief Unpack High Data (SSE2). + inline void punpckhqdq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckHQDQ, &dst, &src); } + + //! @brief Unpack Low Data (SSE2). + inline void punpcklbw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPunpckLBW, &dst, &src); } + //! @brief Unpack Low Data (SSE2). + inline void punpcklbw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLBW, &dst, &src); } + + //! @brief Unpack Low Data (SSE2). + inline void punpcklwd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPunpckLWD, &dst, &src); } + //! @brief Unpack Low Data (SSE2). + inline void punpcklwd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLWD, &dst, &src); } + + //! @brief Unpack Low Data (SSE2). + inline void punpckldq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPunpckLDQ, &dst, &src); } + //! @brief Unpack Low Data (SSE2). + inline void punpckldq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLDQ, &dst, &src); } + + //! @brief Unpack Low Data (SSE2). + inline void punpcklqdq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPunpckLQDQ, &dst, &src); } + //! @brief Unpack Low Data (SSE2). + inline void punpcklqdq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPunpckLQDQ, &dst, &src); } + + //! @brief Bitwise Exclusive OR (SSE2). + inline void pxor(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPXor, &dst, &src); } + //! @brief Bitwise Exclusive OR (SSE2). + inline void pxor(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPXor, &dst, &src); } + + //! @brief Shuffle DP-FP (SSE2). + inline void shufpd(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstShufPD, &dst, &src, &imm8); } + //! @brief Shuffle DP-FP (SSE2). + inline void shufpd(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstShufPD, &dst, &src, &imm8); } + + //! @brief Compute Square Roots of Packed DP-FP Values (SSE2). + inline void sqrtpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstSqrtPD, &dst, &src); } + //! @brief Compute Square Roots of Packed DP-FP Values (SSE2). + inline void sqrtpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtPD, &dst, &src); } + + //! @brief Compute Square Root of Scalar DP-FP Value (SSE2). + inline void sqrtsd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstSqrtSD, &dst, &src); } + //! @brief Compute Square Root of Scalar DP-FP Value (SSE2). + inline void sqrtsd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstSqrtSD, &dst, &src); } + + //! @brief Packed DP-FP Subtract (SSE2). + inline void subpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstSubPD, &dst, &src); } + //! @brief Packed DP-FP Subtract (SSE2). + inline void subpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstSubPD, &dst, &src); } + + //! @brief Scalar DP-FP Subtract (SSE2). + inline void subsd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstSubSD, &dst, &src); } + //! @brief Scalar DP-FP Subtract (SSE2). + inline void subsd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstSubSD, &dst, &src); } + + //! @brief Scalar Unordered DP-FP Compare and Set EFLAGS (SSE2). + inline void ucomisd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstUComISD, &dst, &src); } + //! @brief Scalar Unordered DP-FP Compare and Set EFLAGS (SSE2). + inline void ucomisd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstUComISD, &dst, &src); } + + //! @brief Unpack and Interleave High Packed Double-Precision FP Values (SSE2). + inline void unpckhpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstUnpckHPD, &dst, &src); } + //! @brief Unpack and Interleave High Packed Double-Precision FP Values (SSE2). + inline void unpckhpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstUnpckHPD, &dst, &src); } + + //! @brief Unpack and Interleave Low Packed Double-Precision FP Values (SSE2). + inline void unpcklpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstUnpckLPD, &dst, &src); } + //! @brief Unpack and Interleave Low Packed Double-Precision FP Values (SSE2). + inline void unpcklpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstUnpckLPD, &dst, &src); } + + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void xorpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstXorPD, &dst, &src); } + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void xorpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstXorPD, &dst, &src); } + + // -------------------------------------------------------------------------- + // [SSE3] + // -------------------------------------------------------------------------- + + //! @brief Packed DP-FP Add/Subtract (SSE3). + inline void addsubpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstAddSubPD, &dst, &src); } + //! @brief Packed DP-FP Add/Subtract (SSE3). + inline void addsubpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstAddSubPD, &dst, &src); } + + //! @brief Packed SP-FP Add/Subtract (SSE3). + inline void addsubps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstAddSubPS, &dst, &src); } + //! @brief Packed SP-FP Add/Subtract (SSE3). + inline void addsubps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstAddSubPS, &dst, &src); } + +#if ASMJIT_NOT_SUPPORTED_BY_COMPILER + // TODO: NOT IMPLEMENTED BY THE COMPILER. + //! @brief Store Integer with Truncation (SSE3). + inline void fisttp(const Mem& dst) + { _emitInstruction(kX86InstFISttP, &dst); } +#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER + + //! @brief Packed DP-FP Horizontal Add (SSE3). + inline void haddpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstHAddPD, &dst, &src); } + //! @brief Packed DP-FP Horizontal Add (SSE3). + inline void haddpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstHAddPD, &dst, &src); } + + //! @brief Packed SP-FP Horizontal Add (SSE3). + inline void haddps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstHAddPS, &dst, &src); } + //! @brief Packed SP-FP Horizontal Add (SSE3). + inline void haddps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstHAddPS, &dst, &src); } + + //! @brief Packed DP-FP Horizontal Subtract (SSE3). + inline void hsubpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstHSubPD, &dst, &src); } + //! @brief Packed DP-FP Horizontal Subtract (SSE3). + inline void hsubpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstHSubPD, &dst, &src); } + + //! @brief Packed SP-FP Horizontal Subtract (SSE3). + inline void hsubps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstHSubPS, &dst, &src); } + //! @brief Packed SP-FP Horizontal Subtract (SSE3). + inline void hsubps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstHSubPS, &dst, &src); } + + //! @brief Load Unaligned Integer 128 Bits (SSE3). + inline void lddqu(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstLdDQU, &dst, &src); } + +#if ASMJIT_NOT_SUPPORTED_BY_COMPILER + //! @brief Set Up Monitor Address (SSE3). + inline void monitor() + { _emitInstruction(kX86InstMonitor); } +#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER + + //! @brief Move One DP-FP and Duplicate (SSE3). + inline void movddup(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovDDup, &dst, &src); } + //! @brief Move One DP-FP and Duplicate (SSE3). + inline void movddup(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovDDup, &dst, &src); } + + //! @brief Move Packed SP-FP High and Duplicate (SSE3). + inline void movshdup(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovSHDup, &dst, &src); } + //! @brief Move Packed SP-FP High and Duplicate (SSE3). + inline void movshdup(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovSHDup, &dst, &src); } + + //! @brief Move Packed SP-FP Low and Duplicate (SSE3). + inline void movsldup(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstMovSLDup, &dst, &src); } + //! @brief Move Packed SP-FP Low and Duplicate (SSE3). + inline void movsldup(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovSLDup, &dst, &src); } + +#if ASMJIT_NOT_SUPPORTED_BY_COMPILER + //! @brief Monitor Wait (SSE3). + inline void mwait() + { _emitInstruction(kX86InstMWait); } +#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER + + // -------------------------------------------------------------------------- + // [SSSE3] + // -------------------------------------------------------------------------- + + //! @brief Packed SIGN (SSSE3). + inline void psignb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSignB, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSignB, &dst, &src); } + + //! @brief Packed SIGN (SSSE3). + inline void psignb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSignB, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSignB, &dst, &src); } + + //! @brief Packed SIGN (SSSE3). + inline void psignw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSignW, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSignW, &dst, &src); } + + //! @brief Packed SIGN (SSSE3). + inline void psignw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSignW, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSignW, &dst, &src); } + + //! @brief Packed SIGN (SSSE3). + inline void psignd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPSignD, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSignD, &dst, &src); } + + //! @brief Packed SIGN (SSSE3). + inline void psignd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPSignD, &dst, &src); } + //! @brief Packed SIGN (SSSE3). + inline void psignd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPSignD, &dst, &src); } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPHAddW, &dst, &src); } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddW, &dst, &src); } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPHAddW, &dst, &src); } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddW, &dst, &src); } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPHAddD, &dst, &src); } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddD, &dst, &src); } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPHAddD, &dst, &src); } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddD, &dst, &src); } + + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPHAddSW, &dst, &src); } + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddSW, &dst, &src); } + + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPHAddSW, &dst, &src); } + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHAddSW, &dst, &src); } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPHSubW, &dst, &src); } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubW, &dst, &src); } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPHSubW, &dst, &src); } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubW, &dst, &src); } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPHSubD, &dst, &src); } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubD, &dst, &src); } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPHSubD, &dst, &src); } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubD, &dst, &src); } + + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPHSubSW, &dst, &src); } + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubSW, &dst, &src); } + + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPHSubSW, &dst, &src); } + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHSubSW, &dst, &src); } + + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMAddUBSW, &dst, &src); } + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMAddUBSW, &dst, &src); } + + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMAddUBSW, &dst, &src); } + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMAddUBSW, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAbsB, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsB, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAbsB, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsB, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAbsW, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsW, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAbsW, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsW, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPAbsD, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsD, &dst, &src); } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPAbsD, &dst, &src); } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPAbsD, &dst, &src); } + + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPMulHRSW, &dst, &src); } + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHRSW, &dst, &src); } + + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMulHRSW, &dst, &src); } + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulHRSW, &dst, &src); } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const MmVar& dst, const MmVar& src) + { _emitInstruction(kX86InstPShufB, &dst, &src); } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const MmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPShufB, &dst, &src); } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPShufB, &dst, &src); } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPShufB, &dst, &src); } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const MmVar& dst, const MmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPAlignR, &dst, &src, &imm8); } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const MmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPAlignR, &dst, &src, &imm8); } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPAlignR, &dst, &src, &imm8); } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPAlignR, &dst, &src, &imm8); } + + // -------------------------------------------------------------------------- + // [SSE4.1] + // -------------------------------------------------------------------------- + + //! @brief Blend Packed DP-FP Values (SSE4.1). + inline void blendpd(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstBlendPD, &dst, &src, &imm8); } + //! @brief Blend Packed DP-FP Values (SSE4.1). + inline void blendpd(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstBlendPD, &dst, &src, &imm8); } + + //! @brief Blend Packed SP-FP Values (SSE4.1). + inline void blendps(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstBlendPS, &dst, &src, &imm8); } + //! @brief Blend Packed SP-FP Values (SSE4.1). + inline void blendps(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstBlendPS, &dst, &src, &imm8); } + + //! @brief Variable Blend Packed DP-FP Values (SSE4.1). + inline void blendvpd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstBlendVPD, &dst, &src); } + //! @brief Variable Blend Packed DP-FP Values (SSE4.1). + inline void blendvpd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstBlendVPD, &dst, &src); } + + //! @brief Variable Blend Packed SP-FP Values (SSE4.1). + inline void blendvps(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstBlendVPS, &dst, &src); } + //! @brief Variable Blend Packed SP-FP Values (SSE4.1). + inline void blendvps(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstBlendVPS, &dst, &src); } + + //! @brief Dot Product of Packed DP-FP Values (SSE4.1). + inline void dppd(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstDpPD, &dst, &src, &imm8); } + //! @brief Dot Product of Packed DP-FP Values (SSE4.1). + inline void dppd(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstDpPD, &dst, &src, &imm8); } + + //! @brief Dot Product of Packed SP-FP Values (SSE4.1). + inline void dpps(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstDpPS, &dst, &src, &imm8); } + //! @brief Dot Product of Packed SP-FP Values (SSE4.1). + inline void dpps(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstDpPS, &dst, &src, &imm8); } + + //! @brief Extract Packed SP-FP Value (SSE4.1). + inline void extractps(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstExtractPS, &dst, &src, &imm8); } + //! @brief Extract Packed SP-FP Value (SSE4.1). + inline void extractps(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstExtractPS, &dst, &src, &imm8); } + + //! @brief Load Double Quadword Non-Temporal Aligned Hint (SSE4.1). + inline void movntdqa(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstMovNTDQA, &dst, &src); } + + //! @brief Compute Multiple Packed Sums of Absolute Difference (SSE4.1). + inline void mpsadbw(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstMPSADBW, &dst, &src, &imm8); } + //! @brief Compute Multiple Packed Sums of Absolute Difference (SSE4.1). + inline void mpsadbw(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstMPSADBW, &dst, &src, &imm8); } + + //! @brief Pack with Unsigned Saturation (SSE4.1). + inline void packusdw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPackUSDW, &dst, &src); } + //! @brief Pack with Unsigned Saturation (SSE4.1). + inline void packusdw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPackUSDW, &dst, &src); } + + //! @brief Variable Blend Packed Bytes (SSE4.1). + inline void pblendvb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPBlendVB, &dst, &src); } + //! @brief Variable Blend Packed Bytes (SSE4.1). + inline void pblendvb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPBlendVB, &dst, &src); } + + //! @brief Blend Packed Words (SSE4.1). + inline void pblendw(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPBlendW, &dst, &src, &imm8); } + //! @brief Blend Packed Words (SSE4.1). + inline void pblendw(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPBlendW, &dst, &src, &imm8); } + + //! @brief Compare Packed Qword Data for Equal (SSE4.1). + inline void pcmpeqq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPCmpEqQ, &dst, &src); } + //! @brief Compare Packed Qword Data for Equal (SSE4.1). + inline void pcmpeqq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpEqQ, &dst, &src); } + + //! @brief Extract Byte (SSE4.1). + inline void pextrb(const GpVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrB, &dst, &src, &imm8); } + //! @brief Extract Byte (SSE4.1). + inline void pextrb(const Mem& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrB, &dst, &src, &imm8); } + + //! @brief Extract Dword (SSE4.1). + inline void pextrd(const GpVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrD, &dst, &src, &imm8); } + //! @brief Extract Dword (SSE4.1). + inline void pextrd(const Mem& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrD, &dst, &src, &imm8); } + + //! @brief Extract Dword (SSE4.1). + inline void pextrq(const GpVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrQ, &dst, &src, &imm8); } + //! @brief Extract Dword (SSE4.1). + inline void pextrq(const Mem& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPExtrQ, &dst, &src, &imm8); } + + //! @brief Packed Horizontal Word Minimum (SSE4.1). + inline void phminposuw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPHMinPOSUW, &dst, &src); } + //! @brief Packed Horizontal Word Minimum (SSE4.1). + inline void phminposuw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPHMinPOSUW, &dst, &src); } + + //! @brief Insert Byte (SSE4.1). + inline void pinsrb(const XmmVar& dst, const GpVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRB, &dst, &src, &imm8); } + //! @brief Insert Byte (SSE4.1). + inline void pinsrb(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRB, &dst, &src, &imm8); } + + //! @brief Insert Dword (SSE4.1). + inline void pinsrd(const XmmVar& dst, const GpVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRD, &dst, &src, &imm8); } + //! @brief Insert Dword (SSE4.1). + inline void pinsrd(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRD, &dst, &src, &imm8); } + + //! @brief Insert Dword (SSE4.1). + inline void pinsrq(const XmmVar& dst, const GpVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRQ, &dst, &src, &imm8); } + //! @brief Insert Dword (SSE4.1). + inline void pinsrq(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRQ, &dst, &src, &imm8); } + + //! @brief Insert Word (SSE2). + inline void pinsrw(const XmmVar& dst, const GpVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRW, &dst, &src, &imm8); } + //! @brief Insert Word (SSE2). + inline void pinsrw(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPInsRW, &dst, &src, &imm8); } + + //! @brief Maximum of Packed Word Integers (SSE4.1). + inline void pmaxuw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMaxUW, &dst, &src); } + //! @brief Maximum of Packed Word Integers (SSE4.1). + inline void pmaxuw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxUW, &dst, &src); } + + //! @brief Maximum of Packed Signed Byte Integers (SSE4.1). + inline void pmaxsb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMaxSB, &dst, &src); } + //! @brief Maximum of Packed Signed Byte Integers (SSE4.1). + inline void pmaxsb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxSB, &dst, &src); } + + //! @brief Maximum of Packed Signed Dword Integers (SSE4.1). + inline void pmaxsd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMaxSD, &dst, &src); } + //! @brief Maximum of Packed Signed Dword Integers (SSE4.1). + inline void pmaxsd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxSD, &dst, &src); } + + //! @brief Maximum of Packed Unsigned Dword Integers (SSE4.1). + inline void pmaxud(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMaxUD, &dst, &src); } + //! @brief Maximum of Packed Unsigned Dword Integers (SSE4.1). + inline void pmaxud(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMaxUD, &dst, &src); } + + //! @brief Minimum of Packed Signed Byte Integers (SSE4.1). + inline void pminsb(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMinSB, &dst, &src); } + //! @brief Minimum of Packed Signed Byte Integers (SSE4.1). + inline void pminsb(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMinSB, &dst, &src); } + + //! @brief Minimum of Packed Word Integers (SSE4.1). + inline void pminuw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMinUW, &dst, &src); } + //! @brief Minimum of Packed Word Integers (SSE4.1). + inline void pminuw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMinUW, &dst, &src); } + + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminud(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMinUD, &dst, &src); } + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminud(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMinUD, &dst, &src); } + + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminsd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMinSD, &dst, &src); } + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminsd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMinSD, &dst, &src); } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovSXBW, &dst, &src); } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXBW, &dst, &src); } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovSXBD, &dst, &src); } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXBD, &dst, &src); } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovSXBQ, &dst, &src); } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXBQ, &dst, &src); } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxwd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovSXWD, &dst, &src); } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxwd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXWD, &dst, &src); } + + //! @brief (SSE4.1). + inline void pmovsxwq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovSXWQ, &dst, &src); } + //! @brief (SSE4.1). + inline void pmovsxwq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXWQ, &dst, &src); } + + //! @brief (SSE4.1). + inline void pmovsxdq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovSXDQ, &dst, &src); } + //! @brief (SSE4.1). + inline void pmovsxdq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovSXDQ, &dst, &src); } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbw(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovZXBW, &dst, &src); } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbw(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXBW, &dst, &src); } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovZXBD, &dst, &src); } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXBD, &dst, &src); } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovZXBQ, &dst, &src); } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXBQ, &dst, &src); } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxwd(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovZXWD, &dst, &src); } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxwd(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXWD, &dst, &src); } + + //! @brief (SSE4.1). + inline void pmovzxwq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovZXWQ, &dst, &src); } + //! @brief (SSE4.1). + inline void pmovzxwq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXWQ, &dst, &src); } + + //! @brief (SSE4.1). + inline void pmovzxdq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMovZXDQ, &dst, &src); } + //! @brief (SSE4.1). + inline void pmovzxdq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMovZXDQ, &dst, &src); } + + //! @brief Multiply Packed Signed Dword Integers (SSE4.1). + inline void pmuldq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMulDQ, &dst, &src); } + //! @brief Multiply Packed Signed Dword Integers (SSE4.1). + inline void pmuldq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulDQ, &dst, &src); } + + //! @brief Multiply Packed Signed Integers and Store Low Result (SSE4.1). + inline void pmulld(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPMulLD, &dst, &src); } + //! @brief Multiply Packed Signed Integers and Store Low Result (SSE4.1). + inline void pmulld(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPMulLD, &dst, &src); } + + //! @brief Logical Compare (SSE4.1). + inline void ptest(const XmmVar& op1, const XmmVar& op2) + { _emitInstruction(kX86InstPTest, &op1, &op2); } + //! @brief Logical Compare (SSE4.1). + inline void ptest(const XmmVar& op1, const Mem& op2) + { _emitInstruction(kX86InstPTest, &op1, &op2); } + + //! Round Packed SP-FP Values @brief (SSE4.1). + inline void roundps(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundPS, &dst, &src, &imm8); } + //! Round Packed SP-FP Values @brief (SSE4.1). + inline void roundps(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundPS, &dst, &src, &imm8); } + + //! @brief Round Scalar SP-FP Values (SSE4.1). + inline void roundss(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundSS, &dst, &src, &imm8); } + //! @brief Round Scalar SP-FP Values (SSE4.1). + inline void roundss(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundSS, &dst, &src, &imm8); } + + //! @brief Round Packed DP-FP Values (SSE4.1). + inline void roundpd(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundPD, &dst, &src, &imm8); } + //! @brief Round Packed DP-FP Values (SSE4.1). + inline void roundpd(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundPD, &dst, &src, &imm8); } + + //! @brief Round Scalar DP-FP Values (SSE4.1). + inline void roundsd(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundSD, &dst, &src, &imm8); } + //! @brief Round Scalar DP-FP Values (SSE4.1). + inline void roundsd(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstRoundSD, &dst, &src, &imm8); } + + // -------------------------------------------------------------------------- + // [SSE4.2] + // -------------------------------------------------------------------------- + + //! @brief Accumulate CRC32 Value (polynomial 0x11EDC6F41) (SSE4.2). + inline void crc32(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstCrc32, &dst, &src); } + //! @brief Accumulate CRC32 Value (polynomial 0x11EDC6F41) (SSE4.2). + inline void crc32(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstCrc32, &dst, &src); } + + //! @brief Packed Compare Explicit Length Strings, Return Index (SSE4.2). + inline void pcmpestri(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpEStrI, &dst, &src, &imm8); } + //! @brief Packed Compare Explicit Length Strings, Return Index (SSE4.2). + inline void pcmpestri(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpEStrI, &dst, &src, &imm8); } + + //! @brief Packed Compare Explicit Length Strings, Return Mask (SSE4.2). + inline void pcmpestrm(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpEStrM, &dst, &src, &imm8); } + //! @brief Packed Compare Explicit Length Strings, Return Mask (SSE4.2). + inline void pcmpestrm(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpEStrM, &dst, &src, &imm8); } + + //! @brief Packed Compare Implicit Length Strings, Return Index (SSE4.2). + inline void pcmpistri(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpIStrI, &dst, &src, &imm8); } + //! @brief Packed Compare Implicit Length Strings, Return Index (SSE4.2). + inline void pcmpistri(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpIStrI, &dst, &src, &imm8); } + + //! @brief Packed Compare Implicit Length Strings, Return Mask (SSE4.2). + inline void pcmpistrm(const XmmVar& dst, const XmmVar& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpIStrM, &dst, &src, &imm8); } + //! @brief Packed Compare Implicit Length Strings, Return Mask (SSE4.2). + inline void pcmpistrm(const XmmVar& dst, const Mem& src, const Imm& imm8) + { _emitInstruction(kX86InstPCmpIStrM, &dst, &src, &imm8); } + + //! @brief Compare Packed Data for Greater Than (SSE4.2). + inline void pcmpgtq(const XmmVar& dst, const XmmVar& src) + { _emitInstruction(kX86InstPCmpGtQ, &dst, &src); } + //! @brief Compare Packed Data for Greater Than (SSE4.2). + inline void pcmpgtq(const XmmVar& dst, const Mem& src) + { _emitInstruction(kX86InstPCmpGtQ, &dst, &src); } + + //! @brief Return the Count of Number of Bits Set to 1 (SSE4.2). + inline void popcnt(const GpVar& dst, const GpVar& src) + { _emitInstruction(kX86InstPopCnt, &dst, &src); } + //! @brief Return the Count of Number of Bits Set to 1 (SSE4.2). + inline void popcnt(const GpVar& dst, const Mem& src) + { _emitInstruction(kX86InstPopCnt, &dst, &src); } + + // -------------------------------------------------------------------------- + // [AMD only] + // -------------------------------------------------------------------------- + + //! @brief Prefetch (3dNow - Amd). + //! + //! Loads the entire 64-byte aligned memory sequence containing the + //! specified memory address into the L1 data cache. The position of + //! the specified memory address within the 64-byte cache line is + //! irrelevant. If a cache hit occurs, or if a memory fault is detected, + //! no bus cycle is initiated and the instruction is treated as a NOP. + inline void amd_prefetch(const Mem& mem) + { _emitInstruction(kX86InstAmdPrefetch, &mem); } + + //! @brief Prefetch and set cache to modified (3dNow - Amd). + //! + //! The PREFETCHW instruction loads the prefetched line and sets the + //! cache-line state to Modified, in anticipation of subsequent data + //! writes to the line. The PREFETCH instruction, by contrast, typically + //! sets the cache-line state to Exclusive (depending on the hardware + //! implementation). + inline void amd_prefetchw(const Mem& mem) + { _emitInstruction(kX86InstAmdPrefetchW, &mem); } + + // -------------------------------------------------------------------------- + // [Intel only] + // -------------------------------------------------------------------------- + + //! @brief Move Data After Swapping Bytes (SSE3 - Intel Atom). + inline void movbe(const GpVar& dst, const Mem& src) + { + ASMJIT_ASSERT(!dst.isGpb()); + _emitInstruction(kX86InstMovBE, &dst, &src); + } + + //! @brief Move Data After Swapping Bytes (SSE3 - Intel Atom). + inline void movbe(const Mem& dst, const GpVar& src) + { + ASMJIT_ASSERT(!src.isGpb()); + _emitInstruction(kX86InstMovBE, &dst, &src); + } + + // ------------------------------------------------------------------------- + // [Emit Options] + // ------------------------------------------------------------------------- + + //! @brief Assert LOCK# Signal Prefix. + //! + //! This instruction causes the processor's LOCK# signal to be asserted + //! during execution of the accompanying instruction (turns the + //! instruction into an atomic instruction). In a multiprocessor environment, + //! the LOCK# signal insures that the processor has exclusive use of any shared + //! memory while the signal is asserted. + //! + //! The LOCK prefix can be prepended only to the following instructions and + //! to those forms of the instructions that use a memory operand: ADD, ADC, + //! AND, BTC, BTR, BTS, CMPXCHG, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, + //! and XCHG. An undefined opcode exception will be generated if the LOCK + //! prefix is used with any other instruction. The XCHG instruction always + //! asserts the LOCK# signal regardless of the presence or absence of the LOCK + //! prefix. + inline void lock() + { _emitOptions |= kX86EmitOptionLock; } + + //! @brief Force REX prefix to be emitted. + //! + //! This option should be used carefully, because there are unencodable + //! combinations. If you want to access ah, bh, ch or dh registers then you + //! can't emit REX prefix and it will cause an illegal instruction error. + //! + //! @note REX prefix is only valid for X64/AMD64 platform. + //! + //! @sa @c kX86EmitOptionRex. + inline void rex() + { _emitOptions |= kX86EmitOptionRex; } +}; + +//! @} + +} // AsmJit namespace + +#undef ASMJIT_NOT_SUPPORTED_BY_COMPILER + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_X86_X86COMPILER_H diff --git a/desmume/src/utils/AsmJit/x86/x86compilercontext.cpp b/desmume/src/utils/AsmJit/x86/x86compilercontext.cpp new file mode 100644 index 000000000..0fe0222d0 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86compilercontext.cpp @@ -0,0 +1,1876 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/intutil.h" +#include "../core/stringutil.h" + +#include "../x86/x86assembler.h" +#include "../x86/x86compiler.h" +#include "../x86/x86compilercontext.h" +#include "../x86/x86compilerfunc.h" +#include "../x86/x86compileritem.h" +#include "../x86/x86util.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::CompilerContext - Construction / Destruction] +// ============================================================================ + +X86CompilerContext::X86CompilerContext(X86Compiler* x86Compiler) : + CompilerContext(x86Compiler) +{ + _state = &_x86State; + + _clear(); + _emitComments = x86Compiler->getLogger() != NULL; +} + +X86CompilerContext::~X86CompilerContext() +{ +} + +// ============================================================================ +// [AsmJit::CompilerContext - Clear] +// ============================================================================ + +void X86CompilerContext::_clear() +{ + _zoneMemory.clear(); + _func = NULL; + + _start = NULL; + _stop = NULL; + + _x86State.clear(); + _active = NULL; + + _forwardJumps = NULL; + + _currentOffset = 0; + _isUnreachable = 0; + + _modifiedGpRegisters = 0; + _modifiedMmRegisters = 0; + _modifiedXmmRegisters = 0; + + _allocableEBP = false; + + _adjustESP = 0; + + _argumentsBaseReg = kRegIndexInvalid; // Used by patcher. + _argumentsBaseOffset = 0; // Used by patcher. + _argumentsActualDisp = 0; // Used by translate(). + + _variablesBaseReg = kRegIndexInvalid; // Used by patcher. + _variablesBaseOffset = 0; // Used by patcher. + _variablesActualDisp = 0; // Used by translate() + + _memUsed = NULL; + _memFree = NULL; + + _mem4BlocksCount = 0; + _mem8BlocksCount = 0; + _mem16BlocksCount = 0; + + _memBytesTotal = 0; + + _backCode.clear(); + _backPos = 0; +} + +// ============================================================================ +// [AsmJit::CompilerContext - Construction / Destruction] +// ============================================================================ + +void X86CompilerContext::allocVar(X86CompilerVar* var, uint32_t regMask, uint32_t vflags) +{ + switch (var->getType()) + { + case kX86VarTypeGpd: +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: +#endif // ASMJIT_X64 + allocGpVar(var, regMask, vflags); + break; + + case kX86VarTypeX87: + case kX86VarTypeX87SS: + case kX86VarTypeX87SD: + // TODO: X87 Support. + break; + + case kX86VarTypeMm: + allocMmVar(var, regMask, vflags); + break; + + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + allocXmmVar(var, regMask, vflags); + break; + } + + _postAlloc(var, vflags); +} + +void X86CompilerContext::saveVar(X86CompilerVar* var) +{ + switch (var->getType()) + { + case kX86VarTypeGpd: +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: +#endif // ASMJIT_X64 + saveGpVar(var); + break; + + case kX86VarTypeX87: + case kX86VarTypeX87SS: + case kX86VarTypeX87SD: + // TODO: X87 Support. + break; + + case kX86VarTypeMm: + saveMmVar(var); + break; + + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + saveXmmVar(var); + break; + } +} + +void X86CompilerContext::spillVar(X86CompilerVar* var) +{ + switch (var->getType()) + { + case kX86VarTypeGpd: +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: +#endif // ASMJIT_X64 + spillGpVar(var); + break; + + case kX86VarTypeX87: + case kX86VarTypeX87SS: + case kX86VarTypeX87SD: + // TODO: X87 Support. + break; + + case kX86VarTypeMm: + spillMmVar(var); + break; + + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + spillXmmVar(var); + break; + } +} + +void X86CompilerContext::unuseVar(X86CompilerVar* var, uint32_t toState) +{ + ASMJIT_ASSERT(toState != kVarStateReg); + + if (var->state == kVarStateReg) + { + uint32_t regIndex = var->regIndex; + switch (var->getType()) + { + case kX86VarTypeGpd: +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: +#endif // ASMJIT_X64 + _x86State.gp[regIndex] = NULL; + _freedGpRegister(regIndex); + break; + + case kX86VarTypeX87: + case kX86VarTypeX87SS: + case kX86VarTypeX87SD: + // TODO: X87 Support. + break; + + case kX86VarTypeMm: + _x86State.mm[regIndex] = NULL; + _freedMmRegister(regIndex); + break; + + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + _x86State.xmm[regIndex] = NULL; + _freedXmmRegister(regIndex); + break; + } + } + + var->state = toState; + var->changed = false; + var->regIndex = kRegIndexInvalid; +} + +void X86CompilerContext::allocGpVar(X86CompilerVar* var, uint32_t regMask, uint32_t vflags) +{ + uint32_t fullMask = IntUtil::maskUpToIndex(kX86RegNumGp) & ~IntUtil::maskFromIndex(kX86RegIndexEsp); + if (!_allocableEBP) + fullMask &= ~IntUtil::maskFromIndex(kX86RegIndexEbp); + + // Fix the regMask (0 or full bit-array means that any register may be used). + if (regMask == 0) + regMask = 0xFFFFFFFF; + regMask &= fullMask; + + // Working variables. + uint32_t i; + uint32_t mask; + + // Last register code (aka home). + uint32_t home = var->homeRegisterIndex; + // New register code. + uint32_t idx = kRegIndexInvalid; + + // Preserved GP variables. + uint32_t preservedGP = var->funcScope->getDecl()->getGpPreservedMask(); + + // Spill candidate. + X86CompilerVar* spillCandidate = NULL; + + // Whether to alloc the non-preserved variables first. + bool nonPreservedFirst = true; + + if (getFunc()->isCaller()) + nonPreservedFirst = (var->funcCall == NULL) || (var->funcCall->getOffset() >= var->lastItem->getOffset()); + + // -------------------------------------------------------------------------- + // [Already Allocated] + // -------------------------------------------------------------------------- + + // Go away if variable is already allocated. + if (var->state == kVarStateReg) + { + uint32_t oldIndex = var->regIndex; + + // Already allocated in the right register. + if (IntUtil::maskFromIndex(oldIndex) & regMask) + return; + + // Try to find unallocated register first. + mask = regMask & ~_x86State.usedGP; + if (mask != 0) + { + idx = IntUtil::findFirstBit((nonPreservedFirst && (mask & ~preservedGP) != 0) ? mask & ~preservedGP : mask); + } + // Then find the allocated and exchange later. + else + { + idx = IntUtil::findFirstBit(regMask & _x86State.usedGP); + } + ASMJIT_ASSERT(idx != kRegIndexInvalid); + + X86CompilerVar* other = _x86State.gp[idx]; + emitExchangeVar(var, idx, vflags, other); + + _x86State.gp[oldIndex] = other; + _x86State.gp[idx ] = var; + + if (other) + other->regIndex = oldIndex; + else + _freedGpRegister(oldIndex); + + // Update X86CompilerVar. + var->state = kVarStateReg; + var->regIndex = idx; + var->homeRegisterIndex = idx; + + _allocatedGpRegister(idx); + return; + } + + // -------------------------------------------------------------------------- + // [Find Unused GP] + // -------------------------------------------------------------------------- + + // Home register code. + if ((idx == kRegIndexInvalid) && + (home != kRegIndexInvalid) && + (regMask & IntUtil::maskFromIndex(home)) != 0 && + (_x86State.usedGP & IntUtil::maskFromIndex(home)) == 0) + { + idx = home; + goto _Alloc; + } + + // We start from 1, because EAX/RAX register is sometimes explicitly + // needed. So we trying to prevent reallocation in near future. + if (idx == kRegIndexInvalid) + { + for (i = 1, mask = (1 << i); i < kX86RegNumGp; i++, mask <<= 1) + { + if ((regMask & mask) != 0 && (_x86State.usedGP & mask) == 0) + { + // Convenience to alloc non-preserved first or non-preserved last. + if (nonPreservedFirst) + { + if (idx != kRegIndexInvalid && (preservedGP & mask) != 0) + continue; + + idx = i; + // If current register is preserved, we should try to find different + // one that is not. This can save one push / pop in prolog / epilog. + if ((preservedGP & mask) == 0) + break; + } + else + { + if (idx != kRegIndexInvalid && (preservedGP & mask) == 0) + continue; + + idx = i; + // The opposite. + if ((preservedGP & mask) != 0) + break; + } + } + } + } + + // If not found, try EAX/RAX. + if ((idx == kRegIndexInvalid) && + (regMask & IntUtil::maskFromIndex(kX86RegIndexEax)) != 0 && + (_x86State.usedGP & IntUtil::maskFromIndex(kX86RegIndexEax)) == 0) + { + idx = kX86RegIndexEax; + goto _Alloc; + } + + // If regMask contains restricted registers which may be used then everything + // is handled inside this block. + if ((idx == kRegIndexInvalid) && (regMask != fullMask)) + { + // Try to find unallocated register first. + mask = regMask & ~_x86State.usedGP; + if (mask != 0) + { + idx = IntUtil::findFirstBit((nonPreservedFirst && (mask & ~preservedGP) != 0) ? (mask & ~preservedGP) : mask); + ASMJIT_ASSERT(idx != kRegIndexInvalid); + } + // Then find the allocated and spill later. + else + { + idx = IntUtil::findFirstBit(regMask & _x86State.usedGP); + ASMJIT_ASSERT(idx != kRegIndexInvalid); + + // Spill register we need. + spillCandidate = _x86State.gp[idx]; + + // Jump to spill part of allocation. + goto L_Spill; + } + } + + // -------------------------------------------------------------------------- + // [Spill] + // -------------------------------------------------------------------------- + + // If register is still not found, spill other variable. + if (idx == kRegIndexInvalid) + { + if (spillCandidate == NULL) + { + spillCandidate = _getSpillCandidateGP(); + } + + // Spill candidate not found? + if (spillCandidate == NULL) + { + _compiler->setError(kErrorNoRegisters); + return; + } + +L_Spill: + // Prevented variables can't be spilled. _getSpillCandidate() never returns + // prevented variables, but when jumping to L_Spill it could happen. + if (spillCandidate->workOffset == _currentOffset) + { + _compiler->setError(kErrorOverlappedRegisters); + return; + } + + idx = spillCandidate->regIndex; + spillGpVar(spillCandidate); + } + + // -------------------------------------------------------------------------- + // [Alloc] + // -------------------------------------------------------------------------- + +_Alloc: + if (var->state == kVarStateMem && (vflags & kVarAllocRead) != 0) + { + emitLoadVar(var, idx); + } + + // Update X86CompilerVar. + var->state = kVarStateReg; + var->regIndex = idx; + var->homeRegisterIndex = idx; + + // Update CompilerState. + _allocatedVariable(var); +} + +void X86CompilerContext::saveGpVar(X86CompilerVar* var) +{ + // Can't save variable that isn't allocated. + ASMJIT_ASSERT(var->state == kVarStateReg); + ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid); + + uint32_t idx = var->regIndex; + emitSaveVar(var, idx); + + // Update X86CompilerVar. + var->changed = false; +} + +void X86CompilerContext::spillGpVar(X86CompilerVar* var) +{ + // Can't spill variable that isn't allocated. + ASMJIT_ASSERT(var->state == kVarStateReg); + ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid); + + uint32_t idx = var->regIndex; + + if (var->changed) emitSaveVar(var, idx); + + // Update X86CompilerVar. + var->regIndex = kRegIndexInvalid; + var->state = kVarStateMem; + var->changed = false; + + // Update CompilerState. + _x86State.gp[idx] = NULL; + _freedGpRegister(idx); +} + +void X86CompilerContext::allocMmVar(X86CompilerVar* var, uint32_t regMask, uint32_t vflags) +{ + // Fix the regMask (0 or full bit-array means that any register may be used). + if (regMask == 0) regMask = IntUtil::maskUpToIndex(kX86RegNumMm); + regMask &= IntUtil::maskUpToIndex(kX86RegNumMm); + + // Working variables. + uint32_t i; + uint32_t mask; + + // Last register code (aka home). + uint32_t home = var->homeRegisterIndex; + // New register code. + uint32_t idx = kRegIndexInvalid; + + // Preserved MM variables. + // + // NOTE: Currently MM variables are not preserved and there is no calling + // convention known to me that does that. But on the other side it's possible + // to write such calling convention. + uint32_t preservedMM = var->funcScope->getDecl()->getMmPreservedMask(); + + // Spill candidate. + X86CompilerVar* spillCandidate = NULL; + + // Whether to alloc non-preserved first or last. + bool nonPreservedFirst = true; + if (this->getFunc()->isCaller()) + { + nonPreservedFirst = var->funcCall == NULL || var->funcCall->getOffset() >= var->lastItem->getOffset(); + } + + // -------------------------------------------------------------------------- + // [Already Allocated] + // -------------------------------------------------------------------------- + + // Go away if variable is already allocated. + if (var->state == kVarStateReg) + { + uint32_t oldIndex = var->regIndex; + + // Already allocated in the right register. + if (IntUtil::maskFromIndex(oldIndex) & regMask) return; + + // Try to find unallocated register first. + mask = regMask & ~_x86State.usedMM; + if (mask != 0) + { + idx = IntUtil::findFirstBit( + (nonPreservedFirst && (mask & ~preservedMM) != 0) ? mask & ~preservedMM : mask); + } + // Then find the allocated and exchange later. + else + { + idx = IntUtil::findFirstBit(regMask & _x86State.usedMM); + } + ASMJIT_ASSERT(idx != kRegIndexInvalid); + + X86CompilerVar* other = _x86State.mm[idx]; + if (other) spillMmVar(other); + + emitMoveVar(var, idx, vflags); + _freedMmRegister(oldIndex); + _x86State.mm[idx] = var; + + // Update X86CompilerVar. + var->state = kVarStateReg; + var->regIndex = idx; + var->homeRegisterIndex = idx; + + _allocatedMmRegister(idx); + return; + } + + // -------------------------------------------------------------------------- + // [Find Unused MM] + // -------------------------------------------------------------------------- + + // If regMask contains restricted registers which may be used then everything + // is handled in this block. + if (regMask != IntUtil::maskUpToIndex(kX86RegNumMm)) + { + // Try to find unallocated register first. + mask = regMask & ~_x86State.usedMM; + if (mask != 0) + { + idx = IntUtil::findFirstBit( + (nonPreservedFirst && (mask & ~preservedMM) != 0) ? mask & ~preservedMM : mask); + ASMJIT_ASSERT(idx != kRegIndexInvalid); + } + // Then find the allocated and spill later. + else + { + idx = IntUtil::findFirstBit(regMask & _x86State.usedMM); + ASMJIT_ASSERT(idx != kRegIndexInvalid); + + // Spill register we need. + spillCandidate = _x86State.mm[idx]; + + // Jump to spill part of allocation. + goto L_Spill; + } + } + + // Home register code. + if (idx == kRegIndexInvalid && home != kRegIndexInvalid) + { + if ((_x86State.usedMM & (1U << home)) == 0) idx = home; + } + + if (idx == kRegIndexInvalid) + { + for (i = 0, mask = (1 << i); i < kX86RegNumMm; i++, mask <<= 1) + { + if ((_x86State.usedMM & mask) == 0) + { + // Convenience to alloc non-preserved first or non-preserved last. + if (nonPreservedFirst) + { + if (idx != kRegIndexInvalid && (preservedMM & mask) != 0) continue; + idx = i; + // If current register is preserved, we should try to find different + // one that is not. This can save one push / pop in prolog / epilog. + if ((preservedMM & mask) == 0) break; + } + else + { + if (idx != kRegIndexInvalid && (preservedMM & mask) == 0) continue; + idx = i; + // The opposite. + if ((preservedMM & mask) != 0) break; + } + } + } + } + + // -------------------------------------------------------------------------- + // [Spill] + // -------------------------------------------------------------------------- + + // If register is still not found, spill other variable. + if (idx == kRegIndexInvalid) + { + if (spillCandidate == NULL) spillCandidate = _getSpillCandidateMM(); + + // Spill candidate not found? + if (spillCandidate == NULL) + { + _compiler->setError(kErrorNoRegisters); + return; + } + +L_Spill: + + // Prevented variables can't be spilled. _getSpillCandidate() never returns + // prevented variables, but when jumping to L_spill it can happen. + if (spillCandidate->workOffset == _currentOffset) + { + _compiler->setError(kErrorOverlappedRegisters); + return; + } + + idx = spillCandidate->regIndex; + spillMmVar(spillCandidate); + } + + // -------------------------------------------------------------------------- + // [Alloc] + // -------------------------------------------------------------------------- + + if (var->state == kVarStateMem && (vflags & kVarAllocRead) != 0) + { + emitLoadVar(var, idx); + } + + // Update X86CompilerVar. + var->state = kVarStateReg; + var->regIndex = idx; + var->homeRegisterIndex = idx; + + // Update CompilerState. + _allocatedVariable(var); +} + +void X86CompilerContext::saveMmVar(X86CompilerVar* var) +{ + // Can't save variable that isn't allocated. + ASMJIT_ASSERT(var->state == kVarStateReg); + ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid); + + uint32_t idx = var->regIndex; + emitSaveVar(var, idx); + + // Update X86CompilerVar. + var->changed = false; +} + +void X86CompilerContext::spillMmVar(X86CompilerVar* var) +{ + // Can't spill variable that isn't allocated. + ASMJIT_ASSERT(var->state == kVarStateReg); + ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid); + + uint32_t idx = var->regIndex; + + if (var->changed) emitSaveVar(var, idx); + + // Update X86CompilerVar. + var->regIndex = kRegIndexInvalid; + var->state = kVarStateMem; + var->changed = false; + + // Update CompilerState. + _x86State.mm[idx] = NULL; + _freedMmRegister(idx); +} + +void X86CompilerContext::allocXmmVar(X86CompilerVar* var, uint32_t regMask, uint32_t vflags) +{ + // Fix the regMask (0 or full bit-array means that any register may be used). + if (regMask == 0) regMask = IntUtil::maskUpToIndex(kX86RegNumXmm); + regMask &= IntUtil::maskUpToIndex(kX86RegNumXmm); + + // Working variables. + uint32_t i; + uint32_t mask; + + // Last register code (aka home). + uint32_t home = var->homeRegisterIndex; + // New register code. + uint32_t idx = kRegIndexInvalid; + + // Preserved XMM variables. + uint32_t preservedXMM = var->funcScope->getDecl()->getXmmPreservedMask(); + + // Spill candidate. + X86CompilerVar* spillCandidate = NULL; + + // Whether to alloc non-preserved first or last. + bool nonPreservedFirst = true; + + if (this->getFunc()->isCaller()) + nonPreservedFirst = (var->funcCall == NULL) || (var->funcCall->getOffset() >= var->lastItem->getOffset()); + + // -------------------------------------------------------------------------- + // [Already Allocated] + // -------------------------------------------------------------------------- + + // Go away if variable is already allocated. + if (var->state == kVarStateReg) + { + uint32_t oldIndex = var->regIndex; + + // Already allocated in the right register. + if (IntUtil::maskFromIndex(oldIndex) & regMask) return; + + // Try to find unallocated register first. + mask = regMask & ~_x86State.usedXMM; + if (mask != 0) + { + idx = IntUtil::findFirstBit( + (nonPreservedFirst && (mask & ~preservedXMM) != 0) ? mask & ~preservedXMM : mask); + } + // Then find the allocated and exchange later. + else + { + idx = IntUtil::findFirstBit(regMask & _x86State.usedXMM); + } + ASMJIT_ASSERT(idx != kRegIndexInvalid); + + X86CompilerVar* other = _x86State.xmm[idx]; + if (other) spillXmmVar(other); + + emitMoveVar(var, idx, vflags); + _freedXmmRegister(oldIndex); + _x86State.xmm[idx] = var; + + // Update X86CompilerVar. + var->state = kVarStateReg; + var->regIndex = idx; + var->homeRegisterIndex = idx; + + _allocatedXmmRegister(idx); + return; + } + + // -------------------------------------------------------------------------- + // [Find Unused XMM] + // -------------------------------------------------------------------------- + + // If regMask contains restricted registers which may be used then everything + // is handled in this block. + if (regMask != IntUtil::maskUpToIndex(kX86RegNumXmm)) + { + // Try to find unallocated register first. + mask = regMask & ~_x86State.usedXMM; + if (mask != 0) + { + idx = IntUtil::findFirstBit( + (nonPreservedFirst && (mask & ~preservedXMM) != 0) ? mask & ~preservedXMM : mask); + ASMJIT_ASSERT(idx != kRegIndexInvalid); + } + // Then find the allocated and spill later. + else + { + idx = IntUtil::findFirstBit(regMask & _x86State.usedXMM); + ASMJIT_ASSERT(idx != kRegIndexInvalid); + + // Spill register we need. + spillCandidate = _x86State.xmm[idx]; + + // Jump to spill part of allocation. + goto L_Spill; + } + } + + // Home register code. + if (idx == kRegIndexInvalid && home != kRegIndexInvalid) + { + if ((_x86State.usedXMM & (1U << home)) == 0) idx = home; + } + + if (idx == kRegIndexInvalid) + { + for (i = 0, mask = (1 << i); i < kX86RegNumXmm; i++, mask <<= 1) + { + if ((_x86State.usedXMM & mask) == 0) + { + // Convenience to alloc non-preserved first or non-preserved last. + if (nonPreservedFirst) + { + if (idx != kRegIndexInvalid && (preservedXMM & mask) != 0) continue; + idx = i; + // If current register is preserved, we should try to find different + // one that is not. This can save one push / pop in prolog / epilog. + if ((preservedXMM & mask) == 0) break; + } + else + { + if (idx != kRegIndexInvalid && (preservedXMM & mask) == 0) continue; + idx = i; + // The opposite. + if ((preservedXMM & mask) != 0) break; + } + } + } + } + + // -------------------------------------------------------------------------- + // [Spill] + // -------------------------------------------------------------------------- + + // If register is still not found, spill other variable. + if (idx == kRegIndexInvalid) + { + if (spillCandidate == NULL) + spillCandidate = _getSpillCandidateXMM(); + + // Spill candidate not found? + if (spillCandidate == NULL) + { + _compiler->setError(kErrorNoRegisters); + return; + } + +L_Spill: + + // Prevented variables can't be spilled. _getSpillCandidate() never returns + // prevented variables, but when jumping to L_spill it can happen. + if (spillCandidate->workOffset == _currentOffset) + { + _compiler->setError(kErrorOverlappedRegisters); + return; + } + + idx = spillCandidate->regIndex; + spillXmmVar(spillCandidate); + } + + // -------------------------------------------------------------------------- + // [Alloc] + // -------------------------------------------------------------------------- + + if (var->state == kVarStateMem && (vflags & kVarAllocRead) != 0) + { + emitLoadVar(var, idx); + } + + // Update X86CompilerVar. + var->state = kVarStateReg; + var->regIndex = idx; + var->homeRegisterIndex = idx; + + // Update CompilerState. + _allocatedVariable(var); +} + +void X86CompilerContext::saveXmmVar(X86CompilerVar* var) +{ + // Can't save variable that isn't allocated. + ASMJIT_ASSERT(var->state == kVarStateReg); + ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid); + + uint32_t idx = var->regIndex; + emitSaveVar(var, idx); + + // Update X86CompilerVar. + var->changed = false; +} + +void X86CompilerContext::spillXmmVar(X86CompilerVar* var) +{ + // Can't spill variable that isn't allocated. + ASMJIT_ASSERT(var->state == kVarStateReg); + ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid); + + uint32_t idx = var->regIndex; + + if (var->changed) emitSaveVar(var, idx); + + // Update CompilerVar. + var->regIndex = kRegIndexInvalid; + var->state = kVarStateMem; + var->changed = false; + + // Update CompilerState. + _x86State.xmm[idx] = NULL; + _freedXmmRegister(idx); +} + +void X86CompilerContext::emitLoadVar(X86CompilerVar* var, uint32_t regIndex) +{ + X86Compiler* x86Compiler = getCompiler(); + Mem m = _getVarMem(var); + + switch (var->getType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMov, gpd(regIndex), m); + if (_emitComments) goto _AddComment; + break; +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + x86Compiler->emit(kX86InstMov, gpq(regIndex), m); + if (_emitComments) goto _AddComment; + break; +#endif // ASMJIT_X64 + + case kX86VarTypeX87: + case kX86VarTypeX87SS: + case kX86VarTypeX87SD: + // TODO: X87 Support. + break; + + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, mm(regIndex), m); + if (_emitComments) goto _AddComment; + break; + + case kX86VarTypeXmm: + x86Compiler->emit(kX86InstMovDQA, xmm(regIndex), m); + if (_emitComments) goto _AddComment; + break; + case kX86VarTypeXmmSS: + x86Compiler->emit(kX86InstMovSS, xmm(regIndex), m); + if (_emitComments) goto _AddComment; + break; + case kX86VarTypeXmmSD: + x86Compiler->emit(kX86InstMovSD, xmm(regIndex), m); + if (_emitComments) goto _AddComment; + break; + case kX86VarTypeXmmPS: + x86Compiler->emit(kX86InstMovAPS, xmm(regIndex), m); + if (_emitComments) goto _AddComment; + break; + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovAPD, xmm(regIndex), m); + if (_emitComments) goto _AddComment; + break; + } + return; + +_AddComment: + x86Compiler->getCurrentItem()->formatComment("Alloc %s", var->getName()); +} + +void X86CompilerContext::emitSaveVar(X86CompilerVar* var, uint32_t regIndex) +{ + // Caller must ensure that variable is allocated. + ASMJIT_ASSERT(regIndex != kRegIndexInvalid); + + X86Compiler* x86Compiler = getCompiler(); + Mem m = _getVarMem(var); + + switch (var->getType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMov, m, gpd(regIndex)); + if (_emitComments) goto _AddComment; + break; +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + x86Compiler->emit(kX86InstMov, m, gpq(regIndex)); + if (_emitComments) goto _AddComment; + break; +#endif // ASMJIT_X64 + + case kX86VarTypeX87: + case kX86VarTypeX87SS: + case kX86VarTypeX87SD: + // TODO: X87 Support. + break; + + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, m, mm(regIndex)); + if (_emitComments) goto _AddComment; + break; + + case kX86VarTypeXmm: + x86Compiler->emit(kX86InstMovDQA, m, xmm(regIndex)); + if (_emitComments) goto _AddComment; + break; + case kX86VarTypeXmmSS: + x86Compiler->emit(kX86InstMovSS, m, xmm(regIndex)); + if (_emitComments) goto _AddComment; + break; + case kX86VarTypeXmmSD: + x86Compiler->emit(kX86InstMovSD, m, xmm(regIndex)); + if (_emitComments) goto _AddComment; + break; + case kX86VarTypeXmmPS: + x86Compiler->emit(kX86InstMovAPS, m, xmm(regIndex)); + if (_emitComments) goto _AddComment; + break; + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovAPD, m, xmm(regIndex)); + if (_emitComments) goto _AddComment; + break; + } + return; + +_AddComment: + x86Compiler->getCurrentItem()->formatComment("Spill %s", var->getName()); +} + +void X86CompilerContext::emitMoveVar(X86CompilerVar* var, uint32_t regIndex, uint32_t vflags) +{ + // Caller must ensure that the given variable is allocated. + ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid); + + X86Compiler* x86Compiler = getCompiler(); + if ((vflags & kVarAllocRead) == 0) return; + + switch (var->getType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMov, gpd(regIndex), gpd(var->regIndex)); + break; +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + x86Compiler->emit(kX86InstMov, gpq(regIndex), gpq(var->regIndex)); + break; +#endif // ASMJIT_X64 + + case kX86VarTypeX87: + case kX86VarTypeX87SS: + case kX86VarTypeX87SD: + // TODO: X87 Support. + break; + + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, mm(regIndex), mm(var->regIndex)); + break; + + case kX86VarTypeXmm: + x86Compiler->emit(kX86InstMovDQA, xmm(regIndex), xmm(var->regIndex)); + break; + case kX86VarTypeXmmSS: + x86Compiler->emit(kX86InstMovSS, xmm(regIndex), xmm(var->regIndex)); + break; + case kX86VarTypeXmmSD: + x86Compiler->emit(kX86InstMovSD, xmm(regIndex), xmm(var->regIndex)); + break; + case kX86VarTypeXmmPS: + x86Compiler->emit(kX86InstMovAPS, xmm(regIndex), xmm(var->regIndex)); + break; + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovAPD, xmm(regIndex), xmm(var->regIndex)); + break; + } +} + +void X86CompilerContext::emitExchangeVar(X86CompilerVar* var, uint32_t regIndex, uint32_t vflags, X86CompilerVar* other) +{ + // Caller must ensure that the given variable is allocated. + ASMJIT_ASSERT(var->regIndex != kRegIndexInvalid); + + X86Compiler* x86Compiler = getCompiler(); + + // If other is not valid then we can just emit MOV (or other similar instruction). + if (other == NULL) + { + emitMoveVar(var, regIndex, vflags); + return; + } + + // If we need to alloc for write-only operation then we can move other + // variable away instead of exchanging them. + if ((vflags & kVarAllocRead) == 0) + { + emitMoveVar(other, var->regIndex, kVarAllocRead); + return; + } + + switch (var->getType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstXchg, gpd(regIndex), gpd(var->regIndex)); + break; +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + x86Compiler->emit(kX86InstXchg, gpq(regIndex), gpq(var->regIndex)); + break; +#endif // ASMJIT_X64 + + case kX86VarTypeX87: + case kX86VarTypeX87SS: + case kX86VarTypeX87SD: + // TODO: X87 Support. + break; + + // NOTE: MM and XMM registers shoudln't be exchanged using this way, it's + // correct, but instead of using one instruction we need three. + + case kX86VarTypeMm: + { + MmReg a = mm(regIndex); + MmReg b = mm(var->regIndex); + + x86Compiler->emit(kX86InstPXor, a, b); + x86Compiler->emit(kX86InstPXor, b, a); + x86Compiler->emit(kX86InstPXor, a, b); + break; + } + + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + { + XmmReg a = xmm(regIndex); + XmmReg b = xmm(var->regIndex); + + x86Compiler->emit(kX86InstXorPS, a, b); + x86Compiler->emit(kX86InstXorPS, b, a); + x86Compiler->emit(kX86InstXorPS, a, b); + break; + } + + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + { + XmmReg a = xmm(regIndex); + XmmReg b = xmm(var->regIndex); + + x86Compiler->emit(kX86InstXorPD, a, b); + x86Compiler->emit(kX86InstXorPD, b, a); + x86Compiler->emit(kX86InstXorPD, a, b); + break; + } + + case kX86VarTypeXmm: + { + XmmReg a = xmm(regIndex); + XmmReg b = xmm(var->regIndex); + + x86Compiler->emit(kX86InstPXor, a, b); + x86Compiler->emit(kX86InstPXor, b, a); + x86Compiler->emit(kX86InstPXor, a, b); + break; + } + } +} + +void X86CompilerContext::_postAlloc(X86CompilerVar* var, uint32_t vflags) +{ + if (vflags & kVarAllocWrite) + var->changed = true; +} + +void X86CompilerContext::_markMemoryUsed(X86CompilerVar* var) +{ + if (var->homeMemoryData != NULL) return; + + VarMemBlock* mem = _allocMemBlock(var->getSize()); + if (!mem) return; + + var->homeMemoryData = mem; +} + +Mem X86CompilerContext::_getVarMem(X86CompilerVar* var) +{ + Mem m; + m._mem.id = var->getId(); + + if (!var->isMemArgument()) + m._mem.displacement = _adjustESP; + + _markMemoryUsed(var); + return m; +} + +static int32_t getSpillScore(X86CompilerVar* var, uint32_t currentOffset) +{ + int32_t score = 0; + + ASMJIT_ASSERT(var->lastItem != NULL); + uint32_t lastOffset = var->lastItem->getOffset(); + + if (lastOffset >= currentOffset) + score += (int32_t)(lastOffset - currentOffset); + + // Each write access decreases probability of spill. + score -= static_cast(var->regWriteCount) + static_cast(var->regRwCount); + // Each read-only access increases probability of spill. + score += static_cast(var->regReadCount); + + // Each memory access increases probability of spill. + score += static_cast(var->memWriteCount) + static_cast(var->memRwCount); + score += static_cast(var->memReadCount); + + return score; +} + +X86CompilerVar* X86CompilerContext::_getSpillCandidateGP() +{ + return _getSpillCandidateGeneric(_x86State.gp, kX86RegNumGp); +} + +X86CompilerVar* X86CompilerContext::_getSpillCandidateMM() +{ + return _getSpillCandidateGeneric(_x86State.mm, kX86RegNumMm); +} + +X86CompilerVar* X86CompilerContext::_getSpillCandidateXMM() +{ + return _getSpillCandidateGeneric(_x86State.xmm, kX86RegNumXmm); +} + +X86CompilerVar* X86CompilerContext::_getSpillCandidateGeneric(X86CompilerVar** varArray, uint32_t count) +{ + uint32_t i; + + X86CompilerVar* candidate = NULL; + uint32_t candidatePriority = 0; + int32_t candidateScore = 0; + + uint32_t currentOffset = _compiler->getCurrentItem()->getOffset(); + + for (i = 0; i < count; i++) + { + // Get variable. + X86CompilerVar* cv = varArray[i]; + + // Never spill variables needed for next instruction. + if (cv == NULL || cv->workOffset == _currentOffset) continue; + + uint32_t variablePriority = cv->getPriority(); + int32_t variableScore = getSpillScore(cv, currentOffset); + + if ((candidate == NULL) || + (variablePriority > candidatePriority) || + (variablePriority == candidatePriority && variableScore > candidateScore)) + { + candidate = cv; + candidatePriority = variablePriority; + candidateScore = variableScore; + } + } + + return candidate; +} + +void X86CompilerContext::_addActive(X86CompilerVar* var) +{ + // Never call with variable that is already in active list. + ASMJIT_ASSERT(var->nextActive == NULL); + ASMJIT_ASSERT(var->prevActive == NULL); + + if (_active == NULL) + { + var->nextActive = var; + var->prevActive = var; + + _active = var; + } + else + { + X86CompilerVar* vlast = static_cast(_active)->prevActive; + + vlast->nextActive = var; + static_cast(_active)->prevActive = var; + + var->nextActive = static_cast(_active); + var->prevActive = vlast; + } +} + +void X86CompilerContext::_freeActive(X86CompilerVar* var) +{ + X86CompilerVar* next = var->nextActive; + X86CompilerVar* prev = var->prevActive; + + if (prev == next) + { + _active = NULL; + } + else + { + if (_active == var) + _active = next; + + prev->nextActive = next; + next->prevActive = prev; + } + + var->nextActive = NULL; + var->prevActive = NULL; +} + +void X86CompilerContext::_freeAllActive() +{ + if (_active == NULL) + return; + + X86CompilerVar* cur = static_cast(_active); + for (;;) + { + X86CompilerVar* next = cur->nextActive; + + cur->nextActive = NULL; + cur->prevActive = NULL; + + if (next == _active) + break; + } + + _active = NULL; +} + +void X86CompilerContext::_allocatedVariable(X86CompilerVar* var) +{ + uint32_t idx = var->regIndex; + + switch (var->getType()) + { + case kX86VarTypeGpd: + case kX86VarTypeGpq: + _x86State.gp[idx] = var; + _allocatedGpRegister(idx); + break; + + case kX86VarTypeMm: + _x86State.mm[idx] = var; + _allocatedMmRegister(idx); + break; + + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + _x86State.xmm[idx] = var; + _allocatedXmmRegister(idx); + break; + + default: + ASMJIT_ASSERT(0); + break; + } +} + +void X86CompilerContext::translateOperands(Operand* operands, uint32_t count) +{ + X86Compiler* x86Compiler = getCompiler(); + uint32_t i; + + // Translate variables to registers. + for (i = 0; i < count; i++) + { + Operand& o = operands[i]; + + if (o.isVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(o.getId()); + ASMJIT_ASSERT(cv != NULL); + + o._reg.op = kOperandReg; + o._reg.code |= cv->regIndex; + } + else if (o.isMem()) + { + if ((o.getId() & kOperandIdTypeMask) == kOperandIdTypeVar) + { + // Memory access. We just increment here actual displacement. + X86CompilerVar* cv = x86Compiler->_getVar(o.getId()); + ASMJIT_ASSERT(cv != NULL); + + o._mem.displacement += cv->isMemArgument() + ? _argumentsActualDisp + : _variablesActualDisp; + // NOTE: This is not enough, variable position will be patched later + // by X86CompilerContext::_patchMemoryOperands(). + } + else if ((o._mem.base & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* cv = x86Compiler->_getVar(o._mem.base); + ASMJIT_ASSERT(cv != NULL); + + o._mem.base = cv->regIndex; + } + + if ((o._mem.index & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* cv = x86Compiler->_getVar(o._mem.index); + ASMJIT_ASSERT(cv != NULL); + + o._mem.index = cv->regIndex; + } + } + } +} + +void X86CompilerContext::addBackwardCode(X86CompilerJmpInst* from) +{ + _backCode.append(from); +} + +void X86CompilerContext::addForwardJump(X86CompilerJmpInst* inst) +{ + ForwardJumpData* j = + reinterpret_cast(_zoneMemory.alloc(sizeof(ForwardJumpData))); + if (j == NULL) { _compiler->setError(kErrorNoHeapMemory); return; } + + j->inst = inst; + j->state = _saveState(); + j->next = _forwardJumps; + _forwardJumps = j; +} + +X86CompilerState* X86CompilerContext::_saveState() +{ + X86Compiler* x86Compiler = getCompiler(); + + // Get count of variables stored in memory. + uint32_t memVarsCount = 0; + X86CompilerVar* cur = static_cast(_active); + + if (cur) + { + do { + if (cur->state == kVarStateMem) memVarsCount++; + cur = cur->nextActive; + } while (cur != _active); + } + + // Alloc X86CompilerState structure (using zone allocator) and copy current + // state into it. + X86CompilerState* state = x86Compiler->_newState(memVarsCount); + memcpy(state, &_x86State, sizeof(X86CompilerState)); + + // Clear changed flags. + state->changedGP = 0; + state->changedMM = 0; + state->changedXMM = 0; + + uint i; + uint mask; + + // Save variables stored in REGISTERs and CHANGE flag. + for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1) + { + if (state->gp[i] && state->gp[i]->changed) + state->changedGP |= mask; + } + + for (i = 0, mask = 1; i < kX86RegNumMm; i++, mask <<= 1) + { + if (state->mm[i] && state->mm[i]->changed) + state->changedMM |= mask; + } + + for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1) + { + if (state->xmm[i] && state->xmm[i]->changed) + state->changedXMM |= mask; + } + + // Save variables stored in MEMORY. + state->memVarsCount = memVarsCount; + memVarsCount = 0; + + cur = static_cast(_active); + if (cur) + { + do { + if (cur->state == kVarStateMem) state->memVarsData[memVarsCount++] = cur; + cur = cur->nextActive; + } while (cur != _active); + } + + // Finished. + return state; +} + +void X86CompilerContext::_assignState(X86CompilerState* state) +{ + Compiler* compiler = getCompiler(); + + memcpy(&_x86State, state, sizeof(X86CompilerState)); + _x86State.memVarsCount = 0; + + uint i, mask; + X86CompilerVar* cv; + + // Unuse all variables first. + cv = static_cast(_active); + if (cv) + { + do { + cv->state = kVarStateUnused; + cv = cv->nextActive; + } while (cv != _active); + } + + // Assign variables stored in memory which are not unused. + for (i = 0; i < state->memVarsCount; i++) + { + state->memVarsData[i]->state = kVarStateMem; + } + + // Assign allocated variables. + for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1) + { + if ((cv = _x86State.gp[i]) != NULL) + { + cv->state = kVarStateReg; + cv->regIndex = i; + cv->changed = (_x86State.changedGP & mask) != 0; + } + } + + for (i = 0, mask = 1; i < kX86RegNumMm; i++, mask <<= 1) + { + if ((cv = _x86State.mm[i]) != NULL) + { + cv->state = kVarStateReg; + cv->regIndex = i; + cv->changed = (_x86State.changedMM & mask) != 0; + } + } + + for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1) + { + if ((cv = _x86State.xmm[i]) != NULL) + { + cv->state = kVarStateReg; + cv->regIndex = i; + cv->changed = (_x86State.changedXMM & mask) != 0; + } + } +} + +void X86CompilerContext::_restoreState(X86CompilerState* state, uint32_t targetOffset) +{ + X86CompilerState* fromState = &_x86State; + X86CompilerState* toState = state; + + // No change, rare... + if (fromState == toState) + return; + + uint base; + uint i; + + // -------------------------------------------------------------------------- + // Set target state to all variables. cv->tInt is target state in this func. + // -------------------------------------------------------------------------- + + { + // UNUSED. + X86CompilerVar* cv = static_cast(_active); + if (cv) + { + do { + cv->tInt = kVarStateUnused; + cv = cv->nextActive; + } while (cv != _active); + } + + // MEMORY. + for (i = 0; i < toState->memVarsCount; i++) + { + toState->memVarsData[i]->tInt = kVarStateMem; + } + + // REGISTER. + for (i = 0; i < X86CompilerState::kStateRegCount; i++) + { + if ((cv = toState->regs[i]) != NULL) cv->tInt = kVarStateReg; + } + } + + // -------------------------------------------------------------------------- + // [GP-Registers Switch] + // -------------------------------------------------------------------------- + + // TODO. +#if 0 + for (i = 0; i < kX86RegNumGp; i++) + { + X86CompilerVar* fromVar = fromState->gp[i]; + X86CompilerVar* toVar = toState->gp[i]; + + if (fromVar != toVar) + { + if (fromVar != NULL) + { + if (toVar != NULL) + { + if (fromState->gp[to + } + else + { + // It is possible that variable that was saved in state currently not + // exists (tInt is target scope!). + if (fromVar->tInt == kVarStateUnused) + { + unuseVar(fromVar, kVarStateUnused); + } + else + { + spillVar(fromVar); + } + } + } + } + else if (fromVar != NULL) + { + uint32_t mask = IntUtil::maskFromIndex(i); + // Variables are the same, we just need to compare changed flags. + if ((fromState->changedGP & mask) && !(toState->changedGP & mask)) saveVar(fromVar); + } + } +#endif + + // Spill. + for (base = 0, i = 0; i < X86CompilerState::kStateRegCount; i++) + { + // Change the base offset (from base offset so the register index can be calculated). + if (i == X86CompilerState::kStateRegMmBase || i == X86CompilerState::kStateRegXmmBase) + base = i; + + uint32_t regIndex = i - base; + X86CompilerVar* fromVar = fromState->regs[i]; + X86CompilerVar* toVar = toState->regs[i]; + + if (fromVar != toVar) + { + // Spill the register. + if (fromVar != NULL) + { + // It is possible that variable that was saved in state currently not + // exists (tInt is target scope!). + if (fromVar->tInt == kVarStateUnused) + unuseVar(fromVar, kVarStateUnused); + else + spillVar(fromVar); + } + } + else if (fromVar != NULL) + { + // Variables are the same, we just need to compare changed flags. + uint32_t mask = IntUtil::maskFromIndex(regIndex); + + if ((fromState->changedGP & mask) && !(toState->changedGP & mask)) + saveVar(fromVar); + } + } + + // Alloc. + for (base = 0, i = 0; i < X86CompilerState::kStateRegCount; i++) + { + // Change the base offset (from base offset so the register index can be calculated). + if (i == X86CompilerState::kStateRegMmBase || i == X86CompilerState::kStateRegXmmBase) + base = i; + + X86CompilerVar* fromVar = fromState->regs[i]; + X86CompilerVar* toVar = toState->regs[i]; + + if (fromVar != toVar) + { + // Alloc register. + uint32_t regIndex = i - base; + + if (toVar != NULL) + allocVar(toVar, IntUtil::maskFromIndex(regIndex), kVarAllocRead); + } + + // TODO: + //if (toVar) + //{ + // toVar->changed = to->changed; + //} + } + + // -------------------------------------------------------------------------- + // Update used masks. + // -------------------------------------------------------------------------- + + _x86State.usedGP = state->usedGP; + _x86State.usedMM = state->usedMM; + _x86State.usedXMM = state->usedXMM; + + // -------------------------------------------------------------------------- + // Update changed masks and cleanup. + // -------------------------------------------------------------------------- + + { + X86CompilerVar* cv = static_cast(_active); + if (cv) + { + do { + if (cv->tInt != kVarStateReg) + { + cv->state = (int)cv->tInt; + cv->changed = false; + } + + cv->tInt = 0; + cv = cv->nextActive; + } while (cv != _active); + } + } +} + +VarMemBlock* X86CompilerContext::_allocMemBlock(uint32_t size) +{ + ASMJIT_ASSERT(size != 0); + + // First try to find mem blocks. + VarMemBlock* mem = _memFree; + VarMemBlock* prev = NULL; + + while (mem) + { + VarMemBlock* next = mem->nextFree; + + if (mem->size == size) + { + if (prev) + prev->nextFree = next; + else + _memFree = next; + + mem->nextFree = NULL; + return mem; + } + + prev = mem; + mem = next; + } + + // Never mind, create new. + mem = reinterpret_cast(_zoneMemory.alloc(sizeof(VarMemBlock))); + if (mem == NULL) + { + _compiler->setError(kErrorNoHeapMemory); + return NULL; + } + + mem->offset = 0; + mem->size = size; + + mem->nextUsed = _memUsed; + mem->nextFree = NULL; + + _memUsed = mem; + + switch (size) + { + case 16: _mem16BlocksCount++; break; + case 8: _mem8BlocksCount++; break; + case 4: _mem4BlocksCount++; break; + } + + return mem; +} + +void X86CompilerContext::_freeMemBlock(VarMemBlock* mem) +{ + // Add mem to free blocks. + mem->nextFree = _memFree; + _memFree = mem; +} + +void X86CompilerContext::_allocMemoryOperands() +{ + VarMemBlock* mem; + + // Variables are allocated in this order: + // 1. 16-byte variables. + // 2. 8-byte variables. + // 3. 4-byte variables. + // 4. All others. + + uint32_t start16 = 0; + uint32_t start8 = start16 + _mem16BlocksCount * 16; + uint32_t start4 = start8 + _mem8BlocksCount * 8; + uint32_t startX = IntUtil::align(start4 + _mem4BlocksCount * 4, 16); + + for (mem = _memUsed; mem; mem = mem->nextUsed) + { + uint32_t size = mem->size; + uint32_t offset; + + switch (size) + { + case 16: + offset = start16; + start16 += 16; + break; + + case 8: + offset = start8; + start8 += 8; + break; + + case 4: + offset = start4; + start4 += 4; + break; + + default: + // Align to 16 bytes if size is 16 or more. + if (size >= 16) + { + size = IntUtil::align(size, 16); + startX = IntUtil::align(startX, 16); + } + + offset = startX; + startX += size; + break; + } + + mem->offset = (int32_t)offset; + _memBytesTotal += size; + } +} + +void X86CompilerContext::_patchMemoryOperands(CompilerItem* start, CompilerItem* stop) +{ + CompilerItem* cur; + + for (cur = start;; cur = cur->getNext()) + { + if (cur->getType() == kCompilerItemInst) + { + Mem* mem = reinterpret_cast(cur)->_memOp; + + if (mem && (mem->_mem.id & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* cv = getCompiler()->_getVar(mem->_mem.id); + ASMJIT_ASSERT(cv != NULL); + + if (cv->isMemArgument()) + { + mem->_mem.base = _argumentsBaseReg; + mem->_mem.displacement += cv->homeMemoryOffset; + mem->_mem.displacement += _argumentsBaseOffset; + } + else + { + VarMemBlock* mb = reinterpret_cast(cv->homeMemoryData); + ASMJIT_ASSERT(mb != NULL); + + mem->_mem.base = _variablesBaseReg; + mem->_mem.displacement += mb->offset; + mem->_mem.displacement += _variablesBaseOffset; + } + } + } + if (cur == stop) break; + } +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/x86/x86compilercontext.h b/desmume/src/utils/AsmJit/x86/x86compilercontext.h new file mode 100644 index 000000000..80d3d4123 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86compilercontext.h @@ -0,0 +1,321 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_X86_X86COMPILERCONTEXT_H +#define _ASMJIT_X86_X86COMPILERCONTEXT_H + +// [Dependencies - AsmJit] +#include "../core/intutil.h" +#include "../core/podvector.h" + +#include "../x86/x86assembler.h" +#include "../x86/x86compiler.h" +#include "../x86/x86compilerfunc.h" +#include "../x86/x86compileritem.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_X86 +//! @{ + +// ============================================================================ +// [AsmJit::X86CompilerContext] +// ============================================================================ + +//! @internal +//! +//! @brief Compiler context is used by @ref X86Compiler. +//! +//! X86Compiler context is used during compilation and normally developer doesn't +//! need access to it. The context is user per function (it's reset after each +//! function is generated). +struct X86CompilerContext : public CompilerContext +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref X86CompilerContext instance. + ASMJIT_API X86CompilerContext(X86Compiler* x86Compiler); + //! @brief Destroy the @ref X86CompilerContext instance. + ASMJIT_API ~X86CompilerContext(); + + // -------------------------------------------------------------------------- + // [Accessor] + // -------------------------------------------------------------------------- + + //! @brief Get compiler as @ref X86Compiler. + inline X86Compiler* getCompiler() const + { return reinterpret_cast(_compiler); } + + //! @brief Get function as @ref X86CompilerFuncDecl. + inline X86CompilerFuncDecl* getFunc() const + { return reinterpret_cast(_func); } + + // -------------------------------------------------------------------------- + // [Clear] + // -------------------------------------------------------------------------- + + //! @brief Clear context, preparing it for next function generation. + ASMJIT_API void _clear(); + + // -------------------------------------------------------------------------- + // [Register Allocator] + // -------------------------------------------------------------------------- + + //! @brief Allocate variable + //! + //! Calls @c allocGpVar, @c allocMmVar or @c allocXmmVar methods. + ASMJIT_API void allocVar(X86CompilerVar* cv, uint32_t regMask, uint32_t vflags); + + //! @brief Save variable. + //! + //! Calls @c saveGpVar, @c saveMmVar or @c saveXmmVar methods. + ASMJIT_API void saveVar(X86CompilerVar* cv); + + //! @brief Spill variable. + //! + //! Calls @c spillGpVar, @c spillMmVar or @c spillXmmVar methods. + ASMJIT_API void spillVar(X86CompilerVar* cv); + + //! @brief Unuse variable (didn't spill, just forget about it). + ASMJIT_API void unuseVar(X86CompilerVar* cv, uint32_t toState); + + //! @brief Helper method that is called for each variable per item. + inline void _unuseVarOnEndOfScope(CompilerItem* item, X86CompilerVar* cv) + { + if (cv->lastItem == item) + unuseVar(cv, kVarStateUnused); + } + //! @overload + inline void _unuseVarOnEndOfScope(CompilerItem* item, VarAllocRecord* rec) + { + X86CompilerVar* cv = rec->vdata; + if (cv->lastItem == item || (rec->vflags & kVarAllocUnuseAfterUse)) + unuseVar(cv, kVarStateUnused); + } + //! @overload + inline void _unuseVarOnEndOfScope(CompilerItem* item, VarCallRecord* rec) + { + X86CompilerVar* v = rec->vdata; + if (v->lastItem == item || (rec->flags & VarCallRecord::kFlagUnuseAfterUse)) + unuseVar(v, kVarStateUnused); + } + + //! @brief Allocate variable (GP). + ASMJIT_API void allocGpVar(X86CompilerVar* cv, uint32_t regMask, uint32_t vflags); + //! @brief Save variable (GP). + ASMJIT_API void saveGpVar(X86CompilerVar* cv); + //! @brief Spill variable (GP). + ASMJIT_API void spillGpVar(X86CompilerVar* cv); + + //! @brief Allocate variable (MM). + ASMJIT_API void allocMmVar(X86CompilerVar* cv, uint32_t regMask, uint32_t vflags); + //! @brief Save variable (MM). + ASMJIT_API void saveMmVar(X86CompilerVar* cv); + //! @brief Spill variable (MM). + ASMJIT_API void spillMmVar(X86CompilerVar* cv); + + //! @brief Allocate variable (XMM). + ASMJIT_API void allocXmmVar(X86CompilerVar* cv, uint32_t regMask, uint32_t vflags); + //! @brief Save variable (XMM). + ASMJIT_API void saveXmmVar(X86CompilerVar* cv); + //! @brief Spill variable (XMM). + ASMJIT_API void spillXmmVar(X86CompilerVar* cv); + + //! @brief Emit load variable instruction(s). + ASMJIT_API void emitLoadVar(X86CompilerVar* cv, uint32_t regIndex); + //! @brief Emit save variable instruction(s). + ASMJIT_API void emitSaveVar(X86CompilerVar* cv, uint32_t regIndex); + + //! @brief Emit move variable instruction(s). + ASMJIT_API void emitMoveVar(X86CompilerVar* cv, uint32_t regIndex, uint32_t vflags); + //! @brief Emit exchange variable instruction(s). + ASMJIT_API void emitExchangeVar(X86CompilerVar* cv, uint32_t regIndex, uint32_t vflags, X86CompilerVar* other); + + //! @brief Called each time a variable is alloceted. + ASMJIT_API void _postAlloc(X86CompilerVar* cv, uint32_t vflags); + //! @brief Marks variable home memory as used (must be called at least once + //! for each variable that uses function local memory - stack). + ASMJIT_API void _markMemoryUsed(X86CompilerVar* cv); + + ASMJIT_API Mem _getVarMem(X86CompilerVar* cv); + + ASMJIT_API X86CompilerVar* _getSpillCandidateGP(); + ASMJIT_API X86CompilerVar* _getSpillCandidateMM(); + ASMJIT_API X86CompilerVar* _getSpillCandidateXMM(); + ASMJIT_API X86CompilerVar* _getSpillCandidateGeneric(X86CompilerVar** varArray, uint32_t count); + + inline bool _isActive(X86CompilerVar* cv) + { return cv->nextActive != NULL; } + + ASMJIT_API void _addActive(X86CompilerVar* cv); + ASMJIT_API void _freeActive(X86CompilerVar* cv); + ASMJIT_API void _freeAllActive(); + + ASMJIT_API void _allocatedVariable(X86CompilerVar* cv); + + inline void _allocatedGpRegister(uint32_t index) + { + _x86State.usedGP |= IntUtil::maskFromIndex(index); + _modifiedGpRegisters |= IntUtil::maskFromIndex(index); + } + + inline void _allocatedMmRegister(uint32_t index) + { + _x86State.usedMM |= IntUtil::maskFromIndex(index); + _modifiedMmRegisters |= IntUtil::maskFromIndex(index); + } + + inline void _allocatedXmmRegister(uint32_t index) + { + _x86State.usedXMM |= IntUtil::maskFromIndex(index); + _modifiedXmmRegisters |= IntUtil::maskFromIndex(index); + } + + inline void _freedGpRegister(uint32_t index) + { _x86State.usedGP &= ~IntUtil::maskFromIndex(index); } + + inline void _freedMmRegister(uint32_t index) + { _x86State.usedMM &= ~IntUtil::maskFromIndex(index); } + + inline void _freedXmmRegister(uint32_t index) + { _x86State.usedXMM &= ~IntUtil::maskFromIndex(index); } + + inline void _markGpRegisterModified(uint32_t index) + { _modifiedGpRegisters |= IntUtil::maskFromIndex(index); } + + inline void _markMmRegisterModified(uint32_t index) + { _modifiedMmRegisters |= IntUtil::maskFromIndex(index); } + + inline void _markXmmRegisterModified(uint32_t index) + { _modifiedXmmRegisters |= IntUtil::maskFromIndex(index); } + + // TODO: Find code which uses this and improve. + inline void _newRegisterHomeIndex(X86CompilerVar* cv, uint32_t idx) + { + if (cv->homeRegisterIndex == kRegIndexInvalid) + cv->homeRegisterIndex = idx; + cv->prefRegisterMask |= (1U << idx); + } + + // TODO: Find code which uses this and improve. + inline void _newRegisterHomeMask(X86CompilerVar* cv, uint32_t mask) + { + cv->prefRegisterMask |= mask; + } + + // -------------------------------------------------------------------------- + // [Operand Patcher] + // -------------------------------------------------------------------------- + + ASMJIT_API void translateOperands(Operand* operands, uint32_t count); + + // -------------------------------------------------------------------------- + // [Backward Code] + // -------------------------------------------------------------------------- + + ASMJIT_API void addBackwardCode(X86CompilerJmpInst* from); + + // -------------------------------------------------------------------------- + // [Forward Jump] + // -------------------------------------------------------------------------- + + ASMJIT_API void addForwardJump(X86CompilerJmpInst* inst); + + // -------------------------------------------------------------------------- + // [State] + // -------------------------------------------------------------------------- + + ASMJIT_API X86CompilerState* _saveState(); + ASMJIT_API void _assignState(X86CompilerState* state); + ASMJIT_API void _restoreState(X86CompilerState* state, uint32_t targetOffset = kInvalidValue); + + // -------------------------------------------------------------------------- + // [Memory Allocator] + // -------------------------------------------------------------------------- + + ASMJIT_API VarMemBlock* _allocMemBlock(uint32_t size); + ASMJIT_API void _freeMemBlock(VarMemBlock* mem); + + ASMJIT_API void _allocMemoryOperands(); + ASMJIT_API void _patchMemoryOperands(CompilerItem* start, CompilerItem* stop); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief X86 specific compiler state (linked with @ref _state). + X86CompilerState _x86State; + + //! @brief Forward jumps (single linked list). + ForwardJumpData* _forwardJumps; + + //! @brief Global modified GP registers mask (per function). + uint32_t _modifiedGpRegisters; + //! @brief Global modified MM registers mask (per function). + uint32_t _modifiedMmRegisters; + //! @brief Global modified XMM registers mask (per function). + uint32_t _modifiedXmmRegisters; + + //! @brief Whether the EBP/RBP register can be used by register allocator. + uint32_t _allocableEBP; + + //! @brief ESP adjust constant (changed during PUSH/POP or when using + //! stack. + int _adjustESP; + + //! @brief Function arguments base pointer (register). + uint32_t _argumentsBaseReg; + //! @brief Function arguments base offset. + int32_t _argumentsBaseOffset; + //! @brief Function arguments displacement. + int32_t _argumentsActualDisp; + + //! @brief Function variables base pointer (register). + uint32_t _variablesBaseReg; + //! @brief Function variables base offset. + int32_t _variablesBaseOffset; + //! @brief Function variables displacement. + int32_t _variablesActualDisp; + + //! @brief Used memory blocks (for variables, here is each created mem block + //! that can be also in _memFree list). + VarMemBlock* _memUsed; + //! @brief Free memory blocks (freed, prepared for another allocation). + VarMemBlock* _memFree; + //! @brief Count of 4-byte memory blocks used by the function. + uint32_t _mem4BlocksCount; + //! @brief Count of 8-byte memory blocks used by the function. + uint32_t _mem8BlocksCount; + //! @brief Count of 16-byte memory blocks used by the function. + uint32_t _mem16BlocksCount; + //! @brief Count of total bytes of stack memory used by the function. + uint32_t _memBytesTotal; + + //! @brief List of items which need to be translated. These items are filled + //! by @c addBackwardCode(). + PodVector _backCode; + + //! @brief Backward code position (starts at 0). + sysuint_t _backPos; + //! @brief Whether to emit comments. + bool _emitComments; +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_X86_X86COMPILERCONTEXT_H diff --git a/desmume/src/utils/AsmJit/x86/x86compilerfunc.cpp b/desmume/src/utils/AsmJit/x86/x86compilerfunc.cpp new file mode 100644 index 000000000..c610560f2 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86compilerfunc.cpp @@ -0,0 +1,2902 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/intutil.h" +#include "../core/stringutil.h" + +#include "../x86/x86compiler.h" +#include "../x86/x86compilercontext.h" +#include "../x86/x86compilerfunc.h" +#include "../x86/x86compileritem.h" +#include "../x86/x86cpuinfo.h" +#include "../x86/x86util.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::X86Assembler - Logging] +// ============================================================================ + +// Defined in AsmJit/X86/X86Assembler.cpp. +char* X86Assembler_dumpRegister(char* buf, uint32_t type, uint32_t index); +char* X86Assembler_dumpOperand(char* buf, const Operand* op, uint32_t memRegType, uint32_t loggerFlags); + +// ============================================================================ +// [AsmJit::X86CompilerFuncDecl - Construction / Destructioin] +// ============================================================================ + +X86CompilerFuncDecl::X86CompilerFuncDecl(X86Compiler* x86Compiler) : + CompilerFuncDecl(x86Compiler), + _gpModifiedAndPreserved(0), + _mmModifiedAndPreserved(0), + _xmmModifiedAndPreserved(0), + _movDqInstCode(kInstNone), + _pePushPopStackSize(0), + _peMovStackSize(0), + _peAdjustStackSize(0), + _memStackSize(0), + _memStackSize16(0) +{ + _decl = &_x86Decl; + + // Just clear to safe defaults. + _funcHints |= IntUtil::maskFromIndex(kX86FuncHintPushPop); + + // Stack is always aligned to 16-bytes when using 64-bit OS. + if (CompilerUtil::isStack16ByteAligned()) + _funcHints |= IntUtil::maskFromIndex(kX86FuncHintAssume16ByteAlignment); + + _entryLabel = x86Compiler->newLabel(); + _exitLabel = x86Compiler->newLabel(); + + _entryTarget = x86Compiler->_getTarget(_entryLabel.getId()); + _exitTarget = x86Compiler->_getTarget(_exitLabel.getId()); + + _end = Compiler_newItem(x86Compiler, this); +} + +X86CompilerFuncDecl::~X86CompilerFuncDecl() +{ +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncDecl - Interface] +// ============================================================================ + +void X86CompilerFuncDecl::prepare(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + _offset = x86Context._currentOffset++; + + _prepareVariables(this); +} + +CompilerItem* X86CompilerFuncDecl::translate(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + + _allocVariables(x86Context); + return translated(); +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncDecl - Misc] +// ============================================================================ + +int X86CompilerFuncDecl::getMaxSize() const +{ + // NOP. + return 0; +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncDecl - Prototype] +// ============================================================================ + +void X86CompilerFuncDecl::setPrototype(uint32_t convention, uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount) +{ + _x86Decl.setPrototype(convention, returnType, arguments, argumentsCount); +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncDecl - Helpers] +// ============================================================================ + +void X86CompilerFuncDecl::_createVariables() +{ + X86Compiler* x86Compiler = getCompiler(); + + uint32_t i, count = _x86Decl.getArgumentsCount(); + if (count == 0) return; + + _vars = reinterpret_cast(x86Compiler->getZoneMemory().alloc(count * sizeof(void*))); + if (_vars == NULL) + { + x86Compiler->setError(kErrorNoHeapMemory); + return; + } + + char argNameStorage[64]; + char* argName = NULL; + + bool debug = x86Compiler->getLogger() != NULL; + if (debug) argName = argNameStorage; + + for (i = 0; i < count; i++) + { + FuncArg& arg = _x86Decl.getArgument(i); + + if (debug) + snprintf(argName, ASMJIT_ARRAY_SIZE(argNameStorage), "arg_%u", i); + + uint32_t size = X86Util::getVarSizeFromVarType(arg.getVarType()); + X86CompilerVar* cv = x86Compiler->_newVar(argName, arg.getVarType(), size); + + if (arg.getRegIndex() != kRegIndexInvalid) + { + cv->_isRegArgument = true; + cv->regIndex = arg.getRegIndex(); + } + + if (arg.getStackOffset() != kFuncStackInvalid) + { + cv->_isMemArgument = true; + cv->homeMemoryOffset = arg.getStackOffset(); + } + + _vars[i] = cv; + } +} + +void X86CompilerFuncDecl::_prepareVariables(CompilerItem* first) +{ + uint32_t count = _x86Decl.getArgumentsCount(); + if (count == 0) return; + + for (uint32_t i = 0; i < count; i++) + { + X86CompilerVar* cv = getVar(i); + + // This is where variable scope starts. + cv->firstItem = first; + // If this will not be changed then it will be deallocated immediately. + cv->lastItem = first; + } +} + +void X86CompilerFuncDecl::_allocVariables(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + uint32_t count = getDecl()->getArgumentsCount(); + + if (count == 0) + return; + + for (uint32_t i = 0; i < count; i++) + { + X86CompilerVar* cv = getVar(i); + + if (cv->firstItem != NULL || cv->isArgument()) + { + // Variable is used. + if (cv->regIndex != kRegIndexInvalid) + { + cv->state = kVarStateReg; + // If variable is in register -> mark it as changed so it will not be + // lost by first spill. + cv->changed = true; + x86Context._allocatedVariable(cv); + } + else if (cv->isMemArgument()) + { + cv->state = kVarStateMem; + } + } + else + { + // Variable is not used. + cv->regIndex = kRegIndexInvalid; + } + } +} + +void X86CompilerFuncDecl::_preparePrologEpilog(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + const X86CpuInfo* cpuInfo = X86CpuInfo::getGlobal(); + + clearFuncFlag( + kX86FuncFlagPushPop | + kX86FuncFlagEmitEmms | + kX86FuncFlagEmitSFence | + kX86FuncFlagEmitLFence | + kX86FuncFlagAssume16ByteAlignment | + kX86FuncFlagPerform16ByteAlignment); + + uint32_t accessibleMemoryBelowStack = 0; + if (getDecl()->getConvention() == kX86FuncConvX64U) + accessibleMemoryBelowStack = 128; + + if (getHint(kX86FuncHintAssume16ByteAlignment )) + setFuncFlag(kX86FuncFlagAssume16ByteAlignment); + + if (getHint(kX86FuncHintPerform16ByteAlignment)) + setFuncFlag(kX86FuncFlagPerform16ByteAlignment); + + if (getHint(kFuncHintNaked) != 0) + setFuncFlag(kFuncFlagIsNaked); + + if (isCaller() && (x86Context._memBytesTotal > 0 || isAssumed16ByteAlignment())) + setFuncFlag(kX86FuncFlagIsEspAdjusted); + + if (x86Context._memBytesTotal > accessibleMemoryBelowStack) + setFuncFlag(kX86FuncFlagIsEspAdjusted); + + if (getHint(kX86FuncHintPushPop) != 0) + setFuncFlag(kX86FuncFlagPushPop); + + if (getHint(kX86FuncHintEmms) != 0) + setFuncFlag(kX86FuncFlagEmitEmms); + + if (getHint(kX86FuncHintSFence) != 0) + setFuncFlag(kX86FuncFlagEmitSFence); + + if (getHint(kX86FuncHintLFence) != 0) + setFuncFlag(kX86FuncFlagEmitLFence); + + // Updated to respect comment from issue #47, align also when using MMX code. + if (!isAssumed16ByteAlignment() && !isNaked() && (x86Context._mem16BlocksCount + (x86Context._mem8BlocksCount > 0))) + { + // Have to align stack to 16-bytes. + setFuncFlag(kX86FuncFlagIsEspAdjusted | kX86FuncFlagPerform16ByteAlignment); + } + + _gpModifiedAndPreserved = x86Context._modifiedGpRegisters & _x86Decl.getGpPreservedMask() & (~IntUtil::maskFromIndex(kX86RegIndexEsp)); + _mmModifiedAndPreserved = x86Context._modifiedMmRegisters & _x86Decl.getMmPreservedMask(); + _xmmModifiedAndPreserved = x86Context._modifiedXmmRegisters & _x86Decl.getXmmPreservedMask(); + _movDqInstCode = (isAssumed16ByteAlignment() | isPerformed16ByteAlignment()) ? kX86InstMovDQA : kX86InstMovDQU; + + // Prolog & Epilog stack size. + { + int32_t memGpSize = IntUtil::bitCount(_gpModifiedAndPreserved) * sizeof(intptr_t); + int32_t memMmSize = IntUtil::bitCount(_mmModifiedAndPreserved) * 8; + int32_t memXmmSize = IntUtil::bitCount(_xmmModifiedAndPreserved) * 16; + + if (hasFuncFlag(kX86FuncFlagPushPop)) + { + _pePushPopStackSize = memGpSize; + _peMovStackSize = memXmmSize + IntUtil::align(memMmSize, 16); + } + else + { + _pePushPopStackSize = 0; + _peMovStackSize = memXmmSize + IntUtil::align(memMmSize + memGpSize, 16); + } + } + + if (isPerformed16ByteAlignment()) + { + _peAdjustStackSize += IntUtil::delta(_pePushPopStackSize, 16); + } + else + { + int32_t v = 16 - sizeof(uintptr_t); + + if (!isNaked()) + v -= sizeof(uintptr_t); + + v -= _pePushPopStackSize & 15; + + if (v < 0) + v += 16; + + _peAdjustStackSize = v; + + //_peAdjustStackSize += IntUtil::delta(_pePushPopStackSize + v, 16); + } + + // Memory stack size. + _memStackSize = x86Context._memBytesTotal; + _memStackSize16 = IntUtil::align(_memStackSize, 16); + + if (isNaked()) + { + x86Context._argumentsBaseReg = kX86RegIndexEsp; + x86Context._argumentsBaseOffset = hasFuncFlag(kX86FuncFlagIsEspAdjusted) + ? (_funcCallStackSize + _memStackSize16 + _peMovStackSize + _pePushPopStackSize + _peAdjustStackSize) + : (_pePushPopStackSize); + } + else + { + x86Context._argumentsBaseReg = kX86RegIndexEbp; + x86Context._argumentsBaseOffset = sizeof(sysint_t); + } + + x86Context._variablesBaseReg = kX86RegIndexEsp; + x86Context._variablesBaseOffset = _funcCallStackSize; + + if (!hasFuncFlag(kX86FuncFlagIsEspAdjusted)) + x86Context._variablesBaseOffset = -_memStackSize16 - _peMovStackSize - _peAdjustStackSize; +} + +void X86CompilerFuncDecl::_dumpFunction(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = getCompiler(); + + Logger* logger = x86Compiler->getLogger(); + ASMJIT_ASSERT(logger != NULL); + + uint32_t i; + char _buf[1024]; + char* p; + + // Log function prototype. + { + uint32_t argumentsCount = _x86Decl.getArgumentsCount(); + bool first = true; + + logger->logString("; Function Prototype:\n"); + logger->logString(";\n"); + + for (i = 0; i < argumentsCount; i++) + { + const FuncArg& a = _x86Decl.getArgument(i); + X86CompilerVar* cv = getVar(i); + + if (first) + { + logger->logString("; IDX| Type | Sz | Home |\n"); + logger->logString("; ---+----------+----+----------------+\n"); + } + + char* memHome = memHome = _buf; + + if (a.hasRegIndex()) + { + Reg regOp(a.getRegIndex() | kX86RegTypeGpz, 0); + X86Assembler_dumpOperand(memHome, ®Op, kX86RegTypeGpz, 0)[0] = '\0'; + } + else + { + Mem memOp; + memOp._mem.base = kX86RegIndexEsp; + memOp._mem.displacement = a.getStackOffset(); + X86Assembler_dumpOperand(memHome, &memOp, kX86RegTypeGpz, 0)[0] = '\0'; + } + + logger->logFormat("; %-3u| %-9s| %-3u| %-15s|\n", + // Argument index. + i, + // Argument type. + cv->getType() < kX86VarTypeCount ? x86VarInfo[cv->getType()].getName() : "invalid", + // Argument size. + cv->getSize(), + // Argument memory home. + memHome + ); + + first = false; + } + logger->logString(";\n"); + } + + // Log variables. + { + uint32_t variablesCount = (uint32_t)x86Compiler->_vars.getLength(); + bool first = true; + + logger->logString("; Variables:\n"); + logger->logString(";\n"); + + for (i = 0; i < variablesCount; i++) + { + X86CompilerVar* cv = static_cast(x86Compiler->_vars[i]); + + // If this variable is not related to this function then skip it. + if (cv->funcScope != this) + continue; + + // Get some information about variable type. + const X86VarInfo& vinfo = x86VarInfo[cv->getType()]; + + if (first) + { + logger->logString("; ID | Type | Sz | Home | Register Access | Memory Access |\n"); + logger->logString("; ---+----------+----+----------------+-------------------+-------------------+\n"); + } + + char* memHome = (char*)"[None]"; + if (cv->homeMemoryData != NULL) + { + VarMemBlock* memBlock = reinterpret_cast(cv->homeMemoryData); + memHome = _buf; + + Mem memOp; + if (cv->isMemArgument()) + { + const FuncArg& a = _x86Decl.getArgument(i); + + memOp._mem.base = x86Context._argumentsBaseReg; + memOp._mem.displacement += x86Context._argumentsBaseOffset; + memOp._mem.displacement += a.getStackOffset(); + } + else + { + memOp._mem.base = x86Context._variablesBaseReg; + memOp._mem.displacement += x86Context._variablesBaseOffset; + memOp._mem.displacement += memBlock->offset; + } + X86Assembler_dumpOperand(memHome, &memOp, kX86RegTypeGpz, 0)[0] = '\0'; + } + + logger->logFormat("; %-3u| %-9s| %-3u| %-15s| r=%-4uw=%-4ux=%-4u| r=%-4uw=%-4ux=%-4u|\n", + // Variable id. + (uint)(i & kOperandIdValueMask), + // Variable type. + cv->getType() < kX86VarTypeCount ? vinfo.getName() : "invalid", + // Variable size. + cv->getSize(), + // Variable memory home. + memHome, + // Register access count. + (unsigned int)cv->regReadCount, + (unsigned int)cv->regWriteCount, + (unsigned int)cv->regRwCount, + // Memory access count. + (unsigned int)cv->memReadCount, + (unsigned int)cv->memWriteCount, + (unsigned int)cv->memRwCount + ); + first = false; + } + logger->logString(";\n"); + } + + // Log modified registers. + { + p = _buf; + + uint32_t r; + uint32_t modifiedRegisters = 0; + + for (r = 0; r < 3; r++) + { + bool first = true; + uint32_t regs; + uint32_t type; + + switch (r) + { + case 0: + regs = x86Context._modifiedGpRegisters; + type = kX86RegTypeGpz; + p = StringUtil::copy(p, "; GP : "); + break; + case 1: + regs = x86Context._modifiedMmRegisters; + type = kX86RegTypeMm; + p = StringUtil::copy(p, "; MM : "); + break; + case 2: + regs = x86Context._modifiedXmmRegisters; + type = kX86RegTypeXmm; + p = StringUtil::copy(p, "; XMM: "); + break; + default: + ASMJIT_ASSERT(0); + } + + for (i = 0; i < kX86RegNumBase; i++) + { + if ((regs & IntUtil::maskFromIndex(i)) != 0) + { + if (!first) { *p++ = ','; *p++ = ' '; } + p = X86Assembler_dumpRegister(p, type, i); + first = false; + modifiedRegisters++; + } + } + *p++ = '\n'; + } + *p = '\0'; + + logger->logFormat("; Modified registers (%u):\n", (unsigned int)modifiedRegisters); + logger->logString(_buf); + } + + logger->logString("\n"); +} + +void X86CompilerFuncDecl::_emitProlog(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = getCompiler(); + + // -------------------------------------------------------------------------- + // [Init] + // -------------------------------------------------------------------------- + + uint32_t i, mask; + uint32_t preservedGP = _gpModifiedAndPreserved; + uint32_t preservedMM = _mmModifiedAndPreserved; + uint32_t preservedXMM = _xmmModifiedAndPreserved; + + int32_t stackOffset = _getRequiredStackOffset(); + int32_t stackPos; + + // -------------------------------------------------------------------------- + // [Prolog] + // -------------------------------------------------------------------------- + + if (x86Compiler->getLogger()) + x86Compiler->comment("Prolog"); + + // Emit standard prolog entry code (but don't do it if function is set to be + // naked). + // + // Also see the _prologEpilogStackAdjust variable. If function is naked (so + // prolog and epilog will not contain "push ebp" and "mov ebp, esp", we need + // to adjust stack by 8 bytes in 64-bit mode (this will give us that stack + // will remain aligned to 16 bytes). + if (!isNaked()) + { + x86Compiler->emit(kX86InstPush, zbp); + x86Compiler->emit(kX86InstMov, zbp, zsp); + } + + // Align manually stack-pointer to 16-bytes. + if (isPerformed16ByteAlignment()) + { + ASMJIT_ASSERT(!isNaked()); + x86Compiler->emit(kX86InstAnd, zsp, imm(-16)); + } + + // -------------------------------------------------------------------------- + // [Save Gp - Push/Pop] + // -------------------------------------------------------------------------- + + if (preservedGP != 0 && hasFuncFlag(kX86FuncFlagPushPop)) + { + for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1) + { + if (preservedGP & mask) + x86Compiler->emit(kX86InstPush, gpz(i)); + } + } + + // -------------------------------------------------------------------------- + // [Adjust Scack] + // -------------------------------------------------------------------------- + + if (isEspAdjusted()) + { + stackPos = _memStackSize16 + _funcCallStackSize; + if (stackOffset != 0) + x86Compiler->emit(kX86InstSub, zsp, imm(stackOffset)); + } + else + { + stackPos = -(_peMovStackSize + _peAdjustStackSize); + //if (_pePushPop) stackPos += IntUtil::bitCount(preservedGP) * sizeof(sysint_t); + } + + // -------------------------------------------------------------------------- + // [Save Xmm - MovDqa/MovDqu] + // -------------------------------------------------------------------------- + + if (preservedXMM != 0) + { + for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1) + { + if (preservedXMM & mask) + { + x86Compiler->emit(_movDqInstCode, dqword_ptr(zsp, stackPos), xmm(i)); + stackPos += 16; + } + } + } + + // -------------------------------------------------------------------------- + // [Save Mm - MovQ] + // -------------------------------------------------------------------------- + + if (preservedMM != 0) + { + for (i = 0, mask = 1; i < 8; i++, mask <<= 1) + { + if (preservedMM & mask) + { + x86Compiler->emit(kX86InstMovQ, qword_ptr(zsp, stackPos), mm(i)); + stackPos += 8; + } + } + } + + // -------------------------------------------------------------------------- + // [Save Gp - Mov] + // -------------------------------------------------------------------------- + + if (preservedGP != 0 && !hasFuncFlag(kX86FuncFlagPushPop)) + { + for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1) + { + if (preservedGP & mask) + { + x86Compiler->emit(kX86InstMov, sysint_ptr(zsp, stackPos), gpz(i)); + stackPos += sizeof(sysint_t); + } + } + } + + // -------------------------------------------------------------------------- + // [...] + // -------------------------------------------------------------------------- + + if (x86Compiler->getLogger()) + x86Compiler->comment("Body"); +} + +void X86CompilerFuncDecl::_emitEpilog(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = getCompiler(); + + const X86CpuInfo* cpuInfo = X86CpuInfo::getGlobal(); + + // -------------------------------------------------------------------------- + // [Init] + // -------------------------------------------------------------------------- + + uint32_t i, mask; + uint32_t preservedGP = _gpModifiedAndPreserved; + uint32_t preservedMM = _mmModifiedAndPreserved; + uint32_t preservedXMM = _xmmModifiedAndPreserved; + + int32_t stackOffset = _getRequiredStackOffset(); + int32_t stackPos; + + if (isEspAdjusted()) + stackPos = _memStackSize16 + _funcCallStackSize; + else + stackPos = -(_peMovStackSize + _peAdjustStackSize); + + // -------------------------------------------------------------------------- + // [Epilog] + // -------------------------------------------------------------------------- + + if (x86Compiler->getLogger()) + x86Compiler->comment("Epilog"); + + // -------------------------------------------------------------------------- + // [Restore Xmm - MovDqa/ModDqu] + // -------------------------------------------------------------------------- + + if (preservedXMM != 0) + { + for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1) + { + if (preservedXMM & mask) + { + x86Compiler->emit(_movDqInstCode, xmm(i), dqword_ptr(zsp, stackPos)); + stackPos += 16; + } + } + } + + // -------------------------------------------------------------------------- + // [Restore Mm - MovQ] + // -------------------------------------------------------------------------- + + if (preservedMM != 0) + { + for (i = 0, mask = 1; i < 8; i++, mask <<= 1) + { + if (preservedMM & mask) + { + x86Compiler->emit(kX86InstMovQ, mm(i), qword_ptr(zsp, stackPos)); + stackPos += 8; + } + } + } + + // -------------------------------------------------------------------------- + // [Restore Gp - Mov] + // -------------------------------------------------------------------------- + + if (preservedGP != 0 && !hasFuncFlag(kX86FuncFlagPushPop)) + { + for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1) + { + if (preservedGP & mask) + { + x86Compiler->emit(kX86InstMov, gpz(i), sysint_ptr(zsp, stackPos)); + stackPos += sizeof(sysint_t); + } + } + } + + // -------------------------------------------------------------------------- + // [Adjust Stack] + // -------------------------------------------------------------------------- + + if (isEspAdjusted() && stackOffset != 0) + x86Compiler->emit(kX86InstAdd, zsp, imm(stackOffset)); + + // -------------------------------------------------------------------------- + // [Restore Gp - Push/Pop] + // -------------------------------------------------------------------------- + + if (preservedGP != 0 && hasFuncFlag(kX86FuncFlagPushPop)) + { + for (i = kX86RegNumGp - 1, mask = 1 << i; (int32_t)i >= 0; i--, mask >>= 1) + { + if (preservedGP & mask) + x86Compiler->emit(kX86InstPop, gpz(i)); + } + } + + // -------------------------------------------------------------------------- + // [Emms] + // -------------------------------------------------------------------------- + + if (hasFuncFlag(kX86FuncFlagEmitEmms)) + x86Compiler->emit(kX86InstEmms); + + // -------------------------------------------------------------------------- + // [MFence/SFence/LFence] + // -------------------------------------------------------------------------- + + if (hasFuncFlag(kX86FuncFlagEmitSFence) & hasFuncFlag(kX86FuncFlagEmitLFence)) + x86Compiler->emit(kX86InstMFence); + else if (hasFuncFlag(kX86FuncFlagEmitSFence)) + x86Compiler->emit(kX86InstSFence); + else if (hasFuncFlag(kX86FuncFlagEmitLFence)) + x86Compiler->emit(kX86InstLFence); + + // -------------------------------------------------------------------------- + // [Epilog] + // -------------------------------------------------------------------------- + + // Emit standard epilog leave code (if needed). + if (!isNaked()) + { + // AMD seems to prefer LEAVE instead of MOV/POP sequence. + if (cpuInfo->getVendorId() == kCpuAmd) + { + x86Compiler->emit(kX86InstLeave); + } + else + { + x86Compiler->emit(kX86InstMov, zsp, zbp); + x86Compiler->emit(kX86InstPop, zbp); + } + } + + // Emit return. + if (_x86Decl.getCalleePopsStack()) + x86Compiler->emit(kX86InstRet, imm((int16_t)_x86Decl.getArgumentsStackSize())); + else + x86Compiler->emit(kX86InstRet); +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncDecl - Function-Call] +// ============================================================================ + +void X86CompilerFuncDecl::reserveStackForFunctionCall(int32_t size) +{ + size = IntUtil::align(size, 16); + if (size > _funcCallStackSize) + _funcCallStackSize = size; + setFuncFlag(kFuncFlagIsCaller); +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncEnd - Construction / Destruction] +// ============================================================================ + +X86CompilerFuncEnd::X86CompilerFuncEnd(X86Compiler* x86Compiler, X86CompilerFuncDecl* func) : + CompilerFuncEnd(x86Compiler, func) +{ +} + +X86CompilerFuncEnd::~X86CompilerFuncEnd() +{ +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncEnd - Interface] +// ============================================================================ + +void X86CompilerFuncEnd::prepare(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + _offset = x86Context._currentOffset++; +} + +CompilerItem* X86CompilerFuncEnd::translate(CompilerContext& cc) +{ + _isTranslated = true; + return NULL; +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncRet - Construction / Destruction] +// ============================================================================ + +X86CompilerFuncRet::X86CompilerFuncRet(X86Compiler* x86Compiler, X86CompilerFuncDecl* func, const Operand* first, const Operand* second) : + CompilerFuncRet(x86Compiler, func, first, second) +{ +/* + // TODO:? + + // Check whether the return value is compatible. + uint32_t retValType = function->_x86Decl.getReturnType(); + bool valid = false; + + switch (retValType) + { + case kX86VarTypeGpd: + case kX86VarTypeGpq: + if ((_ret[0].isVar() && (reinterpret_cast(_ret[0]).isGpVar())) || + (_ret[0].isImm())) + { + valid = true; + } + break; + + case kX86VarTypeX87: + case kX86VarTypeX87SS: + case kX86VarTypeX87SD: + if ((_ret[0].isVar() && (reinterpret_cast(_ret[0]).isX87Var() || + reinterpret_cast(_ret[0]).isXmmVar() )) ) + { + valid = true; + } + break; + + case kX86VarTypeMm: + break; + + case kVarTypeInvalid: + if (_ret[0].isNone() && + _ret[1].isNone()) + { + valid = true; + } + break; + + default: + break; + } + + // Incompatible return value. + if (!valid) + { + c->setError(kErrorIncompatibleReturnType); + } +*/ +} + +X86CompilerFuncRet::~X86CompilerFuncRet() +{ +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncRet - Interface] +// ============================================================================ + +void X86CompilerFuncRet::prepare(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = x86Context.getCompiler(); + + uint32_t retValType = getFunc()->_x86Decl.getReturnType(); + _offset = x86Context._currentOffset; + + if (retValType != kVarTypeInvalid) + { + uint32_t i; + for (i = 0; i < 2; i++) + { + Operand& o = _ret[i]; + + if (o.isVar()) + { + ASMJIT_ASSERT(o.getId() != kInvalidValue); + X86CompilerVar* cv = x86Compiler->_getVar(o.getId()); + ASMJIT_ASSERT(cv != NULL); + + // First item (begin of variable scope). + if (cv->firstItem == NULL) cv->firstItem = this; + + // Last item (end of variable scope). + cv->lastItem = this; + + if (cv->workOffset == _offset) continue; + if (!x86Context._isActive(cv)) x86Context._addActive(cv); + + cv->workOffset = _offset; + cv->regReadCount++; + + if (X86Util::isVarTypeInt(cv->getType()) && X86Util::isVarTypeInt(retValType)) + { + x86Context._newRegisterHomeIndex(cv, (i == 0) ? kX86RegIndexEax : kX86RegIndexEdx); + } + } + } + } + + x86Context._currentOffset++; +} + +CompilerItem* X86CompilerFuncRet::translate(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = x86Context.getCompiler(); + + // Check whether the return value is compatible. + uint32_t retValType = getFunc()->getDecl()->getReturnType(); + uint32_t i; + + switch (retValType) + { + case kX86VarTypeGpd: + case kX86VarTypeGpq: + for (i = 0; i < 2; i++) + { + uint32_t dstIndex = (i == 0) ? kX86RegIndexEax : kX86RegIndexEdx; + uint32_t srcIndex; + + if (_ret[i].isVar()) + { + if (reinterpret_cast(_ret[i]).isGpVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId()); + ASMJIT_ASSERT(cv != NULL); + + srcIndex = cv->regIndex; + if (srcIndex == kRegIndexInvalid) + x86Compiler->emit(kX86InstMov, gpz(dstIndex), x86Context._getVarMem(cv)); + else if (dstIndex != srcIndex) + x86Compiler->emit(kX86InstMov, gpz(dstIndex), gpz(srcIndex)); + } + } + else if (_ret[i].isImm()) + { + x86Compiler->emit(kX86InstMov, gpz(dstIndex), _ret[i]); + } + } + break; + + case kX86VarTypeX87: + case kX86VarTypeX87SS: + case kX86VarTypeX87SD: + // There is case that we need to return two values (Unix-ABI specific): + // - FLD #2 + //- FLD #1 + i = 2; + do { + i--; + uint32_t dsti = i; + uint32_t srci; + + if (_ret[i].isVar()) + { + if (reinterpret_cast(_ret[i]).isX87Var()) + { + // TODO: X87 Support. + } + else if (reinterpret_cast(_ret[i]).isXmmVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId()); + ASMJIT_ASSERT(cv != NULL); + + srci = cv->regIndex; + if (srci != kRegIndexInvalid) + x86Context.saveXmmVar(cv); + + switch (cv->getType()) + { + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + x86Compiler->emit(kX86InstFLd, _BaseVarMem(reinterpret_cast(_ret[i]), 4)); + break; + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstFLd, _BaseVarMem(reinterpret_cast(_ret[i]), 8)); + break; + } + } + } + } while (i != 0); + break; + + case kX86VarTypeMm: + for (i = 0; i < 2; i++) + { + uint32_t dsti = i; + uint32_t srci; + + if (_ret[i].isVar()) + { + if (reinterpret_cast(_ret[i]).isGpVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId()); + ASMJIT_ASSERT(cv != NULL); + + srci = cv->regIndex; + uint32_t inst = _ret[i].isRegType(kX86RegTypeGpq) ? kX86InstMovQ : kX86InstMovD; + + if (srci == kRegIndexInvalid) + x86Compiler->emit(inst, mm(dsti), x86Context._getVarMem(cv)); + else +#if defined(ASMJIT_X86) + x86Compiler->emit(inst, mm(dsti), gpd(srci)); +#else + x86Compiler->emit(inst, mm(dsti), _ret[i].isRegType(kX86RegTypeGpq) ? gpq(srci) : gpd(srci)); +#endif + } + else if (reinterpret_cast(_ret[i]).isMmVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId()); + ASMJIT_ASSERT(cv != NULL); + + srci = cv->regIndex; + uint32_t inst = kX86InstMovQ; + + if (srci == kRegIndexInvalid) + x86Compiler->emit(inst, mm(dsti), x86Context._getVarMem(cv)); + else if (dsti != srci) + x86Compiler->emit(inst, mm(dsti), mm(srci)); + } + else if (reinterpret_cast(_ret[i]).isXmmVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId()); + ASMJIT_ASSERT(cv != NULL); + + srci = cv->regIndex; + uint32_t inst = kX86InstMovQ; + if (reinterpret_cast(_ret[i]).getVarType() == kX86VarTypeXmmSS) inst = kX86InstMovD; + + if (srci == kRegIndexInvalid) + x86Compiler->emit(inst, mm(dsti), x86Context._getVarMem(cv)); + else + x86Compiler->emit(inst, mm(dsti), xmm(srci)); + } + } + } + break; + + case kX86VarTypeXmm: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmPD: + for (i = 0; i < 2; i++) + { + uint32_t dsti = i; + uint32_t srci; + + if (_ret[i].isVar()) + { + if (reinterpret_cast(_ret[i]).isGpVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId()); + ASMJIT_ASSERT(cv != NULL); + + srci = cv->regIndex; + uint32_t inst = _ret[i].isRegType(kX86RegTypeGpq) ? kX86InstMovQ : kX86InstMovD; + + if (srci == kRegIndexInvalid) + x86Compiler->emit(inst, xmm(dsti), x86Context._getVarMem(cv)); + else +#if defined(ASMJIT_X86) + x86Compiler->emit(inst, xmm(dsti), gpd(srci)); +#else + x86Compiler->emit(inst, xmm(dsti), _ret[i].isRegType(kX86RegTypeGpq) ? gpq(srci) : gpd(srci)); +#endif + } + else if (reinterpret_cast(_ret[i]).isX87Var()) + { + // TODO: X87 Support. + } + else if (reinterpret_cast(_ret[i]).isMmVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId()); + ASMJIT_ASSERT(cv != NULL); + + srci = cv->regIndex; + if (srci == kRegIndexInvalid) + x86Compiler->emit(kX86InstMovQ, xmm(dsti), x86Context._getVarMem(cv)); + else + x86Compiler->emit(kX86InstMovQ, xmm(dsti), mm(srci)); + } + else if (reinterpret_cast(_ret[i]).isXmmVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId()); + ASMJIT_ASSERT(cv != NULL); + + srci = cv->regIndex; + if (srci == kRegIndexInvalid) + x86Compiler->emit(kX86InstMovDQA, xmm(dsti), x86Context._getVarMem(cv)); + else if (dsti != srci) + x86Compiler->emit(kX86InstMovDQA, xmm(dsti), xmm(srci)); + } + } + } + break; + + case kX86VarTypeXmmSS: + for (i = 0; i < 2; i++) + { + uint32_t dsti = i; + uint32_t srci; + + if (_ret[i].isVar()) + { + if (reinterpret_cast(_ret[i]).isX87Var()) + { + // TODO: X87 Support. + } + else if (reinterpret_cast(_ret[i]).isXmmVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId()); + ASMJIT_ASSERT(cv != NULL); + + srci = cv->regIndex; + switch (cv->getType()) + { + case kX86VarTypeXmm: + if (srci == kRegIndexInvalid) + x86Compiler->emit(kX86InstMovDQA, xmm(dsti), x86Context._getVarMem(cv)); + else if (dsti != srci) + x86Compiler->emit(kX86InstMovDQA, xmm(dsti), xmm(srci)); + break; + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + if (srci == kRegIndexInvalid) + x86Compiler->emit(kX86InstMovSS, xmm(dsti), x86Context._getVarMem(cv)); + else + x86Compiler->emit(kX86InstMovSS, xmm(dsti), xmm(srci)); + break; + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + if (srci == kRegIndexInvalid) + x86Compiler->emit(kX86InstCvtSD2SS, xmm(dsti), x86Context._getVarMem(cv)); + else if (dsti != srci) + x86Compiler->emit(kX86InstCvtSD2SS, xmm(dsti), xmm(srci)); + break; + } + } + } + } + break; + + case kX86VarTypeXmmSD: + for (i = 0; i < 2; i++) + { + uint32_t dsti = i; + uint32_t srci; + + if (_ret[i].isVar()) + { + if (reinterpret_cast(_ret[i]).isX87Var()) + { + // TODO: X87 Support. + } + else if (reinterpret_cast(_ret[i]).isXmmVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId()); + ASMJIT_ASSERT(cv != NULL); + + srci = cv->regIndex; + switch (cv->getType()) + { + case kX86VarTypeXmm: + if (srci == kRegIndexInvalid) + x86Compiler->emit(kX86InstMovDQA, xmm(dsti), x86Context._getVarMem(cv)); + else if (dsti != srci) + x86Compiler->emit(kX86InstMovDQA, xmm(dsti), xmm(srci)); + break; + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + if (srci == kRegIndexInvalid) + x86Compiler->emit(kX86InstCvtSS2SD, xmm(dsti), x86Context._getVarMem(cv)); + else + x86Compiler->emit(kX86InstCvtSS2SD, xmm(dsti), xmm(srci)); + break; + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + if (srci == kRegIndexInvalid) + x86Compiler->emit(kX86InstMovSD, xmm(dsti), x86Context._getVarMem(cv)); + else + x86Compiler->emit(kX86InstMovSD, xmm(dsti), xmm(srci)); + break; + } + } + } + } + break; + + case kInvalidValue: + default: + break; + } + + if (mustEmitJump()) + { + x86Context._isUnreachable = 1; + } + + for (i = 0; i < 2; i++) + { + if (_ret[i].isVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(_ret[i].getId()); + x86Context._unuseVarOnEndOfScope(this, cv); + } + } + + return translated(); +} + +void X86CompilerFuncRet::emit(Assembler& a) +{ + X86Assembler& x86Asm = static_cast(a); + + if (mustEmitJump()) + x86Asm.jmp(getFunc()->getExitLabel()); +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncRet - Misc] +// ============================================================================ + +int X86CompilerFuncRet::getMaxSize() const +{ + return mustEmitJump() ? 15 : 0; +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncCall - Construction / Destruction] +// ============================================================================ + +X86CompilerFuncCall::X86CompilerFuncCall(X86Compiler* x86Compiler, X86CompilerFuncDecl* caller, const Operand* target) : + CompilerFuncCall(x86Compiler, caller, target), + _gpParams(0), + _mmParams(0), + _xmmParams(0), + _variablesCount(0), + _variables(NULL) +{ +} + +X86CompilerFuncCall::~X86CompilerFuncCall() +{ + memset(_argumentToVarRecord, 0, sizeof(VarCallRecord*) * kFuncArgsMax); +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncCall - Interface] +// ============================================================================ + +void X86CompilerFuncCall::prepare(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = getCompiler(); + + // Prepare is similar to X86CompilerInst::prepare(). We collect unique variables + // and update statistics, but we don't use standard alloc/free register calls. + // + // The calling function is also unique in variable allocator point of view, + // because we need to alloc some variables that may be destroyed be the + // callee (okay, may not, but this is not guaranteed). + _offset = x86Context._currentOffset; + + // Tell EFunction that another function will be called inside. It needs this + // information to reserve stack for the call and to mark esp adjustable. + getCaller()->reserveStackForFunctionCall(static_cast(_x86Decl.getArgumentsStackSize())); + + uint32_t i; + uint32_t argumentsCount = _x86Decl.getArgumentsCount(); + uint32_t operandsCount = argumentsCount; + uint32_t variablesCount = 0; + + // Create registers used as arguments mask. + for (i = 0; i < argumentsCount; i++) + { + const FuncArg& fArg = _x86Decl.getArguments()[i]; + + if (fArg.hasRegIndex()) + { + switch (fArg.getVarType()) + { + case kX86VarTypeGpd: + case kX86VarTypeGpq: + _gpParams |= IntUtil::maskFromIndex(fArg.getRegIndex()); + break; + case kX86VarTypeMm: + _mmParams |= IntUtil::maskFromIndex(fArg.getRegIndex()); + break; + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + _xmmParams |= IntUtil::maskFromIndex(fArg.getRegIndex()); + break; + default: + ASMJIT_ASSERT(0); + } + } + else + { + x86Context.getFunc()->setFuncFlag(kX86FuncFlagIsEspAdjusted); + } + } + + // Call address. + operandsCount++; + + // The first and the second return value. + if (!_ret[0].isNone()) + operandsCount++; + if (!_ret[1].isNone()) + operandsCount++; + +#define __GET_VARIABLE(__vardata__) \ + { \ + X86CompilerVar* _candidate = __vardata__; \ + \ + for (var = cur; ;) \ + { \ + if (var == _variables) \ + { \ + var = cur++; \ + var->vdata = _candidate; \ + break; \ + } \ + \ + var--; \ + \ + if (var->vdata == _candidate) \ + { \ + break; \ + } \ + } \ + \ + ASMJIT_ASSERT(var != NULL); \ + } + + for (i = 0; i < operandsCount; i++) + { + Operand& o = (i < argumentsCount) + ? (_args[i]) + : (i == argumentsCount ? _target : _ret[i - argumentsCount - 1]); + + if (o.isVar()) + { + ASMJIT_ASSERT(o.getId() != kInvalidValue); + X86CompilerVar* cv = x86Compiler->_getVar(o.getId()); + ASMJIT_ASSERT(cv != NULL); + + if (cv->workOffset == _offset) continue; + if (!x86Context._isActive(cv)) x86Context._addActive(cv); + + cv->workOffset = _offset; + variablesCount++; + } + else if (o.isMem()) + { + if ((o.getId() & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* cv = x86Compiler->_getVar(o.getId()); + ASMJIT_ASSERT(cv != NULL); + + x86Context._markMemoryUsed(cv); + if (!x86Context._isActive(cv)) x86Context._addActive(cv); + + continue; + } + else if ((o._mem.base & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* cv = x86Compiler->_getVar(o._mem.base); + ASMJIT_ASSERT(cv != NULL); + + if (cv->workOffset == _offset) continue; + if (!x86Context._isActive(cv)) x86Context._addActive(cv); + + cv->workOffset = _offset; + variablesCount++; + } + + if ((o._mem.index & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* cv = x86Compiler->_getVar(o._mem.index); + ASMJIT_ASSERT(cv != NULL); + + if (cv->workOffset == _offset) continue; + if (!x86Context._isActive(cv)) x86Context._addActive(cv); + + cv->workOffset = _offset; + variablesCount++; + } + } + } + + // Traverse all active variables and set their funcCall pointer to this + // call. This information can be used to choose between the preserved-first + // and preserved-last register allocation. + if (x86Context._active) + { + X86CompilerVar* first = static_cast(x86Context._active); + X86CompilerVar* active = first; + do { + if (active->funcCall == NULL) + active->funcCall = this; + active = active->nextActive; + } while (active != first); + } + + if (!variablesCount) + { + x86Context._currentOffset++; + return; + } + + _variables = reinterpret_cast(x86Compiler->getZoneMemory().alloc(sizeof(VarCallRecord) * variablesCount)); + if (!_variables) + { + x86Compiler->setError(kErrorNoHeapMemory); + x86Context._currentOffset++; + return; + } + + _variablesCount = variablesCount; + memset(_variables, 0, sizeof(VarCallRecord) * variablesCount); + + VarCallRecord* cur = _variables; + VarCallRecord* var = NULL; + + for (i = 0; i < operandsCount; i++) + { + Operand& o = (i < argumentsCount) + ? (_args[i]) + : (i == argumentsCount ? _target : _ret[i - argumentsCount - 1]); + + if (o.isVar()) + { + X86CompilerVar* cv = x86Compiler->_getVar(o.getId()); + ASMJIT_ASSERT(cv != NULL); + + __GET_VARIABLE(cv) + _argumentToVarRecord[i] = var; + + if (i < argumentsCount) + { + const FuncArg& fArg = _x86Decl.getArgument(i); + + if (fArg.hasRegIndex()) + { + x86Context._newRegisterHomeIndex(cv, fArg.getRegIndex()); + + switch (fArg.getVarType()) + { + case kX86VarTypeGpd: + case kX86VarTypeGpq: + var->flags |= VarCallRecord::kFlagInGp; + var->inCount++; + break; + + case kX86VarTypeMm: + var->flags |= VarCallRecord::kFlagInMm; + var->inCount++; + break; + + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + var->flags |= VarCallRecord::kFlagInXmm; + var->inCount++; + break; + + default: + ASMJIT_ASSERT(0); + } + } + else + { + var->inCount++; + } + + cv->regReadCount++; + } + else if (i == argumentsCount) + { + uint32_t mask = (~_x86Decl.getGpPreservedMask()) & + (~_x86Decl.getGpArgumentsMask()) & + (IntUtil::maskUpToIndex(kX86RegNumGp)); + + x86Context._newRegisterHomeIndex(cv, IntUtil::findFirstBit(mask)); + x86Context._newRegisterHomeMask(cv, mask); + + var->flags |= VarCallRecord::kFlagCallReg; + cv->regReadCount++; + } + else + { + switch (cv->getType()) + { + case kX86VarTypeGpd: + case kX86VarTypeGpq: + if (i == argumentsCount+1) + var->flags |= VarCallRecord::kFlagOutEax; + else + var->flags |= VarCallRecord::kFlagOutEdx; + break; + + case kX86VarTypeX87: + case kX86VarTypeX87SS: + case kX86VarTypeX87SD: +#if defined(ASMJIT_X86) + if (i == argumentsCount+1) + var->flags |= VarCallRecord::kFlagOutSt0; + else + var->flags |= VarCallRecord::kFlagOutSt1; +#else + if (i == argumentsCount+1) + var->flags |= VarCallRecord::kFlagOutXmm0; + else + var->flags |= VarCallRecord::kFlagOutXmm1; +#endif + break; + + case kX86VarTypeMm: + var->flags |= VarCallRecord::kFlagOutMm0; + break; + + case kX86VarTypeXmm: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmPD: + if (i == argumentsCount+1) + var->flags |= VarCallRecord::kFlagOutXmm0; + else + var->flags |= VarCallRecord::kFlagOutXmm1; + break; + + case kX86VarTypeXmmSS: + case kX86VarTypeXmmSD: +#if defined(ASMJIT_X86) + if (i == argumentsCount+1) + var->flags |= VarCallRecord::kFlagOutSt0; + else + var->flags |= VarCallRecord::kFlagOutSt1; +#else + if (i == argumentsCount+1) + var->flags |= VarCallRecord::kFlagOutXmm0; + else + var->flags |= VarCallRecord::kFlagOutXmm1; +#endif + break; + + default: + ASMJIT_ASSERT(0); + } + + cv->regWriteCount++; + } + } + else if (o.isMem()) + { + ASMJIT_ASSERT(i == argumentsCount); + + if ((o.getId() & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* cv = x86Compiler->_getVar(o.getId()); + ASMJIT_ASSERT(cv != NULL); + + cv->memReadCount++; + } + else if ((o._mem.base & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* cv = x86Compiler->_getVar(reinterpret_cast(o).getBase()); + ASMJIT_ASSERT(cv != NULL); + + cv->regReadCount++; + + __GET_VARIABLE(cv) + var->flags |= VarCallRecord::kFlagCallReg | VarCallRecord::kFlagCallMem; + } + + if ((o._mem.index & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* cv = x86Compiler->_getVar(reinterpret_cast(o).getIndex()); + ASMJIT_ASSERT(cv != NULL); + + cv->regReadCount++; + + __GET_VARIABLE(cv) + var->flags |= VarCallRecord::kFlagCallReg | VarCallRecord::kFlagCallMem; + } + } + } + + // Traverse all variables and update firstItem / lastItem. This + // function is called from iterator that scans items using forward + // direction so we can use this knowledge to optimize the process. + // + // Same code is in X86CompilerInst::prepare(). + for (i = 0; i < _variablesCount; i++) + { + X86CompilerVar* v = _variables[i].vdata; + + // First item (begin of variable scope). + if (v->firstItem == NULL) v->firstItem = this; + + // Last item (end of variable scope). + v->lastItem = this; + } + + x86Context._currentOffset++; + +#undef __GET_VARIABLE +} + +CompilerItem* X86CompilerFuncCall::translate(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = x86Context.getCompiler(); + + uint32_t i; + uint32_t preserved, mask; + + uint32_t temporaryGpReg; + uint32_t temporaryXmmReg; + + uint32_t offset = x86Context._currentOffset; + + // Constants. + const FuncArg* targs = _x86Decl.getArguments(); + + uint32_t argumentsCount = _x86Decl.getArgumentsCount(); + uint32_t variablesCount = _variablesCount; + + // Processed arguments kFuncArgsMax. + uint8_t processed[kFuncArgsMax] = { 0 }; + + x86Compiler->comment("Call"); + + // These variables are used by the instruction so we set current offset + // to their work offsets -> The getSpillCandidate() method never returns + // the variable used by this instruction. + for (i = 0; i < variablesCount; i++) + { + _variables[i].vdata->workOffset = offset; + + // Init back-reference to VarCallRecord. + _variables[i].vdata->tPtr = &_variables[i]; + } + + // -------------------------------------------------------------------------- + // STEP 1: + // + // Spill variables which are not used by the function call and have to + // be destroyed. These registers may be used by callee. + // -------------------------------------------------------------------------- + + preserved = _x86Decl.getGpPreservedMask(); + for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1) + { + X86CompilerVar* cv = x86Context._x86State.gp[i]; + if (cv && cv->workOffset != offset && (preserved & mask) == 0) + x86Context.spillGpVar(cv); + } + + preserved = _x86Decl.getMmPreservedMask(); + for (i = 0, mask = 1; i < kX86RegNumMm; i++, mask <<= 1) + { + X86CompilerVar* cv = x86Context._x86State.mm[i]; + if (cv && cv->workOffset != offset && (preserved & mask) == 0) + x86Context.spillMmVar(cv); + } + + preserved = _x86Decl.getXmmPreservedMask(); + for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1) + { + X86CompilerVar* cv = x86Context._x86State.xmm[i]; + if (cv && cv->workOffset != offset && (preserved & mask) == 0) + x86Context.spillXmmVar(cv); + } + + // -------------------------------------------------------------------------- + // STEP 2: + // + // Move all arguments to the stack which all already in registers. + // -------------------------------------------------------------------------- + + for (i = 0; i < argumentsCount; i++) + { + if (processed[i]) + continue; + + const FuncArg& argType = targs[i]; + if (argType.hasRegIndex()) + continue; + + Operand& operand = _args[i]; + + if (operand.isVar()) + { + VarCallRecord* rec = _argumentToVarRecord[i]; + X86CompilerVar* cv = x86Compiler->_getVar(operand.getId()); + + if (cv->regIndex != kRegIndexInvalid) + { + _moveAllocatedVariableToStack(cc, + cv, argType); + + rec->inDone++; + processed[i] = true; + } + } + } + + // -------------------------------------------------------------------------- + // STEP 3: + // + // Spill all non-preserved variables we moved to stack in STEP #2. + // -------------------------------------------------------------------------- + + for (i = 0; i < argumentsCount; i++) + { + VarCallRecord* rec = _argumentToVarRecord[i]; + if (!rec || processed[i]) + continue; + + if (rec->inDone >= rec->inCount) + { + X86CompilerVar* cv = rec->vdata; + if (cv->regIndex == kRegIndexInvalid) + continue; + + if (rec->outCount) + { + // Variable will be rewritten by function return value, it's not needed + // to spill it. It will be allocated again by X86CompilerFuncCall. + x86Context.unuseVar(rec->vdata, kVarStateUnused); + } + else + { + switch (cv->getType()) + { + case kX86VarTypeGpd: + case kX86VarTypeGpq: + if ((_x86Decl.getGpPreservedMask() & IntUtil::maskFromIndex(cv->regIndex)) == 0) + x86Context.spillGpVar(cv); + break; + case kX86VarTypeMm: + if ((_x86Decl.getMmPreservedMask() & IntUtil::maskFromIndex(cv->regIndex)) == 0) + x86Context.spillMmVar(cv); + break; + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmPD: + if ((_x86Decl.getXmmPreservedMask() & IntUtil::maskFromIndex(cv->regIndex)) == 0) + x86Context.spillXmmVar(cv); + break; + } + } + } + } + + // -------------------------------------------------------------------------- + // STEP 4: + // + // Get temporary register that we can use to pass input function arguments. + // Now it's safe to do, because the non-needed variables should be spilled. + // -------------------------------------------------------------------------- + + temporaryGpReg = _findTemporaryGpRegister(cc); + temporaryXmmReg = _findTemporaryXmmRegister(cc); + + // If failed to get temporary register then we need just to pick one. + if (temporaryGpReg == kRegIndexInvalid) + { + // TODO. + } + if (temporaryXmmReg == kRegIndexInvalid) + { + // TODO. + } + + // -------------------------------------------------------------------------- + // STEP 5: + // + // Move all remaining arguments to the stack (we can use temporary register). + // or allocate it to the primary register. Also move immediates. + // -------------------------------------------------------------------------- + + for (i = 0; i < argumentsCount; i++) + { + if (processed[i]) + continue; + + const FuncArg& argType = targs[i]; + + if (argType.hasRegIndex()) + continue; + + Operand& operand = _args[i]; + + if (operand.isVar()) + { + VarCallRecord* rec = _argumentToVarRecord[i]; + X86CompilerVar* cv = x86Compiler->_getVar(operand.getId()); + + _moveSpilledVariableToStack(cc, + cv, argType, + temporaryGpReg, temporaryXmmReg); + + rec->inDone++; + processed[i] = true; + } + else if (operand.isImm()) + { + // TODO. + } + } + + // -------------------------------------------------------------------------- + // STEP 6: + // + // Allocate arguments to registers. + // -------------------------------------------------------------------------- + + bool didWork; + + do { + didWork = false; + + for (i = 0; i < argumentsCount; i++) + { + if (processed[i]) + continue; + + VarCallRecord* rsrc = _argumentToVarRecord[i]; + + Operand& osrc = _args[i]; + ASMJIT_ASSERT(osrc.isVar()); + X86CompilerVar* vsrc = x86Compiler->_getVar(osrc.getId()); + + const FuncArg& srcArgType = targs[i]; + X86CompilerVar* vdst = _getOverlappingVariable(cc, srcArgType); + + if (vsrc == vdst) + { + rsrc->inDone++; + processed[i] = true; + + didWork = true; + continue; + } + else if (vdst != NULL) + { + VarCallRecord* rdst = reinterpret_cast(vdst->tPtr); + + if (rdst == NULL) + { + x86Context.spillVar(vdst); + vdst = NULL; + } + else if (rdst->inDone >= rdst->inCount && (rdst->flags & VarCallRecord::kFlagCallReg) == 0) + { + // Safe to spill. + if (rdst->outCount || vdst->lastItem == this) + x86Context.unuseVar(vdst, kVarStateUnused); + else + x86Context.spillVar(vdst); + vdst = NULL; + } + else + { + uint32_t x = _x86Decl.findArgumentByRegCode(X86Util::getRegCodeFromVarType(vsrc->getType(), vsrc->regIndex)); + bool doSpill = true; + + if ((vdst->getClass() & kX86VarClassGp) != 0) + { + // Try to emit mov to register which is possible for call() operand. + if (x == kInvalidValue && (rdst->flags & VarCallRecord::kFlagCallReg) != 0) + { + uint32_t rIndex; + uint32_t rBit; + + // The mask which contains registers which are not-preserved + // (these that might be clobbered by the callee) and which are + // not used to pass function arguments. Each register contained + // in this mask is ideal to be used by call() instruction. + uint32_t possibleMask = (~_x86Decl.getGpPreservedMask()) & + (~_x86Decl.getGpArgumentsMask()) & + (IntUtil::maskUpToIndex(kX86RegNumGp)); + + if (possibleMask != 0) + { + for (rIndex = 0, rBit = 1; rIndex < kX86RegNumGp; rIndex++, rBit <<= 1) + { + if ((possibleMask & rBit) != 0) + { + if (x86Context._x86State.gp[rIndex] == NULL) + { + // This is the best possible solution, the register is + // free. We do not need to continue with this loop, the + // rIndex will be used by the call(). + break; + } + else + { + // Wait until the register is freed or try to find another. + doSpill = false; + didWork = true; + } + } + } + } + else + { + // Try to find a register which is free and which is not used + // to pass a function argument. + possibleMask = _x86Decl.getGpPreservedMask(); + + for (rIndex = 0, rBit = 1; rIndex < kX86RegNumGp; rIndex++, rBit <<= 1) + { + if ((possibleMask & rBit) != 0) + { + // Found one. + if (x86Context._x86State.gp[rIndex] == NULL) break; + } + } + } + + if (rIndex < kX86RegNumGp) + { + if (temporaryGpReg == vsrc->regIndex) temporaryGpReg = rIndex; + x86Compiler->emit(kX86InstMov, gpz(rIndex), gpz(vsrc->regIndex)); + + x86Context._x86State.gp[vsrc->regIndex] = NULL; + x86Context._x86State.gp[rIndex] = vsrc; + + vsrc->regIndex = rIndex; + x86Context._allocatedGpRegister(rIndex); + + doSpill = false; + didWork = true; + } + } + // Emit xchg instead of spill/alloc if possible. + else if (x != kInvalidValue) + { + const FuncArg& dstArgType = targs[x]; + if (X86Util::getVarClassFromVarType(dstArgType.getVarType()) == X86Util::getVarClassFromVarType(srcArgType.getVarType())) + { + uint32_t dstIndex = vdst->regIndex; + uint32_t srcIndex = vsrc->regIndex; + + if (srcIndex == dstArgType.getRegIndex()) + { +#if defined(ASMJIT_X64) + if (vdst->getType() != kX86VarTypeGpd || vsrc->getType() != kX86VarTypeGpd) + x86Compiler->emit(kX86InstXchg, gpq(dstIndex), gpq(srcIndex)); + else +#endif + x86Compiler->emit(kX86InstXchg, gpd(dstIndex), gpd(srcIndex)); + + x86Context._x86State.gp[srcIndex] = vdst; + x86Context._x86State.gp[dstIndex] = vsrc; + + vdst->regIndex = srcIndex; + vsrc->regIndex = dstIndex; + + rdst->inDone++; + rsrc->inDone++; + + processed[i] = true; + processed[x] = true; + + doSpill = false; + } + } + } + } + + if (doSpill) + { + x86Context.spillVar(vdst); + vdst = NULL; + } + } + } + + if (vdst == NULL) + { + VarCallRecord* rec = reinterpret_cast(vsrc->tPtr); + + _moveSrcVariableToRegister(cc, vsrc, srcArgType); + + switch (srcArgType.getVarType()) + { + case kX86VarTypeGpd: + case kX86VarTypeGpq: + x86Context._markGpRegisterModified(srcArgType.getRegIndex()); + break; + case kX86VarTypeMm: + x86Context._markMmRegisterModified(srcArgType.getRegIndex()); + break; + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmPD: + x86Context._markMmRegisterModified(srcArgType.getRegIndex()); + break; + } + + rec->inDone++; + processed[i] = true; + } + } + } while (didWork); + + // -------------------------------------------------------------------------- + // STEP 7: + // + // Allocate operand used by CALL instruction. + // -------------------------------------------------------------------------- + + for (i = 0; i < variablesCount; i++) + { + VarCallRecord& r = _variables[i]; + if ((r.flags & VarCallRecord::kFlagCallReg) && + (r.vdata->regIndex == kRegIndexInvalid)) + { + // If the register is not allocated and the call form is 'call reg' then + // it's possible to keep it in memory. + if ((r.flags & VarCallRecord::kFlagCallMem) == 0) + { + _target = r.vdata->asGpVar().m(); + break; + } + + if (temporaryGpReg == kRegIndexInvalid) + temporaryGpReg = _findTemporaryGpRegister(cc); + + x86Context.allocGpVar(r.vdata, + IntUtil::maskFromIndex(temporaryGpReg), + kVarAllocRegister | kVarAllocRead); + } + } + + x86Context.translateOperands(&_target, 1); + + // -------------------------------------------------------------------------- + // STEP 8: + // + // Spill all preserved variables. + // -------------------------------------------------------------------------- + + preserved = _x86Decl.getGpPreservedMask(); + for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1) + { + X86CompilerVar* vdata = x86Context._x86State.gp[i]; + if (vdata && (preserved & mask) == 0) + { + VarCallRecord* rec = reinterpret_cast(vdata->tPtr); + if (rec && (rec->outCount || rec->flags & VarCallRecord::kFlagUnuseAfterUse || vdata->lastItem == this)) + x86Context.unuseVar(vdata, kVarStateUnused); + else + x86Context.spillGpVar(vdata); + } + } + + preserved = _x86Decl.getMmPreservedMask(); + for (i = 0, mask = 1; i < kX86RegNumMm; i++, mask <<= 1) + { + X86CompilerVar* vdata = x86Context._x86State.mm[i]; + if (vdata && (preserved & mask) == 0) + { + VarCallRecord* rec = reinterpret_cast(vdata->tPtr); + if (rec && (rec->outCount || vdata->lastItem == this)) + x86Context.unuseVar(vdata, kVarStateUnused); + else + x86Context.spillMmVar(vdata); + } + } + + preserved = _x86Decl.getXmmPreservedMask(); + for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1) + { + X86CompilerVar* vdata = x86Context._x86State.xmm[i]; + if (vdata && (preserved & mask) == 0) + { + VarCallRecord* rec = reinterpret_cast(vdata->tPtr); + if (rec && (rec->outCount || vdata->lastItem == this)) + x86Context.unuseVar(vdata, kVarStateUnused); + else + x86Context.spillXmmVar(vdata); + } + } + + // -------------------------------------------------------------------------- + // STEP 9: + // + // Emit CALL instruction. + // -------------------------------------------------------------------------- + + x86Compiler->emit(kX86InstCall, _target); + + // Restore the stack offset. + if (_x86Decl.getCalleePopsStack()) + { + int32_t s = static_cast(_x86Decl.getArgumentsStackSize()); + + if (s != 0) + x86Compiler->emit(kX86InstSub, zsp, imm(s)); + } + + // -------------------------------------------------------------------------- + // STEP 10: + // + // Prepare others for return value(s) and cleanup. + // -------------------------------------------------------------------------- + + // Clear temp data, see AsmJit::X86CompilerVar::temp why it's needed. + for (i = 0; i < variablesCount; i++) + { + VarCallRecord* rec = &_variables[i]; + X86CompilerVar* vdata = rec->vdata; + + if (rec->flags & (VarCallRecord::kFlagOutEax | VarCallRecord::kFlagOutEdx)) + { + if (vdata->getClass() & kX86VarClassGp) + { + x86Context.allocGpVar(vdata, + IntUtil::maskFromIndex((rec->flags & VarCallRecord::kFlagOutEax) != 0 + ? kX86RegIndexEax + : kX86RegIndexEdx), + kVarAllocRegister | kVarAllocWrite); + vdata->changed = true; + } + } + + if (rec->flags & (VarCallRecord::kFlagOutMm0)) + { + if (vdata->getClass() & kX86VarClassMm) + { + x86Context.allocMmVar(vdata, IntUtil::maskFromIndex(kX86RegIndexMm0), + kVarAllocRegister | kVarAllocWrite); + vdata->changed = true; + } + } + + if (rec->flags & (VarCallRecord::kFlagOutXmm0 | VarCallRecord::kFlagOutXmm1)) + { + if (vdata->getClass() & kX86VarClassXmm) + { + x86Context.allocXmmVar(vdata, + IntUtil::maskFromIndex((rec->flags & VarCallRecord::kFlagOutXmm0) != 0 + ? kX86RegIndexXmm0 + : kX86RegIndexXmm1), + kVarAllocRegister | kVarAllocWrite); + vdata->changed = true; + } + } + + if (rec->flags & (VarCallRecord::kFlagOutSt0 | VarCallRecord::kFlagOutSt1)) + { + if (vdata->getClass() & kX86VarClassXmm) + { + Mem mem(x86Context._getVarMem(vdata)); + x86Context.unuseVar(vdata, kVarStateMem); + + switch (vdata->getType()) + { + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + { + mem.setSize(4); + x86Compiler->emit(kX86InstFStP, mem); + break; + } + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + { + mem.setSize(8); + x86Compiler->emit(kX86InstFStP, mem); + break; + } + default: + { + x86Compiler->comment("*** WARNING: Can't convert float return value to untyped XMM\n"); + break; + } + } + } + } + + // Cleanup. + vdata->tPtr = NULL; + } + + for (i = 0; i < variablesCount; i++) + { + x86Context._unuseVarOnEndOfScope(this, &_variables[i]); + } + + return translated(); +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncCall - Misc] +// ============================================================================ + +int X86CompilerFuncCall::getMaxSize() const +{ + // TODO: Instruction max size. + return 15; +} + +bool X86CompilerFuncCall::_tryUnuseVar(CompilerVar* _v) +{ + X86CompilerVar* cv = static_cast(_v); + + for (uint32_t i = 0; i < _variablesCount; i++) + { + if (_variables[i].vdata == cv) + { + _variables[i].flags |= VarCallRecord::kFlagUnuseAfterUse; + return true; + } + } + + return false; +} + +// ============================================================================ +// [AsmJit::X86CompilerFuncCall - Helpers] +// ============================================================================ + +uint32_t X86CompilerFuncCall::_findTemporaryGpRegister(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + + uint32_t i; + uint32_t mask; + + uint32_t passedGP = _x86Decl.getGpArgumentsMask(); + uint32_t candidate = kRegIndexInvalid; + + // Find all registers used to pass function arguments. We shouldn't use these + // if possible. + for (i = 0, mask = 1; i < kX86RegNumGp; i++, mask <<= 1) + { + if (x86Context._x86State.gp[i] == NULL) + { + // If this register is used to pass arguments to function, we will mark + // it and use it only if there is no other one. + if ((passedGP & mask) != 0) + candidate = i; + else + return i; + } + } + + return candidate; +} + +uint32_t X86CompilerFuncCall::_findTemporaryXmmRegister(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + + uint32_t i; + uint32_t mask; + + uint32_t passedXMM = _x86Decl.getXmmArgumentsMask(); + uint32_t candidate = kRegIndexInvalid; + + // Find all registers used to pass function arguments. We shouldn't use these + // if possible. + for (i = 0, mask = 1; i < kX86RegNumXmm; i++, mask <<= 1) + { + if (x86Context._x86State.xmm[i] == NULL) + { + // If this register is used to pass arguments to function, we will mark + // it and use it only if there is no other one. + if ((passedXMM & mask) != 0) + candidate = i; + else + return i; + } + } + + return candidate; +} + +X86CompilerVar* X86CompilerFuncCall::_getOverlappingVariable(CompilerContext& cc, const FuncArg& argType) const +{ + X86CompilerContext& x86Context = static_cast(cc); + ASMJIT_ASSERT(argType.getVarType() != kVarTypeInvalid); + + switch (argType.getVarType()) + { + case kX86VarTypeGpd: + case kX86VarTypeGpq: + return x86Context._x86State.gp[argType.getRegIndex()]; + case kX86VarTypeMm: + return x86Context._x86State.mm[argType.getRegIndex()]; + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmPD: + return x86Context._x86State.xmm[argType.getRegIndex()]; + } + + return NULL; +} + +void X86CompilerFuncCall::_moveAllocatedVariableToStack(CompilerContext& cc, X86CompilerVar* vdata, const FuncArg& argType) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = x86Context.getCompiler(); + + ASMJIT_ASSERT(!argType.hasRegIndex()); + ASMJIT_ASSERT(vdata->regIndex != kRegIndexInvalid); + + uint32_t src = vdata->regIndex; + Mem dst = ptr(zsp, -(int)sizeof(uintptr_t) + argType.getStackOffset()); + + switch (vdata->getType()) + { + case kX86VarTypeGpd: + switch (argType.getVarType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMov, dst, gpd(src)); + return; +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMov, dst, gpq(src)); + return; +#endif // ASMJIT_X64 + } + break; + +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + switch (argType.getVarType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMov, dst, gpd(src)); + return; + case kX86VarTypeGpq: + x86Compiler->emit(kX86InstMov, dst, gpq(src)); + return; + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, dst, gpq(src)); + return; + } + break; +#endif // ASMJIT_X64 + + case kX86VarTypeMm: + switch (argType.getVarType()) + { + case kX86VarTypeGpd: + case kX86VarTypeX87SS: + case kX86VarTypeXmmSS: + x86Compiler->emit(kX86InstMovD, dst, mm(src)); + return; + case kX86VarTypeGpq: + case kX86VarTypeMm: + case kX86VarTypeX87SD: + case kX86VarTypeXmmSD: + x86Compiler->emit(kX86InstMovQ, dst, mm(src)); + return; + } + break; + + // We allow incompatible types here, because the called can convert them + // to correct format before function is called. + + case kX86VarTypeXmm: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmPD: + switch (argType.getVarType()) + { + case kX86VarTypeXmm: + x86Compiler->emit(kX86InstMovDQU, dst, xmm(src)); + return; + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + x86Compiler->emit(kX86InstMovUPS, dst, xmm(src)); + return; + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovUPD, dst, xmm(src)); + return; + } + break; + + case kX86VarTypeXmmSS: + switch (argType.getVarType()) + { + case kX86VarTypeX87SS: + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovSS, dst, xmm(src)); + return; + } + break; + + case kX86VarTypeXmmSD: + switch (argType.getVarType()) + { + case kX86VarTypeX87SD: + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovSD, dst, xmm(src)); + return; + } + break; + } + + x86Compiler->setError(kErrorIncompatibleArgumentType); +} + +void X86CompilerFuncCall::_moveSpilledVariableToStack(CompilerContext& cc, + X86CompilerVar* cv, const FuncArg& argType, + uint32_t temporaryGpReg, + uint32_t temporaryXmmReg) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = x86Context.getCompiler(); + + ASMJIT_ASSERT(!argType.hasRegIndex()); + ASMJIT_ASSERT(cv->regIndex == kRegIndexInvalid); + + Mem src = x86Context._getVarMem(cv); + Mem dst = ptr(zsp, -(int)sizeof(sysint_t) + argType.getStackOffset()); + + switch (cv->getType()) + { + case kX86VarTypeGpd: + switch (argType.getVarType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMov, gpd(temporaryGpReg), src); + x86Compiler->emit(kX86InstMov, dst, gpd(temporaryGpReg)); + return; +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMov, gpd(temporaryGpReg), src); + x86Compiler->emit(kX86InstMov, dst, gpq(temporaryGpReg)); + return; +#endif // ASMJIT_X64 + } + break; + +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + switch (argType.getVarType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMov, gpd(temporaryGpReg), src); + x86Compiler->emit(kX86InstMov, dst, gpd(temporaryGpReg)); + return; + case kX86VarTypeGpq: + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMov, gpq(temporaryGpReg), src); + x86Compiler->emit(kX86InstMov, dst, gpq(temporaryGpReg)); + return; + } + break; +#endif // ASMJIT_X64 + + case kX86VarTypeMm: + switch (argType.getVarType()) + { + case kX86VarTypeGpd: + case kX86VarTypeX87SS: + case kX86VarTypeXmmSS: + x86Compiler->emit(kX86InstMov, gpd(temporaryGpReg), src); + x86Compiler->emit(kX86InstMov, dst, gpd(temporaryGpReg)); + return; + case kX86VarTypeGpq: + case kX86VarTypeMm: + case kX86VarTypeX87SD: + case kX86VarTypeXmmSD: + // TODO + return; + } + break; + + // We allow incompatible types here, because the caller can convert them + // to correct format before function is called. + + case kX86VarTypeXmm: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmPD: + switch (argType.getVarType()) + { + case kX86VarTypeXmm: + x86Compiler->emit(kX86InstMovDQU, xmm(temporaryXmmReg), src); + x86Compiler->emit(kX86InstMovDQU, dst, xmm(temporaryXmmReg)); + return; + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + x86Compiler->emit(kX86InstMovUPS, xmm(temporaryXmmReg), src); + x86Compiler->emit(kX86InstMovUPS, dst, xmm(temporaryXmmReg)); + return; + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovUPD, xmm(temporaryXmmReg), src); + x86Compiler->emit(kX86InstMovUPD, dst, xmm(temporaryXmmReg)); + return; + } + break; + + case kX86VarTypeXmmSS: + switch (argType.getVarType()) + { + case kX86VarTypeX87SS: + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovSS, xmm(temporaryXmmReg), src); + x86Compiler->emit(kX86InstMovSS, dst, xmm(temporaryXmmReg)); + return; + } + break; + + case kX86VarTypeXmmSD: + switch (argType.getVarType()) + { + case kX86VarTypeX87SD: + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovSD, xmm(temporaryXmmReg), src); + x86Compiler->emit(kX86InstMovSD, dst, xmm(temporaryXmmReg)); + return; + } + break; + } + + x86Compiler->setError(kErrorIncompatibleArgumentType); +} + +void X86CompilerFuncCall::_moveSrcVariableToRegister(CompilerContext& cc, + X86CompilerVar* cv, const FuncArg& argType) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = x86Context.getCompiler(); + + uint32_t dst = argType.getRegIndex(); + uint32_t src = cv->regIndex; + + if (src != kRegIndexInvalid) + { + switch (argType.getVarType()) + { + case kX86VarTypeGpd: + switch (cv->getType()) + { + case kX86VarTypeGpd: +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: +#endif // ASMJIT_X64 + x86Compiler->emit(kX86InstMov, gpd(dst), gpd(src)); + return; + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovD, gpd(dst), mm(src)); + return; + } + break; + +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + switch (cv->getType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMov, gpd(dst), gpd(src)); + return; + case kX86VarTypeGpq: + x86Compiler->emit(kX86InstMov, gpq(dst), gpq(src)); + return; + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, gpq(dst), mm(src)); + return; + } + break; +#endif // ASMJIT_X64 + + case kX86VarTypeMm: + switch (cv->getType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMovD, gpd(dst), gpd(src)); + return; +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + x86Compiler->emit(kX86InstMovQ, gpq(dst), gpq(src)); + return; +#endif // ASMJIT_X64 + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, mm(dst), mm(src)); + return; + } + break; + + case kX86VarTypeXmm: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmPD: + switch (cv->getType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMovD, xmm(dst), gpd(src)); + return; +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + x86Compiler->emit(kX86InstMovQ, xmm(dst), gpq(src)); + return; +#endif // ASMJIT_X64 + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, xmm(dst), mm(src)); + return; + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovDQA, xmm(dst), xmm(src)); + return; + } + break; + + case kX86VarTypeXmmSS: + switch (cv->getType()) + { + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, xmm(dst), mm(src)); + return; + + case kX86VarTypeXmm: + x86Compiler->emit(kX86InstMovDQA, xmm(dst), xmm(src)); + return; + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + x86Compiler->emit(kX86InstMovSS, xmm(dst), xmm(src)); + return; + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstCvtSD2SS, xmm(dst), xmm(src)); + return; + } + break; + + case kX86VarTypeXmmSD: + switch (cv->getType()) + { + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, xmm(dst), mm(src)); + return; + + case kX86VarTypeXmm: + x86Compiler->emit(kX86InstMovDQA, xmm(dst), xmm(src)); + return; + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + x86Compiler->emit(kX86InstCvtSS2SD, xmm(dst), xmm(src)); + return; + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovSD, xmm(dst), xmm(src)); + return; + } + break; + } + } + else + { + Mem mem = x86Context._getVarMem(cv); + + switch (argType.getVarType()) + { + case kX86VarTypeGpd: + switch (cv->getType()) + { + case kX86VarTypeGpd: +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: +#endif // ASMJIT_X64 + x86Compiler->emit(kX86InstMov, gpd(dst), mem); + return; + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovD, gpd(dst), mem); + return; + } + break; + +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + switch (cv->getType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMov, gpd(dst), mem); + return; + case kX86VarTypeGpq: + x86Compiler->emit(kX86InstMov, gpq(dst), mem); + return; + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, gpq(dst), mem); + return; + } + break; +#endif // ASMJIT_X64 + + case kX86VarTypeMm: + switch (cv->getType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMovD, gpd(dst), mem); + return; +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + x86Compiler->emit(kX86InstMovQ, gpq(dst), mem); + return; +#endif // ASMJIT_X64 + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, mm(dst), mem); + return; + } + break; + + case kX86VarTypeXmm: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmPD: + switch (cv->getType()) + { + case kX86VarTypeGpd: + x86Compiler->emit(kX86InstMovD, xmm(dst), mem); + return; +#if defined(ASMJIT_X64) + case kX86VarTypeGpq: + x86Compiler->emit(kX86InstMovQ, xmm(dst), mem); + return; +#endif // ASMJIT_X64 + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, xmm(dst), mem); + return; + case kX86VarTypeXmm: + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovDQA, xmm(dst), mem); + return; + } + break; + + case kX86VarTypeXmmSS: + switch (cv->getType()) + { + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, xmm(dst), mem); + return; + + case kX86VarTypeXmm: + x86Compiler->emit(kX86InstMovDQA, xmm(dst), mem); + return; + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + x86Compiler->emit(kX86InstMovSS, xmm(dst), mem); + return; + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstCvtSD2SS, xmm(dst), mem); + return; + } + break; + + case kX86VarTypeXmmSD: + switch (cv->getType()) + { + case kX86VarTypeMm: + x86Compiler->emit(kX86InstMovQ, xmm(dst), mem); + return; + + case kX86VarTypeXmm: + x86Compiler->emit(kX86InstMovDQA, xmm(dst), mem); + return; + case kX86VarTypeXmmSS: + case kX86VarTypeXmmPS: + x86Compiler->emit(kX86InstCvtSS2SD, xmm(dst), mem); + return; + case kX86VarTypeXmmSD: + case kX86VarTypeXmmPD: + x86Compiler->emit(kX86InstMovSD, xmm(dst), mem); + return; + } + break; + } + } + + x86Compiler->setError(kErrorIncompatibleArgumentType); +} + +// Prototype & Arguments Management. +void X86CompilerFuncCall::setPrototype(uint32_t callingConvention, uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount) +{ + _x86Decl.setPrototype(callingConvention, returnType, arguments, argumentsCount); + _args = reinterpret_cast( + getCompiler()->getZoneMemory().alloc(sizeof(Operand) * argumentsCount)); + memset(_args, 0, sizeof(Operand) * argumentsCount); +} + +bool X86CompilerFuncCall::setArgument(uint32_t i, const Var& var) +{ + ASMJIT_ASSERT(i < _x86Decl.getArgumentsCount()); + + if (i >= _x86Decl.getArgumentsCount()) + return false; + + _args[i] = var; + return true; +} + +bool X86CompilerFuncCall::setArgument(uint32_t i, const Imm& imm) +{ + ASMJIT_ASSERT(i < _x86Decl.getArgumentsCount()); + + if (i >= _x86Decl.getArgumentsCount()) + return false; + + _args[i] = imm; + return true; +} + +bool X86CompilerFuncCall::setReturn(const Operand& first, const Operand& second) +{ + _ret[0] = first; + _ret[1] = second; + + return true; +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/x86/x86compilerfunc.h b/desmume/src/utils/AsmJit/x86/x86compilerfunc.h new file mode 100644 index 000000000..7474e314b --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86compilerfunc.h @@ -0,0 +1,369 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_X86_X86COMPILERFUNC_H +#define _ASMJIT_X86_X86COMPILERFUNC_H + +// [Dependencies - AsmJit] +#include "../x86/x86assembler.h" +#include "../x86/x86compiler.h" +#include "../x86/x86compileritem.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_X86 +//! @{ + +// ============================================================================ +// [AsmJit::X86CompilerFuncDecl] +// ============================================================================ + +//! @brief @ref X86Compiler specific function declaration item. +struct X86CompilerFuncDecl : public CompilerFuncDecl +{ + ASMJIT_NO_COPY(X86CompilerFuncDecl) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref X86CompilerFuncDecl instance. + ASMJIT_API X86CompilerFuncDecl(X86Compiler* x86Compiler); + //! @brief Destroy the @ref X86CompilerFuncDecl instance. + ASMJIT_API virtual ~X86CompilerFuncDecl(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get compiler as @ref X86Compiler. + inline X86Compiler* getCompiler() const + { return reinterpret_cast(_compiler); } + + //! @brief Get function end item as @ref X86CompilerFuncEnd. + inline X86CompilerFuncEnd* getEnd() const + { return reinterpret_cast(_end); } + + //! @brief Get function declaration as @ref X86FuncDecl. + inline X86FuncDecl* getDecl() const + { return reinterpret_cast(_decl); } + + //! @brief Get function arguments as variables as @ref X86CompilerVar. + inline X86CompilerVar** getVars() const + { return reinterpret_cast(_vars); } + + //! @brief Get function argument at @a index. + inline X86CompilerVar* getVar(uint32_t index) const + { + ASMJIT_ASSERT(index < _x86Decl.getArgumentsCount()); + return reinterpret_cast(_vars)[index]; + } + + //! @brief Get whether it's assumed that stack is aligned to 16 bytes. + inline bool isAssumed16ByteAlignment() const + { return hasFuncFlag(kX86FuncFlagAssume16ByteAlignment); } + + //! @brief Get whether it's required to align stack to 16 bytes by function. + inline bool isPerformed16ByteAlignment() const + { return hasFuncFlag(kX86FuncFlagPerform16ByteAlignment); } + + //! @brief Get whether the ESP is adjusted. + inline bool isEspAdjusted() const + { return hasFuncFlag(kX86FuncFlagIsEspAdjusted); } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void prepare(CompilerContext& cc); + ASMJIT_API virtual CompilerItem* translate(CompilerContext& cc); + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual int getMaxSize() const; + + // -------------------------------------------------------------------------- + // [Prototype] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void setPrototype( + uint32_t convention, + uint32_t returnType, + const uint32_t* arguments, + uint32_t argumentsCount); + + // -------------------------------------------------------------------------- + // [Helpers] + // -------------------------------------------------------------------------- + + //! @internal + //! + //! @brief Get required stack offset needed to subtract/add Esp/Rsp in + //! prolog/epilog. + inline int32_t _getRequiredStackOffset() const + { return _funcCallStackSize + _memStackSize16 + _peMovStackSize + _peAdjustStackSize; } + + //! @brief Create variables from FunctionPrototype declaration. This is just + //! parsing what FunctionPrototype generated for current function calling + //! convention and arguments. + ASMJIT_API void _createVariables(); + + //! @brief Prepare variables (ids, names, scope, registers). + ASMJIT_API void _prepareVariables(CompilerItem* first); + + //! @brief Allocate variables (setting correct state, changing masks, etc). + ASMJIT_API void _allocVariables(CompilerContext& cc); + + ASMJIT_API void _preparePrologEpilog(CompilerContext& cc); + ASMJIT_API void _dumpFunction(CompilerContext& cc); + ASMJIT_API void _emitProlog(CompilerContext& cc); + ASMJIT_API void _emitEpilog(CompilerContext& cc); + + // -------------------------------------------------------------------------- + // [Function-Call] + // -------------------------------------------------------------------------- + + //! @brief Reserve stack for calling other function and mark function as + //! callee. + ASMJIT_API void reserveStackForFunctionCall(int32_t size); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief X86 function decl. + X86FuncDecl _x86Decl; + + //! @brief Modified and preserved GP registers mask. + uint32_t _gpModifiedAndPreserved; + //! @brief Modified and preserved MM registers mask. + uint32_t _mmModifiedAndPreserved; + //! @brief Modified and preserved XMM registers mask. + uint32_t _xmmModifiedAndPreserved; + + //! @brief Id of MovDQWord instruction (@c kX86InstMovDQA or @c kX86InstMovDQU). + //! + //! The value is based on stack alignment. If it's guaranteed that stack + //! is aligned to 16-bytes then @c kX86InstMovDQA instruction is used, otherwise + //! the @c kX86InstMovDQU instruction is used for 16-byte mov. + uint32_t _movDqInstCode; + + //! @brief Prolog / epilog stack size for PUSH/POP sequences. + int32_t _pePushPopStackSize; + //! @brief Prolog / epilog stack size for MOV sequences. + int32_t _peMovStackSize; + //! @brief Prolog / epilog stack adjust size (to make it 16-byte aligned). + int32_t _peAdjustStackSize; + + //! @brief Memory stack size (for all variables and temporary memory). + int32_t _memStackSize; + //! @brief Like @c _memStackSize, but aligned to 16-bytes. + int32_t _memStackSize16; +}; + +// ============================================================================ +// [AsmJit::X86CompilerFuncEnd] +// ============================================================================ + +//! @brief @ref X86Compiler function end item. +struct X86CompilerFuncEnd : public CompilerFuncEnd +{ + ASMJIT_NO_COPY(X86CompilerFuncEnd) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref X86CompilerFuncEnd instance. + ASMJIT_API X86CompilerFuncEnd(X86Compiler* x86Compiler, X86CompilerFuncDecl* func); + //! @brief Destroy the @ref X86CompilerFuncEnd instance. + ASMJIT_API virtual ~X86CompilerFuncEnd(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get compiler as @ref X86Compiler. + inline X86Compiler* getCompiler() const + { return reinterpret_cast(_compiler); } + + //! @brief Get related function as @ref X86CompilerFuncDecl. + inline X86CompilerFuncDecl* getFunc() const + { return reinterpret_cast(_func); } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void prepare(CompilerContext& cc); + ASMJIT_API virtual CompilerItem* translate(CompilerContext& cc); +}; + +// ============================================================================ +// [AsmJit::X86CompilerFuncRet] +// ============================================================================ + +//! @brief Function return. +struct X86CompilerFuncRet : public CompilerFuncRet +{ + ASMJIT_NO_COPY(X86CompilerFuncRet) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref X86CompilerFuncRet instance. + ASMJIT_API X86CompilerFuncRet(X86Compiler* c, X86CompilerFuncDecl* func, + const Operand* first, const Operand* second); + //! @brief Destroy the @ref X86CompilerFuncRet instance. + ASMJIT_API virtual ~X86CompilerFuncRet(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get compiler as @ref X86Compiler. + inline X86Compiler* getCompiler() const + { return reinterpret_cast(_compiler); } + + //! @Brief Get related function as @ref X86CompilerFuncDecl. + inline X86CompilerFuncDecl* getFunc() const + { return reinterpret_cast(_func); } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void prepare(CompilerContext& cc); + ASMJIT_API virtual CompilerItem* translate(CompilerContext& cc); + ASMJIT_API virtual void emit(Assembler& a); + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual int getMaxSize() const; +}; + +// ============================================================================ +// [AsmJit::X86CompilerFuncCall] +// ============================================================================ + +//! @brief Compiler function call item. +struct X86CompilerFuncCall : public CompilerFuncCall +{ + ASMJIT_NO_COPY(X86CompilerFuncCall) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref X86CompilerFuncCall instance. + ASMJIT_API X86CompilerFuncCall(X86Compiler* x86Compiler, X86CompilerFuncDecl* caller, const Operand* target); + //! @brief Destroy the @ref X86CompilerFuncCall instance. + ASMJIT_API virtual ~X86CompilerFuncCall(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get compiler as @ref X86Compiler. + inline X86Compiler* getCompiler() const + { return reinterpret_cast(_compiler); } + + //! @brief Get caller as @ref X86CompilerFuncDecl. + inline X86CompilerFuncDecl* getCaller() const + { return reinterpret_cast(_caller); } + + //! @brief Get function prototype. + inline const X86FuncDecl* getDecl() const + { return reinterpret_cast(_decl); } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void prepare(CompilerContext& cc); + ASMJIT_API virtual CompilerItem* translate(CompilerContext& cc); + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual int getMaxSize() const; + ASMJIT_API virtual bool _tryUnuseVar(CompilerVar* v); + + // -------------------------------------------------------------------------- + // [Prototype] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void setPrototype(uint32_t convention, uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount); + + //! @brief Set function prototype. + inline void setPrototype(uint32_t convention, const FuncPrototype& func) + { setPrototype(convention, func.getReturnType(), func.getArguments(), func.getArgumentsCount()); } + + //! @brief Set return value. + ASMJIT_API bool setReturn(const Operand& first, const Operand& second = Operand()); + + //! @brief Set function argument @a i to @a var. + ASMJIT_API bool setArgument(uint32_t i, const Var& var); + //! @brief Set function argument @a i to @a imm. + ASMJIT_API bool setArgument(uint32_t i, const Imm& imm); + + // -------------------------------------------------------------------------- + // [Internal] + // -------------------------------------------------------------------------- + + ASMJIT_API uint32_t _findTemporaryGpRegister(CompilerContext& cc); + ASMJIT_API uint32_t _findTemporaryXmmRegister(CompilerContext& cc); + + ASMJIT_API X86CompilerVar* _getOverlappingVariable(CompilerContext& cc, const FuncArg& argType) const; + + ASMJIT_API void _moveAllocatedVariableToStack(CompilerContext& cc, X86CompilerVar* vdata, const FuncArg& argType); + ASMJIT_API void _moveSpilledVariableToStack(CompilerContext& cc, X86CompilerVar* vdata, const FuncArg& argType, + uint32_t temporaryGpReg, + uint32_t temporaryXmmReg); + ASMJIT_API void _moveSrcVariableToRegister(CompilerContext& cc, X86CompilerVar* vdata, const FuncArg& argType); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief X86 declaration. + X86FuncDecl _x86Decl; + + //! @brief Mask of GP registers used as function arguments. + uint32_t _gpParams; + //! @brief Mask of MM registers used as function arguments. + uint32_t _mmParams; + //! @brief Mask of XMM registers used as function arguments. + uint32_t _xmmParams; + + //! @brief Variables count. + uint32_t _variablesCount; + + //! @brief Variables (extracted from operands). + VarCallRecord* _variables; + //! @brief Argument index to @c VarCallRecord. + VarCallRecord* _argumentToVarRecord[kFuncArgsMax]; +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_X86_X86COMPILERFUNC_H diff --git a/desmume/src/utils/AsmJit/x86/x86compileritem.cpp b/desmume/src/utils/AsmJit/x86/x86compileritem.cpp new file mode 100644 index 000000000..5fa4c1eaf --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86compileritem.cpp @@ -0,0 +1,1829 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/intutil.h" +#include "../core/stringutil.h" + +#include "../x86/x86compiler.h" +#include "../x86/x86compilercontext.h" +#include "../x86/x86compilerfunc.h" +#include "../x86/x86compileritem.h" +#include "../x86/x86util.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::X86CompilerAlign - Construction / Destruction] +// ============================================================================ + +X86CompilerAlign::X86CompilerAlign(X86Compiler* x86Compiler, uint32_t size) : + CompilerAlign(x86Compiler, size) +{ +} + +X86CompilerAlign::~X86CompilerAlign() +{ +} + +// ============================================================================ +// [AsmJit::X86CompilerAlign - Interface] +// ============================================================================ + +void X86CompilerAlign::emit(Assembler& a) +{ + X86Assembler& x86Asm = static_cast(a); + + x86Asm.align(_size); +} + +// ============================================================================ +// [AsmJit::X86CompilerTarget - Construction / Destruction] +// ============================================================================ + +X86CompilerTarget::X86CompilerTarget(X86Compiler* c, const Label& label) : + CompilerTarget(c, label) +{ +} + +X86CompilerTarget::~X86CompilerTarget() +{ +} + +// ============================================================================ +// [AsmJit::X86CompilerTarget - Interface] +// ============================================================================ + +static X86CompilerTarget* X86CompilerTarget_removeUnreachableItems(X86CompilerTarget* target) +{ + CompilerItem* prev = target->getPrev(); + CompilerItem* item = target->getNext(); + + ASMJIT_ASSERT(prev != NULL); + ASMJIT_ASSERT(item != NULL); + + for (;;) + { + CompilerItem* next = item->getNext(); + ASMJIT_ASSERT(next != NULL); + + if (item->getType() == kCompilerItemTarget) + break; + + item->_prev = NULL; + item->_next = NULL; + item->_isUnreachable = true; + + item = next; + } + + target->_prev = NULL; + target->_next = NULL; + target->_isTranslated = true; + + prev->_next = item; + item->_prev = prev; + + return static_cast(item); +} + +void X86CompilerTarget::prepare(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + _offset = x86Context._currentOffset++; +} + +CompilerItem* X86CompilerTarget::translate(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + + // If this X86CompilerTarget was already translated, it's needed to change + // the current state and return NULL to tell CompilerContext to process next + // untranslated item. + if (_isTranslated) + { + x86Context._restoreState(getState()); + return NULL; + } + + if (x86Context._isUnreachable) + { + // If the context has "isUnreachable" flag set and there is no state then + // it means that this code will be never called. This is a problem, because + // we are unable to assign a state to current location so we can't allocate + // registers for variables used inside. So instead of doing anything wrong + // we remove the unreachable code. + if (_state == NULL) + return X86CompilerTarget_removeUnreachableItems(this); + + // Assign state to the compiler context. + x86Context._isUnreachable = 0; + x86Context._assignState(getState()); + } + else + { + _state = x86Context._saveState(); + } + + return translated(); +} + +void X86CompilerTarget::emit(Assembler& a) +{ + X86Assembler& x86Asm = static_cast(a); + x86Asm.bind(_label); +} + +// ============================================================================ +// [AsmJit::X86CompilerHint - Construction / Destruction] +// ============================================================================ + +X86CompilerHint::X86CompilerHint(X86Compiler* compiler, X86CompilerVar* var, uint32_t hintId, uint32_t hintValue) : + CompilerHint(compiler, var, hintId, hintValue) +{ +} + +X86CompilerHint::~X86CompilerHint() +{ +} + +// ============================================================================ +// [AsmJit::X86CompilerHint - Interface] +// ============================================================================ + +void X86CompilerHint::prepare(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86CompilerVar* var = getVar(); + + _offset = x86Context._currentOffset; + + // First item (begin of variable scope). + if (var->firstItem == NULL) + var->firstItem = this; + + // Last item (end of variable scope). + CompilerItem* oldLast = var->lastItem; + var->lastItem = this; + + switch (_hintId) + { + case kVarHintAlloc: + case kVarHintSpill: + case kVarHintSave: + if (!x86Context._isActive(var)) + x86Context._addActive(var); + break; + + case kVarHintSaveAndUnuse: + if (!x86Context._isActive(var)) + x86Context._addActive(var); + break; + + case kVarHintUnuse: + if (oldLast) + oldLast->_tryUnuseVar(var); + break; + } +} + +CompilerItem* X86CompilerHint::translate(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86CompilerVar* var = getVar(); + + switch (_hintId) + { + case kVarHintAlloc: + x86Context.allocVar(var, _hintValue, kVarAllocRead); + break; + + case kVarHintSpill: + if (var->state == kVarStateReg) + x86Context.spillVar(var); + break; + + case kVarHintSave: + case kVarHintSaveAndUnuse: + if (var->state == kVarStateReg && var->changed) + { + x86Context.emitSaveVar(var, var->regIndex); + var->changed = false; + } + if (_hintId == kVarHintSaveAndUnuse) + goto _Unuse; + break; + + case kVarHintUnuse: +_Unuse: + x86Context.unuseVar(var, kVarStateUnused); + goto _End; + } + + x86Context._unuseVarOnEndOfScope(this, var); + +_End: + return translated(); +} + +// ============================================================================ +// [AsmJit::X86CompilerHint - Misc] +// ============================================================================ + +int X86CompilerHint::getMaxSize() const +{ + // Compiler hint is NOP, but it can generate other items which can do + // something - in such more items are added into the stream so we don't need + // to worry about this. + return 0; +} + +// ============================================================================ +// [AsmJit::X86CompilerInst - Construction / Destruction] +// ============================================================================ + +X86CompilerInst::X86CompilerInst(X86Compiler* x86Compiler, uint32_t code, Operand* opData, uint32_t opCount) : + CompilerInst(x86Compiler, code, opData, opCount) +{ + uint32_t i; + + _memOp = NULL; + _vars = NULL; + _variablesCount = 0; + + for (i = 0; i < opCount; i++) + { + if (_operands[i].isMem()) + { + _memOp = reinterpret_cast(&_operands[i]); + break; + } + } + + const X86InstInfo* info = &x86InstInfo[_code]; + + if (info->isSpecial()) + setInstFlag(kX86CompilerInstFlagIsSpecial); + if (info->isFpu()) + setInstFlag(kX86CompilerInstFlagIsFpu); + + if (isSpecial()) + { + // ${SPECIAL_INSTRUCTION_HANDLING_BEGIN} + switch (_code) + { + case kX86InstCpuId: + // Special... + break; + + case kX86InstCbw: + case kX86InstCdq: + case kX86InstCdqe: + case kX86InstCwd: + case kX86InstCwde: + case kX86InstCqo: + // Special... + break; + + case kX86InstCmpXCHG: + case kX86InstCmpXCHG8B: +#if defined(ASMJIT_X64) + case kX86InstCmpXCHG16B: +#endif // ASMJIT_X64 + // Special... + break; + +#if defined(ASMJIT_X86) + case kX86InstDaa: + case kX86InstDas: + // Special... + break; +#endif // ASMJIT_X86 + + case kX86InstIMul: + switch (_operandsCount) + { + case 2: + // IMUL dst, src is not special instruction. + clearInstFlag(kX86CompilerInstFlagIsSpecial); + break; + case 3: + // Only IMUL dst_hi, dst_lo, reg/mem is special, all others don't. + if (!(_operands[0].isVar() && _operands[1].isVar() && _operands[2].isVarMem())) + clearInstFlag(kX86CompilerInstFlagIsSpecial); + break; + } + break; + case kX86InstMul: + case kX86InstIDiv: + case kX86InstDiv: + // Special... + break; + + case kX86InstMovPtr: + // Special... + break; + + case kX86InstLahf: + case kX86InstSahf: + // Special... + break; + + case kX86InstMaskMovQ: + case kX86InstMaskMovDQU: + // Special... + break; + + case kX86InstEnter: + case kX86InstLeave: + // Special... + break; + + case kX86InstRet: + // Special... + break; + + case kX86InstMonitor: + case kX86InstMWait: + // Special... + break; + + case kX86InstPop: + case kX86InstPopAD: + case kX86InstPopFD: + case kX86InstPopFQ: + // Special... + break; + + case kX86InstPush: + case kX86InstPushAD: + case kX86InstPushFD: + case kX86InstPushFQ: + // Special... + break; + + case kX86InstRcl: + case kX86InstRcr: + case kX86InstRol: + case kX86InstRor: + case kX86InstSal: + case kX86InstSar: + case kX86InstShl: + case kX86InstShr: + // Rot instruction is special only if last operand is variable (register). + if (!_operands[1].isVar()) + clearInstFlag(kX86CompilerInstFlagIsSpecial); + break; + + case kX86InstShld: + case kX86InstShrd: + // Shld/Shrd instruction is special only if last operand is variable (register). + if (!_operands[2].isVar()) + clearInstFlag(kX86CompilerInstFlagIsSpecial); + break; + + case kX86InstRdtsc: + case kX86InstRdtscP: + // Special... + break; + + case kX86InstRepLodSB: + case kX86InstRepLodSD: + case kX86InstRepLodSQ: + case kX86InstRepLodSW: + case kX86InstRepMovSB: + case kX86InstRepMovSD: + case kX86InstRepMovSQ: + case kX86InstRepMovSW: + case kX86InstRepStoSB: + case kX86InstRepStoSD: + case kX86InstRepStoSQ: + case kX86InstRepStoSW: + case kX86InstRepECmpSB: + case kX86InstRepECmpSD: + case kX86InstRepECmpSQ: + case kX86InstRepECmpSW: + case kX86InstRepEScaSB: + case kX86InstRepEScaSD: + case kX86InstRepEScaSQ: + case kX86InstRepEScaSW: + case kX86InstRepNECmpSB: + case kX86InstRepNECmpSD: + case kX86InstRepNECmpSQ: + case kX86InstRepNECmpSW: + case kX86InstRepNEScaSB: + case kX86InstRepNEScaSD: + case kX86InstRepNEScaSQ: + case kX86InstRepNEScaSW: + // Special... + break; + + default: + ASMJIT_ASSERT(0); + } + // ${SPECIAL_INSTRUCTION_HANDLING_END} + } +} + +X86CompilerInst::~X86CompilerInst() +{ +} + +// ============================================================================ +// [AsmJit::X86CompilerInst - Interface] +// ============================================================================ + +void X86CompilerInst::prepare(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = getCompiler(); + +#define __GET_VARIABLE(__vardata__) \ + { \ + X86CompilerVar* _candidate = __vardata__; \ + \ + for (var = cur; ;) \ + { \ + if (var == _vars) \ + { \ + var = cur++; \ + var->vdata = _candidate; \ + var->vflags = 0; \ + var->regMask = 0xFFFFFFFF; \ + break; \ + } \ + \ + var--; \ + \ + if (var->vdata == _candidate) \ + { \ + break; \ + } \ + } \ + \ + ASMJIT_ASSERT(var != NULL); \ + } + + _offset = x86Context._currentOffset; + + const X86InstInfo* id = &x86InstInfo[_code]; + + uint32_t i, len = _operandsCount; + uint32_t variablesCount = 0; + + for (i = 0; i < len; i++) + { + Operand& o = _operands[i]; + + if (o.isVar()) + { + ASMJIT_ASSERT(o.getId() != kInvalidValue); + X86CompilerVar* vdata = x86Compiler->_getVar(o.getId()); + ASMJIT_ASSERT(vdata != NULL); + + if (reinterpret_cast(&o)->isGpVar()) + { + if (reinterpret_cast(&o)->isGpbLo()) { setInstFlag(kX86CompilerInstFlagIsGpbLoUsed); vdata->regGpbLoCount++; }; + if (reinterpret_cast(&o)->isGpbHi()) { setInstFlag(kX86CompilerInstFlagIsGpbHiUsed); vdata->regGpbHiCount++; }; + } + + if (vdata->workOffset != _offset) + { + if (!x86Context._isActive(vdata)) x86Context._addActive(vdata); + + vdata->workOffset = _offset; + variablesCount++; + } + } + else if (o.isMem()) + { + if ((o.getId() & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* vdata = x86Compiler->_getVar(o.getId()); + ASMJIT_ASSERT(vdata != NULL); + + x86Context._markMemoryUsed(vdata); + + if (vdata->workOffset != _offset) + { + if (!x86Context._isActive(vdata)) x86Context._addActive(vdata); + + vdata->workOffset = _offset; + variablesCount++; + } + } + else if ((o._mem.base & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* vdata = x86Compiler->_getVar(o._mem.base); + ASMJIT_ASSERT(vdata != NULL); + + if (vdata->workOffset != _offset) + { + if (!x86Context._isActive(vdata)) x86Context._addActive(vdata); + + vdata->workOffset = _offset; + variablesCount++; + } + } + + if ((o._mem.index & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* vdata = x86Compiler->_getVar(o._mem.index); + ASMJIT_ASSERT(vdata != NULL); + + if (vdata->workOffset != _offset) + { + if (!x86Context._isActive(vdata)) x86Context._addActive(vdata); + + vdata->workOffset = _offset; + variablesCount++; + } + } + } + } + + if (!variablesCount) + { + x86Context._currentOffset++; + return; + } + + _vars = reinterpret_cast(x86Compiler->getZoneMemory().alloc(sizeof(VarAllocRecord) * variablesCount)); + if (_vars == NULL) + { + x86Compiler->setError(kErrorNoHeapMemory); + x86Context._currentOffset++; + return; + } + + _variablesCount = variablesCount; + + VarAllocRecord* cur = _vars; + VarAllocRecord* var = NULL; + + bool _isGpbUsed = hasInstFlag(kX86CompilerInstFlagIsGpbLoUsed) | + hasInstFlag(kX86CompilerInstFlagIsGpbHiUsed) ; + uint32_t gpRestrictMask = IntUtil::maskUpToIndex(kX86RegNumGp); + +#if defined(ASMJIT_X64) + if (hasInstFlag(kX86CompilerInstFlagIsGpbHiUsed)) + { + gpRestrictMask &= IntUtil::maskFromIndex(kX86RegIndexEax) | + IntUtil::maskFromIndex(kX86RegIndexEbx) | + IntUtil::maskFromIndex(kX86RegIndexEcx) | + IntUtil::maskFromIndex(kX86RegIndexEdx) | + IntUtil::maskFromIndex(kX86RegIndexEbp) | + IntUtil::maskFromIndex(kX86RegIndexEsi) | + IntUtil::maskFromIndex(kX86RegIndexEdi) ; + } +#endif // ASMJIT_X64 + + for (i = 0; i < len; i++) + { + Operand& o = _operands[i]; + + if (o.isVar()) + { + X86CompilerVar* vdata = x86Compiler->_getVar(o.getId()); + ASMJIT_ASSERT(vdata != NULL); + + __GET_VARIABLE(vdata) + var->vflags |= kVarAllocRegister; + + if (_isGpbUsed) + { +#if defined(ASMJIT_X86) + if (reinterpret_cast(&o)->isGpb()) + { + var->regMask &= IntUtil::maskFromIndex(kX86RegIndexEax) | + IntUtil::maskFromIndex(kX86RegIndexEbx) | + IntUtil::maskFromIndex(kX86RegIndexEcx) | + IntUtil::maskFromIndex(kX86RegIndexEdx) ; + } +#else + // Restrict all BYTE registers to RAX/RBX/RCX/RDX if HI BYTE register + // is used (REX prefix makes HI BYTE addressing unencodable). + if (hasInstFlag(kX86CompilerInstFlagIsGpbHiUsed)) + { + if (reinterpret_cast(&o)->isGpb()) + { + var->regMask &= IntUtil::maskFromIndex(kX86RegIndexEax) | + IntUtil::maskFromIndex(kX86RegIndexEbx) | + IntUtil::maskFromIndex(kX86RegIndexEcx) | + IntUtil::maskFromIndex(kX86RegIndexEdx) ; + } + } +#endif // ASMJIT_X86/X64 + } + + if (isSpecial()) + { + // ${SPECIAL_INSTRUCTION_HANDLING_BEGIN} + switch (_code) + { + case kX86InstCpuId: + switch (i) + { + case 0: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + case 1: + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEbx); + gpRestrictMask &= ~var->regMask; + break; + case 2: + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEcx); + gpRestrictMask &= ~var->regMask; + break; + case 3: + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEdx); + gpRestrictMask &= ~var->regMask; + break; + + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstCbw: + case kX86InstCdqe: + case kX86InstCwde: + switch (i) + { + case 0: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstCdq: + case kX86InstCwd: + case kX86InstCqo: + switch (i) + { + case 0: + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEdx); + gpRestrictMask &= ~var->regMask; + break; + case 1: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstCmpXCHG: + switch (i) + { + case 0: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + case 1: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite; + break; + case 2: + vdata->regReadCount++; + var->vflags |= kVarAllocRead; + break; + + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstCmpXCHG8B: +#if defined(ASMJIT_X64) + case kX86InstCmpXCHG16B: +#endif // ASMJIT_X64 + switch (i) + { + case 0: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEdx); + gpRestrictMask &= ~var->regMask; + break; + case 1: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + case 2: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEcx); + gpRestrictMask &= ~var->regMask; + break; + case 3: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEbx); + gpRestrictMask &= ~var->regMask; + break; + + default: + ASMJIT_ASSERT(0); + } + break; + +#if defined(ASMJIT_X86) + case kX86InstDaa: + case kX86InstDas: + ASMJIT_ASSERT(i == 0); + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; +#endif // ASMJIT_X86 + + case kX86InstIMul: + case kX86InstMul: + case kX86InstIDiv: + case kX86InstDiv: + switch (i) + { + case 0: + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEdx); + gpRestrictMask &= ~var->regMask; + break; + case 1: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + case 2: + vdata->regReadCount++; + var->vflags |= kVarAllocRead; + break; + + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstMovPtr: + switch (i) + { + case 0: + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + case 1: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstLahf: + ASMJIT_ASSERT(i == 0); + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + + case kX86InstSahf: + ASMJIT_ASSERT(i == 0); + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + + case kX86InstMaskMovQ: + case kX86InstMaskMovDQU: + switch (i) + { + case 0: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEdi); + gpRestrictMask &= ~var->regMask; + break; + case 1: + case 2: + vdata->regReadCount++; + var->vflags |= kVarAllocRead; + break; + } + break; + + case kX86InstEnter: + case kX86InstLeave: + // TODO: SPECIAL INSTRUCTION. + break; + + case kX86InstRet: + // TODO: SPECIAL INSTRUCTION. + break; + + case kX86InstMonitor: + case kX86InstMWait: + // TODO: MONITOR/MWAIT (COMPILER). + break; + + case kX86InstPop: + // TODO: SPECIAL INSTRUCTION. + break; + + case kX86InstPopAD: + case kX86InstPopFD: + case kX86InstPopFQ: + // TODO: SPECIAL INSTRUCTION. + break; + + case kX86InstPush: + // TODO: SPECIAL INSTRUCTION. + break; + + case kX86InstPushAD: + case kX86InstPushFD: + case kX86InstPushFQ: + // TODO: SPECIAL INSTRUCTION. + break; + + case kX86InstRcl: + case kX86InstRcr: + case kX86InstRol: + case kX86InstRor: + case kX86InstSal: + case kX86InstSar: + case kX86InstShl: + case kX86InstShr: + switch (i) + { + case 0: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite; + break; + case 1: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEcx); + gpRestrictMask &= ~var->regMask; + break; + + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstShld: + case kX86InstShrd: + switch (i) + { + case 0: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite; + break; + case 1: + vdata->regReadCount++; + var->vflags |= kVarAllocRead; + break; + case 2: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEcx); + gpRestrictMask &= ~var->regMask; + break; + + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstRdtsc: + case kX86InstRdtscP: + switch (i) + { + case 0: + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEdx); + gpRestrictMask &= ~var->regMask; + break; + case 1: + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + case 2: + ASMJIT_ASSERT(_code == kX86InstRdtscP); + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEcx); + gpRestrictMask &= ~var->regMask; + break; + + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstRepLodSB: + case kX86InstRepLodSD: + case kX86InstRepLodSQ: + case kX86InstRepLodSW: + switch (i) + { + case 0: + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + case 1: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEsi); + gpRestrictMask &= ~var->regMask; + break; + case 2: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEcx); + gpRestrictMask &= ~var->regMask; + break; + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstRepMovSB: + case kX86InstRepMovSD: + case kX86InstRepMovSQ: + case kX86InstRepMovSW: + case kX86InstRepECmpSB: + case kX86InstRepECmpSD: + case kX86InstRepECmpSQ: + case kX86InstRepECmpSW: + case kX86InstRepNECmpSB: + case kX86InstRepNECmpSD: + case kX86InstRepNECmpSQ: + case kX86InstRepNECmpSW: + switch (i) + { + case 0: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEdi); + gpRestrictMask &= ~var->regMask; + break; + case 1: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEsi); + gpRestrictMask &= ~var->regMask; + break; + case 2: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEcx); + gpRestrictMask &= ~var->regMask; + break; + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstRepStoSB: + case kX86InstRepStoSD: + case kX86InstRepStoSQ: + case kX86InstRepStoSW: + switch (i) + { + case 0: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEdi); + gpRestrictMask &= ~var->regMask; + break; + case 1: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + case 2: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEcx); + gpRestrictMask &= ~var->regMask; + break; + default: + ASMJIT_ASSERT(0); + } + break; + + case kX86InstRepEScaSB: + case kX86InstRepEScaSD: + case kX86InstRepEScaSQ: + case kX86InstRepEScaSW: + case kX86InstRepNEScaSB: + case kX86InstRepNEScaSD: + case kX86InstRepNEScaSQ: + case kX86InstRepNEScaSW: + switch (i) + { + case 0: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEdi); + gpRestrictMask &= ~var->regMask; + break; + case 1: + vdata->regReadCount++; + var->vflags |= kVarAllocRead | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEax); + gpRestrictMask &= ~var->regMask; + break; + case 2: + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite | kVarAllocSpecial; + var->regMask = IntUtil::maskFromIndex(kX86RegIndexEcx); + gpRestrictMask &= ~var->regMask; + break; + default: + ASMJIT_ASSERT(0); + } + break; + + default: + ASMJIT_ASSERT(0); + } + // ${SPECIAL_INSTRUCTION_HANDLING_END} + } + else + { + if (i == 0) + { + // CMP/TEST instruction. + if (id->getCode() == kX86InstCmp || id->getCode() == kX86InstTest) + { + // Read-only case. + vdata->regReadCount++; + var->vflags |= kVarAllocRead; + } + // CVTTSD2SI/CVTTSS2SI instructions. + else if (id->getCode() == kX86InstCvttSD2SI || id->getCode() == kX86InstCvttSS2SI) + { + // In 32-bit mode the whole destination is replaced. In 64-bit mode + // we need to check whether the destination operand size is 64-bits. +#if defined(ASMJIT_X64) + if (_operands[0].isRegType(kX86RegTypeGpq)) + { +#endif // ASMJIT_X64 + // Write-only case. + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite; +#if defined(ASMJIT_X64) + } + else + { + // Read/Write. + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite; + } +#endif // ASMJIT_X64 + } + // MOV/MOVSS/MOVSD instructions. + // + // If instruction is MOV (source replaces the destination) or + // MOVSS/MOVSD and source operand is memory location then register + // allocator should know that previous destination value is lost + // (write only operation). + else if ((id->isMov()) || + ((id->getCode() == kX86InstMovSS || id->getCode() == kX86InstMovSD) /* && _operands[1].isMem() */) || + (id->getCode() == kX86InstIMul && _operandsCount == 3 && !isSpecial())) + { + // Write-only case. + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite; + } + else if (id->getCode() == kX86InstLea) + { + // Write. + vdata->regWriteCount++; + var->vflags |= kVarAllocWrite; + } + else + { + // Read/Write. + vdata->regRwCount++; + var->vflags |= kVarAllocReadWrite; + } + } + else + { + // Second, third, ... operands are read-only. + vdata->regReadCount++; + var->vflags |= kVarAllocRead; + } + + if (!_memOp && i < 2 && (id->_opFlags[i] & kX86InstOpMem) != 0) + { + var->vflags |= kVarAllocMem; + } + } + + // If variable must be in specific register we could add some hint to allocator. + if (var->vflags & kVarAllocSpecial) + { + vdata->prefRegisterMask |= var->regMask; + x86Context._newRegisterHomeIndex(vdata, IntUtil::findFirstBit(var->regMask)); + } + } + else if (o.isMem()) + { + if ((o.getId() & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* vdata = x86Compiler->_getVar(o.getId()); + ASMJIT_ASSERT(vdata != NULL); + + __GET_VARIABLE(vdata) + + if (i == 0) + { + // If variable is MOV instruction type (source replaces the destination) + // or variable is MOVSS/MOVSD instruction then register allocator should + // know that previous destination value is lost (write only operation). + if (id->isMov() || ((id->getCode() == kX86InstMovSS || id->getCode() == kX86InstMovSD))) + { + // Write only case. + vdata->memWriteCount++; + } + else + { + vdata->memRwCount++; + } + } + else + { + vdata->memReadCount++; + } + } + else if ((o._mem.base & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* vdata = x86Compiler->_getVar(reinterpret_cast(o).getBase()); + ASMJIT_ASSERT(vdata != NULL); + + __GET_VARIABLE(vdata) + vdata->regReadCount++; + var->vflags |= kVarAllocRegister | kVarAllocRead; + var->regMask &= gpRestrictMask; + } + + if ((o._mem.index & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* vdata = x86Compiler->_getVar(reinterpret_cast(o).getIndex()); + ASMJIT_ASSERT(vdata != NULL); + + __GET_VARIABLE(vdata) + vdata->regReadCount++; + var->vflags |= kVarAllocRegister | kVarAllocRead; + var->regMask &= gpRestrictMask; + } + } + } + + // Traverse all variables and update firstItem / lastItem. This + // function is called from iterator that scans items using forward + // direction so we can use this knowledge to optimize the process. + // + // Similar to X86CompilerFuncCall::prepare(). + for (i = 0; i < _variablesCount; i++) + { + X86CompilerVar* v = _vars[i].vdata; + + // Update GP register allocator restrictions. + if (X86Util::isVarTypeInt(v->getType())) + { + if (_vars[i].regMask == 0xFFFFFFFF) _vars[i].regMask &= gpRestrictMask; + } + + // Update first/last item (begin of variable scope). + if (v->firstItem == NULL) v->firstItem = this; + v->lastItem = this; + } + + // There are some instructions that can be used to clear or to set all bits + // in a register: + // + // - andn reg, reg ; Set all bits in reg to 0. + // - xor/pxor reg, reg ; Set all bits in reg to 0. + // - sub/psub reg, reg ; Set all bits in reg to 0. + // - pcmpgt reg, reg ; Set all bits in reg to 0. + // - pcmpeq reg, reg ; Set all bits in reg to 1. + // + // There are also combinations which do nothing: + // + // - and reg, reg ; Nop. + // - or reg, reg ; Nop. + // - xchg reg, reg ; Nop. + + if (_variablesCount == 1 && _operandsCount > 1 && _operands[0].isVar() && _operands[1].isVar() && !_memOp) + { + switch (_code) + { + // ---------------------------------------------------------------------- + // [Zeros/Ones] + // ---------------------------------------------------------------------- + + // ANDN Instructions. + case kX86InstPAndN: + + // XOR Instructions. + case kX86InstXor: + case kX86InstXorPD: + case kX86InstXorPS: + case kX86InstPXor: + + // SUB Instructions. + case kX86InstSub: + case kX86InstPSubB: + case kX86InstPSubW: + case kX86InstPSubD: + case kX86InstPSubQ: + case kX86InstPSubSB: + case kX86InstPSubSW: + case kX86InstPSubUSB: + case kX86InstPSubUSW: + + // PCMPEQ Instructions. + case kX86InstPCmpEqB: + case kX86InstPCmpEqW: + case kX86InstPCmpEqD: + case kX86InstPCmpEqQ: + + // PCMPGT Instructions. + case kX86InstPCmpGtB: + case kX86InstPCmpGtW: + case kX86InstPCmpGtD: + case kX86InstPCmpGtQ: + // Clear the read flag. This prevents variable alloc/spill. + _vars[0].vflags = kVarAllocWrite; + _vars[0].vdata->regReadCount--; + break; + + // ---------------------------------------------------------------------- + // [Nop] + // ---------------------------------------------------------------------- + + // AND Instructions. + case kX86InstAnd: + case kX86InstAndPD: + case kX86InstAndPS: + case kX86InstPAnd: + + // OR Instructions. + case kX86InstOr: + case kX86InstOrPD: + case kX86InstOrPS: + case kX86InstPOr: + + // XCHG Instruction. + case kX86InstXchg: + + // Clear the write flag. + _vars[0].vflags = kVarAllocRead; + _vars[0].vdata->regWriteCount--; + break; + } + } + x86Context._currentOffset++; + +#undef __GET_VARIABLE +} + +CompilerItem* X86CompilerInst::translate(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = getCompiler(); + + uint32_t i; + uint32_t variablesCount = _variablesCount; + + if (variablesCount > 0) + { + // These variables are used by the instruction and we set current offset + // to their work offsets -> getSpillCandidate never return the variable + // used this instruction. + for (i = 0; i < variablesCount; i++) + { + _vars[i].vdata->workOffset = x86Context._currentOffset; + } + + // Alloc variables used by the instruction (special first). + for (i = 0; i < variablesCount; i++) + { + VarAllocRecord& r = _vars[i]; + // Alloc variables with specific register first. + if ((r.vflags & kVarAllocSpecial) != 0) + x86Context.allocVar(r.vdata, r.regMask, r.vflags); + } + + for (i = 0; i < variablesCount; i++) + { + VarAllocRecord& r = _vars[i]; + // Alloc variables without specific register last. + if ((r.vflags & kVarAllocSpecial) == 0) + x86Context.allocVar(r.vdata, r.regMask, r.vflags); + } + + x86Context.translateOperands(_operands, _operandsCount); + } + + if (_memOp && (_memOp->getId() & kOperandIdTypeMask) == kOperandIdTypeVar) + { + X86CompilerVar* cv = x86Compiler->_getVar(_memOp->getId()); + ASMJIT_ASSERT(cv != NULL); + + switch (cv->state) + { + case kVarStateUnused: + cv->state = kVarStateMem; + break; + case kVarStateReg: + cv->changed = false; + x86Context.unuseVar(cv, kVarStateMem); + break; + } + } + + for (i = 0; i < variablesCount; i++) + { + x86Context._unuseVarOnEndOfScope(this, &_vars[i]); + } + + return translated(); +} + +void X86CompilerInst::emit(Assembler& a) +{ + X86Assembler& x86Asm = static_cast(a); + + x86Asm._inlineComment = _comment; + x86Asm._emitOptions = _emitOptions; + + if (isSpecial()) + { + // ${SPECIAL_INSTRUCTION_HANDLING_BEGIN} + switch (_code) + { + case kX86InstCpuId: + x86Asm._emitInstruction(_code); + return; + + case kX86InstCbw: + case kX86InstCdq: + case kX86InstCdqe: + case kX86InstCwd: + case kX86InstCwde: + case kX86InstCqo: + x86Asm._emitInstruction(_code); + return; + + case kX86InstCmpXCHG: + x86Asm._emitInstruction(_code, &_operands[1], &_operands[2]); + return; + + case kX86InstCmpXCHG8B: +#if defined(ASMJIT_X64) + case kX86InstCmpXCHG16B: +#endif // ASMJIT_X64 + x86Asm._emitInstruction(_code, &_operands[4]); + return; + +#if defined(ASMJIT_X86) + case kX86InstDaa: + case kX86InstDas: + x86Asm._emitInstruction(_code); + return; +#endif // ASMJIT_X86 + + case kX86InstIMul: + case kX86InstMul: + case kX86InstIDiv: + case kX86InstDiv: + // INST dst_lo (implicit), dst_hi (implicit), src (explicit) + ASMJIT_ASSERT(_operandsCount == 3); + x86Asm._emitInstruction(_code, &_operands[2]); + return; + + case kX86InstMovPtr: + break; + + case kX86InstLahf: + case kX86InstSahf: + x86Asm._emitInstruction(_code); + return; + + case kX86InstMaskMovQ: + case kX86InstMaskMovDQU: + x86Asm._emitInstruction(_code, &_operands[1], &_operands[2]); + return; + + case kX86InstEnter: + case kX86InstLeave: + // TODO: SPECIAL INSTRUCTION. + break; + + case kX86InstRet: + // TODO: SPECIAL INSTRUCTION. + break; + + case kX86InstMonitor: + case kX86InstMWait: + // TODO: MONITOR/MWAIT (COMPILER). + break; + + case kX86InstPop: + case kX86InstPopAD: + case kX86InstPopFD: + case kX86InstPopFQ: + // TODO: SPECIAL INSTRUCTION. + break; + + case kX86InstPush: + case kX86InstPushAD: + case kX86InstPushFD: + case kX86InstPushFQ: + // TODO: SPECIAL INSTRUCTION. + break; + + case kX86InstRcl: + case kX86InstRcr: + case kX86InstRol: + case kX86InstRor: + case kX86InstSal: + case kX86InstSar: + case kX86InstShl: + case kX86InstShr: + x86Asm._emitInstruction(_code, &_operands[0], &cl); + return; + + case kX86InstShld: + case kX86InstShrd: + x86Asm._emitInstruction(_code, &_operands[0], &_operands[1], &cl); + return; + + case kX86InstRdtsc: + case kX86InstRdtscP: + x86Asm._emitInstruction(_code); + return; + + case kX86InstRepLodSB: + case kX86InstRepLodSD: + case kX86InstRepLodSQ: + case kX86InstRepLodSW: + case kX86InstRepMovSB: + case kX86InstRepMovSD: + case kX86InstRepMovSQ: + case kX86InstRepMovSW: + case kX86InstRepStoSB: + case kX86InstRepStoSD: + case kX86InstRepStoSQ: + case kX86InstRepStoSW: + case kX86InstRepECmpSB: + case kX86InstRepECmpSD: + case kX86InstRepECmpSQ: + case kX86InstRepECmpSW: + case kX86InstRepEScaSB: + case kX86InstRepEScaSD: + case kX86InstRepEScaSQ: + case kX86InstRepEScaSW: + case kX86InstRepNECmpSB: + case kX86InstRepNECmpSD: + case kX86InstRepNECmpSQ: + case kX86InstRepNECmpSW: + case kX86InstRepNEScaSB: + case kX86InstRepNEScaSD: + case kX86InstRepNEScaSQ: + case kX86InstRepNEScaSW: + x86Asm._emitInstruction(_code); + return; + + default: + ASMJIT_ASSERT(0); + } + // ${SPECIAL_INSTRUCTION_HANDLING_END} + } + + switch (_operandsCount) + { + case 0: + x86Asm._emitInstruction(_code); + break; + case 1: + x86Asm._emitInstruction(_code, &_operands[0]); + break; + case 2: + x86Asm._emitInstruction(_code, &_operands[0], &_operands[1]); + break; + case 3: + x86Asm._emitInstruction(_code, &_operands[0], &_operands[1], &_operands[2]); + break; + default: + ASMJIT_ASSERT(0); + break; + } +} + +// ============================================================================ +// [AsmJit::X86CompilerInst - Misc] +// ============================================================================ + +int X86CompilerInst::getMaxSize() const +{ + // TODO: Instruction max size. + return 15; +} + +bool X86CompilerInst::_tryUnuseVar(CompilerVar* _v) +{ + X86CompilerVar* cv = static_cast(_v); + + for (uint32_t i = 0; i < _variablesCount; i++) + { + if (_vars[i].vdata == cv) + { + _vars[i].vflags |= kVarAllocUnuseAfterUse; + return true; + } + } + + return false; +} + +// ============================================================================ +// [AsmJit::X86CompilerJmpInst - Construction / Destruction] +// ============================================================================ + +X86CompilerJmpInst::X86CompilerJmpInst(X86Compiler* x86Compiler, uint32_t code, Operand* opData, uint32_t opCount) : + X86CompilerInst(x86Compiler, code, opData, opCount) +{ + _jumpTarget = x86Compiler->_getTarget(_operands[0].getId()); + _jumpTarget->_jumpsCount++; + + _jumpNext = static_cast(_jumpTarget->_from); + _jumpTarget->_from = this; + + // The 'jmp' is always taken, conditional jump can contain hint, we detect it. + if (getCode() == kX86InstJmp) + setInstFlag(kX86CompilerInstFlagIsTaken); + else if (opCount > 1 && opData[1].isImm() && reinterpret_cast(&opData[1])->getValue() == kCondHintLikely) + setInstFlag(kX86CompilerInstFlagIsTaken); +} + +X86CompilerJmpInst::~X86CompilerJmpInst() +{ +} + +// ============================================================================ +// [AsmJit::X86CompilerJmpInst - Interface] +// ============================================================================ + +void X86CompilerJmpInst::prepare(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + _offset = x86Context._currentOffset; + + // Update _isTaken to true if this is conditional backward jump. This behavior + // can be overridden by using kCondHintUnlikely when using the instruction. + if (getCode() != kX86InstJmp && _operandsCount == 1 && _jumpTarget->getOffset() < getOffset()) + { + setInstFlag(kX86CompilerInstFlagIsTaken); + } + + // Now patch all variables where jump location is in the active range. + if (_jumpTarget->getOffset() != kInvalidValue && x86Context._active) + { + X86CompilerVar* first = static_cast(x86Context._active); + X86CompilerVar* var = first; + uint32_t jumpOffset = _jumpTarget->getOffset(); + + do { + if (var->firstItem) + { + ASMJIT_ASSERT(var->lastItem != NULL); + uint32_t start = var->firstItem->getOffset(); + uint32_t end = var->lastItem->getOffset(); + + if (jumpOffset >= start && jumpOffset <= end) + var->lastItem = this; + } + var = var->nextActive; + } while (var != first); + } + + x86Context._currentOffset++; +} + +CompilerItem* X86CompilerJmpInst::translate(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = getCompiler(); + + // Translate using X86CompilerInst. + CompilerItem* ret = X86CompilerInst::translate(cc); + + // We jump with item if its kX86InstJUMP (not based on condiiton) and it + // points into yet unknown location. + if (_code == kX86InstJmp && !_jumpTarget->isTranslated()) + { + x86Context.addBackwardCode(this); + ret = _jumpTarget; + } + else + { + _state = x86Context._saveState(); + if (_jumpTarget->isTranslated()) + { + doJump(cc); + } + else + { + // State is not known, so we need to call doJump() later. Compiler will + // do it for us. + x86Context.addForwardJump(this); + _jumpTarget->_state = _state; + } + + // Mark next code as unreachable, cleared by a next label (CompilerTarget). + if (_code == kX86InstJmp) + x86Context._isUnreachable = 1; + } + + // Need to traverse over all active variables and unuse them if their scope ends + // here. + if (x86Context._active) + { + X86CompilerVar* first = static_cast(x86Context._active); + X86CompilerVar* var = first; + + do { + x86Context._unuseVarOnEndOfScope(this, var); + var = var->nextActive; + } while (var != first); + } + + return ret; +} + +void X86CompilerJmpInst::emit(Assembler& a) +{ + static const uint MAXIMUM_SHORT_JMP_SIZE = 127; + + // Try to minimize size of jump using SHORT jump (8-bit displacement) by + // traversing into the target and calculating the maximum code size. We + // end when code size reaches MAXIMUM_SHORT_JMP_SIZE. + if (!(_emitOptions & kX86EmitOptionShortJump) && getJumpTarget()->getOffset() > getOffset()) + { + // Calculate the code size. + uint codeSize = 0; + CompilerItem* cur = this->getNext(); + CompilerItem* target = getJumpTarget(); + + while (cur) + { + if (cur == target) + { + // Target found, we can tell assembler to generate short form of jump. + _emitOptions |= kX86EmitOptionShortJump; + goto _End; + } + + int s = cur->getMaxSize(); + if (s == -1) break; + + codeSize += (uint)s; + if (codeSize > MAXIMUM_SHORT_JMP_SIZE) break; + + cur = cur->getNext(); + } + } + +_End: + X86CompilerInst::emit(a); +} + +// ============================================================================ +// [AsmJit::X86CompilerJmpInst - DoJump] +// ============================================================================ + +void X86CompilerJmpInst::doJump(CompilerContext& cc) +{ + X86CompilerContext& x86Context = static_cast(cc); + X86Compiler* x86Compiler = getCompiler(); + + // The state have to be already known. The doJump() method is called by + // translate() or by Compiler in case that it's forward jump. + ASMJIT_ASSERT(_jumpTarget->getState()); + + if (getCode() == kX86InstJmp || (isTaken() && _jumpTarget->getOffset() < getOffset())) + { + // Instruction type is JMP or conditional jump that should be taken (likely). + // We can set state here instead of jumping out, setting state and jumping + // to _jumpTarget. + // + // NOTE: We can't use this technique if instruction is forward conditional + // jump. The reason is that when generating code we can't change state here, + // because the next instruction depends on it. + x86Context._restoreState(_jumpTarget->getState(), _jumpTarget->getOffset()); + } + else + { + // Instruction type is JMP or conditional jump that should be not normally + // taken. If we need add code that will switch between different states we + // add it after the end of function body (after epilog, using 'ExtraBlock'). + CompilerItem* ext = x86Context.getExtraBlock(); + CompilerItem* old = x86Compiler->setCurrentItem(ext); + + x86Context._restoreState(_jumpTarget->getState(), _jumpTarget->getOffset()); + + if (x86Compiler->getCurrentItem() != ext) + { + // Add the jump to the target. + x86Compiler->jmp(_jumpTarget->_label); + ext = x86Compiler->getCurrentItem(); + + // The x86Context._restoreState() method emitted some instructions so we need to + // patch the jump. + Label L = x86Compiler->newLabel(); + x86Compiler->setCurrentItem(x86Context.getExtraBlock()); + x86Compiler->bind(L); + + // Finally, patch the jump target. + ASMJIT_ASSERT(_operandsCount > 0); + _operands[0] = L; // Operand part (Label). + _jumpTarget = x86Compiler->_getTarget(L.getId()); // Compiler part (CompilerTarget). + } + + x86Context.setExtraBlock(ext); + x86Compiler->setCurrentItem(old); + + // Assign state back. + x86Context._assignState(static_cast(_state)); + } +} + +// ============================================================================ +// [AsmJit::X86CompilerJmpInst - GetJumpTarget] +// ============================================================================ + +CompilerTarget* X86CompilerJmpInst::getJumpTarget() const +{ + return _jumpTarget; +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/x86/x86compileritem.h b/desmume/src/utils/AsmJit/x86/x86compileritem.h new file mode 100644 index 000000000..fb05d2e47 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86compileritem.h @@ -0,0 +1,284 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_X86_X86COMPILERITEM_H +#define _ASMJIT_X86_X86COMPILERITEM_H + +// [Dependencies - AsmJit] +#include "../x86/x86assembler.h" +#include "../x86/x86compiler.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_X86 +//! @{ + +// ============================================================================ +// [AsmJit::X86CompilerAlign] +// ============================================================================ + +//! @brief Compiler align item. +struct X86CompilerAlign : public CompilerAlign +{ + ASMJIT_NO_COPY(X86CompilerAlign) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerAlign instance. + ASMJIT_API X86CompilerAlign(X86Compiler* x86Compiler, uint32_t size = 0); + //! @brief Destroy the @ref CompilerAlign instance. + ASMJIT_API virtual ~X86CompilerAlign(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get compiler as @ref X86Compiler. + inline X86Compiler* getCompiler() const + { return reinterpret_cast(_compiler); } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void emit(Assembler& a); +}; + +// ============================================================================ +// [AsmJit::X86CompilerHint] +// ============================================================================ + +//! @brief @ref X86Compiler variable hint item. +struct X86CompilerHint : public CompilerHint +{ + ASMJIT_NO_COPY(X86CompilerHint) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref X86CompilerHint instance. + ASMJIT_API X86CompilerHint(X86Compiler* compiler, X86CompilerVar* var, uint32_t hintId, uint32_t hintValue); + //! @brief Destroy the @ref X86CompilerHint instance. + ASMJIT_API virtual ~X86CompilerHint(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get variable as @ref X86CompilerVar. + inline X86CompilerVar* getVar() const + { return reinterpret_cast(_var); } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void prepare(CompilerContext& cc); + ASMJIT_API virtual CompilerItem* translate(CompilerContext& cc); + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual int getMaxSize() const; +}; + +// ============================================================================ +// [AsmJit::X86CompilerTarget] +// ============================================================================ + +//! @brief X86Compiler target item. +struct X86CompilerTarget : public CompilerTarget +{ + ASMJIT_NO_COPY(X86CompilerTarget) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref X86CompilerTarget instance. + ASMJIT_API X86CompilerTarget(X86Compiler* x86Compiler, const Label& target); + //! @brief Destroy the @ref X86CompilerTarget instance. + ASMJIT_API virtual ~X86CompilerTarget(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get compiler as @ref X86Compiler. + inline X86Compiler* getCompiler() const + { return reinterpret_cast(_compiler); } + + //! @brief Get state as @ref X86CompilerState. + inline X86CompilerState* getState() const + { return reinterpret_cast(_state); } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void prepare(CompilerContext& cc); + ASMJIT_API virtual CompilerItem* translate(CompilerContext& cc); + ASMJIT_API virtual void emit(Assembler& a); +}; + +// ============================================================================ +// [AsmJit::X86CompilerInst] +// ============================================================================ + +//! @brief @ref X86Compiler instruction item. +struct X86CompilerInst : public CompilerInst +{ + ASMJIT_NO_COPY(X86CompilerInst) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref X86CompilerInst instance. + ASMJIT_API X86CompilerInst(X86Compiler* x86Compiler, uint32_t code, Operand* opData, uint32_t opCount); + //! @brief Destroy the @ref X86CompilerInst instance. + ASMJIT_API virtual ~X86CompilerInst(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get compiler as @ref X86Compiler. + inline X86Compiler* getCompiler() const + { return reinterpret_cast(_compiler); } + + //! @brief Get whether the instruction is special. + inline bool isSpecial() const + { return (_instFlags & kX86CompilerInstFlagIsSpecial) != 0; } + + //! @brief Get whether the instruction is FPU. + inline bool isFpu() const + { return (_instFlags & kX86CompilerInstFlagIsFpu) != 0; } + + //! @brief Get whether the instruction is used with GpbLo register. + inline bool isGpbLoUsed() const + { return (_instFlags & kX86CompilerInstFlagIsGpbLoUsed) != 0; } + + //! @brief Get whether the instruction is used with GpbHi register. + inline bool isGpbHiUsed() const + { return (_instFlags & kX86CompilerInstFlagIsGpbHiUsed) != 0; } + + //! @brief Get memory operand. + inline Mem* getMemOp() + { return _memOp; } + + //! @brief Set memory operand. + inline void setMemOp(Mem* memOp) + { _memOp = memOp; } + + //! @brief Get operands array (3 operands total). + inline VarAllocRecord* getVars() + { return _vars; } + + //! @brief Get operands array (3 operands total). + inline const VarAllocRecord* getVars() const + { return _vars; } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void prepare(CompilerContext& cc); + ASMJIT_API virtual CompilerItem* translate(CompilerContext& cc); + ASMJIT_API virtual void emit(Assembler& a); + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual int getMaxSize() const; + ASMJIT_API virtual bool _tryUnuseVar(CompilerVar* v); + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Memory operand or NULL. + Mem* _memOp; + //! @brief Variables (extracted from operands). + VarAllocRecord* _vars; +}; + +// ============================================================================ +// [AsmJit::X86CompilerJmpInst] +// ============================================================================ + +//! @brief @ref X86Compiler "jmp" instruction item. +struct X86CompilerJmpInst : public X86CompilerInst +{ + ASMJIT_NO_COPY(X86CompilerJmpInst) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + ASMJIT_API X86CompilerJmpInst(X86Compiler* x86Compiler, uint32_t code, Operand* opData, uint32_t opCount); + ASMJIT_API virtual ~X86CompilerJmpInst(); + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + inline X86CompilerJmpInst* getJumpNext() const + { return _jumpNext; } + + inline bool isTaken() const + { return (_instFlags & kX86CompilerInstFlagIsTaken) != 0; } + + // -------------------------------------------------------------------------- + // [Interface] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual void prepare(CompilerContext& cc); + ASMJIT_API virtual CompilerItem* translate(CompilerContext& cc); + ASMJIT_API virtual void emit(Assembler& a); + + // -------------------------------------------------------------------------- + // [DoJump] + // -------------------------------------------------------------------------- + + ASMJIT_API void doJump(CompilerContext& cc); + + // -------------------------------------------------------------------------- + // [Jump] + // -------------------------------------------------------------------------- + + ASMJIT_API virtual CompilerTarget* getJumpTarget() const; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Jump target. + X86CompilerTarget* _jumpTarget; + //! @brief Next jump to the same target in a single linked list. + X86CompilerJmpInst *_jumpNext; + //! @brief State associated with the jump. + X86CompilerState* _state; +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_X86_X86COMPILERITEM_H diff --git a/desmume/src/utils/AsmJit/x86/x86cpuinfo.cpp b/desmume/src/utils/AsmJit/x86/x86cpuinfo.cpp new file mode 100644 index 000000000..70e2c9ddd --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86cpuinfo.cpp @@ -0,0 +1,304 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../x86/x86cpuinfo.h" +#include "../x86/x86defs.h" + +// 2009-02-05: Thanks to Mike Tajmajer for VC7.1 compiler support. It shouldn't +// affect x64 compilation, because x64 compiler starts with VS2005 (VC8.0). +#if defined(_MSC_VER) +# if _MSC_VER >= 1400 +# include +# endif // _MSC_VER >= 1400 (>= VS2005) +#endif // _MSC_VER + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::X86CpuVendor] +// ============================================================================ + +struct X86CpuVendor +{ + uint32_t id; + char text[12]; +}; + +static const X86CpuVendor x86CpuVendor[] = +{ + { kCpuIntel , { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' } }, + + { kCpuAmd , { 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' } }, + { kCpuAmd , { 'A', 'M', 'D', 'i', 's', 'b', 'e', 't', 't', 'e', 'r', '!' } }, + + { kCpuNSM , { 'G', 'e', 'o', 'd', 'e', ' ', 'b', 'y', ' ', 'N', 'S', 'C' } }, + { kCpuNSM , { 'C', 'y', 'r', 'i', 'x', 'I', 'n', 's', 't', 'e', 'a', 'd' } }, + + { kCpuTransmeta, { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'T', 'M', 'x', '8', '6' } }, + { kCpuTransmeta, { 'T', 'r', 'a', 'n', 's', 'm', 'e', 't', 'a', 'C', 'P', 'U' } }, + + { kCpuVia , { 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 } }, + { kCpuVia , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } } +}; + +static inline bool x86CpuVendorEq(const X86CpuVendor& info, const char* vendorString) +{ + const uint32_t* a = reinterpret_cast(info.text); + const uint32_t* b = reinterpret_cast(vendorString); + + return (a[0] == b[0]) & + (a[1] == b[1]) & + (a[2] == b[2]) ; +} + +// ============================================================================ +// [AsmJit::x86CpuSimplifyBrandString] +// ============================================================================ + +static inline void x86CpuSimplifyBrandString(char* s) +{ + // Always clear the current character in the buffer. This ensures that there + // is no garbage after the string NULL terminator. + char* d = s; + + char prev = 0; + char curr = s[0]; + s[0] = '\0'; + + for (;;) + { + if (curr == 0) break; + + if (curr == ' ') + { + if (prev == '@') goto _Skip; + if (s[1] == ' ' || s[1] == '@') goto _Skip; + } + + d[0] = curr; + d++; + prev = curr; + +_Skip: + curr = *++s; + s[0] = '\0'; + } + + d[0] = '\0'; +} + +// ============================================================================ +// [AsmJit::x86CpuId] +// ============================================================================ + +// This is messy, I know. cpuid is implemented as intrinsic in VS2005, but +// we should support other compilers as well. Main problem is that MS compilers +// in 64-bit mode not allows to use inline assembler, so we need intrinsic and +// we need also asm version. + +// x86CpuId() and detectCpuInfo() for x86 and x64 platforms begins here. +#if defined(ASMJIT_X86) || defined(ASMJIT_X64) +void x86CpuId(uint32_t in, X86CpuId* out) +{ +#if defined(_MSC_VER) + +// 2009-02-05: Thanks to Mike Tajmajer for supporting VC7.1 compiler. +// ASMJIT_X64 is here only for readibility, only VS2005 can compile 64-bit code. +# if _MSC_VER >= 1400 || defined(ASMJIT_X64) + // Done by intrinsics. + __cpuid(reinterpret_cast(out->i), in); +# else // _MSC_VER < 1400 + uint32_t cpuid_in = in; + uint32_t* cpuid_out = out->i; + + __asm + { + mov eax, cpuid_in + mov edi, cpuid_out + cpuid + mov dword ptr[edi + 0], eax + mov dword ptr[edi + 4], ebx + mov dword ptr[edi + 8], ecx + mov dword ptr[edi + 12], edx + } +# endif // _MSC_VER < 1400 + +#elif defined(__GNUC__) + +// Note, need to preserve ebx/rbx register! +# if defined(ASMJIT_X86) +# define __myCpuId(a, b, c, d, inp) \ + asm ("mov %%ebx, %%edi\n" \ + "cpuid\n" \ + "xchg %%edi, %%ebx\n" \ + : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) +# else +# define __myCpuId(a, b, c, d, inp) \ + asm ("mov %%rbx, %%rdi\n" \ + "cpuid\n" \ + "xchg %%rdi, %%rbx\n" \ + : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) +# endif + __myCpuId(out->eax, out->ebx, out->ecx, out->edx, in); + +#endif // Compiler #ifdef. +} + +// ============================================================================ +// [AsmJit::x86CpuDetect] +// ============================================================================ + +void x86CpuDetect(X86CpuInfo* out) +{ + uint32_t i; + X86CpuId regs; + + // Clear everything except the '_size' member. + memset(reinterpret_cast(out) + sizeof(uint32_t), + 0, sizeof(CpuInfo) - sizeof(uint32_t)); + + // Fill safe defaults. + memcpy(out->_vendorString, "Unknown", 8); + out->_numberOfProcessors = CpuInfo::detectNumberOfProcessors(); + + // Get vendor string/id. + x86CpuId(0, ®s); + + memcpy(out->_vendorString, ®s.ebx, 4); + memcpy(out->_vendorString + 4, ®s.edx, 4); + memcpy(out->_vendorString + 8, ®s.ecx, 4); + + for (i = 0; i < 3; i++) + { + if (x86CpuVendorEq(x86CpuVendor[i], out->_vendorString)) + { + out->_vendorId = x86CpuVendor[i].id; + break; + } + } + + // Get feature flags in ecx/edx, and family/model in eax. + x86CpuId(1, ®s); + + // Fill family and model fields. + out->_family = (regs.eax >> 8) & 0x0F; + out->_model = (regs.eax >> 4) & 0x0F; + out->_stepping = (regs.eax ) & 0x0F; + + // Use extended family and model fields. + if (out->_family == 0x0F) + { + out->_family += ((regs.eax >> 20) & 0xFF); + out->_model += ((regs.eax >> 16) & 0x0F) << 4; + } + + out->_processorType = ((regs.eax >> 12) & 0x03); + out->_brandIndex = ((regs.ebx ) & 0xFF); + out->_flushCacheLineSize = ((regs.ebx >> 8) & 0xFF) * 8; + out->_maxLogicalProcessors = ((regs.ebx >> 16) & 0xFF); + out->_apicPhysicalId = ((regs.ebx >> 24) & 0xFF); + + if (regs.ecx & 0x00000001U) out->_features |= kX86FeatureSse3; + if (regs.ecx & 0x00000002U) out->_features |= kX86FeaturePclMulDQ; + if (regs.ecx & 0x00000008U) out->_features |= kX86FeatureMonitorMWait; + if (regs.ecx & 0x00000200U) out->_features |= kX86FeatureSsse3; + if (regs.ecx & 0x00002000U) out->_features |= kX86FeatureCmpXchg16B; + if (regs.ecx & 0x00080000U) out->_features |= kX86FeatureSse41; + if (regs.ecx & 0x00100000U) out->_features |= kX86FeatureSse42; + if (regs.ecx & 0x00400000U) out->_features |= kX86FeatureMovBE; + if (regs.ecx & 0x00800000U) out->_features |= kX86FeaturePopCnt; + if (regs.ecx & 0x10000000U) out->_features |= kX86FeatureAvx; + + if (regs.edx & 0x00000010U) out->_features |= kX86FeatureRdtsc; + if (regs.edx & 0x00000100U) out->_features |= kX86FeatureCmpXchg8B; + if (regs.edx & 0x00008000U) out->_features |= kX86FeatureCMov; + if (regs.edx & 0x00800000U) out->_features |= kX86FeatureMmx; + if (regs.edx & 0x01000000U) out->_features |= kX86FeatureFXSR; + if (regs.edx & 0x02000000U) out->_features |= kX86FeatureSse | kX86FeatureMmxExt; + if (regs.edx & 0x04000000U) out->_features |= kX86FeatureSse | kX86FeatureSse2; + if (regs.edx & 0x10000000U) out->_features |= kX86FeatureMultiThreading; + + if (out->_vendorId == kCpuAmd && (regs.edx & 0x10000000U)) + { + // AMD sets Multithreading to ON if it has more cores. + if (out->_numberOfProcessors == 1) out->_numberOfProcessors = 2; + } + + // This comment comes from V8 and I think that its important: + // + // Opteron Rev E has i bug in which on very rare occasions i locked + // instruction doesn't act as i read-acquire barrier if followed by i + // non-locked read-modify-write instruction. Rev F has this bug in + // pre-release versions, but not in versions released to customers, + // so we test only for Rev E, which is family 15, model 32..63 inclusive. + + if (out->_vendorId == kCpuAmd && out->_family == 15 && out->_model >= 32 && out->_model <= 63) + { + out->_bugs |= kX86BugAmdLockMB; + } + + // Calling cpuid with 0x80000000 as the in argument + // gets the number of valid extended IDs. + + x86CpuId(0x80000000, ®s); + + uint32_t exIds = regs.eax; + if (exIds > 0x80000004) exIds = 0x80000004; + + uint32_t* brand = reinterpret_cast(out->_brandString); + + for (i = 0x80000001; i <= exIds; i++) + { + x86CpuId(i, ®s); + + switch (i) + { + case 0x80000001: + if (regs.ecx & 0x00000001U) out->_features |= kX86FeatureLahfSahf; + if (regs.ecx & 0x00000020U) out->_features |= kX86FeatureLzCnt; + if (regs.ecx & 0x00000040U) out->_features |= kX86FeatureSse4A; + if (regs.ecx & 0x00000080U) out->_features |= kX86FeatureMSse; + if (regs.ecx & 0x00000100U) out->_features |= kX86FeaturePrefetch; + + if (regs.edx & 0x00100000U) out->_features |= kX86FeatureExecuteDisableBit; + if (regs.edx & 0x00200000U) out->_features |= kX86FeatureFFXSR; + if (regs.edx & 0x00400000U) out->_features |= kX86FeatureMmxExt; + if (regs.edx & 0x08000000U) out->_features |= kX86FeatureRdtscP; + if (regs.edx & 0x20000000U) out->_features |= kX86Feature64Bit; + if (regs.edx & 0x40000000U) out->_features |= kX86Feature3dNowExt | kX86FeatureMmxExt; + if (regs.edx & 0x80000000U) out->_features |= kX86Feature3dNow; + break; + + case 0x80000002: + case 0x80000003: + case 0x80000004: + *brand++ = regs.eax; + *brand++ = regs.ebx; + *brand++ = regs.ecx; + *brand++ = regs.edx; + break; + + default: + // Additional features can be detected in the future. + break; + } + } + + // Simplify the brand string (remove unnecessary spaces to make it printable). + x86CpuSimplifyBrandString(out->_brandString); +} +#endif + +} // AsmJit + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/x86/x86cpuinfo.h b/desmume/src/utils/AsmJit/x86/x86cpuinfo.h new file mode 100644 index 000000000..faa4ac7c6 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86cpuinfo.h @@ -0,0 +1,130 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_X86_X86CPUINFO_H +#define _ASMJIT_X86_X86CPUINFO_H + +// [Dependencies - AsmJit] +#include "../core/cpuinfo.h" +#include "../core/defs.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_X86 +//! @{ + +// ============================================================================ +// [AsmJit::X86CpuId] +// ============================================================================ + +//! @brief X86 CpuId output. +union X86CpuId +{ + //! @brief EAX/EBX/ECX/EDX output. + uint32_t i[4]; + + struct + { + //! @brief EAX output. + uint32_t eax; + //! @brief EBX output. + uint32_t ebx; + //! @brief ECX output. + uint32_t ecx; + //! @brief EDX output. + uint32_t edx; + }; +}; + +// ============================================================================ +// [AsmJit::X86CpuInfo] +// ============================================================================ + +struct X86CpuInfo : public CpuInfo +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + inline X86CpuInfo(uint32_t size = sizeof(X86CpuInfo)) : + CpuInfo(size) + { + } + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get processor type. + inline uint32_t getProcessorType() const { return _processorType; } + //! @brief Get brand index. + inline uint32_t getBrandIndex() const { return _brandIndex; } + //! @brief Get flush cache line size. + inline uint32_t getFlushCacheLineSize() const { return _flushCacheLineSize; } + //! @brief Get maximum logical processors count. + inline uint32_t getMaxLogicalProcessors() const { return _maxLogicalProcessors; } + //! @brief Get APIC physical ID. + inline uint32_t getApicPhysicalId() const { return _apicPhysicalId; } + + // -------------------------------------------------------------------------- + // [Statics] + // -------------------------------------------------------------------------- + + //! @brief Get global instance of @ref X86CpuInfo. + static inline const X86CpuInfo* getGlobal() + { return static_cast(CpuInfo::getGlobal()); } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Processor type. + uint32_t _processorType; + //! @brief Brand index. + uint32_t _brandIndex; + //! @brief Flush cache line size in bytes. + uint32_t _flushCacheLineSize; + //! @brief Maximum number of addressable IDs for logical processors. + uint32_t _maxLogicalProcessors; + //! @brief Initial APIC ID. + uint32_t _apicPhysicalId; +}; + +// ============================================================================ +// [AsmJit::x86CpuId] +// ============================================================================ + +#if defined(ASMJIT_X86) || defined(ASMJIT_X64) +//! @brief Calls CPUID instruction with eax == @a in and stores output to @a out. +//! +//! @c cpuid() function has one input parameter that is passed to cpuid through +//! eax register and results in four output values representing result of cpuid +//! instruction (eax, ebx, ecx and edx registers). +ASMJIT_API void x86CpuId(uint32_t in, X86CpuId* out); + +// ============================================================================ +// [AsmJit::x86CpuDetect] +// ============================================================================ + +//! @brief Detect CPU features to CpuInfo structure @a out. +//! +//! @sa @c CpuInfo. +ASMJIT_API void x86CpuDetect(X86CpuInfo* out); +#endif // ASMJIT_X86 || ASMJIT_X64 + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_X86_X86CPUINFO_H diff --git a/desmume/src/utils/AsmJit/x86/x86defs.cpp b/desmume/src/utils/AsmJit/x86/x86defs.cpp new file mode 100644 index 000000000..5ac62f238 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86defs.cpp @@ -0,0 +1,1816 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../x86/x86defs.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::x86InstName] +// ============================================================================ + +// Following {DATA SECTION} is auto-generated by generate-defs.py tool using +// X86InstInfo data. +// +// ${X86_INST_DATA:BEGIN} +const char x86InstName[] = + "\0" + "adc\0" + "add\0" + "addpd\0" + "addps\0" + "addsd\0" + "addss\0" + "addsubpd\0" + "addsubps\0" + "amd_prefetch\0" + "amd_prefetchw\0" + "and\0" + "andnpd\0" + "andnps\0" + "andpd\0" + "andps\0" + "blendpd\0" + "blendps\0" + "blendvpd\0" + "blendvps\0" + "bsf\0" + "bsr\0" + "bswap\0" + "bt\0" + "btc\0" + "btr\0" + "bts\0" + "call\0" + "cbw\0" + "cdq\0" + "cdqe\0" + "clc\0" + "cld\0" + "clflush\0" + "cmc\0" + "cmova\0" + "cmovae\0" + "cmovb\0" + "cmovbe\0" + "cmovc\0" + "cmove\0" + "cmovg\0" + "cmovge\0" + "cmovl\0" + "cmovle\0" + "cmovna\0" + "cmovnae\0" + "cmovnb\0" + "cmovnbe\0" + "cmovnc\0" + "cmovne\0" + "cmovng\0" + "cmovnge\0" + "cmovnl\0" + "cmovnle\0" + "cmovno\0" + "cmovnp\0" + "cmovns\0" + "cmovnz\0" + "cmovo\0" + "cmovp\0" + "cmovpe\0" + "cmovpo\0" + "cmovs\0" + "cmovz\0" + "cmp\0" + "cmppd\0" + "cmpps\0" + "cmpsd\0" + "cmpss\0" + "cmpxchg\0" + "cmpxchg16b\0" + "cmpxchg8b\0" + "comisd\0" + "comiss\0" + "cpuid\0" + "cqo\0" + "crc32\0" + "cvtdq2pd\0" + "cvtdq2ps\0" + "cvtpd2dq\0" + "cvtpd2pi\0" + "cvtpd2ps\0" + "cvtpi2pd\0" + "cvtpi2ps\0" + "cvtps2dq\0" + "cvtps2pd\0" + "cvtps2pi\0" + "cvtsd2si\0" + "cvtsd2ss\0" + "cvtsi2sd\0" + "cvtsi2ss\0" + "cvtss2sd\0" + "cvtss2si\0" + "cvttpd2dq\0" + "cvttpd2pi\0" + "cvttps2dq\0" + "cvttps2pi\0" + "cvttsd2si\0" + "cvttss2si\0" + "cwd\0" + "cwde\0" + "daa\0" + "das\0" + "dec\0" + "div\0" + "divpd\0" + "divps\0" + "divsd\0" + "divss\0" + "dppd\0" + "dpps\0" + "emms\0" + "enter\0" + "extractps\0" + "f2xm1\0" + "fabs\0" + "fadd\0" + "faddp\0" + "fbld\0" + "fbstp\0" + "fchs\0" + "fclex\0" + "fcmovb\0" + "fcmovbe\0" + "fcmove\0" + "fcmovnb\0" + "fcmovnbe\0" + "fcmovne\0" + "fcmovnu\0" + "fcmovu\0" + "fcom\0" + "fcomi\0" + "fcomip\0" + "fcomp\0" + "fcompp\0" + "fcos\0" + "fdecstp\0" + "fdiv\0" + "fdivp\0" + "fdivr\0" + "fdivrp\0" + "femms\0" + "ffree\0" + "fiadd\0" + "ficom\0" + "ficomp\0" + "fidiv\0" + "fidivr\0" + "fild\0" + "fimul\0" + "fincstp\0" + "finit\0" + "fist\0" + "fistp\0" + "fisttp\0" + "fisub\0" + "fisubr\0" + "fld\0" + "fld1\0" + "fldcw\0" + "fldenv\0" + "fldl2e\0" + "fldl2t\0" + "fldlg2\0" + "fldln2\0" + "fldpi\0" + "fldz\0" + "fmul\0" + "fmulp\0" + "fnclex\0" + "fninit\0" + "fnop\0" + "fnsave\0" + "fnstcw\0" + "fnstenv\0" + "fnstsw\0" + "fpatan\0" + "fprem\0" + "fprem1\0" + "fptan\0" + "frndint\0" + "frstor\0" + "fsave\0" + "fscale\0" + "fsin\0" + "fsincos\0" + "fsqrt\0" + "fst\0" + "fstcw\0" + "fstenv\0" + "fstp\0" + "fstsw\0" + "fsub\0" + "fsubp\0" + "fsubr\0" + "fsubrp\0" + "ftst\0" + "fucom\0" + "fucomi\0" + "fucomip\0" + "fucomp\0" + "fucompp\0" + "fwait\0" + "fxam\0" + "fxch\0" + "fxrstor\0" + "fxsave\0" + "fxtract\0" + "fyl2x\0" + "fyl2xp1\0" + "haddpd\0" + "haddps\0" + "hsubpd\0" + "hsubps\0" + "idiv\0" + "imul\0" + "inc\0" + "int3\0" + "ja\0" + "jae\0" + "jb\0" + "jbe\0" + "jc\0" + "je\0" + "jg\0" + "jge\0" + "jl\0" + "jle\0" + "jna\0" + "jnae\0" + "jnb\0" + "jnbe\0" + "jnc\0" + "jne\0" + "jng\0" + "jnge\0" + "jnl\0" + "jnle\0" + "jno\0" + "jnp\0" + "jns\0" + "jnz\0" + "jo\0" + "jp\0" + "jpe\0" + "jpo\0" + "js\0" + "jz\0" + "jmp\0" + "lddqu\0" + "ldmxcsr\0" + "lahf\0" + "lea\0" + "leave\0" + "lfence\0" + "maskmovdqu\0" + "maskmovq\0" + "maxpd\0" + "maxps\0" + "maxsd\0" + "maxss\0" + "mfence\0" + "minpd\0" + "minps\0" + "minsd\0" + "minss\0" + "monitor\0" + "mov\0" + "movapd\0" + "movaps\0" + "movbe\0" + "movd\0" + "movddup\0" + "movdq2q\0" + "movdqa\0" + "movdqu\0" + "movhlps\0" + "movhpd\0" + "movhps\0" + "movlhps\0" + "movlpd\0" + "movlps\0" + "movmskpd\0" + "movmskps\0" + "movntdq\0" + "movntdqa\0" + "movnti\0" + "movntpd\0" + "movntps\0" + "movntq\0" + "movq\0" + "movq2dq\0" + "movsd\0" + "movshdup\0" + "movsldup\0" + "movss\0" + "movsx\0" + "movsxd\0" + "movupd\0" + "movups\0" + "movzx\0" + "mov_ptr\0" + "mpsadbw\0" + "mul\0" + "mulpd\0" + "mulps\0" + "mulsd\0" + "mulss\0" + "mwait\0" + "neg\0" + "nop\0" + "not\0" + "or\0" + "orpd\0" + "orps\0" + "pabsb\0" + "pabsd\0" + "pabsw\0" + "packssdw\0" + "packsswb\0" + "packusdw\0" + "packuswb\0" + "paddb\0" + "paddd\0" + "paddq\0" + "paddsb\0" + "paddsw\0" + "paddusb\0" + "paddusw\0" + "paddw\0" + "palignr\0" + "pand\0" + "pandn\0" + "pause\0" + "pavgb\0" + "pavgw\0" + "pblendvb\0" + "pblendw\0" + "pcmpeqb\0" + "pcmpeqd\0" + "pcmpeqq\0" + "pcmpeqw\0" + "pcmpestri\0" + "pcmpestrm\0" + "pcmpgtb\0" + "pcmpgtd\0" + "pcmpgtq\0" + "pcmpgtw\0" + "pcmpistri\0" + "pcmpistrm\0" + "pextrb\0" + "pextrd\0" + "pextrq\0" + "pextrw\0" + "pf2id\0" + "pf2iw\0" + "pfacc\0" + "pfadd\0" + "pfcmpeq\0" + "pfcmpge\0" + "pfcmpgt\0" + "pfmax\0" + "pfmin\0" + "pfmul\0" + "pfnacc\0" + "pfpnacc\0" + "pfrcp\0" + "pfrcpit1\0" + "pfrcpit2\0" + "pfrsqit1\0" + "pfrsqrt\0" + "pfsub\0" + "pfsubr\0" + "phaddd\0" + "phaddsw\0" + "phaddw\0" + "phminposuw\0" + "phsubd\0" + "phsubsw\0" + "phsubw\0" + "pi2fd\0" + "pi2fw\0" + "pinsrb\0" + "pinsrd\0" + "pinsrq\0" + "pinsrw\0" + "pmaddubsw\0" + "pmaddwd\0" + "pmaxsb\0" + "pmaxsd\0" + "pmaxsw\0" + "pmaxub\0" + "pmaxud\0" + "pmaxuw\0" + "pminsb\0" + "pminsd\0" + "pminsw\0" + "pminub\0" + "pminud\0" + "pminuw\0" + "pmovmskb\0" + "pmovsxbd\0" + "pmovsxbq\0" + "pmovsxbw\0" + "pmovsxdq\0" + "pmovsxwd\0" + "pmovsxwq\0" + "pmovzxbd\0" + "pmovzxbq\0" + "pmovzxbw\0" + "pmovzxdq\0" + "pmovzxwd\0" + "pmovzxwq\0" + "pmuldq\0" + "pmulhrsw\0" + "pmulhuw\0" + "pmulhw\0" + "pmulld\0" + "pmullw\0" + "pmuludq\0" + "pop\0" + "popad\0" + "popcnt\0" + "popfd\0" + "popfq\0" + "por\0" + "prefetch\0" + "psadbw\0" + "pshufb\0" + "pshufd\0" + "pshufw\0" + "pshufhw\0" + "pshuflw\0" + "psignb\0" + "psignd\0" + "psignw\0" + "pslld\0" + "pslldq\0" + "psllq\0" + "psllw\0" + "psrad\0" + "psraw\0" + "psrld\0" + "psrldq\0" + "psrlq\0" + "psrlw\0" + "psubb\0" + "psubd\0" + "psubq\0" + "psubsb\0" + "psubsw\0" + "psubusb\0" + "psubusw\0" + "psubw\0" + "pswapd\0" + "ptest\0" + "punpckhbw\0" + "punpckhdq\0" + "punpckhqdq\0" + "punpckhwd\0" + "punpcklbw\0" + "punpckldq\0" + "punpcklqdq\0" + "punpcklwd\0" + "push\0" + "pushad\0" + "pushfd\0" + "pushfq\0" + "pxor\0" + "rcl\0" + "rcpps\0" + "rcpss\0" + "rcr\0" + "rdtsc\0" + "rdtscp\0" + "rep lodsb\0" + "rep lodsd\0" + "rep lodsq\0" + "rep lodsw\0" + "rep movsb\0" + "rep movsd\0" + "rep movsq\0" + "rep movsw\0" + "rep stosb\0" + "rep stosd\0" + "rep stosq\0" + "rep stosw\0" + "repe cmpsb\0" + "repe cmpsd\0" + "repe cmpsq\0" + "repe cmpsw\0" + "repe scasb\0" + "repe scasd\0" + "repe scasq\0" + "repe scasw\0" + "repne cmpsb\0" + "repne cmpsd\0" + "repne cmpsq\0" + "repne cmpsw\0" + "repne scasb\0" + "repne scasd\0" + "repne scasq\0" + "repne scasw\0" + "ret\0" + "rol\0" + "ror\0" + "roundpd\0" + "roundps\0" + "roundsd\0" + "roundss\0" + "rsqrtps\0" + "rsqrtss\0" + "sahf\0" + "sal\0" + "sar\0" + "sbb\0" + "seta\0" + "setae\0" + "setb\0" + "setbe\0" + "setc\0" + "sete\0" + "setg\0" + "setge\0" + "setl\0" + "setle\0" + "setna\0" + "setnae\0" + "setnb\0" + "setnbe\0" + "setnc\0" + "setne\0" + "setng\0" + "setnge\0" + "setnl\0" + "setnle\0" + "setno\0" + "setnp\0" + "setns\0" + "setnz\0" + "seto\0" + "setp\0" + "setpe\0" + "setpo\0" + "sets\0" + "setz\0" + "sfence\0" + "shl\0" + "shld\0" + "shr\0" + "shrd\0" + "shufpd\0" + "shufps\0" + "sqrtpd\0" + "sqrtps\0" + "sqrtsd\0" + "sqrtss\0" + "stc\0" + "std\0" + "stmxcsr\0" + "sub\0" + "subpd\0" + "subps\0" + "subsd\0" + "subss\0" + "test\0" + "ucomisd\0" + "ucomiss\0" + "ud2\0" + "unpckhpd\0" + "unpckhps\0" + "unpcklpd\0" + "unpcklps\0" + "xadd\0" + "xchg\0" + "xor\0" + "xorpd\0" + "xorps\0" + ; + +#define INDEX_kInstNone 0 +#define INDEX_kX86InstAdc 1 +#define INDEX_kX86InstAdd 5 +#define INDEX_kX86InstAddPD 9 +#define INDEX_kX86InstAddPS 15 +#define INDEX_kX86InstAddSD 21 +#define INDEX_kX86InstAddSS 27 +#define INDEX_kX86InstAddSubPD 33 +#define INDEX_kX86InstAddSubPS 42 +#define INDEX_kX86InstAmdPrefetch 51 +#define INDEX_kX86InstAmdPrefetchW 64 +#define INDEX_kX86InstAnd 78 +#define INDEX_kX86InstAndnPD 82 +#define INDEX_kX86InstAndnPS 89 +#define INDEX_kX86InstAndPD 96 +#define INDEX_kX86InstAndPS 102 +#define INDEX_kX86InstBlendPD 108 +#define INDEX_kX86InstBlendPS 116 +#define INDEX_kX86InstBlendVPD 124 +#define INDEX_kX86InstBlendVPS 133 +#define INDEX_kX86InstBsf 142 +#define INDEX_kX86InstBsr 146 +#define INDEX_kX86InstBSwap 150 +#define INDEX_kX86InstBt 156 +#define INDEX_kX86InstBtc 159 +#define INDEX_kX86InstBtr 163 +#define INDEX_kX86InstBts 167 +#define INDEX_kX86InstCall 171 +#define INDEX_kX86InstCbw 176 +#define INDEX_kX86InstCdq 180 +#define INDEX_kX86InstCdqe 184 +#define INDEX_kX86InstClc 189 +#define INDEX_kX86InstCld 193 +#define INDEX_kX86InstClFlush 197 +#define INDEX_kX86InstCmc 205 +#define INDEX_kX86InstCMovA 209 +#define INDEX_kX86InstCMovAE 215 +#define INDEX_kX86InstCMovB 222 +#define INDEX_kX86InstCMovBE 228 +#define INDEX_kX86InstCMovC 235 +#define INDEX_kX86InstCMovE 241 +#define INDEX_kX86InstCMovG 247 +#define INDEX_kX86InstCMovGE 253 +#define INDEX_kX86InstCMovL 260 +#define INDEX_kX86InstCMovLE 266 +#define INDEX_kX86InstCMovNA 273 +#define INDEX_kX86InstCMovNAE 280 +#define INDEX_kX86InstCMovNB 288 +#define INDEX_kX86InstCMovNBE 295 +#define INDEX_kX86InstCMovNC 303 +#define INDEX_kX86InstCMovNE 310 +#define INDEX_kX86InstCMovNG 317 +#define INDEX_kX86InstCMovNGE 324 +#define INDEX_kX86InstCMovNL 332 +#define INDEX_kX86InstCMovNLE 339 +#define INDEX_kX86InstCMovNO 347 +#define INDEX_kX86InstCMovNP 354 +#define INDEX_kX86InstCMovNS 361 +#define INDEX_kX86InstCMovNZ 368 +#define INDEX_kX86InstCMovO 375 +#define INDEX_kX86InstCMovP 381 +#define INDEX_kX86InstCMovPE 387 +#define INDEX_kX86InstCMovPO 394 +#define INDEX_kX86InstCMovS 401 +#define INDEX_kX86InstCMovZ 407 +#define INDEX_kX86InstCmp 413 +#define INDEX_kX86InstCmpPD 417 +#define INDEX_kX86InstCmpPS 423 +#define INDEX_kX86InstCmpSD 429 +#define INDEX_kX86InstCmpSS 435 +#define INDEX_kX86InstCmpXCHG 441 +#define INDEX_kX86InstCmpXCHG16B 449 +#define INDEX_kX86InstCmpXCHG8B 460 +#define INDEX_kX86InstComISD 470 +#define INDEX_kX86InstComISS 477 +#define INDEX_kX86InstCpuId 484 +#define INDEX_kX86InstCqo 490 +#define INDEX_kX86InstCrc32 494 +#define INDEX_kX86InstCvtDQ2PD 500 +#define INDEX_kX86InstCvtDQ2PS 509 +#define INDEX_kX86InstCvtPD2DQ 518 +#define INDEX_kX86InstCvtPD2PI 527 +#define INDEX_kX86InstCvtPD2PS 536 +#define INDEX_kX86InstCvtPI2PD 545 +#define INDEX_kX86InstCvtPI2PS 554 +#define INDEX_kX86InstCvtPS2DQ 563 +#define INDEX_kX86InstCvtPS2PD 572 +#define INDEX_kX86InstCvtPS2PI 581 +#define INDEX_kX86InstCvtSD2SI 590 +#define INDEX_kX86InstCvtSD2SS 599 +#define INDEX_kX86InstCvtSI2SD 608 +#define INDEX_kX86InstCvtSI2SS 617 +#define INDEX_kX86InstCvtSS2SD 626 +#define INDEX_kX86InstCvtSS2SI 635 +#define INDEX_kX86InstCvttPD2DQ 644 +#define INDEX_kX86InstCvttPD2PI 654 +#define INDEX_kX86InstCvttPS2DQ 664 +#define INDEX_kX86InstCvttPS2PI 674 +#define INDEX_kX86InstCvttSD2SI 684 +#define INDEX_kX86InstCvttSS2SI 694 +#define INDEX_kX86InstCwd 704 +#define INDEX_kX86InstCwde 708 +#define INDEX_kX86InstDaa 713 +#define INDEX_kX86InstDas 717 +#define INDEX_kX86InstDec 721 +#define INDEX_kX86InstDiv 725 +#define INDEX_kX86InstDivPD 729 +#define INDEX_kX86InstDivPS 735 +#define INDEX_kX86InstDivSD 741 +#define INDEX_kX86InstDivSS 747 +#define INDEX_kX86InstDpPD 753 +#define INDEX_kX86InstDpPS 758 +#define INDEX_kX86InstEmms 763 +#define INDEX_kX86InstEnter 768 +#define INDEX_kX86InstExtractPS 774 +#define INDEX_kX86InstF2XM1 784 +#define INDEX_kX86InstFAbs 790 +#define INDEX_kX86InstFAdd 795 +#define INDEX_kX86InstFAddP 800 +#define INDEX_kX86InstFBLd 806 +#define INDEX_kX86InstFBStP 811 +#define INDEX_kX86InstFCHS 817 +#define INDEX_kX86InstFClex 822 +#define INDEX_kX86InstFCMovB 828 +#define INDEX_kX86InstFCMovBE 835 +#define INDEX_kX86InstFCMovE 843 +#define INDEX_kX86InstFCMovNB 850 +#define INDEX_kX86InstFCMovNBE 858 +#define INDEX_kX86InstFCMovNE 867 +#define INDEX_kX86InstFCMovNU 875 +#define INDEX_kX86InstFCMovU 883 +#define INDEX_kX86InstFCom 890 +#define INDEX_kX86InstFComI 895 +#define INDEX_kX86InstFComIP 901 +#define INDEX_kX86InstFComP 908 +#define INDEX_kX86InstFComPP 914 +#define INDEX_kX86InstFCos 921 +#define INDEX_kX86InstFDecStP 926 +#define INDEX_kX86InstFDiv 934 +#define INDEX_kX86InstFDivP 939 +#define INDEX_kX86InstFDivR 945 +#define INDEX_kX86InstFDivRP 951 +#define INDEX_kX86InstFEmms 958 +#define INDEX_kX86InstFFree 964 +#define INDEX_kX86InstFIAdd 970 +#define INDEX_kX86InstFICom 976 +#define INDEX_kX86InstFIComP 982 +#define INDEX_kX86InstFIDiv 989 +#define INDEX_kX86InstFIDivR 995 +#define INDEX_kX86InstFILd 1002 +#define INDEX_kX86InstFIMul 1007 +#define INDEX_kX86InstFIncStP 1013 +#define INDEX_kX86InstFInit 1021 +#define INDEX_kX86InstFISt 1027 +#define INDEX_kX86InstFIStP 1032 +#define INDEX_kX86InstFISttP 1038 +#define INDEX_kX86InstFISub 1045 +#define INDEX_kX86InstFISubR 1051 +#define INDEX_kX86InstFLd 1058 +#define INDEX_kX86InstFLd1 1062 +#define INDEX_kX86InstFLdCw 1067 +#define INDEX_kX86InstFLdEnv 1073 +#define INDEX_kX86InstFLdL2E 1080 +#define INDEX_kX86InstFLdL2T 1087 +#define INDEX_kX86InstFLdLg2 1094 +#define INDEX_kX86InstFLdLn2 1101 +#define INDEX_kX86InstFLdPi 1108 +#define INDEX_kX86InstFLdZ 1114 +#define INDEX_kX86InstFMul 1119 +#define INDEX_kX86InstFMulP 1124 +#define INDEX_kX86InstFNClex 1130 +#define INDEX_kX86InstFNInit 1137 +#define INDEX_kX86InstFNop 1144 +#define INDEX_kX86InstFNSave 1149 +#define INDEX_kX86InstFNStCw 1156 +#define INDEX_kX86InstFNStEnv 1163 +#define INDEX_kX86InstFNStSw 1171 +#define INDEX_kX86InstFPAtan 1178 +#define INDEX_kX86InstFPRem 1185 +#define INDEX_kX86InstFPRem1 1191 +#define INDEX_kX86InstFPTan 1198 +#define INDEX_kX86InstFRndInt 1204 +#define INDEX_kX86InstFRstor 1212 +#define INDEX_kX86InstFSave 1219 +#define INDEX_kX86InstFScale 1225 +#define INDEX_kX86InstFSin 1232 +#define INDEX_kX86InstFSinCos 1237 +#define INDEX_kX86InstFSqrt 1245 +#define INDEX_kX86InstFSt 1251 +#define INDEX_kX86InstFStCw 1255 +#define INDEX_kX86InstFStEnv 1261 +#define INDEX_kX86InstFStP 1268 +#define INDEX_kX86InstFStSw 1273 +#define INDEX_kX86InstFSub 1279 +#define INDEX_kX86InstFSubP 1284 +#define INDEX_kX86InstFSubR 1290 +#define INDEX_kX86InstFSubRP 1296 +#define INDEX_kX86InstFTst 1303 +#define INDEX_kX86InstFUCom 1308 +#define INDEX_kX86InstFUComI 1314 +#define INDEX_kX86InstFUComIP 1321 +#define INDEX_kX86InstFUComP 1329 +#define INDEX_kX86InstFUComPP 1336 +#define INDEX_kX86InstFWait 1344 +#define INDEX_kX86InstFXam 1350 +#define INDEX_kX86InstFXch 1355 +#define INDEX_kX86InstFXRstor 1360 +#define INDEX_kX86InstFXSave 1368 +#define INDEX_kX86InstFXtract 1375 +#define INDEX_kX86InstFYL2X 1383 +#define INDEX_kX86InstFYL2XP1 1389 +#define INDEX_kX86InstHAddPD 1397 +#define INDEX_kX86InstHAddPS 1404 +#define INDEX_kX86InstHSubPD 1411 +#define INDEX_kX86InstHSubPS 1418 +#define INDEX_kX86InstIDiv 1425 +#define INDEX_kX86InstIMul 1430 +#define INDEX_kX86InstInc 1435 +#define INDEX_kX86InstInt3 1439 +#define INDEX_kX86InstJA 1444 +#define INDEX_kX86InstJAE 1447 +#define INDEX_kX86InstJB 1451 +#define INDEX_kX86InstJBE 1454 +#define INDEX_kX86InstJC 1458 +#define INDEX_kX86InstJE 1461 +#define INDEX_kX86InstJG 1464 +#define INDEX_kX86InstJGE 1467 +#define INDEX_kX86InstJL 1471 +#define INDEX_kX86InstJLE 1474 +#define INDEX_kX86InstJNA 1478 +#define INDEX_kX86InstJNAE 1482 +#define INDEX_kX86InstJNB 1487 +#define INDEX_kX86InstJNBE 1491 +#define INDEX_kX86InstJNC 1496 +#define INDEX_kX86InstJNE 1500 +#define INDEX_kX86InstJNG 1504 +#define INDEX_kX86InstJNGE 1508 +#define INDEX_kX86InstJNL 1513 +#define INDEX_kX86InstJNLE 1517 +#define INDEX_kX86InstJNO 1522 +#define INDEX_kX86InstJNP 1526 +#define INDEX_kX86InstJNS 1530 +#define INDEX_kX86InstJNZ 1534 +#define INDEX_kX86InstJO 1538 +#define INDEX_kX86InstJP 1541 +#define INDEX_kX86InstJPE 1544 +#define INDEX_kX86InstJPO 1548 +#define INDEX_kX86InstJS 1552 +#define INDEX_kX86InstJZ 1555 +#define INDEX_kX86InstJmp 1558 +#define INDEX_kX86InstLdDQU 1562 +#define INDEX_kX86InstLdMXCSR 1568 +#define INDEX_kX86InstLahf 1576 +#define INDEX_kX86InstLea 1581 +#define INDEX_kX86InstLeave 1585 +#define INDEX_kX86InstLFence 1591 +#define INDEX_kX86InstMaskMovDQU 1598 +#define INDEX_kX86InstMaskMovQ 1609 +#define INDEX_kX86InstMaxPD 1618 +#define INDEX_kX86InstMaxPS 1624 +#define INDEX_kX86InstMaxSD 1630 +#define INDEX_kX86InstMaxSS 1636 +#define INDEX_kX86InstMFence 1642 +#define INDEX_kX86InstMinPD 1649 +#define INDEX_kX86InstMinPS 1655 +#define INDEX_kX86InstMinSD 1661 +#define INDEX_kX86InstMinSS 1667 +#define INDEX_kX86InstMonitor 1673 +#define INDEX_kX86InstMov 1681 +#define INDEX_kX86InstMovAPD 1685 +#define INDEX_kX86InstMovAPS 1692 +#define INDEX_kX86InstMovBE 1699 +#define INDEX_kX86InstMovD 1705 +#define INDEX_kX86InstMovDDup 1710 +#define INDEX_kX86InstMovDQ2Q 1718 +#define INDEX_kX86InstMovDQA 1726 +#define INDEX_kX86InstMovDQU 1733 +#define INDEX_kX86InstMovHLPS 1740 +#define INDEX_kX86InstMovHPD 1748 +#define INDEX_kX86InstMovHPS 1755 +#define INDEX_kX86InstMovLHPS 1762 +#define INDEX_kX86InstMovLPD 1770 +#define INDEX_kX86InstMovLPS 1777 +#define INDEX_kX86InstMovMskPD 1784 +#define INDEX_kX86InstMovMskPS 1793 +#define INDEX_kX86InstMovNTDQ 1802 +#define INDEX_kX86InstMovNTDQA 1810 +#define INDEX_kX86InstMovNTI 1819 +#define INDEX_kX86InstMovNTPD 1826 +#define INDEX_kX86InstMovNTPS 1834 +#define INDEX_kX86InstMovNTQ 1842 +#define INDEX_kX86InstMovQ 1849 +#define INDEX_kX86InstMovQ2DQ 1854 +#define INDEX_kX86InstMovSD 1862 +#define INDEX_kX86InstMovSHDup 1868 +#define INDEX_kX86InstMovSLDup 1877 +#define INDEX_kX86InstMovSS 1886 +#define INDEX_kX86InstMovSX 1892 +#define INDEX_kX86InstMovSXD 1898 +#define INDEX_kX86InstMovUPD 1905 +#define INDEX_kX86InstMovUPS 1912 +#define INDEX_kX86InstMovZX 1919 +#define INDEX_kX86InstMovPtr 1925 +#define INDEX_kX86InstMPSADBW 1933 +#define INDEX_kX86InstMul 1941 +#define INDEX_kX86InstMulPD 1945 +#define INDEX_kX86InstMulPS 1951 +#define INDEX_kX86InstMulSD 1957 +#define INDEX_kX86InstMulSS 1963 +#define INDEX_kX86InstMWait 1969 +#define INDEX_kX86InstNeg 1975 +#define INDEX_kX86InstNop 1979 +#define INDEX_kX86InstNot 1983 +#define INDEX_kX86InstOr 1987 +#define INDEX_kX86InstOrPD 1990 +#define INDEX_kX86InstOrPS 1995 +#define INDEX_kX86InstPAbsB 2000 +#define INDEX_kX86InstPAbsD 2006 +#define INDEX_kX86InstPAbsW 2012 +#define INDEX_kX86InstPackSSDW 2018 +#define INDEX_kX86InstPackSSWB 2027 +#define INDEX_kX86InstPackUSDW 2036 +#define INDEX_kX86InstPackUSWB 2045 +#define INDEX_kX86InstPAddB 2054 +#define INDEX_kX86InstPAddD 2060 +#define INDEX_kX86InstPAddQ 2066 +#define INDEX_kX86InstPAddSB 2072 +#define INDEX_kX86InstPAddSW 2079 +#define INDEX_kX86InstPAddUSB 2086 +#define INDEX_kX86InstPAddUSW 2094 +#define INDEX_kX86InstPAddW 2102 +#define INDEX_kX86InstPAlignR 2108 +#define INDEX_kX86InstPAnd 2116 +#define INDEX_kX86InstPAndN 2121 +#define INDEX_kX86InstPause 2127 +#define INDEX_kX86InstPAvgB 2133 +#define INDEX_kX86InstPAvgW 2139 +#define INDEX_kX86InstPBlendVB 2145 +#define INDEX_kX86InstPBlendW 2154 +#define INDEX_kX86InstPCmpEqB 2162 +#define INDEX_kX86InstPCmpEqD 2170 +#define INDEX_kX86InstPCmpEqQ 2178 +#define INDEX_kX86InstPCmpEqW 2186 +#define INDEX_kX86InstPCmpEStrI 2194 +#define INDEX_kX86InstPCmpEStrM 2204 +#define INDEX_kX86InstPCmpGtB 2214 +#define INDEX_kX86InstPCmpGtD 2222 +#define INDEX_kX86InstPCmpGtQ 2230 +#define INDEX_kX86InstPCmpGtW 2238 +#define INDEX_kX86InstPCmpIStrI 2246 +#define INDEX_kX86InstPCmpIStrM 2256 +#define INDEX_kX86InstPExtrB 2266 +#define INDEX_kX86InstPExtrD 2273 +#define INDEX_kX86InstPExtrQ 2280 +#define INDEX_kX86InstPExtrW 2287 +#define INDEX_kX86InstPF2ID 2294 +#define INDEX_kX86InstPF2IW 2300 +#define INDEX_kX86InstPFAcc 2306 +#define INDEX_kX86InstPFAdd 2312 +#define INDEX_kX86InstPFCmpEQ 2318 +#define INDEX_kX86InstPFCmpGE 2326 +#define INDEX_kX86InstPFCmpGT 2334 +#define INDEX_kX86InstPFMax 2342 +#define INDEX_kX86InstPFMin 2348 +#define INDEX_kX86InstPFMul 2354 +#define INDEX_kX86InstPFNAcc 2360 +#define INDEX_kX86InstPFPNAcc 2367 +#define INDEX_kX86InstPFRcp 2375 +#define INDEX_kX86InstPFRcpIt1 2381 +#define INDEX_kX86InstPFRcpIt2 2390 +#define INDEX_kX86InstPFRSqIt1 2399 +#define INDEX_kX86InstPFRSqrt 2408 +#define INDEX_kX86InstPFSub 2416 +#define INDEX_kX86InstPFSubR 2422 +#define INDEX_kX86InstPHAddD 2429 +#define INDEX_kX86InstPHAddSW 2436 +#define INDEX_kX86InstPHAddW 2444 +#define INDEX_kX86InstPHMinPOSUW 2451 +#define INDEX_kX86InstPHSubD 2462 +#define INDEX_kX86InstPHSubSW 2469 +#define INDEX_kX86InstPHSubW 2477 +#define INDEX_kX86InstPI2FD 2484 +#define INDEX_kX86InstPI2FW 2490 +#define INDEX_kX86InstPInsRB 2496 +#define INDEX_kX86InstPInsRD 2503 +#define INDEX_kX86InstPInsRQ 2510 +#define INDEX_kX86InstPInsRW 2517 +#define INDEX_kX86InstPMAddUBSW 2524 +#define INDEX_kX86InstPMAddWD 2534 +#define INDEX_kX86InstPMaxSB 2542 +#define INDEX_kX86InstPMaxSD 2549 +#define INDEX_kX86InstPMaxSW 2556 +#define INDEX_kX86InstPMaxUB 2563 +#define INDEX_kX86InstPMaxUD 2570 +#define INDEX_kX86InstPMaxUW 2577 +#define INDEX_kX86InstPMinSB 2584 +#define INDEX_kX86InstPMinSD 2591 +#define INDEX_kX86InstPMinSW 2598 +#define INDEX_kX86InstPMinUB 2605 +#define INDEX_kX86InstPMinUD 2612 +#define INDEX_kX86InstPMinUW 2619 +#define INDEX_kX86InstPMovMskB 2626 +#define INDEX_kX86InstPMovSXBD 2635 +#define INDEX_kX86InstPMovSXBQ 2644 +#define INDEX_kX86InstPMovSXBW 2653 +#define INDEX_kX86InstPMovSXDQ 2662 +#define INDEX_kX86InstPMovSXWD 2671 +#define INDEX_kX86InstPMovSXWQ 2680 +#define INDEX_kX86InstPMovZXBD 2689 +#define INDEX_kX86InstPMovZXBQ 2698 +#define INDEX_kX86InstPMovZXBW 2707 +#define INDEX_kX86InstPMovZXDQ 2716 +#define INDEX_kX86InstPMovZXWD 2725 +#define INDEX_kX86InstPMovZXWQ 2734 +#define INDEX_kX86InstPMulDQ 2743 +#define INDEX_kX86InstPMulHRSW 2750 +#define INDEX_kX86InstPMulHUW 2759 +#define INDEX_kX86InstPMulHW 2767 +#define INDEX_kX86InstPMulLD 2774 +#define INDEX_kX86InstPMulLW 2781 +#define INDEX_kX86InstPMulUDQ 2788 +#define INDEX_kX86InstPop 2796 +#define INDEX_kX86InstPopAD 2800 +#define INDEX_kX86InstPopCnt 2806 +#define INDEX_kX86InstPopFD 2813 +#define INDEX_kX86InstPopFQ 2819 +#define INDEX_kX86InstPOr 2825 +#define INDEX_kX86InstPrefetch 2829 +#define INDEX_kX86InstPSADBW 2838 +#define INDEX_kX86InstPShufB 2845 +#define INDEX_kX86InstPShufD 2852 +#define INDEX_kX86InstPShufW 2859 +#define INDEX_kX86InstPShufHW 2866 +#define INDEX_kX86InstPShufLW 2874 +#define INDEX_kX86InstPSignB 2882 +#define INDEX_kX86InstPSignD 2889 +#define INDEX_kX86InstPSignW 2896 +#define INDEX_kX86InstPSllD 2903 +#define INDEX_kX86InstPSllDQ 2909 +#define INDEX_kX86InstPSllQ 2916 +#define INDEX_kX86InstPSllW 2922 +#define INDEX_kX86InstPSraD 2928 +#define INDEX_kX86InstPSraW 2934 +#define INDEX_kX86InstPSrlD 2940 +#define INDEX_kX86InstPSrlDQ 2946 +#define INDEX_kX86InstPSrlQ 2953 +#define INDEX_kX86InstPSrlW 2959 +#define INDEX_kX86InstPSubB 2965 +#define INDEX_kX86InstPSubD 2971 +#define INDEX_kX86InstPSubQ 2977 +#define INDEX_kX86InstPSubSB 2983 +#define INDEX_kX86InstPSubSW 2990 +#define INDEX_kX86InstPSubUSB 2997 +#define INDEX_kX86InstPSubUSW 3005 +#define INDEX_kX86InstPSubW 3013 +#define INDEX_kX86InstPSwapD 3019 +#define INDEX_kX86InstPTest 3026 +#define INDEX_kX86InstPunpckHBW 3032 +#define INDEX_kX86InstPunpckHDQ 3042 +#define INDEX_kX86InstPunpckHQDQ 3052 +#define INDEX_kX86InstPunpckHWD 3063 +#define INDEX_kX86InstPunpckLBW 3073 +#define INDEX_kX86InstPunpckLDQ 3083 +#define INDEX_kX86InstPunpckLQDQ 3093 +#define INDEX_kX86InstPunpckLWD 3104 +#define INDEX_kX86InstPush 3114 +#define INDEX_kX86InstPushAD 3119 +#define INDEX_kX86InstPushFD 3126 +#define INDEX_kX86InstPushFQ 3133 +#define INDEX_kX86InstPXor 3140 +#define INDEX_kX86InstRcl 3145 +#define INDEX_kX86InstRcpPS 3149 +#define INDEX_kX86InstRcpSS 3155 +#define INDEX_kX86InstRcr 3161 +#define INDEX_kX86InstRdtsc 3165 +#define INDEX_kX86InstRdtscP 3171 +#define INDEX_kX86InstRepLodSB 3178 +#define INDEX_kX86InstRepLodSD 3188 +#define INDEX_kX86InstRepLodSQ 3198 +#define INDEX_kX86InstRepLodSW 3208 +#define INDEX_kX86InstRepMovSB 3218 +#define INDEX_kX86InstRepMovSD 3228 +#define INDEX_kX86InstRepMovSQ 3238 +#define INDEX_kX86InstRepMovSW 3248 +#define INDEX_kX86InstRepStoSB 3258 +#define INDEX_kX86InstRepStoSD 3268 +#define INDEX_kX86InstRepStoSQ 3278 +#define INDEX_kX86InstRepStoSW 3288 +#define INDEX_kX86InstRepECmpSB 3298 +#define INDEX_kX86InstRepECmpSD 3309 +#define INDEX_kX86InstRepECmpSQ 3320 +#define INDEX_kX86InstRepECmpSW 3331 +#define INDEX_kX86InstRepEScaSB 3342 +#define INDEX_kX86InstRepEScaSD 3353 +#define INDEX_kX86InstRepEScaSQ 3364 +#define INDEX_kX86InstRepEScaSW 3375 +#define INDEX_kX86InstRepNECmpSB 3386 +#define INDEX_kX86InstRepNECmpSD 3398 +#define INDEX_kX86InstRepNECmpSQ 3410 +#define INDEX_kX86InstRepNECmpSW 3422 +#define INDEX_kX86InstRepNEScaSB 3434 +#define INDEX_kX86InstRepNEScaSD 3446 +#define INDEX_kX86InstRepNEScaSQ 3458 +#define INDEX_kX86InstRepNEScaSW 3470 +#define INDEX_kX86InstRet 3482 +#define INDEX_kX86InstRol 3486 +#define INDEX_kX86InstRor 3490 +#define INDEX_kX86InstRoundPD 3494 +#define INDEX_kX86InstRoundPS 3502 +#define INDEX_kX86InstRoundSD 3510 +#define INDEX_kX86InstRoundSS 3518 +#define INDEX_kX86InstRSqrtPS 3526 +#define INDEX_kX86InstRSqrtSS 3534 +#define INDEX_kX86InstSahf 3542 +#define INDEX_kX86InstSal 3547 +#define INDEX_kX86InstSar 3551 +#define INDEX_kX86InstSbb 3555 +#define INDEX_kX86InstSetA 3559 +#define INDEX_kX86InstSetAE 3564 +#define INDEX_kX86InstSetB 3570 +#define INDEX_kX86InstSetBE 3575 +#define INDEX_kX86InstSetC 3581 +#define INDEX_kX86InstSetE 3586 +#define INDEX_kX86InstSetG 3591 +#define INDEX_kX86InstSetGE 3596 +#define INDEX_kX86InstSetL 3602 +#define INDEX_kX86InstSetLE 3607 +#define INDEX_kX86InstSetNA 3613 +#define INDEX_kX86InstSetNAE 3619 +#define INDEX_kX86InstSetNB 3626 +#define INDEX_kX86InstSetNBE 3632 +#define INDEX_kX86InstSetNC 3639 +#define INDEX_kX86InstSetNE 3645 +#define INDEX_kX86InstSetNG 3651 +#define INDEX_kX86InstSetNGE 3657 +#define INDEX_kX86InstSetNL 3664 +#define INDEX_kX86InstSetNLE 3670 +#define INDEX_kX86InstSetNO 3677 +#define INDEX_kX86InstSetNP 3683 +#define INDEX_kX86InstSetNS 3689 +#define INDEX_kX86InstSetNZ 3695 +#define INDEX_kX86InstSetO 3701 +#define INDEX_kX86InstSetP 3706 +#define INDEX_kX86InstSetPE 3711 +#define INDEX_kX86InstSetPO 3717 +#define INDEX_kX86InstSetS 3723 +#define INDEX_kX86InstSetZ 3728 +#define INDEX_kX86InstSFence 3733 +#define INDEX_kX86InstShl 3740 +#define INDEX_kX86InstShld 3744 +#define INDEX_kX86InstShr 3749 +#define INDEX_kX86InstShrd 3753 +#define INDEX_kX86InstShufPD 3758 +#define INDEX_kX86InstShufPS 3765 +#define INDEX_kX86InstSqrtPD 3772 +#define INDEX_kX86InstSqrtPS 3779 +#define INDEX_kX86InstSqrtSD 3786 +#define INDEX_kX86InstSqrtSS 3793 +#define INDEX_kX86InstStc 3800 +#define INDEX_kX86InstStd 3804 +#define INDEX_kX86InstStMXCSR 3808 +#define INDEX_kX86InstSub 3816 +#define INDEX_kX86InstSubPD 3820 +#define INDEX_kX86InstSubPS 3826 +#define INDEX_kX86InstSubSD 3832 +#define INDEX_kX86InstSubSS 3838 +#define INDEX_kX86InstTest 3844 +#define INDEX_kX86InstUComISD 3849 +#define INDEX_kX86InstUComISS 3857 +#define INDEX_kX86InstUd2 3865 +#define INDEX_kX86InstUnpckHPD 3869 +#define INDEX_kX86InstUnpckHPS 3878 +#define INDEX_kX86InstUnpckLPD 3887 +#define INDEX_kX86InstUnpckLPS 3896 +#define INDEX_kX86InstXadd 3905 +#define INDEX_kX86InstXchg 3910 +#define INDEX_kX86InstXor 3915 +#define INDEX_kX86InstXorPD 3919 +#define INDEX_kX86InstXorPS 3925 +// ${X86_INST_DATA:END} + +// ============================================================================ +// [AsmJit::x86InstInfo] +// ============================================================================ + +#define INST(_Code_, _Name_, _Group_, _Flags_, _OpFlags0_, _OpFlags1_, _OpReg_, _OpCode0_, _OpCode1_) \ + { _Code_, INDEX_##_Code_, _Group_, _Flags_, { _OpFlags0_, _OpFlags1_ }, _OpReg_, { _OpCode0_, _OpCode1_ } } + +#define G(_Group_) kX86InstGroup##_Group_ +#define F(_Flags_) kX86InstFlag##_Flags_ +#define O(_Op_) kX86InstOp##_Op_ + +const X86InstInfo x86InstInfo[] = +{ + // Instruction code | Instruction name | Instruction group| Instruction flags| Operand flags[0] | Operand flags[1] | r| opCode[0] | opcode[1] + INST(kInstNone , "" , G(None) , F(None) , 0 , 0 , 0, 0 , 0), + INST(kX86InstAdc , "adc" , G(Arith) , F(Lockable) , O(GqdwbMem) , O(GqdwbMem)|O(Imm) , 2, 0x00000010, 0x00000080), + INST(kX86InstAdd , "add" , G(Arith) , F(Lockable) , O(GqdwbMem) , O(GqdwbMem)|O(Imm) , 0, 0x00000000, 0x00000080), + INST(kX86InstAddPD , "addpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F58, 0), + INST(kX86InstAddPS , "addps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F58, 0), + INST(kX86InstAddSD , "addsd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000F58, 0), + INST(kX86InstAddSS , "addss" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF3000F58, 0), + INST(kX86InstAddSubPD , "addsubpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000FD0, 0), + INST(kX86InstAddSubPS , "addsubps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000FD0, 0), + INST(kX86InstAmdPrefetch , "amd_prefetch" , G(Mem) , F(None) , O(Mem) , 0 , 0, 0x00000F0D, 0), + INST(kX86InstAmdPrefetchW , "amd_prefetchw" , G(Mem) , F(None) , O(Mem) , 0 , 1, 0x00000F0D, 0), + INST(kX86InstAnd , "and" , G(Arith) , F(Lockable) , O(GqdwbMem) , O(GqdwbMem)|O(Imm) , 4, 0x00000020, 0x00000080), + INST(kX86InstAndnPD , "andnpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F55, 0), + INST(kX86InstAndnPS , "andnps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F55, 0), + INST(kX86InstAndPD , "andpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F54, 0), + INST(kX86InstAndPS , "andps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F54, 0), + INST(kX86InstBlendPD , "blendpd" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A0D, 0), + INST(kX86InstBlendPS , "blendps" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A0C, 0), + INST(kX86InstBlendVPD , "blendvpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3815, 0), + INST(kX86InstBlendVPS , "blendvps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3814, 0), + INST(kX86InstBsf , "bsf" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000FBC, 0), + INST(kX86InstBsr , "bsr" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000FBD, 0), + INST(kX86InstBSwap , "bswap" , G(BSwap) , F(None) , O(Gqd) , 0 , 0, 0 , 0), + INST(kX86InstBt , "bt" , G(BTest) , F(None) , O(Gqdw)|O(Mem) , O(Gqdw)|O(Imm) , 4, 0x00000FA3, 0x00000FBA), + INST(kX86InstBtc , "btc" , G(BTest) , F(Lockable) , O(Gqdw)|O(Mem) , O(Gqdw)|O(Imm) , 7, 0x00000FBB, 0x00000FBA), + INST(kX86InstBtr , "btr" , G(BTest) , F(Lockable) , O(Gqdw)|O(Mem) , O(Gqdw)|O(Imm) , 6, 0x00000FB3, 0x00000FBA), + INST(kX86InstBts , "bts" , G(BTest) , F(Lockable) , O(Gqdw)|O(Mem) , O(Gqdw)|O(Imm) , 5, 0x00000FAB, 0x00000FBA), + INST(kX86InstCall , "call" , G(Call) , F(Jump) , O(Gqd) |O(Mem) , 0 , 0, 0 , 0), + INST(kX86InstCbw , "cbw" , G(Emit) , F(Special) , 0 , 0 , 0, 0x66000098, 0), + INST(kX86InstCdq , "cdq" , G(Emit) , F(Special) , 0 , 0 , 0, 0x00000099, 0), + INST(kX86InstCdqe , "cdqe" , G(Emit) , F(Special) , 0 , 0 , 0, 0x48000098, 0), + INST(kX86InstClc , "clc" , G(Emit) , F(None) , 0 , 0 , 0, 0x000000F8, 0), + INST(kX86InstCld , "cld" , G(Emit) , F(None) , 0 , 0 , 0, 0x000000FC, 0), + INST(kX86InstClFlush , "clflush" , G(Mem) , F(None) , O(Mem) , 0 , 7, 0x00000FAE, 0), + INST(kX86InstCmc , "cmc" , G(Emit) , F(None) , 0 , 0 , 0, 0x000000F5, 0), + INST(kX86InstCMovA , "cmova" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F47, 0), + INST(kX86InstCMovAE , "cmovae" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F43, 0), + INST(kX86InstCMovB , "cmovb" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F42, 0), + INST(kX86InstCMovBE , "cmovbe" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F46, 0), + INST(kX86InstCMovC , "cmovc" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F42, 0), + INST(kX86InstCMovE , "cmove" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F44, 0), + INST(kX86InstCMovG , "cmovg" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4F, 0), + INST(kX86InstCMovGE , "cmovge" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4D, 0), + INST(kX86InstCMovL , "cmovl" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4C, 0), + INST(kX86InstCMovLE , "cmovle" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4E, 0), + INST(kX86InstCMovNA , "cmovna" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F46, 0), + INST(kX86InstCMovNAE , "cmovnae" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F42, 0), + INST(kX86InstCMovNB , "cmovnb" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F43, 0), + INST(kX86InstCMovNBE , "cmovnbe" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F47, 0), + INST(kX86InstCMovNC , "cmovnc" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F43, 0), + INST(kX86InstCMovNE , "cmovne" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F45, 0), + INST(kX86InstCMovNG , "cmovng" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4E, 0), + INST(kX86InstCMovNGE , "cmovnge" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4C, 0), + INST(kX86InstCMovNL , "cmovnl" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4D, 0), + INST(kX86InstCMovNLE , "cmovnle" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4F, 0), + INST(kX86InstCMovNO , "cmovno" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F41, 0), + INST(kX86InstCMovNP , "cmovnp" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4B, 0), + INST(kX86InstCMovNS , "cmovns" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F49, 0), + INST(kX86InstCMovNZ , "cmovnz" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F45, 0), + INST(kX86InstCMovO , "cmovo" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F40, 0), + INST(kX86InstCMovP , "cmovp" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4A, 0), + INST(kX86InstCMovPE , "cmovpe" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4A, 0), + INST(kX86InstCMovPO , "cmovpo" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F4B, 0), + INST(kX86InstCMovS , "cmovs" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F48, 0), + INST(kX86InstCMovZ , "cmovz" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0x00000F44, 0), + INST(kX86InstCmp , "cmp" , G(Arith) , F(None) , O(GqdwbMem) , O(GqdwbMem)|O(Imm) , 7, 0x00000038, 0x00000080), + INST(kX86InstCmpPD , "cmppd" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000FC2, 0), + INST(kX86InstCmpPS , "cmpps" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000FC2, 0), + INST(kX86InstCmpSD , "cmpsd" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000FC2, 0), + INST(kX86InstCmpSS , "cmpss" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF3000FC2, 0), + INST(kX86InstCmpXCHG , "cmpxchg" , G(RmReg) , F(Special)|F(Lockable), 0 , 0 , 0, 0x00000FB0, 0), + INST(kX86InstCmpXCHG16B , "cmpxchg16b" , G(Mem) , F(Special) , O(Mem) , 0 , 1, 0x00000FC7, 1 /* RexW */), + INST(kX86InstCmpXCHG8B , "cmpxchg8b" , G(Mem) , F(Special) , O(Mem) , 0 , 1, 0x00000FC7, 0), + INST(kX86InstComISD , "comisd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F2F, 0), + INST(kX86InstComISS , "comiss" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F2F, 0), + INST(kX86InstCpuId , "cpuid" , G(Emit) , F(Special) , 0 , 0 , 0, 0x00000FA2, 0), + INST(kX86InstCqo , "cqo" , G(Emit) , F(Special) , 0 , 0 , 0, 0x48000099, 0), // TODO, set RexW bit instead? + INST(kX86InstCrc32 , "crc32" , G(Crc32) , F(None) , O(Gqd) , O(GqdwbMem) , 0, 0xF20F38F0, 0), + INST(kX86InstCvtDQ2PD , "cvtdq2pd" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0xF3000FE6, 0), + INST(kX86InstCvtDQ2PS , "cvtdq2ps" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x00000F5B, 0), + INST(kX86InstCvtPD2DQ , "cvtpd2dq" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0xF2000FE6, 0), + INST(kX86InstCvtPD2PI , "cvtpd2pi" , G(MmuRmI) , F(Mov) , O(Mm) , O(XmmMem) , 0, 0x66000F2D, 0), + INST(kX86InstCvtPD2PS , "cvtpd2ps" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x66000F5A, 0), + INST(kX86InstCvtPI2PD , "cvtpi2pd" , G(MmuRmI) , F(Mov) , O(Xmm) , O(MmMem) , 0, 0x66000F2A, 0), + INST(kX86InstCvtPI2PS , "cvtpi2ps" , G(MmuRmI) , F(None) , O(Xmm) , O(MmMem) , 0, 0x00000F2A, 0), + INST(kX86InstCvtPS2DQ , "cvtps2dq" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x66000F5B, 0), + INST(kX86InstCvtPS2PD , "cvtps2pd" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x00000F5A, 0), + INST(kX86InstCvtPS2PI , "cvtps2pi" , G(MmuRmI) , F(Mov) , O(Mm) , O(XmmMem) , 0, 0x00000F2D, 0), + INST(kX86InstCvtSD2SI , "cvtsd2si" , G(MmuRmI) , F(Mov) , O(Gqd) , O(XmmMem) , 0, 0xF2000F2D, 0), + INST(kX86InstCvtSD2SS , "cvtsd2ss" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000F5A, 0), + INST(kX86InstCvtSI2SD , "cvtsi2sd" , G(MmuRmI) , F(None) , O(Xmm) , O(Gqd)|O(Mem) , 0, 0xF2000F2A, 0), + INST(kX86InstCvtSI2SS , "cvtsi2ss" , G(MmuRmI) , F(None) , O(Xmm) , O(Gqd)|O(Mem) , 0, 0xF3000F2A, 0), + INST(kX86InstCvtSS2SD , "cvtss2sd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF3000F5A, 0), + INST(kX86InstCvtSS2SI , "cvtss2si" , G(MmuRmI) , F(None) , O(Gqd) , O(XmmMem) , 0, 0xF3000F2D, 0), + INST(kX86InstCvttPD2DQ , "cvttpd2dq" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x66000FE6, 0), + INST(kX86InstCvttPD2PI , "cvttpd2pi" , G(MmuRmI) , F(Mov) , O(Mm) , O(XmmMem) , 0, 0x66000F2C, 0), + INST(kX86InstCvttPS2DQ , "cvttps2dq" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0xF3000F5B, 0), + INST(kX86InstCvttPS2PI , "cvttps2pi" , G(MmuRmI) , F(Mov) , O(Mm) , O(XmmMem) , 0, 0x00000F2C, 0), + INST(kX86InstCvttSD2SI , "cvttsd2si" , G(MmuRmI) , F(None) , O(Gqd) , O(XmmMem) , 0, 0xF2000F2C, 0), + INST(kX86InstCvttSS2SI , "cvttss2si" , G(MmuRmI) , F(None) , O(Gqd) , O(XmmMem) , 0, 0xF3000F2C, 0), + INST(kX86InstCwd , "cwd" , G(Emit) , F(Special) , 0 , 0 , 0, 0x66000099, 0), + INST(kX86InstCwde , "cwde" , G(Emit) , F(Special) , 0 , 0 , 0, 0x00000098, 0), + INST(kX86InstDaa , "daa" , G(Emit) , F(Special) , 0 , 0 , 0, 0x00000027, 0), + INST(kX86InstDas , "das" , G(Emit) , F(Special) , 0 , 0 , 0, 0x0000002F, 0), + INST(kX86InstDec , "dec" , G(IncDec) , F(Lockable) , O(GqdwbMem) , 0 , 1, 0x00000048, 0x000000FE), + INST(kX86InstDiv , "div" , G(Rm) , F(Special) , 0 , 0 , 6, 0x000000F6, 0), + INST(kX86InstDivPD , "divpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F5E, 0), + INST(kX86InstDivPS , "divps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F5E, 0), + INST(kX86InstDivSD , "divsd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000F5E, 0), + INST(kX86InstDivSS , "divss" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF3000F5E, 0), + INST(kX86InstDpPD , "dppd" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A41, 0), + INST(kX86InstDpPS , "dpps" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A40, 0), + INST(kX86InstEmms , "emms" , G(Emit) , F(None) , 0 , 0 , 0, 0x00000F77, 0), + INST(kX86InstEnter , "enter" , G(Enter) , F(Special) , 0 , 0 , 0, 0x000000C8, 0), + INST(kX86InstExtractPS , "extractps" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A17, 0), + INST(kX86InstF2XM1 , "f2xm1" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9F0, 0), + INST(kX86InstFAbs , "fabs" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9E1, 0), + INST(kX86InstFAdd , "fadd" , G(X87StM) , F(Fpu) , 0 , 0 , 0, 0xD8DCC0C0, 0), + INST(kX86InstFAddP , "faddp" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DEC0, 0), + INST(kX86InstFBLd , "fbld" , G(Mem) , F(Fpu) , O(Mem) , 0 , 4, 0x000000DF, 0), + INST(kX86InstFBStP , "fbstp" , G(Mem) , F(Fpu) , O(Mem) , 0 , 6, 0x000000DF, 0), + INST(kX86InstFCHS , "fchs" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9E0, 0), + INST(kX86InstFClex , "fclex" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x9B00DBE2, 0), + INST(kX86InstFCMovB , "fcmovb" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DAC0, 0), + INST(kX86InstFCMovBE , "fcmovbe" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DAD0, 0), + INST(kX86InstFCMovE , "fcmove" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DAC8, 0), + INST(kX86InstFCMovNB , "fcmovnb" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DBC0, 0), + INST(kX86InstFCMovNBE , "fcmovnbe" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DBD0, 0), + INST(kX86InstFCMovNE , "fcmovne" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DBC8, 0), + INST(kX86InstFCMovNU , "fcmovnu" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DBD8, 0), + INST(kX86InstFCMovU , "fcmovu" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DAD8, 0), + INST(kX86InstFCom , "fcom" , G(X87StM) , F(Fpu) , 0 , 0 , 2, 0xD8DCD0D0, 0), + INST(kX86InstFComI , "fcomi" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DBF0, 0), + INST(kX86InstFComIP , "fcomip" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DFF0, 0), + INST(kX86InstFComP , "fcomp" , G(X87StM) , F(Fpu) , 0 , 0 , 3, 0xD8DCD8D8, 0), + INST(kX86InstFComPP , "fcompp" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000DED9, 0), + INST(kX86InstFCos , "fcos" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9FF, 0), + INST(kX86InstFDecStP , "fdecstp" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9F6, 0), + INST(kX86InstFDiv , "fdiv" , G(X87StM) , F(Fpu) , 0 , 0 , 6, 0xD8DCF0F8, 0), + INST(kX86InstFDivP , "fdivp" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DEF8, 0), + INST(kX86InstFDivR , "fdivr" , G(X87StM) , F(Fpu) , 0 , 0 , 7, 0xD8DCF8F0, 0), + INST(kX86InstFDivRP , "fdivrp" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DEF0, 0), + INST(kX86InstFEmms , "femms" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x00000F0E, 0), + INST(kX86InstFFree , "ffree" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DDC0, 0), + INST(kX86InstFIAdd , "fiadd" , G(X87Mem) , F(Fpu) , O(StM2_4) , 0 , 0, 0xDEDA0000, 0), + INST(kX86InstFICom , "ficom" , G(X87Mem) , F(Fpu) , O(StM2_4) , 0 , 2, 0xDEDA0000, 0), + INST(kX86InstFIComP , "ficomp" , G(X87Mem) , F(Fpu) , O(StM2_4) , 0 , 3, 0xDEDA0000, 0), + INST(kX86InstFIDiv , "fidiv" , G(X87Mem) , F(Fpu) , O(StM2_4) , 0 , 6, 0xDEDA0000, 0), + INST(kX86InstFIDivR , "fidivr" , G(X87Mem) , F(Fpu) , O(StM2_4) , 0 , 7, 0xDEDA0000, 0), + INST(kX86InstFILd , "fild" , G(X87Mem) , F(Fpu) , O(StM2_4_8) , 0 , 0, 0xDFDBDF05, 0), + INST(kX86InstFIMul , "fimul" , G(X87Mem) , F(Fpu) , O(StM2_4) , 0 , 1, 0xDEDA0000, 0), + INST(kX86InstFIncStP , "fincstp" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9F7, 0), + INST(kX86InstFInit , "finit" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x9B00DBE3, 0), + INST(kX86InstFISt , "fist" , G(X87Mem) , F(Fpu) , O(StM2_4) , 0 , 2, 0xDFDB0000, 0), + INST(kX86InstFIStP , "fistp" , G(X87Mem) , F(Fpu) , O(StM2_4_8) , 0 , 3, 0xDFDBDF07, 0), + INST(kX86InstFISttP , "fisttp" , G(X87Mem) , F(Fpu) , O(StM2_4_8) , 0 , 1, 0xDFDBDD01, 0), + INST(kX86InstFISub , "fisub" , G(X87Mem) , F(Fpu) , O(StM2_4) , 0 , 4, 0xDEDA0000, 0), + INST(kX86InstFISubR , "fisubr" , G(X87Mem) , F(Fpu) , O(StM2_4) , 0 , 5, 0xDEDA0000, 0), + INST(kX86InstFLd , "fld" , G(X87FldFst) , F(Fpu) , O(StM4_8_10) , 0 , 0, 0x00D9DD00, 0xD9C0DB05), + INST(kX86InstFLd1 , "fld1" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9E8, 0), + INST(kX86InstFLdCw , "fldcw" , G(Mem) , F(Fpu) , O(Mem) , 0 , 5, 0x000000D9, 0), + INST(kX86InstFLdEnv , "fldenv" , G(Mem) , F(Fpu) , O(Mem) , 0 , 4, 0x000000D9, 0), + INST(kX86InstFLdL2E , "fldl2e" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9EA, 0), + INST(kX86InstFLdL2T , "fldl2t" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9E9, 0), + INST(kX86InstFLdLg2 , "fldlg2" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9EC, 0), + INST(kX86InstFLdLn2 , "fldln2" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9ED, 0), + INST(kX86InstFLdPi , "fldpi" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9EB, 0), + INST(kX86InstFLdZ , "fldz" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9EE, 0), + INST(kX86InstFMul , "fmul" , G(X87StM) , F(Fpu) , 0 , 0 , 1, 0xD8DCC8C8, 0), + INST(kX86InstFMulP , "fmulp" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DEC8, 0), + INST(kX86InstFNClex , "fnclex" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000DBE2, 0), + INST(kX86InstFNInit , "fninit" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000DBE3, 0), + INST(kX86InstFNop , "fnop" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9D0, 0), + INST(kX86InstFNSave , "fnsave" , G(Mem) , F(Fpu) , O(Mem) , 0 , 6, 0x000000DD, 0), + INST(kX86InstFNStCw , "fnstcw" , G(Mem) , F(Fpu) , O(Mem) , 0 , 7, 0x000000D9, 0), + INST(kX86InstFNStEnv , "fnstenv" , G(Mem) , F(Fpu) , O(Mem) , 0 , 6, 0x000000D9, 0), + INST(kX86InstFNStSw , "fnstsw" , G(X87Status) , F(Fpu) , O(Mem) , 0 , 7, 0x000000DD, 0x0000DFE0), + INST(kX86InstFPAtan , "fpatan" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9F3, 0), + INST(kX86InstFPRem , "fprem" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9F8, 0), + INST(kX86InstFPRem1 , "fprem1" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9F5, 0), + INST(kX86InstFPTan , "fptan" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9F2, 0), + INST(kX86InstFRndInt , "frndint" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9FC, 0), + INST(kX86InstFRstor , "frstor" , G(Mem) , F(Fpu) , O(Mem) , 0 , 4, 0x000000DD, 0), + INST(kX86InstFSave , "fsave" , G(Mem) , F(Fpu) , O(Mem) , 0 , 6, 0x9B0000DD, 0), + INST(kX86InstFScale , "fscale" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9FD, 0), + INST(kX86InstFSin , "fsin" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9FE, 0), + INST(kX86InstFSinCos , "fsincos" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9FB, 0), + INST(kX86InstFSqrt , "fsqrt" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9FA, 0), + INST(kX86InstFSt , "fst" , G(X87FldFst) , F(Fpu) , O(StM4_8) , 0 , 2, 0x00D9DD02, 0xDDD00000), + INST(kX86InstFStCw , "fstcw" , G(Mem) , F(Fpu) , O(Mem) , 0 , 7, 0x9B0000D9, 0), + INST(kX86InstFStEnv , "fstenv" , G(Mem) , F(Fpu) , O(Mem) , 0 , 6, 0x9B0000D9, 0), + INST(kX86InstFStP , "fstp" , G(X87FldFst) , F(Fpu) , O(StM4_8_10) , 0 , 3, 0x00D9DD03, 0xDDD8DB07), + INST(kX86InstFStSw , "fstsw" , G(X87Status) , F(Fpu) , O(Mem) , 0 , 7, 0x9B0000DD, 0x9B00DFE0), + INST(kX86InstFSub , "fsub" , G(X87StM) , F(Fpu) , 0 , 0 , 4, 0xD8DCE0E8, 0), + INST(kX86InstFSubP , "fsubp" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DEE8, 0), + INST(kX86InstFSubR , "fsubr" , G(X87StM) , F(Fpu) , 0 , 0 , 5, 0xD8DCE8E0, 0), + INST(kX86InstFSubRP , "fsubrp" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DEE0, 0), + INST(kX86InstFTst , "ftst" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9E4, 0), + INST(kX86InstFUCom , "fucom" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DDE0, 0), + INST(kX86InstFUComI , "fucomi" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DBE8, 0), + INST(kX86InstFUComIP , "fucomip" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DFE8, 0), + INST(kX86InstFUComP , "fucomp" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000DDE8, 0), + INST(kX86InstFUComPP , "fucompp" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000DAE9, 0), + INST(kX86InstFWait , "fwait" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x000000DB, 0), + INST(kX86InstFXam , "fxam" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9E5, 0), + INST(kX86InstFXch , "fxch" , G(X87StI) , F(Fpu) , 0 , 0 , 0, 0x0000D9C8, 0), + INST(kX86InstFXRstor , "fxrstor" , G(Mem) , F(Fpu) , 0 , 0 , 1, 0x00000FAE, 0), + INST(kX86InstFXSave , "fxsave" , G(Mem) , F(Fpu) , 0 , 0 , 0, 0x00000FAE, 0), + INST(kX86InstFXtract , "fxtract" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9F4, 0), + INST(kX86InstFYL2X , "fyl2x" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9F1, 0), + INST(kX86InstFYL2XP1 , "fyl2xp1" , G(Emit) , F(Fpu) , 0 , 0 , 0, 0x0000D9F9, 0), + INST(kX86InstHAddPD , "haddpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F7C, 0), + INST(kX86InstHAddPS , "haddps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000F7C, 0), + INST(kX86InstHSubPD , "hsubpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F7D, 0), + INST(kX86InstHSubPS , "hsubps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000F7D, 0), + INST(kX86InstIDiv , "idiv" , G(Rm) , F(Special) , 0 , 0 , 7, 0x000000F6, 0), + INST(kX86InstIMul , "imul" , G(IMul) , F(Special) , 0 , 0 , 0, 0 , 0), + INST(kX86InstInc , "inc" , G(IncDec) , F(Lockable) , O(GqdwbMem) , 0 , 0, 0x00000040, 0x000000FE), + INST(kX86InstInt3 , "int3" , G(Emit) , F(None) , 0 , 0 , 0, 0x000000CC, 0), + INST(kX86InstJA , "ja" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x7 , 0), + INST(kX86InstJAE , "jae" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x3 , 0), + INST(kX86InstJB , "jb" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x2 , 0), + INST(kX86InstJBE , "jbe" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x6 , 0), + INST(kX86InstJC , "jc" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x2 , 0), + INST(kX86InstJE , "je" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x4 , 0), + INST(kX86InstJG , "jg" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xF , 0), + INST(kX86InstJGE , "jge" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xD , 0), + INST(kX86InstJL , "jl" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xC , 0), + INST(kX86InstJLE , "jle" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xE , 0), + INST(kX86InstJNA , "jna" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x6 , 0), + INST(kX86InstJNAE , "jnae" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x2 , 0), + INST(kX86InstJNB , "jnb" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x3 , 0), + INST(kX86InstJNBE , "jnbe" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x7 , 0), + INST(kX86InstJNC , "jnc" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x3 , 0), + INST(kX86InstJNE , "jne" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x5 , 0), + INST(kX86InstJNG , "jng" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xE , 0), + INST(kX86InstJNGE , "jnge" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xC , 0), + INST(kX86InstJNL , "jnl" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xD , 0), + INST(kX86InstJNLE , "jnle" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xF , 0), + INST(kX86InstJNO , "jno" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x1 , 0), + INST(kX86InstJNP , "jnp" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xB , 0), + INST(kX86InstJNS , "jns" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x9 , 0), + INST(kX86InstJNZ , "jnz" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x5 , 0), + INST(kX86InstJO , "jo" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x0 , 0), + INST(kX86InstJP , "jp" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xA , 0), + INST(kX86InstJPE , "jpe" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xA , 0), + INST(kX86InstJPO , "jpo" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0xB , 0), + INST(kX86InstJS , "js" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x8 , 0), + INST(kX86InstJZ , "jz" , G(Jcc) , F(Jump) , 0 , 0 , 0, 0x4 , 0), + INST(kX86InstJmp , "jmp" , G(Jmp) , F(Jump) , 0 , 0 , 0, 0 , 0), + INST(kX86InstLdDQU , "lddqu" , G(MmuRmI) , F(None) , O(Xmm) , O(Mem) , 0, 0xF2000FF0, 0), + INST(kX86InstLdMXCSR , "ldmxcsr" , G(Mem) , F(None) , O(Mem) , 0 , 2, 0x00000FAE, 0), + INST(kX86InstLahf , "lahf" , G(Emit) , F(Special) , 0 , 0 , 0, 0x0000009F, 0), + INST(kX86InstLea , "lea" , G(Lea) , F(None) , O(Gqd) , O(Mem) , 0, 0 , 0), + INST(kX86InstLeave , "leave" , G(Emit) , F(Special) , 0 , 0 , 0, 0x000000C9, 0), + INST(kX86InstLFence , "lfence" , G(Emit) , F(None) , 0 , 0 , 0, 0x000FAEE8, 0), + INST(kX86InstMaskMovDQU , "maskmovdqu" , G(MmuRmI) , F(Special) , O(Xmm) , O(Xmm) , 0, 0x66000F57, 0), + INST(kX86InstMaskMovQ , "maskmovq" , G(MmuRmI) , F(Special) , O(Mm) , O(Mm) , 0, 0x00000FF7, 0), + INST(kX86InstMaxPD , "maxpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F5F, 0), + INST(kX86InstMaxPS , "maxps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F5F, 0), + INST(kX86InstMaxSD , "maxsd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000F5F, 0), + INST(kX86InstMaxSS , "maxss" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF3000F5F, 0), + INST(kX86InstMFence , "mfence" , G(Emit) , F(None) , 0 , 0 , 0, 0x000FAEF0, 0), + INST(kX86InstMinPD , "minpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F5D, 0), + INST(kX86InstMinPS , "minps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F5D, 0), + INST(kX86InstMinSD , "minsd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000F5D, 0), + INST(kX86InstMinSS , "minss" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF3000F5D, 0), + INST(kX86InstMonitor , "monitor" , G(Emit) , F(Special) , 0 , 0 , 0, 0x000F01C8, 0), + INST(kX86InstMov , "mov" , G(Mov) , F(Mov) , O(GqdwbMem) , O(GqdwbMem)|O(Imm) , 0, 0 , 0), + INST(kX86InstMovAPD , "movapd" , G(MmuMov) , F(Mov) , O(XmmMem) , O(XmmMem) , 0, 0x66000F28, 0x66000F29), + INST(kX86InstMovAPS , "movaps" , G(MmuMov) , F(Mov) , O(XmmMem) , O(XmmMem) , 0, 0x00000F28, 0x00000F29), + INST(kX86InstMovBE , "movbe" , G(MovBE) , F(Mov) , O(Gqdw)|O(Mem) , O(Gqdw)|O(Mem) , 0, 0x000F38F0, 0x000F38F1), + INST(kX86InstMovD , "movd" , G(MmuMovD) , F(Mov) , O(Gd)|O(MmXmmMem) , O(Gd)|O(MmXmmMem) , 0, 0 , 0), + INST(kX86InstMovDDup , "movddup" , G(MmuMov) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0xF2000F12, 0), + INST(kX86InstMovDQ2Q , "movdq2q" , G(MmuMov) , F(Mov) , O(Mm) , O(Xmm) , 0, 0xF2000FD6, 0), + INST(kX86InstMovDQA , "movdqa" , G(MmuMov) , F(Mov) , O(XmmMem) , O(XmmMem) , 0, 0x66000F6F, 0x66000F7F), + INST(kX86InstMovDQU , "movdqu" , G(MmuMov) , F(Mov) , O(XmmMem) , O(XmmMem) , 0, 0xF3000F6F, 0xF3000F7F), + INST(kX86InstMovHLPS , "movhlps" , G(MmuMov) , F(None) , O(Xmm) , O(Xmm) , 0, 0x00000F12, 0), + INST(kX86InstMovHPD , "movhpd" , G(MmuMov) , F(None) , O(XmmMem) , O(XmmMem) , 0, 0x66000F16, 0x66000F17), + INST(kX86InstMovHPS , "movhps" , G(MmuMov) , F(None) , O(XmmMem) , O(XmmMem) , 0, 0x00000F16, 0x00000F17), + INST(kX86InstMovLHPS , "movlhps" , G(MmuMov) , F(None) , O(Xmm) , O(Xmm) , 0, 0x00000F16, 0), + INST(kX86InstMovLPD , "movlpd" , G(MmuMov) , F(None) , O(XmmMem) , O(XmmMem) , 0, 0x66000F12, 0x66000F13), + INST(kX86InstMovLPS , "movlps" , G(MmuMov) , F(None) , O(XmmMem) , O(XmmMem) , 0, 0x00000F12, 0x00000F13), + INST(kX86InstMovMskPD , "movmskpd" , G(MmuMov) , F(Mov) , O(Gqd)|O(NoRex) , O(Xmm) , 0, 0x66000F50, 0), + INST(kX86InstMovMskPS , "movmskps" , G(MmuMov) , F(Mov) , O(Gqd)|O(NoRex) , O(Xmm) , 0, 0x00000F50, 0), + INST(kX86InstMovNTDQ , "movntdq" , G(MmuMov) , F(None) , O(Mem) , O(Xmm) , 0, 0 , 0x66000FE7), + INST(kX86InstMovNTDQA , "movntdqa" , G(MmuMov) , F(Mov) , O(Xmm) , O(Mem) , 0, 0x660F382A, 0), + INST(kX86InstMovNTI , "movnti" , G(MmuMov) , F(Mov) , O(Mem) , O(Gqd) , 0, 0 , 0x00000FC3), + INST(kX86InstMovNTPD , "movntpd" , G(MmuMov) , F(None) , O(Mem) , O(Xmm) , 0, 0 , 0x66000F2B), + INST(kX86InstMovNTPS , "movntps" , G(MmuMov) , F(None) , O(Mem) , O(Xmm) , 0, 0 , 0x00000F2B), + INST(kX86InstMovNTQ , "movntq" , G(MmuMov) , F(None) , O(Mem) , O(Mm) , 0, 0 , 0x00000FE7), + INST(kX86InstMovQ , "movq" , G(MmuMovQ) , F(Mov) , O(Gq)|O(MmXmmMem) , O(Gq)|O(MmXmmMem) , 0, 0 , 0), + INST(kX86InstMovQ2DQ , "movq2dq" , G(MmuRmI) , F(Mov) , O(Xmm) , O(Mm) , 0, 0xF3000FD6, 0), + INST(kX86InstMovSD , "movsd" , G(MmuMov) , F(None) , O(XmmMem) , O(XmmMem) , 0, 0xF2000F10, 0xF2000F11), + INST(kX86InstMovSHDup , "movshdup" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0xF3000F16, 0), + INST(kX86InstMovSLDup , "movsldup" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0xF3000F12, 0), + INST(kX86InstMovSS , "movss" , G(MmuMov) , F(None) , O(XmmMem) , O(XmmMem) , 0, 0xF3000F10, 0xF3000F11), + INST(kX86InstMovSX , "movsx" , G(MovSxMovZx) , F(None) , O(Gqdw) , O(GwbMem) , 0, 0x00000FBE, 0), + INST(kX86InstMovSXD , "movsxd" , G(MovSxD) , F(None) , O(Gq) , O(GdMem) , 0, 0 , 0), + INST(kX86InstMovUPD , "movupd" , G(MmuMov) , F(Mov) , O(XmmMem) , O(XmmMem) , 0, 0x66000F10, 0x66000F11), + INST(kX86InstMovUPS , "movups" , G(MmuMov) , F(Mov) , O(XmmMem) , O(XmmMem) , 0, 0x00000F10, 0x00000F11), + INST(kX86InstMovZX , "movzx" , G(MovSxMovZx) , F(Mov) , O(Gqdw) , O(GwbMem) , 0, 0x00000FB6, 0), + INST(kX86InstMovPtr , "mov_ptr" , G(MovPtr) , F(Mov)|F(Special), O(Gqdwb) , O(Imm) , 0, 0 , 0), + INST(kX86InstMPSADBW , "mpsadbw" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A42, 0), + INST(kX86InstMul , "mul" , G(Rm) , F(Special) , 0 , 0 , 4, 0x000000F6, 0), + INST(kX86InstMulPD , "mulpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F59, 0), + INST(kX86InstMulPS , "mulps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F59, 0), + INST(kX86InstMulSD , "mulsd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000F59, 0), + INST(kX86InstMulSS , "mulss" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF3000F59, 0), + INST(kX86InstMWait , "mwait" , G(Emit) , F(Special) , 0 , 0 , 0, 0x000F01C9, 0), + INST(kX86InstNeg , "neg" , G(Rm) , F(Lockable) , O(GqdwbMem) , 0 , 3, 0x000000F6, 0), + INST(kX86InstNop , "nop" , G(Emit) , F(None) , 0 , 0 , 0, 0x00000090, 0), + INST(kX86InstNot , "not" , G(Rm) , F(Lockable) , O(GqdwbMem) , 0 , 2, 0x000000F6, 0), + INST(kX86InstOr , "or" , G(Arith) , F(Lockable) , O(GqdwbMem) , O(GqdwbMem)|O(Imm) , 1, 0x00000008, 0x00000080), + INST(kX86InstOrPD , "orpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F56, 0), + INST(kX86InstOrPS , "orps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F56, 0), + INST(kX86InstPAbsB , "pabsb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F381C, 0), + INST(kX86InstPAbsD , "pabsd" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F381E, 0), + INST(kX86InstPAbsW , "pabsw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F381D, 0), + INST(kX86InstPackSSDW , "packssdw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F6B, 0), + INST(kX86InstPackSSWB , "packsswb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F63, 0), + INST(kX86InstPackUSDW , "packusdw" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F382B, 0), + INST(kX86InstPackUSWB , "packuswb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F67, 0), + INST(kX86InstPAddB , "paddb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FFC, 0), + INST(kX86InstPAddD , "paddd" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FFE, 0), + INST(kX86InstPAddQ , "paddq" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FD4, 0), + INST(kX86InstPAddSB , "paddsb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FEC, 0), + INST(kX86InstPAddSW , "paddsw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FED, 0), + INST(kX86InstPAddUSB , "paddusb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FDC, 0), + INST(kX86InstPAddUSW , "paddusw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FDD, 0), + INST(kX86InstPAddW , "paddw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FFD, 0), + INST(kX86InstPAlignR , "palignr" , G(MmuRmImm8) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F3A0F, 0), + INST(kX86InstPAnd , "pand" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FDB, 0), + INST(kX86InstPAndN , "pandn" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FDF, 0), + INST(kX86InstPause , "pause" , G(Emit) , F(None) , 0 , 0 , 0, 0xF3000090, 0), + INST(kX86InstPAvgB , "pavgb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FE0, 0), + INST(kX86InstPAvgW , "pavgw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FE3, 0), + INST(kX86InstPBlendVB , "pblendvb" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3810, 0), + INST(kX86InstPBlendW , "pblendw" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A0E, 0), + INST(kX86InstPCmpEqB , "pcmpeqb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F74, 0), + INST(kX86InstPCmpEqD , "pcmpeqd" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F76, 0), + INST(kX86InstPCmpEqQ , "pcmpeqq" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3829, 0), + INST(kX86InstPCmpEqW , "pcmpeqw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F75, 0), + INST(kX86InstPCmpEStrI , "pcmpestri" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A61, 0), + INST(kX86InstPCmpEStrM , "pcmpestrm" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A60, 0), + INST(kX86InstPCmpGtB , "pcmpgtb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F64, 0), + INST(kX86InstPCmpGtD , "pcmpgtd" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F66, 0), + INST(kX86InstPCmpGtQ , "pcmpgtq" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3837, 0), + INST(kX86InstPCmpGtW , "pcmpgtw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F65, 0), + INST(kX86InstPCmpIStrI , "pcmpistri" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A63, 0), + INST(kX86InstPCmpIStrM , "pcmpistrm" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A62, 0), + INST(kX86InstPExtrB , "pextrb" , G(MmuExtract) , F(None) , O(Gd)|O(Gb)|O(Mem) , O(Xmm) , 0, 0x000F3A14, 0), + INST(kX86InstPExtrD , "pextrd" , G(MmuExtract) , F(None) , O(Gd) |O(Mem) , O(Xmm) , 0, 0x000F3A16, 0), + INST(kX86InstPExtrQ , "pextrq" , G(MmuExtract) , F(None) , O(Gqd) |O(Mem) , O(Xmm) , 1, 0x000F3A16, 0), + INST(kX86InstPExtrW , "pextrw" , G(MmuExtract) , F(None) , O(Gd) |O(Mem) , O(MmXmm) , 0, 0x000F3A15, 0), + INST(kX86InstPF2ID , "pf2id" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x1D), + INST(kX86InstPF2IW , "pf2iw" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x1C), + INST(kX86InstPFAcc , "pfacc" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0xAE), + INST(kX86InstPFAdd , "pfadd" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x9E), + INST(kX86InstPFCmpEQ , "pfcmpeq" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0xB0), + INST(kX86InstPFCmpGE , "pfcmpge" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x90), + INST(kX86InstPFCmpGT , "pfcmpgt" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0xA0), + INST(kX86InstPFMax , "pfmax" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0xA4), + INST(kX86InstPFMin , "pfmin" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x94), + INST(kX86InstPFMul , "pfmul" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0xB4), + INST(kX86InstPFNAcc , "pfnacc" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x8A), + INST(kX86InstPFPNAcc , "pfpnacc" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x8E), + INST(kX86InstPFRcp , "pfrcp" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x96), + INST(kX86InstPFRcpIt1 , "pfrcpit1" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0xA6), + INST(kX86InstPFRcpIt2 , "pfrcpit2" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0xB6), + INST(kX86InstPFRSqIt1 , "pfrsqit1" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0xA7), + INST(kX86InstPFRSqrt , "pfrsqrt" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x97), + INST(kX86InstPFSub , "pfsub" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x9A), + INST(kX86InstPFSubR , "pfsubr" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0xAA), + INST(kX86InstPHAddD , "phaddd" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F3802, 0), + INST(kX86InstPHAddSW , "phaddsw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F3803, 0), + INST(kX86InstPHAddW , "phaddw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F3801, 0), + INST(kX86InstPHMinPOSUW , "phminposuw" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3841, 0), + INST(kX86InstPHSubD , "phsubd" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F3806, 0), + INST(kX86InstPHSubSW , "phsubsw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F3807, 0), + INST(kX86InstPHSubW , "phsubw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F3805, 0), + INST(kX86InstPI2FD , "pi2fd" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x0D), + INST(kX86InstPI2FW , "pi2fw" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0x0C), + INST(kX86InstPInsRB , "pinsrb" , G(MmuRmImm8) , F(None) , O(Xmm) , O(Gd) | O(Mem) , 0, 0x660F3A20, 0), + INST(kX86InstPInsRD , "pinsrd" , G(MmuRmImm8) , F(None) , O(Xmm) , O(Gd) | O(Mem) , 0, 0x660F3A22, 0), + INST(kX86InstPInsRQ , "pinsrq" , G(MmuRmImm8) , F(None) , O(Xmm) , O(Gq) | O(Mem) , 0, 0x660F3A22, 0), + INST(kX86InstPInsRW , "pinsrw" , G(MmuRmImm8) , F(None) , O(MmXmm) , O(Gd) | O(Mem) , 0, 0x00000FC4, 0), + INST(kX86InstPMAddUBSW , "pmaddubsw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F3804, 0), + INST(kX86InstPMAddWD , "pmaddwd" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FF5, 0), + INST(kX86InstPMaxSB , "pmaxsb" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F383C, 0), + INST(kX86InstPMaxSD , "pmaxsd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F383D, 0), + INST(kX86InstPMaxSW , "pmaxsw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FEE, 0), + INST(kX86InstPMaxUB , "pmaxub" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FDE, 0), + INST(kX86InstPMaxUD , "pmaxud" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F383F, 0), + INST(kX86InstPMaxUW , "pmaxuw" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F383E, 0), + INST(kX86InstPMinSB , "pminsb" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3838, 0), + INST(kX86InstPMinSD , "pminsd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3839, 0), + INST(kX86InstPMinSW , "pminsw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FEA, 0), + INST(kX86InstPMinUB , "pminub" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FDA, 0), + INST(kX86InstPMinUD , "pminud" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F383B, 0), + INST(kX86InstPMinUW , "pminuw" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F383A, 0), + INST(kX86InstPMovMskB , "pmovmskb" , G(MmuRmI) , F(Mov) , O(Gqd) , O(MmXmm) , 0, 0x00000FD7, 0), + INST(kX86InstPMovSXBD , "pmovsxbd" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3821, 0), + INST(kX86InstPMovSXBQ , "pmovsxbq" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3822, 0), + INST(kX86InstPMovSXBW , "pmovsxbw" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3820, 0), + INST(kX86InstPMovSXDQ , "pmovsxdq" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3825, 0), + INST(kX86InstPMovSXWD , "pmovsxwd" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3823, 0), + INST(kX86InstPMovSXWQ , "pmovsxwq" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3824, 0), + INST(kX86InstPMovZXBD , "pmovzxbd" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3831, 0), + INST(kX86InstPMovZXBQ , "pmovzxbq" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3832, 0), + INST(kX86InstPMovZXBW , "pmovzxbw" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3830, 0), + INST(kX86InstPMovZXDQ , "pmovzxdq" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3835, 0), + INST(kX86InstPMovZXWD , "pmovzxwd" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3833, 0), + INST(kX86InstPMovZXWQ , "pmovzxwq" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3834, 0), + INST(kX86InstPMulDQ , "pmuldq" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3828, 0), + INST(kX86InstPMulHRSW , "pmulhrsw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F380B, 0), + INST(kX86InstPMulHUW , "pmulhuw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FE4, 0), + INST(kX86InstPMulHW , "pmulhw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FE5, 0), + INST(kX86InstPMulLD , "pmulld" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3840, 0), + INST(kX86InstPMulLW , "pmullw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FD5, 0), + INST(kX86InstPMulUDQ , "pmuludq" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FF4, 0), + INST(kX86InstPop , "pop" , G(Pop) , F(Special) , 0 , 0 , 0, 0x00000058, 0x0000008F), + INST(kX86InstPopAD , "popad" , G(Emit) , F(Special) , 0 , 0 , 0, 0x00000061, 0), + INST(kX86InstPopCnt , "popcnt" , G(RegRm) , F(None) , O(Gqdw) , O(GqdwMem) , 0, 0xF3000FB8, 0), + INST(kX86InstPopFD , "popfd" , G(Emit) , F(Special) , 0 , 0 , 0, 0x0000009D, 0), + INST(kX86InstPopFQ , "popfq" , G(Emit) , F(Special) , 0 , 0 , 0, 0x0000009D, 0), + INST(kX86InstPOr , "por" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FEB, 0), + INST(kX86InstPrefetch , "prefetch" , G(MmuPrefetch) , F(None) , O(Mem) , O(Imm) , 0, 0 , 0), + INST(kX86InstPSADBW , "psadbw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FF6, 0), + INST(kX86InstPShufB , "pshufb" , G(MmuRmI) , F(Mov) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F3800, 0), + INST(kX86InstPShufD , "pshufd" , G(MmuRmImm8) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x66000F70, 0), + INST(kX86InstPShufW , "pshufw" , G(MmuRmImm8) , F(Mov) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F70, 0), + INST(kX86InstPShufHW , "pshufhw" , G(MmuRmImm8) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0xF3000F70, 0), + INST(kX86InstPShufLW , "pshuflw" , G(MmuRmImm8) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0xF2000F70, 0), + INST(kX86InstPSignB , "psignb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F3808, 0), + INST(kX86InstPSignD , "psignd" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F380A, 0), + INST(kX86InstPSignW , "psignw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x000F3809, 0), + INST(kX86InstPSllD , "pslld" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem)|O(Imm) , 6, 0x00000FF2, 0x00000F72), + INST(kX86InstPSllDQ , "pslldq" , G(MmuRmI) , F(None) , O(Xmm) , O(Imm) , 7, 0 , 0x66000F73), + INST(kX86InstPSllQ , "psllq" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem)|O(Imm) , 6, 0x00000FF3, 0x00000F73), + INST(kX86InstPSllW , "psllw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem)|O(Imm) , 6, 0x00000FF1, 0x00000F71), + INST(kX86InstPSraD , "psrad" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem)|O(Imm) , 4, 0x00000FE2, 0x00000F72), + INST(kX86InstPSraW , "psraw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem)|O(Imm) , 4, 0x00000FE1, 0x00000F71), + INST(kX86InstPSrlD , "psrld" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem)|O(Imm) , 2, 0x00000FD2, 0x00000F72), + INST(kX86InstPSrlDQ , "psrldq" , G(MmuRmI) , F(None) , O(Xmm) , O(Imm) , 3, 0 , 0x66000F73), + INST(kX86InstPSrlQ , "psrlq" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem)|O(Imm) , 2, 0x00000FD3, 0x00000F73), + INST(kX86InstPSrlW , "psrlw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem)|O(Imm) , 2, 0x00000FD1, 0x00000F71), + INST(kX86InstPSubB , "psubb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FF8, 0), + INST(kX86InstPSubD , "psubd" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FFA, 0), + INST(kX86InstPSubQ , "psubq" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FFB, 0), + INST(kX86InstPSubSB , "psubsb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FE8, 0), + INST(kX86InstPSubSW , "psubsw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FE9, 0), + INST(kX86InstPSubUSB , "psubusb" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FD8, 0), + INST(kX86InstPSubUSW , "psubusw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FD9, 0), + INST(kX86InstPSubW , "psubw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FF9, 0), + INST(kX86InstPSwapD , "pswapd" , G(MmuRm3dNow) , F(None) , O(Mm) , O(MmMem) , 0, 0x00000F0F, 0xBB), + INST(kX86InstPTest , "ptest" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3817, 0), + INST(kX86InstPunpckHBW , "punpckhbw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F68, 0), + INST(kX86InstPunpckHDQ , "punpckhdq" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F6A, 0), + INST(kX86InstPunpckHQDQ , "punpckhqdq" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F6D, 0), + INST(kX86InstPunpckHWD , "punpckhwd" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F69, 0), + INST(kX86InstPunpckLBW , "punpcklbw" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F60, 0), + INST(kX86InstPunpckLDQ , "punpckldq" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F62, 0), + INST(kX86InstPunpckLQDQ , "punpcklqdq" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F6C, 0), + INST(kX86InstPunpckLWD , "punpcklwd" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000F61, 0), + INST(kX86InstPush , "push" , G(Push) , F(Special) , 0 , 0 , 6, 0x00000050, 0x000000FF), + INST(kX86InstPushAD , "pushad" , G(Emit) , F(Special) , 0 , 0 , 0, 0x00000060, 0), + INST(kX86InstPushFD , "pushfd" , G(Emit) , F(Special) , 0 , 0 , 0, 0x0000009C, 0), + INST(kX86InstPushFQ , "pushfq" , G(Emit) , F(Special) , 0 , 0 , 0, 0x0000009C, 0), + INST(kX86InstPXor , "pxor" , G(MmuRmI) , F(None) , O(MmXmm) , O(MmXmmMem) , 0, 0x00000FEF, 0), + INST(kX86InstRcl , "rcl" , G(Rot) , F(Special) , O(GqdwbMem) , O(Gb)|O(Imm) , 2, 0 , 0), + INST(kX86InstRcpPS , "rcpps" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x00000F53, 0), + INST(kX86InstRcpSS , "rcpss" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0xF3000F53, 0), + INST(kX86InstRcr , "rcr" , G(Rot) , F(Special) , O(GqdwbMem) , O(Gb)|O(Imm) , 3, 0 , 0), + INST(kX86InstRdtsc , "rdtsc" , G(Emit) , F(Special) , 0 , 0 , 0, 0x00000F31, 0), + INST(kX86InstRdtscP , "rdtscp" , G(Emit) , F(Special) , 0 , 0 , 0, 0x000F01F9, 0), + INST(kX86InstRepLodSB , "rep lodsb" , G(Rep) , F(Special) , O(Mem) , 0 , 0, 0xF30000AC, 1 /* Size of mem */), + INST(kX86InstRepLodSD , "rep lodsd" , G(Rep) , F(Special) , O(Mem) , 0 , 0, 0xF30000AC, 4 /* Size of mem */), + INST(kX86InstRepLodSQ , "rep lodsq" , G(Rep) , F(Special) , O(Mem) , 0 , 0, 0xF30000AC, 8 /* Size of mem */), + INST(kX86InstRepLodSW , "rep lodsw" , G(Rep) , F(Special) , O(Mem) , 0 , 0, 0xF30000AC, 2 /* Size of mem */), + INST(kX86InstRepMovSB , "rep movsb" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000A4, 1 /* Size of mem */), + INST(kX86InstRepMovSD , "rep movsd" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000A4, 4 /* Size of mem */), + INST(kX86InstRepMovSQ , "rep movsq" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000A4, 8 /* Size of mem */), + INST(kX86InstRepMovSW , "rep movsw" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000A4, 2 /* Size of mem */), + INST(kX86InstRepStoSB , "rep stosb" , G(Rep) , F(Special) , O(Mem) , 0 , 0, 0xF30000AA, 1 /* Size of mem */), + INST(kX86InstRepStoSD , "rep stosd" , G(Rep) , F(Special) , O(Mem) , 0 , 0, 0xF30000AA, 4 /* Size of mem */), + INST(kX86InstRepStoSQ , "rep stosq" , G(Rep) , F(Special) , O(Mem) , 0 , 0, 0xF30000AA, 8 /* Size of mem */), + INST(kX86InstRepStoSW , "rep stosw" , G(Rep) , F(Special) , O(Mem) , 0 , 0, 0xF30000AA, 2 /* Size of mem */), + INST(kX86InstRepECmpSB , "repe cmpsb" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000A6, 1 /* Size of mem */), + INST(kX86InstRepECmpSD , "repe cmpsd" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000A6, 4 /* Size of mem */), + INST(kX86InstRepECmpSQ , "repe cmpsq" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000A6, 8 /* Size of mem */), + INST(kX86InstRepECmpSW , "repe cmpsw" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000A6, 2 /* Size of mem */), + INST(kX86InstRepEScaSB , "repe scasb" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000AE, 1 /* Size of mem */), + INST(kX86InstRepEScaSD , "repe scasd" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000AE, 4 /* Size of mem */), + INST(kX86InstRepEScaSQ , "repe scasq" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000AE, 8 /* Size of mem */), + INST(kX86InstRepEScaSW , "repe scasw" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF30000AE, 2 /* Size of mem */), + INST(kX86InstRepNECmpSB , "repne cmpsb" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF20000A6, 1 /* Size of mem */), + INST(kX86InstRepNECmpSD , "repne cmpsd" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF20000A6, 4 /* Size of mem */), + INST(kX86InstRepNECmpSQ , "repne cmpsq" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF20000A6, 8 /* Size of mem */), + INST(kX86InstRepNECmpSW , "repne cmpsw" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF20000A6, 2 /* Size of mem */), + INST(kX86InstRepNEScaSB , "repne scasb" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF20000AE, 1 /* Size of mem */), + INST(kX86InstRepNEScaSD , "repne scasd" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF20000AE, 4 /* Size of mem */), + INST(kX86InstRepNEScaSQ , "repne scasq" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF20000AE, 8 /* Size of mem */), + INST(kX86InstRepNEScaSW , "repne scasw" , G(Rep) , F(Special) , O(Mem) , O(Mem) , 0, 0xF20000AE, 2 /* Size of mem */), + INST(kX86InstRet , "ret" , G(Ret) , F(Special) , 0 , 0 , 0, 0 , 0), + INST(kX86InstRol , "rol" , G(Rot) , F(Special) , O(GqdwbMem) , O(Gb)|O(Imm) , 0, 0 , 0), + INST(kX86InstRor , "ror" , G(Rot) , F(Special) , O(GqdwbMem) , O(Gb)|O(Imm) , 1, 0 , 0), + INST(kX86InstRoundPD , "roundpd" , G(MmuRmImm8) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3A09, 0), + INST(kX86InstRoundPS , "roundps" , G(MmuRmImm8) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x660F3A08, 0), + INST(kX86InstRoundSD , "roundsd" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A0B, 0), + INST(kX86InstRoundSS , "roundss" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x660F3A0A, 0), + INST(kX86InstRSqrtPS , "rsqrtps" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x00000F52, 0), + INST(kX86InstRSqrtSS , "rsqrtss" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF3000F52, 0), + INST(kX86InstSahf , "sahf" , G(Emit) , F(Special) , 0 , 0 , 0, 0x0000009E, 0), + INST(kX86InstSal , "sal" , G(Rot) , F(Special) , O(GqdwbMem) , O(Gb)|O(Imm) , 4, 0 , 0), + INST(kX86InstSar , "sar" , G(Rot) , F(Special) , O(GqdwbMem) , O(Gb)|O(Imm) , 7, 0 , 0), + INST(kX86InstSbb , "sbb" , G(Arith) , F(Lockable) , O(GqdwbMem) , O(GqdwbMem)|O(Imm) , 3, 0x00000018, 0x00000080), + INST(kX86InstSetA , "seta" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F97, 0), + INST(kX86InstSetAE , "setae" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F93, 0), + INST(kX86InstSetB , "setb" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F92, 0), + INST(kX86InstSetBE , "setbe" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F96, 0), + INST(kX86InstSetC , "setc" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F92, 0), + INST(kX86InstSetE , "sete" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F94, 0), + INST(kX86InstSetG , "setg" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9F, 0), + INST(kX86InstSetGE , "setge" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9D, 0), + INST(kX86InstSetL , "setl" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9C, 0), + INST(kX86InstSetLE , "setle" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9E, 0), + INST(kX86InstSetNA , "setna" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F96, 0), + INST(kX86InstSetNAE , "setnae" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F92, 0), + INST(kX86InstSetNB , "setnb" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F93, 0), + INST(kX86InstSetNBE , "setnbe" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F97, 0), + INST(kX86InstSetNC , "setnc" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F93, 0), + INST(kX86InstSetNE , "setne" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F95, 0), + INST(kX86InstSetNG , "setng" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9E, 0), + INST(kX86InstSetNGE , "setnge" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9C, 0), + INST(kX86InstSetNL , "setnl" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9D, 0), + INST(kX86InstSetNLE , "setnle" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9F, 0), + INST(kX86InstSetNO , "setno" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F91, 0), + INST(kX86InstSetNP , "setnp" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9B, 0), + INST(kX86InstSetNS , "setns" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F99, 0), + INST(kX86InstSetNZ , "setnz" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F95, 0), + INST(kX86InstSetO , "seto" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F90, 0), + INST(kX86InstSetP , "setp" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9A, 0), + INST(kX86InstSetPE , "setpe" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9A, 0), + INST(kX86InstSetPO , "setpo" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F9B, 0), + INST(kX86InstSetS , "sets" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F98, 0), + INST(kX86InstSetZ , "setz" , G(RmByte) , F(None) , O(GbMem) , 0 , 0, 0x00000F94, 0), + INST(kX86InstSFence , "sfence" , G(Emit) , F(None) , 0 , 0 , 0, 0x000FAEF8, 0), + INST(kX86InstShl , "shl" , G(Rot) , F(Special) , O(GqdwbMem) , O(Gb)|O(Imm) , 4, 0 , 0), + INST(kX86InstShld , "shld" , G(ShldShrd) , F(Special) , O(GqdwbMem) , O(Gb) , 0, 0x00000FA4, 0), + INST(kX86InstShr , "shr" , G(Rot) , F(Special) , O(GqdwbMem) , O(Gb)|O(Imm) , 5, 0 , 0), + INST(kX86InstShrd , "shrd" , G(ShldShrd) , F(Special) , O(GqdwbMem) , O(Gqdwb) , 0, 0x00000FAC, 0), + INST(kX86InstShufPD , "shufpd" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000FC6, 0), + INST(kX86InstShufPS , "shufps" , G(MmuRmImm8) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000FC6, 0), + INST(kX86InstSqrtPD , "sqrtpd" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x66000F51, 0), + INST(kX86InstSqrtPS , "sqrtps" , G(MmuRmI) , F(Mov) , O(Xmm) , O(XmmMem) , 0, 0x00000F51, 0), + INST(kX86InstSqrtSD , "sqrtsd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000F51, 0), + INST(kX86InstSqrtSS , "sqrtss" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF3000F51, 0), + INST(kX86InstStc , "stc" , G(Emit) , F(None) , 0 , 0 , 0, 0x000000F9, 0), + INST(kX86InstStd , "std" , G(Emit) , F(None) , 0 , 0 , 0, 0x000000FD, 0), + INST(kX86InstStMXCSR , "stmxcsr" , G(Mem) , F(None) , O(Mem) , 0 , 3, 0x00000FAE, 0), + INST(kX86InstSub , "sub" , G(Arith) , F(Lockable) , O(GqdwbMem) , O(GqdwbMem)|O(Imm) , 5, 0x00000028, 0x00000080), + INST(kX86InstSubPD , "subpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F5C, 0), + INST(kX86InstSubPS , "subps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F5C, 0), + INST(kX86InstSubSD , "subsd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF2000F5C, 0), + INST(kX86InstSubSS , "subss" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0xF3000F5C, 0), + INST(kX86InstTest , "test" , G(Test) , F(None) , O(GqdwbMem) , O(Gqdwb)|O(Imm) , 0, 0 , 0), + INST(kX86InstUComISD , "ucomisd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F2E, 0), + INST(kX86InstUComISS , "ucomiss" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F2E, 0), + INST(kX86InstUd2 , "ud2" , G(Emit) , F(None) , 0 , 0 , 0, 0x00000F0B, 0), + INST(kX86InstUnpckHPD , "unpckhpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F15, 0), + INST(kX86InstUnpckHPS , "unpckhps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F15, 0), + INST(kX86InstUnpckLPD , "unpcklpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F14, 0), + INST(kX86InstUnpckLPS , "unpcklps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F14, 0), + INST(kX86InstXadd , "xadd" , G(RmReg) , F(Lockable) , O(GqdwbMem) , O(Gqdwb) , 0, 0x00000FC0, 0), + INST(kX86InstXchg , "xchg" , G(Xchg) , F(Lockable) , O(GqdwbMem) , O(Gqdwb) , 0, 0 , 0), + INST(kX86InstXor , "xor" , G(Arith) , F(Lockable) , O(GqdwbMem) , O(GqdwbMem)|O(Imm) , 6, 0x00000030, 0x00000080), + INST(kX86InstXorPD , "xorpd" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x66000F57, 0), + INST(kX86InstXorPS , "xorps" , G(MmuRmI) , F(None) , O(Xmm) , O(XmmMem) , 0, 0x00000F57, 0) +}; + +#undef G +#undef F +#undef O + +#undef INST + +// ============================================================================ +// [AsmJit::x86VarInfo] +// ============================================================================ + +#define C(_Class_) kX86VarClass##_Class_ +#define F(_Flag_) kX86VarFlag##_Flag_ + +const X86VarInfo x86VarInfo[] = +{ + /* 0 */ { kX86RegTypeGpd , 4 , C(Gp) , 0 , "Gpd" }, + /* 1 */ { kX86RegTypeGpq , 8 , C(Gp) , 0 , "Gpq" }, + /* 2 */ { kX86RegTypeX87 , 4 , C(X87), F(SP) , "X87" }, + /* 3 */ { kX86RegTypeX87 , 4 , C(X87), F(SP) , "X87.SS" }, + /* 4 */ { kX86RegTypeX87 , 8 , C(X87), F(DP) , "X87.SD" }, + /* 5 */ { kX86RegTypeMm , 8 , C(Mm) , 0 , "Mm" }, + /* 6 */ { kX86RegTypeXmm , 16, C(Xmm), 0 , "Xmm" }, + /* 7 */ { kX86RegTypeXmm , 4 , C(Xmm), F(SP) , "Xmm.SS" }, + /* 8 */ { kX86RegTypeXmm , 8 , C(Xmm), F(DP) , "Xmm.SD" }, + /* 9 */ { kX86RegTypeXmm , 16, C(Xmm), F(SP) | F(Packed), "Xmm.PS" }, + /* 10 */ { kX86RegTypeXmm , 16, C(Xmm), F(DP) | F(Packed), "Xmm.PD" } +}; + +#undef F +#undef C + +} // AsmJit namespace + +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/x86/x86defs.h b/desmume/src/utils/AsmJit/x86/x86defs.h new file mode 100644 index 000000000..5c2cd83dd --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86defs.h @@ -0,0 +1,2202 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_X86_X86DEFS_H +#define _ASMJIT_X86_X86DEFS_H + +// [Dependencies - AsmJit] +#include "../core/assert.h" +#include "../core/defs.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_X86 +//! @{ + +// ============================================================================ +// [AsmJit::kX86Feature] +// ============================================================================ + +//! @brief X86 CPU features. +enum kX86Feature +{ + //! @brief Cpu has RDTSC instruction. + kX86FeatureRdtsc = 1U << 0, + //! @brief Cpu has RDTSCP instruction. + kX86FeatureRdtscP = 1U << 1, + //! @brief Cpu has CMOV instruction (conditional move) + kX86FeatureCMov = 1U << 2, + //! @brief Cpu has CMPXCHG8B instruction + kX86FeatureCmpXchg8B = 1U << 3, + //! @brief Cpu has CMPXCHG16B instruction (64-bit processors) + kX86FeatureCmpXchg16B = 1U << 4, + //! @brief Cpu has CLFUSH instruction + kX86FeatureClFlush = 1U << 5, + //! @brief Cpu has PREFETCH instruction + kX86FeaturePrefetch = 1U << 6, + //! @brief Cpu supports LAHF and SAHF instrictions. + kX86FeatureLahfSahf = 1U << 7, + //! @brief Cpu supports FXSAVE and FXRSTOR instructions. + kX86FeatureFXSR = 1U << 8, + //! @brief Cpu supports FXSAVE and FXRSTOR instruction optimizations (FFXSR). + kX86FeatureFFXSR = 1U << 9, + //! @brief Cpu has MMX. + kX86FeatureMmx = 1U << 10, + //! @brief Cpu has extended MMX. + kX86FeatureMmxExt = 1U << 11, + //! @brief Cpu has 3dNow! + kX86Feature3dNow = 1U << 12, + //! @brief Cpu has enchanced 3dNow! + kX86Feature3dNowExt = 1U << 13, + //! @brief Cpu has SSE. + kX86FeatureSse = 1U << 14, + //! @brief Cpu has SSE2. + kX86FeatureSse2 = 1U << 15, + //! @brief Cpu has SSE3. + kX86FeatureSse3 = 1U << 16, + //! @brief Cpu has Supplemental SSE3 (SSSE3). + kX86FeatureSsse3 = 1U << 17, + //! @brief Cpu has SSE4.A. + kX86FeatureSse4A = 1U << 18, + //! @brief Cpu has SSE4.1. + kX86FeatureSse41 = 1U << 19, + //! @brief Cpu has SSE4.2. + kX86FeatureSse42 = 1U << 20, + //! @brief Cpu has AVX. + kX86FeatureAvx = 1U << 22, + //! @brief Cpu has Misaligned SSE (MSSE). + kX86FeatureMSse = 1U << 23, + //! @brief Cpu supports MONITOR and MWAIT instructions. + kX86FeatureMonitorMWait = 1U << 24, + //! @brief Cpu supports MOVBE instruction. + kX86FeatureMovBE = 1U << 25, + //! @brief Cpu supports POPCNT instruction. + kX86FeaturePopCnt = 1U << 26, + //! @brief Cpu supports LZCNT instruction. + kX86FeatureLzCnt = 1U << 27, + //! @brief Cpu supports PCLMULDQ set of instructions. + kX86FeaturePclMulDQ = 1U << 28, + //! @brief Cpu supports multithreading. + kX86FeatureMultiThreading = 1U << 29, + //! @brief Cpu supports execute disable bit (execute protection). + kX86FeatureExecuteDisableBit = 1U << 30, + //! @brief 64-bit CPU. + kX86Feature64Bit = 1U << 31 +}; + +// ============================================================================ +// [AsmJit::kX86Bug] +// ============================================================================ + +//! @brief X86 CPU bugs. +enum kX86Bug +{ + //! @brief Whether the processor contains bug seen in some + //! AMD-Opteron processors. + kX86BugAmdLockMB = 1U << 0 +}; + +// ============================================================================ +// [AsmJit::kX86Property] +// ============================================================================ + +//! @brief @ref X86Assembler and @ref X86Compiler properties. +enum kX86Property +{ + //! @brief Optimize align for current processor. + //! + //! Default: @c true. + kX86PropertyOptimizedAlign = 0, + + //! @brief Emit hints added to jcc() instructions. + //! + //! Default: @c true. + kX86PropertyJumpHints = 1 +}; + +// ============================================================================ +// [AsmJit::kX86Seg] +// ============================================================================ + +//! @brief X86 segment codes. +enum kX86Seg +{ + // DO NOT MODIFY INDEX CODES - They are used by _emitSegmentPrefix() and + // by logger in the following order: + + //! @brief ES segment. + kX86SegEs = 0, + //! @brief CS segment. + kX86SegCs = 1, + //! @brief SS segment. + kX86SegSs = 2, + //! @brief DS segment. + kX86SegDs = 3, + //! @brief FS segment. + kX86SegFs = 4, + //! @brief GS segment. + kX86SegGs = 5, + //! @brief Count of segments. + kX86SegCount = 6, + + //! @brief No segment override prefix. + kX86SegNone = 0xF +}; + +// ============================================================================ +// [AsmJit::kX86RegNum] +// ============================================================================ + +//! @brief X86 registers count. +//! +//! Count of general purpose registers and XMM registers depends on current +//! mode. If application is compiled for 32-bit platform then this number is 8, +//! 64-bit platforms have 8 extra general purpose and XMM registers (16 total). +enum kX86RegNum +{ + //! @var kX86RegNumBase + //! + //! Count of general purpose registers and XMM registers depends on current + //! bit-mode. If application is compiled for 32-bit platform then this number + //! is 8, 64-bit platforms have 8 extra general purpose and XMM registers (16 + //! total). +#if defined(ASMJIT_X86) + kX86RegNumBase = 8, +#else + kX86RegNumBase = 16, +#endif // ASMJIT + + //! @brief Count of general purpose registers. + //! + //! 8 in 32-bit mode and 16 in 64-bit mode. + kX86RegNumGp = kX86RegNumBase, + + //! @brief Count of FPU stack registers (always 8). + kX86RegNumX87 = 8, + //! @brief Count of MM registers (always 8). + kX86RegNumMm = 8, + + //! @brief Count of XMM registers. + //! + //! 8 in 32-bit mode and 16 in 64-bit mode. + kX86RegNumXmm = kX86RegNumBase, + //! @brief Count of YMM registers. + //! + //! 8 in 32-bit mode and 16 in 64-bit mode. + kX86RegNumYmm = kX86RegNumBase, + + //! @brief Count of segment registers, including no segment (AsmJit specific). + //! + //! @note There are 6 segment registers, but AsmJit uses 0 as no segment, and + //! 1...6 as segment registers, this means that there are 7 segment registers + //! in AsmJit API, but only 6 can be used through @c Assembler or @c Compiler + //! API. + kX86RegNumSeg = 7 +}; + +//! @brief X86 register types. +enum kX86RegType +{ + // First byte contains register type (mask 0xFF00), Second byte contains + // register index code. + + // -------------------------------------------------------------------------- + // [GP Register Types] + // -------------------------------------------------------------------------- + + //! @brief 8-bit general purpose register type (LO). + kX86RegTypeGpbLo = 0x0100, + //! @brief 8-bit general purpose register type (HI, only AH, BH, CH, DH). + kX86RegTypeGpbHi = 0x0200, + //! @brief 16-bit general purpose register type. + kX86RegTypeGpw = 0x1000, + //! @brief 32-bit general purpose register type. + kX86RegTypeGpd = 0x2000, + //! @brief 64-bit general purpose register type. + kX86RegTypeGpq = 0x3000, + + //! @var kX86RegTypeGpz + //! @brief 32-bit or 64-bit general purpose register type. +#if defined(ASMJIT_X86) + kX86RegTypeGpz = kX86RegTypeGpd, +#else + kX86RegTypeGpz = kX86RegTypeGpq, +#endif + + //! @brief X87 (FPU) register type. + kX86RegTypeX87 = 0x5000, + //! @brief 64-bit MM register type. + kX86RegTypeMm = 0x6000, + + //! @brief 128-bit XMM register type. + kX86RegTypeXmm = 0x7000, + //! @brief 256-bit YMM register type. + kX86RegTypeYmm = 0x8000, + + //! @brief 16-bit segment register type. + kX86RegTypeSeg = 0xD000 +}; + +// ============================================================================ +// [AsmJit::kX86RegIndex] +// ============================================================================ + +//! @brief X86 register indices. +//! +//! These codes are real, don't miss with @c REG enum! and don't use these +//! values if you are not writing AsmJit code. +enum kX86RegIndex +{ + //! @brief ID for AX/EAX/RAX registers. + kX86RegIndexEax = 0, + //! @brief ID for CX/ECX/RCX registers. + kX86RegIndexEcx = 1, + //! @brief ID for DX/EDX/RDX registers. + kX86RegIndexEdx = 2, + //! @brief ID for BX/EBX/RBX registers. + kX86RegIndexEbx = 3, + //! @brief ID for SP/ESP/RSP registers. + kX86RegIndexEsp = 4, + //! @brief ID for BP/EBP/RBP registers. + kX86RegIndexEbp = 5, + //! @brief ID for SI/ESI/RSI registers. + kX86RegIndexEsi = 6, + //! @brief ID for DI/EDI/RDI registers. + kX86RegIndexEdi = 7, + + //! @brief ID for AX/EAX/RAX registers. + kX86RegIndexRax = 0, + //! @brief ID for CX/ECX/RCX registers. + kX86RegIndexRcx = 1, + //! @brief ID for DX/EDX/RDX registers. + kX86RegIndexRdx = 2, + //! @brief ID for BX/EBX/RBX registers. + kX86RegIndexRbx = 3, + //! @brief ID for SP/ESP/RSP registers. + kX86RegIndexRsp = 4, + //! @brief ID for BP/EBP/RBP registers. + kX86RegIndexRbp = 5, + //! @brief ID for SI/ESI/RSI registers. + kX86RegIndexRsi = 6, + //! @brief ID for DI/EDI/RDI registers. + kX86RegIndexRdi = 7, + + //! @brief ID for r8 register (additional register introduced by 64-bit architecture). + kX86RegIndexR8 = 8, + //! @brief ID for R9 register (additional register introduced by 64-bit architecture). + kX86RegIndexR9 = 9, + //! @brief ID for R10 register (additional register introduced by 64-bit architecture). + kX86RegIndexR10 = 10, + //! @brief ID for R11 register (additional register introduced by 64-bit architecture). + kX86RegIndexR11 = 11, + //! @brief ID for R12 register (additional register introduced by 64-bit architecture). + kX86RegIndexR12 = 12, + //! @brief ID for R13 register (additional register introduced by 64-bit architecture). + kX86RegIndexR13 = 13, + //! @brief ID for R14 register (additional register introduced by 64-bit architecture). + kX86RegIndexR14 = 14, + //! @brief ID for R15 register (additional register introduced by 64-bit architecture). + kX86RegIndexR15 = 15, + + //! @brief ID for mm0 register. + kX86RegIndexMm0 = 0, + //! @brief ID for mm1 register. + kX86RegIndexMm1 = 1, + //! @brief ID for mm2 register. + kX86RegIndexMm2 = 2, + //! @brief ID for mm3 register. + kX86RegIndexMm3 = 3, + //! @brief ID for mm4 register. + kX86RegIndexMm4 = 4, + //! @brief ID for mm5 register. + kX86RegIndexMm5 = 5, + //! @brief ID for mm6 register. + kX86RegIndexMm6 = 6, + //! @brief ID for mm7 register. + kX86RegIndexMm7 = 7, + + //! @brief ID for xmm0 register. + kX86RegIndexXmm0 = 0, + //! @brief ID for xmm1 register. + kX86RegIndexXmm1 = 1, + //! @brief ID for xmm2 register. + kX86RegIndexXmm2 = 2, + //! @brief ID for xmm3 register. + kX86RegIndexXmm3 = 3, + //! @brief ID for xmm4 register. + kX86RegIndexXmm4 = 4, + //! @brief ID for xmm5 register. + kX86RegIndexXmm5 = 5, + //! @brief ID for xmm6 register. + kX86RegIndexXmm6 = 6, + //! @brief ID for xmm7 register. + kX86RegIndexXmm7 = 7, + + //! @brief ID for xmm8 register (additional register introduced by 64-bit architecture). + kX86RegIndexXmm8 = 8, + //! @brief ID for xmm9 register (additional register introduced by 64-bit architecture). + kX86RegIndexXmm9 = 9, + //! @brief ID for xmm10 register (additional register introduced by 64-bit architecture). + kX86RegIndexXmm10 = 10, + //! @brief ID for xmm11 register (additional register introduced by 64-bit architecture). + kX86RegIndexXmm11 = 11, + //! @brief ID for xmm12 register (additional register introduced by 64-bit architecture). + kX86RegIndexXmm12 = 12, + //! @brief ID for xmm13 register (additional register introduced by 64-bit architecture). + kX86RegIndexXmm13 = 13, + //! @brief ID for xmm14 register (additional register introduced by 64-bit architecture). + kX86RegIndexXmm14 = 14, + //! @brief ID for xmm15 register (additional register introduced by 64-bit architecture). + kX86RegIndexXmm15 = 15, + + //! @brief ID for ES segment register. + kX86RegIndexEs = 0, + //! @brief ID for CS segment register. + kX86RegIndexCs = 1, + //! @brief ID for SS segment register. + kX86RegIndexSs = 2, + //! @brief ID for DS segment register. + kX86RegIndexDs = 3, + //! @brief ID for FS segment register. + kX86RegIndexFs = 4, + //! @brief ID for GS segment register. + kX86RegIndexGs = 5 +}; + +// ============================================================================ +// [AsmJit::kX86RegCode] +// ============================================================================ + +//! @brief X86 pseudo (not real X86) register codes used for generating opcodes. +//! +//! From this register code can be generated real x86 register ID, type of +//! register and size of register. +enum kX86RegCode +{ + // -------------------------------------------------------------------------- + // [8-bit Registers] + // -------------------------------------------------------------------------- + + kX86RegAl = kX86RegTypeGpbLo, + kX86RegCl, + kX86RegDl, + kX86RegBl, +#if defined(ASMJIT_X64) + kX86RegSpl, + kX86RegBpl, + kX86RegSil, + kX86RegDil, +#endif // ASMJIT_X64 + +#if defined(ASMJIT_X64) + kX86RegR8b, + kX86RegR9b, + kX86RegR10b, + kX86RegR11b, + kX86RegR12b, + kX86RegR13b, + kX86RegR14b, + kX86RegR15b, +#endif // ASMJIT_X64 + + kX86RegAh = kX86RegTypeGpbHi, + kX86RegCh, + kX86RegDh, + kX86RegBh, + + // -------------------------------------------------------------------------- + // [16-bit Registers] + // -------------------------------------------------------------------------- + + kX86RegAx = kX86RegTypeGpw, + kX86RegCx, + kX86RegDx, + kX86RegBx, + kX86RegSp, + kX86RegBp, + kX86RegSi, + kX86RegDi, +#if defined(ASMJIT_X64) + kX86RegR8w, + kX86RegR9w, + kX86RegR10w, + kX86RegR11w, + kX86RegR12w, + kX86RegR13w, + kX86RegR14w, + kX86RegR15w, +#endif // ASMJIT_X64 + + // -------------------------------------------------------------------------- + // [32-bit Registers] + // -------------------------------------------------------------------------- + + kX86RegEax = kX86RegTypeGpd, + kX86RegEcx, + kX86RegEdx, + kX86RegEbx, + kX86RegEsp, + kX86RegEbp, + kX86RegEsi, + kX86RegEdi, +#if defined(ASMJIT_X64) + kX86RegR8d, + kX86RegR9d, + kX86RegR10d, + kX86RegR11d, + kX86RegR12d, + kX86RegR13d, + kX86RegR14d, + kX86RegR15d, +#endif // ASMJIT_X64 + + // -------------------------------------------------------------------------- + // [64-bit Registers] + // -------------------------------------------------------------------------- + +#if defined(ASMJIT_X64) + kX86RegRax = kX86RegTypeGpq, + kX86RegRcx, + kX86RegRdx, + kX86RegRbx, + kX86RegRsp, + kX86RegRbp, + kX86RegRsi, + kX86RegRdi, + kX86RegR8, + kX86RegR9, + kX86RegR10, + kX86RegR11, + kX86RegR12, + kX86RegR13, + kX86RegR14, + kX86RegR15, +#endif // ASMJIT_X64 + + // -------------------------------------------------------------------------- + // [MM Registers] + // -------------------------------------------------------------------------- + + kX86RegMm0 = kX86RegTypeMm, + kX86RegMm1, + kX86RegMm2, + kX86RegMm3, + kX86RegMm4, + kX86RegMm5, + kX86RegMm6, + kX86RegMm7, + + // -------------------------------------------------------------------------- + // [XMM Registers] + // -------------------------------------------------------------------------- + + kX86RegXmm0 = kX86RegTypeXmm, + kX86RegXmm1, + kX86RegXmm2, + kX86RegXmm3, + kX86RegXmm4, + kX86RegXmm5, + kX86RegXmm6, + kX86RegXmm7, +#if defined(ASMJIT_X64) + kX86RegXmm8, + kX86RegXmm9, + kX86RegXmm10, + kX86RegXmm11, + kX86RegXmm12, + kX86RegXmm13, + kX86RegXmm14, + kX86RegXmm15, +#endif // ASMJIT_X64 + + // -------------------------------------------------------------------------- + // [Native registers (depends on 32-bit or 64-bit mode)] + // -------------------------------------------------------------------------- + + kX86RegZax = kX86RegTypeGpz, + kX86RegZcx, + kX86RegZdx, + kX86RegZbx, + kX86RegZsp, + kX86RegZbp, + kX86RegZsi, + kX86RegZdi, + + // -------------------------------------------------------------------------- + // [Segment registers] + // -------------------------------------------------------------------------- + + //! @brief ES segment register. + kX86RegEs = kX86RegTypeSeg, + //! @brief CS segment register. + kX86RegCs, + //! @brief SS segment register. + kX86RegSs, + //! @brief DS segment register. + kX86RegDs, + //! @brief FS segment register. + kX86RegFs, + //! @brief GS segment register. + kX86RegGs +}; + +// ============================================================================ +// [AsmJit::kX86Cond] +// ============================================================================ + +//! @brief X86 Condition codes. +enum kX86Cond +{ + // Condition codes from processor manuals. + kX86CondA = 0x07, + kX86CondAE = 0x03, + kX86CondB = 0x02, + kX86CondBE = 0x06, + kX86CondC = 0x02, + kX86CondE = 0x04, + kX86CondG = 0x0F, + kX86CondGE = 0x0D, + kX86CondL = 0x0C, + kX86CondLE = 0x0E, + kX86CondNA = 0x06, + kX86CondNAE = 0x02, + kX86CondNB = 0x03, + kX86CondNBE = 0x07, + kX86CondNC = 0x03, + kX86CondNE = 0x05, + kX86CondNG = 0x0E, + kX86CondNGE = 0x0C, + kX86CondNL = 0x0D, + kX86CondNLE = 0x0F, + kX86CondNO = 0x01, + kX86CondNP = 0x0B, + kX86CondNS = 0x09, + kX86CondNZ = 0x05, + kX86CondO = 0x00, + kX86CondP = 0x0A, + kX86CondPE = 0x0A, + kX86CondPO = 0x0B, + kX86CondS = 0x08, + kX86CondZ = 0x04, + + // Simplified condition codes. + kX86CondOverflow = 0x00, + kX86CondNotOverflow = 0x01, + kX86CondBelow = 0x02, + kX86CondAboveEqual = 0x03, + kX86CondEqual = 0x04, + kX86CondNotEqual = 0x05, + kX86CondBelowEqual = 0x06, + kX86CondAbove = 0x07, + kX86CondSign = 0x08, + kX86CondNotSign = 0x09, + kX86CondParityEven = 0x0A, + kX86CondParityOdd = 0x0B, + kX86CondLess = 0x0C, + kX86CondGreaterEqual = 0x0D, + kX86CondLessEqual = 0x0E, + kX86CondGreater = 0x0F, + + // Aliases. + kX86CondZero = 0x04, + kX86CondNotZero = 0x05, + kX86CondNegative = 0x08, + kX86CondPositive = 0x09, + + // X87 floating point only. + kX86CondFpuUnordered = 0x10, + kX86CondFpuNotUnordered = 0x11, + + //! @brief No condition code. + kX86CondNone = 0x12 +}; + +// ============================================================================ +// [AsmJit::kX86CondPrefix] +// ============================================================================ + +//! @brief X86 condition hint prefix code, see @ref kCondHint. +enum kX86CondPrefix +{ + //! @brief Condition is likely to be taken. + kX86CondPrefixLikely = 0x3E, + //! @brief Condition is unlikely to be taken. + kX86CondPrefixUnlikely = 0x2E +}; + +// ============================================================================ +// [AsmJit::kX86PrefetchHint] +// ============================================================================ + +//! @brief X86 Prefetch hints. +enum kX86PrefetchHint +{ + //! @brief Prefetch using NT hint. + kX86PrefetchNta = 0, + //! @brief Prefetch to L0 cache. + kX86PrefetchT0 = 1, + //! @brief Prefetch to L1 cache. + kX86PrefetchT1 = 2, + //! @brief Prefetch to L2 cache. + kX86PrefetchT2 = 3 +}; + +// ============================================================================ +// [AsmJit::kX86FPSW] +// ============================================================================ + +//! @brief X86 FPU status-word. +enum kX86FPSW +{ + kX86FPSW_Invalid = 0x0001, + kX86FPSW_Denormalized = 0x0002, + kX86FPSW_DivByZero = 0x0004, + kX86FPSW_Overflow = 0x0008, + kX86FPSW_Underflow = 0x0010, + kX86FPSW_Precision = 0x0020, + kX86FPSW_StackFault = 0x0040, + kX86FPSW_Interrupt = 0x0080, + kX86FPSW_C0 = 0x0100, + kX86FPSW_C1 = 0x0200, + kX86FPSW_C2 = 0x0400, + kX86FPSW_Top = 0x3800, + kX86FPSW_C3 = 0x4000, + kX86FPSW_Busy = 0x8000 +}; + +// ============================================================================ +// [AsmJit::kX86FPCW] +// ============================================================================ + +//! @brief X86 FPU control-word. +enum kX86FPCW +{ + // -------------------------------------------------------------------------- + // [Exception-Mask] + // -------------------------------------------------------------------------- + + kX86FPCW_EM_Mask = 0x003F, // Bits 0-5. + + kX86FPCW_EM_Invalid = 0x0001, + kX86FPCW_EM_Denormal = 0x0002, + kX86FPCW_EM_DivByZero = 0x0004, + kX86FPCW_EM_Overflow = 0x0008, + kX86FPCW_EM_Underflow = 0x0010, + kX86FPCW_EM_Inexact = 0x0020, + + // -------------------------------------------------------------------------- + // [Precision-Control] + // -------------------------------------------------------------------------- + + kX86FPCW_PC_Mask = 0x0300, // Bits 8-9. + + kX86FPCW_PC_Float = 0x0000, + kX86FPCW_PC_Reserved = 0x0100, + kX86FPCW_PC_Double = 0x0200, + kX86FPCW_PC_Extended = 0x0300, + + // -------------------------------------------------------------------------- + // [Rounding-Control] + // -------------------------------------------------------------------------- + + kX86FPCW_RC_Mask = 0x0C00, // Bits 10-11. + + kX86FPCW_RC_Nearest = 0x0000, + kX86FPCW_RC_Down = 0x0400, + kX86FPCW_RC_Up = 0x0800, + kX86FPCW_RC_Truncate = 0x0C00, + + // -------------------------------------------------------------------------- + // [Infinity-Control] + // -------------------------------------------------------------------------- + + kX86FPCW_IC_Mask = 0x1000, // Bit 12. + + kX86FPCW_IC_Projective = 0x0000, + kX86FPCW_IC_Affine = 0x1000 +}; + +// ============================================================================ +// [AsmJit::kX86EmitOption] +// ============================================================================ + +//! @brief Emit options, mainly for internal purposes. +enum kX86EmitOption +{ + //! @brief Force REX prefix to be emitted. + //! + //! This option should be used carefully, because there are unencodable + //! combinations. If you want to access ah, bh, ch or dh registers then you + //! can't emit REX prefix and it will cause an illegal instruction error. + kX86EmitOptionRex = 0x1, + + //! @brief Tell @c Assembler or @c Compiler to emit and validate lock prefix. + //! + //! If this option is used and instruction doesn't support LOCK prefix then + //! invalid instruction error is generated. + kX86EmitOptionLock = 0x2, + + //! @brief Emit short/near jump or conditional jump instead of far one to + //! some bytes. + //! + //! @note This option could be dangerous in case that the short jump is not + //! possible (displacement can't fit into signed 8-bit integer). AsmJit can + //! automatically generate back short jumps, but always generates long forward + //! jumps, because the information about the code size between the instruction + //! and target is not known. + kX86EmitOptionShortJump = 0x4, + + //! @brief Emit full immediate instead of BYTE in all cases. + //! + //! @note AsmJit is able to emit both forms of immediate value. In case that + //! the instruction supports short form and immediate can fit into a signed + //! 8-bit integer short for is preferred, but if for any reason the full form + //! is required it can be overridden by using this option. + kX86EmitOptionFullImmediate = 0x8 +}; + +// ============================================================================ +// [AsmJit::kX86InstCode] +// ============================================================================ + +//! @brief X86 instruction codes. +//! +//! Note that these instruction codes are AsmJit specific. Each instruction is +//! unique ID into AsmJit instruction table. Instruction codes are used together +//! with AsmJit::Assembler and you can also use instruction codes to serialize +//! instructions by @ref Assembler::_emitInstruction() or +//! @ref Compiler::_emitInstruction() +enum kX86InstCode +{ + kX86InstAdc = 1, // X86/X64 + kX86InstAdd, // X86/X64 + kX86InstAddPD, // SSE2 + kX86InstAddPS, // SSE + kX86InstAddSD, // SSE2 + kX86InstAddSS, // SSE + kX86InstAddSubPD, // SSE3 + kX86InstAddSubPS, // SSE3 + kX86InstAmdPrefetch, // 3dNow! + kX86InstAmdPrefetchW, // 3dNow! + kX86InstAnd, // X86/X64 + kX86InstAndnPD, // SSE2 + kX86InstAndnPS, // SSE + kX86InstAndPD, // SSE2 + kX86InstAndPS, // SSE + kX86InstBlendPD, // SSE4.1 + kX86InstBlendPS, // SSE4.1 + kX86InstBlendVPD, // SSE4.1 + kX86InstBlendVPS, // SSE4.1 + kX86InstBsf, // X86/X64 + kX86InstBsr, // X86/X64 + kX86InstBSwap, // X86/X64 (i486) + kX86InstBt, // X86/X64 + kX86InstBtc, // X86/X64 + kX86InstBtr, // X86/X64 + kX86InstBts, // X86/X64 + kX86InstCall, // X86/X64 + kX86InstCbw, // X86/X64 + kX86InstCdq, // X86/X64 + kX86InstCdqe, // X64 only + kX86InstClc, // X86/X64 + kX86InstCld, // X86/X64 + kX86InstClFlush, // SSE2 + kX86InstCmc, // X86/X64 + + kX86InstCMov, // Begin (cmovcc) (i586) + kX86InstCMovA=kX86InstCMov,//X86/X64 (cmovcc) (i586) + kX86InstCMovAE, // X86/X64 (cmovcc) (i586) + kX86InstCMovB, // X86/X64 (cmovcc) (i586) + kX86InstCMovBE, // X86/X64 (cmovcc) (i586) + kX86InstCMovC, // X86/X64 (cmovcc) (i586) + kX86InstCMovE, // X86/X64 (cmovcc) (i586) + kX86InstCMovG, // X86/X64 (cmovcc) (i586) + kX86InstCMovGE, // X86/X64 (cmovcc) (i586) + kX86InstCMovL, // X86/X64 (cmovcc) (i586) + kX86InstCMovLE, // X86/X64 (cmovcc) (i586) + kX86InstCMovNA, // X86/X64 (cmovcc) (i586) + kX86InstCMovNAE, // X86/X64 (cmovcc) (i586) + kX86InstCMovNB, // X86/X64 (cmovcc) (i586) + kX86InstCMovNBE, // X86/X64 (cmovcc) (i586) + kX86InstCMovNC, // X86/X64 (cmovcc) (i586) + kX86InstCMovNE, // X86/X64 (cmovcc) (i586) + kX86InstCMovNG, // X86/X64 (cmovcc) (i586) + kX86InstCMovNGE, // X86/X64 (cmovcc) (i586) + kX86InstCMovNL, // X86/X64 (cmovcc) (i586) + kX86InstCMovNLE, // X86/X64 (cmovcc) (i586) + kX86InstCMovNO, // X86/X64 (cmovcc) (i586) + kX86InstCMovNP, // X86/X64 (cmovcc) (i586) + kX86InstCMovNS, // X86/X64 (cmovcc) (i586) + kX86InstCMovNZ, // X86/X64 (cmovcc) (i586) + kX86InstCMovO, // X86/X64 (cmovcc) (i586) + kX86InstCMovP, // X86/X64 (cmovcc) (i586) + kX86InstCMovPE, // X86/X64 (cmovcc) (i586) + kX86InstCMovPO, // X86/X64 (cmovcc) (i586) + kX86InstCMovS, // X86/X64 (cmovcc) (i586) + kX86InstCMovZ, // X86/X64 (cmovcc) (i586) + + kX86InstCmp, // X86/X64 + kX86InstCmpPD, // SSE2 + kX86InstCmpPS, // SSE + kX86InstCmpSD, // SSE2 + kX86InstCmpSS, // SSE + kX86InstCmpXCHG, // X86/X64 (i486) + kX86InstCmpXCHG16B, // X64 only + kX86InstCmpXCHG8B, // X86/X64 (i586) + kX86InstComISD, // SSE2 + kX86InstComISS, // SSE + kX86InstCpuId, // X86/X64 (i486) + kX86InstCqo, // X64 only + kX86InstCrc32, // SSE4.2 + kX86InstCvtDQ2PD, // SSE2 + kX86InstCvtDQ2PS, // SSE2 + kX86InstCvtPD2DQ, // SSE2 + kX86InstCvtPD2PI, // SSE2 + kX86InstCvtPD2PS, // SSE2 + kX86InstCvtPI2PD, // SSE2 + kX86InstCvtPI2PS, // SSE + kX86InstCvtPS2DQ, // SSE2 + kX86InstCvtPS2PD, // SSE2 + kX86InstCvtPS2PI, // SSE + kX86InstCvtSD2SI, // SSE2 + kX86InstCvtSD2SS, // SSE2 + kX86InstCvtSI2SD, // SSE2 + kX86InstCvtSI2SS, // SSE + kX86InstCvtSS2SD, // SSE2 + kX86InstCvtSS2SI, // SSE + kX86InstCvttPD2DQ, // SSE2 + kX86InstCvttPD2PI, // SSE2 + kX86InstCvttPS2DQ, // SSE2 + kX86InstCvttPS2PI, // SSE + kX86InstCvttSD2SI, // SSE2 + kX86InstCvttSS2SI, // SSE + kX86InstCwd, // X86/X64 + kX86InstCwde, // X86/X64 + kX86InstDaa, // X86 only + kX86InstDas, // X86 only + kX86InstDec, // X86/X64 + kX86InstDiv, // X86/X64 + kX86InstDivPD, // SSE2 + kX86InstDivPS, // SSE + kX86InstDivSD, // SSE2 + kX86InstDivSS, // SSE + kX86InstDpPD, // SSE4.1 + kX86InstDpPS, // SSE4.1 + kX86InstEmms, // MMX + kX86InstEnter, // X86/X64 + kX86InstExtractPS, // SSE4.1 + kX86InstF2XM1, // X87 + kX86InstFAbs, // X87 + kX86InstFAdd, // X87 + kX86InstFAddP, // X87 + kX86InstFBLd, // X87 + kX86InstFBStP, // X87 + kX86InstFCHS, // X87 + kX86InstFClex, // X87 + kX86InstFCMovB, // X87 + kX86InstFCMovBE, // X87 + kX86InstFCMovE, // X87 + kX86InstFCMovNB, // X87 + kX86InstFCMovNBE, // X87 + kX86InstFCMovNE, // X87 + kX86InstFCMovNU, // X87 + kX86InstFCMovU, // X87 + kX86InstFCom, // X87 + kX86InstFComI, // X87 + kX86InstFComIP, // X87 + kX86InstFComP, // X87 + kX86InstFComPP, // X87 + kX86InstFCos, // X87 + kX86InstFDecStP, // X87 + kX86InstFDiv, // X87 + kX86InstFDivP, // X87 + kX86InstFDivR, // X87 + kX86InstFDivRP, // X87 + kX86InstFEmms, // 3dNow! + kX86InstFFree, // X87 + kX86InstFIAdd, // X87 + kX86InstFICom, // X87 + kX86InstFIComP, // X87 + kX86InstFIDiv, // X87 + kX86InstFIDivR, // X87 + kX86InstFILd, // X87 + kX86InstFIMul, // X87 + kX86InstFIncStP, // X87 + kX86InstFInit, // X87 + kX86InstFISt, // X87 + kX86InstFIStP, // X87 + kX86InstFISttP, // SSE3 + kX86InstFISub, // X87 + kX86InstFISubR, // X87 + kX86InstFLd, // X87 + kX86InstFLd1, // X87 + kX86InstFLdCw, // X87 + kX86InstFLdEnv, // X87 + kX86InstFLdL2E, // X87 + kX86InstFLdL2T, // X87 + kX86InstFLdLg2, // X87 + kX86InstFLdLn2, // X87 + kX86InstFLdPi, // X87 + kX86InstFLdZ, // X87 + kX86InstFMul, // X87 + kX86InstFMulP, // X87 + kX86InstFNClex, // X87 + kX86InstFNInit, // X87 + kX86InstFNop, // X87 + kX86InstFNSave, // X87 + kX86InstFNStCw, // X87 + kX86InstFNStEnv, // X87 + kX86InstFNStSw, // X87 + kX86InstFPAtan, // X87 + kX86InstFPRem, // X87 + kX86InstFPRem1, // X87 + kX86InstFPTan, // X87 + kX86InstFRndInt, // X87 + kX86InstFRstor, // X87 + kX86InstFSave, // X87 + kX86InstFScale, // X87 + kX86InstFSin, // X87 + kX86InstFSinCos, // X87 + kX86InstFSqrt, // X87 + kX86InstFSt, // X87 + kX86InstFStCw, // X87 + kX86InstFStEnv, // X87 + kX86InstFStP, // X87 + kX86InstFStSw, // X87 + kX86InstFSub, // X87 + kX86InstFSubP, // X87 + kX86InstFSubR, // X87 + kX86InstFSubRP, // X87 + kX86InstFTst, // X87 + kX86InstFUCom, // X87 + kX86InstFUComI, // X87 + kX86InstFUComIP, // X87 + kX86InstFUComP, // X87 + kX86InstFUComPP, // X87 + kX86InstFWait, // X87 + kX86InstFXam, // X87 + kX86InstFXch, // X87 + kX86InstFXRstor, // X87 + kX86InstFXSave, // X87 + kX86InstFXtract, // X87 + kX86InstFYL2X, // X87 + kX86InstFYL2XP1, // X87 + kX86InstHAddPD, // SSE3 + kX86InstHAddPS, // SSE3 + kX86InstHSubPD, // SSE3 + kX86InstHSubPS, // SSE3 + kX86InstIDiv, // X86/X64 + kX86InstIMul, // X86/X64 + kX86InstInc, // X86/X64 + kX86InstInt3, // X86/X64 + kX86InstJ, // Begin (jcc) + kX86InstJA = kX86InstJ, // X86/X64 (jcc) + kX86InstJAE, // X86/X64 (jcc) + kX86InstJB, // X86/X64 (jcc) + kX86InstJBE, // X86/X64 (jcc) + kX86InstJC, // X86/X64 (jcc) + kX86InstJE, // X86/X64 (jcc) + kX86InstJG, // X86/X64 (jcc) + kX86InstJGE, // X86/X64 (jcc) + kX86InstJL, // X86/X64 (jcc) + kX86InstJLE, // X86/X64 (jcc) + kX86InstJNA, // X86/X64 (jcc) + kX86InstJNAE, // X86/X64 (jcc) + kX86InstJNB, // X86/X64 (jcc) + kX86InstJNBE, // X86/X64 (jcc) + kX86InstJNC, // X86/X64 (jcc) + kX86InstJNE, // X86/X64 (jcc) + kX86InstJNG, // X86/X64 (jcc) + kX86InstJNGE, // X86/X64 (jcc) + kX86InstJNL, // X86/X64 (jcc) + kX86InstJNLE, // X86/X64 (jcc) + kX86InstJNO, // X86/X64 (jcc) + kX86InstJNP, // X86/X64 (jcc) + kX86InstJNS, // X86/X64 (jcc) + kX86InstJNZ, // X86/X64 (jcc) + kX86InstJO, // X86/X64 (jcc) + kX86InstJP, // X86/X64 (jcc) + kX86InstJPE, // X86/X64 (jcc) + kX86InstJPO, // X86/X64 (jcc) + kX86InstJS, // X86/X64 (jcc) + kX86InstJZ, // X86/X64 (jcc) + kX86InstJmp, // X86/X64 (jmp) + kX86InstLdDQU, // SSE3 + kX86InstLdMXCSR, // SSE + kX86InstLahf, // X86/X64 (CPUID NEEDED) + kX86InstLea, // X86/X64 + kX86InstLeave, // X86/X64 + kX86InstLFence, // SSE2 + kX86InstMaskMovDQU, // SSE2 + kX86InstMaskMovQ, // MMX-Ext + kX86InstMaxPD, // SSE2 + kX86InstMaxPS, // SSE + kX86InstMaxSD, // SSE2 + kX86InstMaxSS, // SSE + kX86InstMFence, // SSE2 + kX86InstMinPD, // SSE2 + kX86InstMinPS, // SSE + kX86InstMinSD, // SSE2 + kX86InstMinSS, // SSE + kX86InstMonitor, // SSE3 + kX86InstMov, // X86/X64 + kX86InstMovAPD, // SSE2 + kX86InstMovAPS, // SSE + kX86InstMovBE, // SSE3 - Intel-Atom + kX86InstMovD, // MMX/SSE2 + kX86InstMovDDup, // SSE3 + kX86InstMovDQ2Q, // SSE2 + kX86InstMovDQA, // SSE2 + kX86InstMovDQU, // SSE2 + kX86InstMovHLPS, // SSE + kX86InstMovHPD, // SSE2 + kX86InstMovHPS, // SSE + kX86InstMovLHPS, // SSE + kX86InstMovLPD, // SSE2 + kX86InstMovLPS, // SSE + kX86InstMovMskPD, // SSE2 + kX86InstMovMskPS, // SSE2 + kX86InstMovNTDQ, // SSE2 + kX86InstMovNTDQA, // SSE4.1 + kX86InstMovNTI, // SSE2 + kX86InstMovNTPD, // SSE2 + kX86InstMovNTPS, // SSE + kX86InstMovNTQ, // MMX-Ext + kX86InstMovQ, // MMX/SSE/SSE2 + kX86InstMovQ2DQ, // SSE2 + kX86InstMovSD, // SSE2 + kX86InstMovSHDup, // SSE3 + kX86InstMovSLDup, // SSE3 + kX86InstMovSS, // SSE + kX86InstMovSX, // X86/X64 + kX86InstMovSXD, // X86/X64 + kX86InstMovUPD, // SSE2 + kX86InstMovUPS, // SSE + kX86InstMovZX, // X86/X64 + kX86InstMovPtr, // X86/X64 + kX86InstMPSADBW, // SSE4.1 + kX86InstMul, // X86/X64 + kX86InstMulPD, // SSE2 + kX86InstMulPS, // SSE + kX86InstMulSD, // SSE2 + kX86InstMulSS, // SSE + kX86InstMWait, // SSE3 + kX86InstNeg, // X86/X64 + kX86InstNop, // X86/X64 + kX86InstNot, // X86/X64 + kX86InstOr, // X86/X64 + kX86InstOrPD, // SSE2 + kX86InstOrPS, // SSE + kX86InstPAbsB, // SSSE3 + kX86InstPAbsD, // SSSE3 + kX86InstPAbsW, // SSSE3 + kX86InstPackSSDW, // MMX/SSE2 + kX86InstPackSSWB, // MMX/SSE2 + kX86InstPackUSDW, // SSE4.1 + kX86InstPackUSWB, // MMX/SSE2 + kX86InstPAddB, // MMX/SSE2 + kX86InstPAddD, // MMX/SSE2 + kX86InstPAddQ, // SSE2 + kX86InstPAddSB, // MMX/SSE2 + kX86InstPAddSW, // MMX/SSE2 + kX86InstPAddUSB, // MMX/SSE2 + kX86InstPAddUSW, // MMX/SSE2 + kX86InstPAddW, // MMX/SSE2 + kX86InstPAlignR, // SSSE3 + kX86InstPAnd, // MMX/SSE2 + kX86InstPAndN, // MMX/SSE2 + kX86InstPause, // SSE2. + kX86InstPAvgB, // MMX-Ext + kX86InstPAvgW, // MMX-Ext + kX86InstPBlendVB, // SSE4.1 + kX86InstPBlendW, // SSE4.1 + kX86InstPCmpEqB, // MMX/SSE2 + kX86InstPCmpEqD, // MMX/SSE2 + kX86InstPCmpEqQ, // SSE4.1 + kX86InstPCmpEqW, // MMX/SSE2 + kX86InstPCmpEStrI, // SSE4.2 + kX86InstPCmpEStrM, // SSE4.2 + kX86InstPCmpGtB, // MMX/SSE2 + kX86InstPCmpGtD, // MMX/SSE2 + kX86InstPCmpGtQ, // SSE4.2 + kX86InstPCmpGtW, // MMX/SSE2 + kX86InstPCmpIStrI, // SSE4.2 + kX86InstPCmpIStrM, // SSE4.2 + kX86InstPExtrB, // SSE4.1 + kX86InstPExtrD, // SSE4.1 + kX86InstPExtrQ, // SSE4.1 + kX86InstPExtrW, // MMX-Ext/SSE2 + kX86InstPF2ID, // 3dNow! + kX86InstPF2IW, // Enhanced 3dNow! + kX86InstPFAcc, // 3dNow! + kX86InstPFAdd, // 3dNow! + kX86InstPFCmpEQ, // 3dNow! + kX86InstPFCmpGE, // 3dNow! + kX86InstPFCmpGT, // 3dNow! + kX86InstPFMax, // 3dNow! + kX86InstPFMin, // 3dNow! + kX86InstPFMul, // 3dNow! + kX86InstPFNAcc, // Enhanced 3dNow! + kX86InstPFPNAcc, // Enhanced 3dNow! + kX86InstPFRcp, // 3dNow! + kX86InstPFRcpIt1, // 3dNow! + kX86InstPFRcpIt2, // 3dNow! + kX86InstPFRSqIt1, // 3dNow! + kX86InstPFRSqrt, // 3dNow! + kX86InstPFSub, // 3dNow! + kX86InstPFSubR, // 3dNow! + kX86InstPHAddD, // SSSE3 + kX86InstPHAddSW, // SSSE3 + kX86InstPHAddW, // SSSE3 + kX86InstPHMinPOSUW, // SSE4.1 + kX86InstPHSubD, // SSSE3 + kX86InstPHSubSW, // SSSE3 + kX86InstPHSubW, // SSSE3 + kX86InstPI2FD, // 3dNow! + kX86InstPI2FW, // Enhanced 3dNow! + kX86InstPInsRB, // SSE4.1 + kX86InstPInsRD, // SSE4.1 + kX86InstPInsRQ, // SSE4.1 + kX86InstPInsRW, // MMX-Ext + kX86InstPMAddUBSW, // SSSE3 + kX86InstPMAddWD, // MMX/SSE2 + kX86InstPMaxSB, // SSE4.1 + kX86InstPMaxSD, // SSE4.1 + kX86InstPMaxSW, // MMX-Ext + kX86InstPMaxUB, // MMX-Ext + kX86InstPMaxUD, // SSE4.1 + kX86InstPMaxUW, // SSE4.1 + kX86InstPMinSB, // SSE4.1 + kX86InstPMinSD, // SSE4.1 + kX86InstPMinSW, // MMX-Ext + kX86InstPMinUB, // MMX-Ext + kX86InstPMinUD, // SSE4.1 + kX86InstPMinUW, // SSE4.1 + kX86InstPMovMskB, // MMX-Ext + kX86InstPMovSXBD, // SSE4.1 + kX86InstPMovSXBQ, // SSE4.1 + kX86InstPMovSXBW, // SSE4.1 + kX86InstPMovSXDQ, // SSE4.1 + kX86InstPMovSXWD, // SSE4.1 + kX86InstPMovSXWQ, // SSE4.1 + kX86InstPMovZXBD, // SSE4.1 + kX86InstPMovZXBQ, // SSE4.1 + kX86InstPMovZXBW, // SSE4.1 + kX86InstPMovZXDQ, // SSE4.1 + kX86InstPMovZXWD, // SSE4.1 + kX86InstPMovZXWQ, // SSE4.1 + kX86InstPMulDQ, // SSE4.1 + kX86InstPMulHRSW, // SSSE3 + kX86InstPMulHUW, // MMX-Ext + kX86InstPMulHW, // MMX/SSE2 + kX86InstPMulLD, // SSE4.1 + kX86InstPMulLW, // MMX/SSE2 + kX86InstPMulUDQ, // SSE2 + kX86InstPop, // X86/X64 + kX86InstPopAD, // X86 only + kX86InstPopCnt, // SSE4.2 + kX86InstPopFD, // X86 only + kX86InstPopFQ, // X64 only + kX86InstPOr, // MMX/SSE2 + kX86InstPrefetch, // MMX-Ext + kX86InstPSADBW, // MMX-Ext + kX86InstPShufB, // SSSE3 + kX86InstPShufD, // SSE2 + kX86InstPShufW, // MMX-Ext + kX86InstPShufHW, // SSE2 + kX86InstPShufLW, // SSE2 + kX86InstPSignB, // SSSE3 + kX86InstPSignD, // SSSE3 + kX86InstPSignW, // SSSE3 + kX86InstPSllD, // MMX/SSE2 + kX86InstPSllDQ, // SSE2 + kX86InstPSllQ, // MMX/SSE2 + kX86InstPSllW, // MMX/SSE2 + kX86InstPSraD, // MMX/SSE2 + kX86InstPSraW, // MMX/SSE2 + kX86InstPSrlD, // MMX/SSE2 + kX86InstPSrlDQ, // SSE2 + kX86InstPSrlQ, // MMX/SSE2 + kX86InstPSrlW, // MMX/SSE2 + kX86InstPSubB, // MMX/SSE2 + kX86InstPSubD, // MMX/SSE2 + kX86InstPSubQ, // SSE2 + kX86InstPSubSB, // MMX/SSE2 + kX86InstPSubSW, // MMX/SSE2 + kX86InstPSubUSB, // MMX/SSE2 + kX86InstPSubUSW, // MMX/SSE2 + kX86InstPSubW, // MMX/SSE2 + kX86InstPSwapD, // Enhanced 3dNow! + kX86InstPTest, // SSE4.1 + kX86InstPunpckHBW, // MMX/SSE2 + kX86InstPunpckHDQ, // MMX/SSE2 + kX86InstPunpckHQDQ, // SSE2 + kX86InstPunpckHWD, // MMX/SSE2 + kX86InstPunpckLBW, // MMX/SSE2 + kX86InstPunpckLDQ, // MMX/SSE2 + kX86InstPunpckLQDQ, // SSE2 + kX86InstPunpckLWD, // MMX/SSE2 + kX86InstPush, // X86/X64 + kX86InstPushAD, // X86 only + kX86InstPushFD, // X86 only + kX86InstPushFQ, // X64 only + kX86InstPXor, // MMX/SSE2 + kX86InstRcl, // X86/X64 + kX86InstRcpPS, // SSE + kX86InstRcpSS, // SSE + kX86InstRcr, // X86/X64 + kX86InstRdtsc, // X86/X64 + kX86InstRdtscP, // X86/X64 + kX86InstRepLodSB, // X86/X64 (REP) + kX86InstRepLodSD, // X86/X64 (REP) + kX86InstRepLodSQ, // X64 only (REP) + kX86InstRepLodSW, // X86/X64 (REP) + kX86InstRepMovSB, // X86/X64 (REP) + kX86InstRepMovSD, // X86/X64 (REP) + kX86InstRepMovSQ, // X64 only (REP) + kX86InstRepMovSW, // X86/X64 (REP) + kX86InstRepStoSB, // X86/X64 (REP) + kX86InstRepStoSD, // X86/X64 (REP) + kX86InstRepStoSQ, // X64 only (REP) + kX86InstRepStoSW, // X86/X64 (REP) + kX86InstRepECmpSB, // X86/X64 (REP) + kX86InstRepECmpSD, // X86/X64 (REP) + kX86InstRepECmpSQ, // X64 only (REP) + kX86InstRepECmpSW, // X86/X64 (REP) + kX86InstRepEScaSB, // X86/X64 (REP) + kX86InstRepEScaSD, // X86/X64 (REP) + kX86InstRepEScaSQ, // X64 only (REP) + kX86InstRepEScaSW, // X86/X64 (REP) + kX86InstRepNECmpSB, // X86/X64 (REP) + kX86InstRepNECmpSD, // X86/X64 (REP) + kX86InstRepNECmpSQ, // X64 only (REP) + kX86InstRepNECmpSW, // X86/X64 (REP) + kX86InstRepNEScaSB, // X86/X64 (REP) + kX86InstRepNEScaSD, // X86/X64 (REP) + kX86InstRepNEScaSQ, // X64 only (REP) + kX86InstRepNEScaSW, // X86/X64 (REP) + kX86InstRet, // X86/X64 + kX86InstRol, // X86/X64 + kX86InstRor, // X86/X64 + kX86InstRoundPD, // SSE4.1 + kX86InstRoundPS, // SSE4.1 + kX86InstRoundSD, // SSE4.1 + kX86InstRoundSS, // SSE4.1 + kX86InstRSqrtPS, // SSE + kX86InstRSqrtSS, // SSE + kX86InstSahf, // X86/X64 (CPUID NEEDED) + kX86InstSal, // X86/X64 + kX86InstSar, // X86/X64 + kX86InstSbb, // X86/X64 + kX86InstSet, // Begin (setcc) + kX86InstSetA=kX86InstSet,// X86/X64 (setcc) + kX86InstSetAE, // X86/X64 (setcc) + kX86InstSetB, // X86/X64 (setcc) + kX86InstSetBE, // X86/X64 (setcc) + kX86InstSetC, // X86/X64 (setcc) + kX86InstSetE, // X86/X64 (setcc) + kX86InstSetG, // X86/X64 (setcc) + kX86InstSetGE, // X86/X64 (setcc) + kX86InstSetL, // X86/X64 (setcc) + kX86InstSetLE, // X86/X64 (setcc) + kX86InstSetNA, // X86/X64 (setcc) + kX86InstSetNAE, // X86/X64 (setcc) + kX86InstSetNB, // X86/X64 (setcc) + kX86InstSetNBE, // X86/X64 (setcc) + kX86InstSetNC, // X86/X64 (setcc) + kX86InstSetNE, // X86/X64 (setcc) + kX86InstSetNG, // X86/X64 (setcc) + kX86InstSetNGE, // X86/X64 (setcc) + kX86InstSetNL, // X86/X64 (setcc) + kX86InstSetNLE, // X86/X64 (setcc) + kX86InstSetNO, // X86/X64 (setcc) + kX86InstSetNP, // X86/X64 (setcc) + kX86InstSetNS, // X86/X64 (setcc) + kX86InstSetNZ, // X86/X64 (setcc) + kX86InstSetO, // X86/X64 (setcc) + kX86InstSetP, // X86/X64 (setcc) + kX86InstSetPE, // X86/X64 (setcc) + kX86InstSetPO, // X86/X64 (setcc) + kX86InstSetS, // X86/X64 (setcc) + kX86InstSetZ, // X86/X64 (setcc) + kX86InstSFence, // MMX-Ext/SSE + kX86InstShl, // X86/X64 + kX86InstShld, // X86/X64 + kX86InstShr, // X86/X64 + kX86InstShrd, // X86/X64 + kX86InstShufPD, // SSE2 + kX86InstShufPS, // SSE + kX86InstSqrtPD, // SSE2 + kX86InstSqrtPS, // SSE + kX86InstSqrtSD, // SSE2 + kX86InstSqrtSS, // SSE + kX86InstStc, // X86/X64 + kX86InstStd, // X86/X64 + kX86InstStMXCSR, // SSE + kX86InstSub, // X86/X64 + kX86InstSubPD, // SSE2 + kX86InstSubPS, // SSE + kX86InstSubSD, // SSE2 + kX86InstSubSS, // SSE + kX86InstTest, // X86/X64 + kX86InstUComISD, // SSE2 + kX86InstUComISS, // SSE + kX86InstUd2, // X86/X64 + kX86InstUnpckHPD, // SSE2 + kX86InstUnpckHPS, // SSE + kX86InstUnpckLPD, // SSE2 + kX86InstUnpckLPS, // SSE + kX86InstXadd, // X86/X64 (i486) + kX86InstXchg, // X86/X64 (i386) + kX86InstXor, // X86/X64 + kX86InstXorPD, // SSE2 + kX86InstXorPS, // SSE + + _kX86InstCount, + + _kX86InstJBegin = kX86InstJ, + _kX86InstJEnd = kX86InstJmp +}; + +// ============================================================================ +// [AsmJit::kX86InstGroup] +// ============================================================================ + +//! @brief X86 instruction groups. +//! +//! This should be only used by assembler, because it's @c AsmJit::Assembler +//! specific grouping. Each group represents one 'case' in the Assembler's +//! main emit method. +enum kX86InstGroup +{ + // Group categories. + kX86InstGroupNone, + kX86InstGroupEmit, + + kX86InstGroupArith, + kX86InstGroupBSwap, + kX86InstGroupBTest, + kX86InstGroupCall, + kX86InstGroupCrc32, + kX86InstGroupEnter, + kX86InstGroupIMul, + kX86InstGroupIncDec, + kX86InstGroupJcc, + kX86InstGroupJmp, + kX86InstGroupLea, + kX86InstGroupMem, + kX86InstGroupMov, + kX86InstGroupMovPtr, + kX86InstGroupMovSxMovZx, + kX86InstGroupMovSxD, + kX86InstGroupPush, + kX86InstGroupPop, + kX86InstGroupRegRm, + kX86InstGroupRm, + kX86InstGroupRmByte, + kX86InstGroupRmReg, + kX86InstGroupRep, + kX86InstGroupRet, + kX86InstGroupRot, + kX86InstGroupShldShrd, + kX86InstGroupTest, + kX86InstGroupXchg, + + // Group for x87 FP instructions in format mem or st(i), st(i) (fadd, fsub, fdiv, ...) + kX86InstGroupX87StM, + // Group for x87 FP instructions in format st(i), st(i) + kX86InstGroupX87StI, + // Group for fld/fst/fstp instruction, internally uses @ref kX86InstGroupX87StM group. + kX86InstGroupX87FldFst, + // Group for x87 FP instructions that uses Word, DWord, QWord or TWord memory pointer. + kX86InstGroupX87Mem, + // Group for x87 FSTSW/FNSTSW instructions + kX86InstGroupX87Status, + + // Group for movbe instruction + kX86InstGroupMovBE, + + // Group for MMX/SSE instructions in format (X)MM|Reg|Mem <- (X)MM|Reg|Mem, + // 0x66 prefix must be set manually in opcodes. + // - Primary opcode is used for instructions in (X)MM <- (X)MM/Mem format, + // - Secondary opcode is used for instructions in (X)MM/Mem <- (X)MM format. + kX86InstGroupMmuMov, + kX86InstGroupMmuMovD, + kX86InstGroupMmuMovQ, + + // Group for pextrd, pextrq and pextrw instructions (it's special instruction + // not similar to others) + kX86InstGroupMmuExtract, + // Group for prefetch instruction + kX86InstGroupMmuPrefetch, + + // Group for MMX/SSE instructions in format (X)MM|Reg <- (X)MM|Reg|Mem|Imm, + // 0x66 prefix is added for MMX instructions that used by SSE2 registers. + // - Primary opcode is used for instructions in (X)MM|Reg <- (X)MM|Reg|Mem format, + // - Secondary opcode is iused for instructions in (X)MM|Reg <- Imm format. + kX86InstGroupMmuRmI, + kX86InstGroupMmuRmImm8, + // Group for 3dNow instructions + kX86InstGroupMmuRm3dNow +}; + +// ============================================================================ +// [AsmJit::kX86InstFlags] +// ============================================================================ + +//! @brief X86 instruction type flags. +enum kX86InstFlags +{ + //! @brief No flags. + kX86InstFlagNone = 0x00, + + //! @brief Instruction is jump, conditional jump, call or ret. + kX86InstFlagJump = 0x01, + + //! @brief Instruction will overwrite first operand - o[0]. + kX86InstFlagMov = 0x02, + + //! @brief Instruction is X87 FPU. + kX86InstFlagFpu = 0x04, + + //! @brief Instruction can be prepended using LOCK prefix + //! (usable for multithreaded applications). + kX86InstFlagLockable = 0x08, + + //! @brief Instruction is special, this is for @c Compiler. + kX86InstFlagSpecial = 0x10, + + //! @brief Instruction always performs memory access. + //! + //! This flag is always combined with @c kX86InstFlagSpecial and signalizes + //! that there is an implicit address which is accessed (usually EDI/RDI or + //! ESI/EDI). + kX86InstFlagSpecialMem = 0x20 +}; + +// ============================================================================ +// [AsmJit::kX86InstOp] +// ============================================================================ + +//! @brief X86 instruction operand flags. +enum kX86InstOp +{ + // X86, MM, XMM + kX86InstOpGb = 0x0001, + kX86InstOpGw = 0x0002, + kX86InstOpGd = 0x0004, + kX86InstOpGq = 0x0008, + kX86InstOpMm = 0x0010, + kX86InstOpXmm = 0x0020, + kX86InstOpMem = 0x0040, + kX86InstOpImm = 0x0080, + + kX86InstOpGbMem = kX86InstOpGb | kX86InstOpMem, + kX86InstOpGwMem = kX86InstOpGw | kX86InstOpMem, + kX86InstOpGdMem = kX86InstOpGd | kX86InstOpMem, + kX86InstOpGqMem = kX86InstOpGq | kX86InstOpMem, + + kX86InstOpGqdwb = kX86InstOpGq | kX86InstOpGd | kX86InstOpGw | kX86InstOpGb, + kX86InstOpGqdw = kX86InstOpGq | kX86InstOpGd | kX86InstOpGw, + kX86InstOpGqd = kX86InstOpGq | kX86InstOpGd, + kX86InstOpGwb = kX86InstOpGw | kX86InstOpGb, + + kX86InstOpGqdwbMem = kX86InstOpGqdwb | kX86InstOpMem, + kX86InstOpGqdwMem = kX86InstOpGqdw | kX86InstOpMem, + kX86InstOpGqdMem = kX86InstOpGqd | kX86InstOpMem, + kX86InstOpGwbMem = kX86InstOpGwb | kX86InstOpMem, + + // MMX/XMM. + kX86InstOpMmMem = kX86InstOpMm | kX86InstOpMem, + kX86InstOpXmmMem = kX86InstOpXmm | kX86InstOpMem, + kX86InstOpMmXmm = kX86InstOpMm | kX86InstOpXmm, + kX86InstOpMmXmmMem = kX86InstOpMmXmm | kX86InstOpMem, + + // X87. + kX86InstOpStM2 = kX86InstOpMem | 0x0100, + kX86InstOpStM4 = kX86InstOpMem | 0x0200, + kX86InstOpStM8 = kX86InstOpMem | 0x0400, + kX86InstOpStM10 = kX86InstOpMem | 0x0800, + + kX86InstOpStM2_4 = kX86InstOpStM2 | kX86InstOpStM4, + kX86InstOpStM2_4_8 = kX86InstOpStM2_4 | kX86InstOpStM8, + kX86InstOpStM4_8 = kX86InstOpStM4 | kX86InstOpStM8, + kX86InstOpStM4_8_10 = kX86InstOpStM4_8 | kX86InstOpStM10, + + // Don't emit REX prefix. + kX86InstOpNoRex = 0x2000 +}; + +// ============================================================================ +// [AsmJit::x86InstName] +// ============================================================================ + +//! @internal +//! +//! @brief X86 instruction names. +ASMJIT_VAR const char x86InstName[]; + +// ============================================================================ +// [AsmJit::X86InstInfo] +// ============================================================================ + +//! @brief X86 instruction information. +struct X86InstInfo +{ + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get instruction code, see @ref kX86InstCode. + inline uint32_t getCode() const + { return _code; } + + //! @brief Get instruction name string (null terminated string). + inline const char* getName() const + { return x86InstName + static_cast(_nameIndex); } + + //! @brief Get instruction name index (index to @ref x86InstName array). + inline uint32_t getNameIndex() const + { return _nameIndex; } + + //! @brief Get instruction group, see @ref kX86InstGroup. + inline uint32_t getGroup() const + { return _group; } + + //! @brief Get instruction flags, see @ref kX86InstFlags. + inline uint32_t getFlags() const + { return _group; } + + //! @brief Get whether the instruction is conditional or standard jump. + inline bool isJump() const + { return (_flags & kX86InstFlagJump) != 0; } + + //! @brief Get whether the instruction is MOV type. + inline bool isMov() const + { return (_flags & kX86InstFlagMov) != 0; } + + //! @brief Get whether the instruction is X87 FPU type. + inline bool isFpu() const + { return (_flags & kX86InstFlagFpu) != 0; } + + //! @brief Get whether the instruction can be prefixed by LOCK prefix. + inline bool isLockable() const + { return (_flags & kX86InstFlagLockable) != 0; } + + //! @brief Get whether the instruction is special type (this is used by + //! @c Compiler to manage additional variables or functionality). + inline bool isSpecial() const + { return (_flags & kX86InstFlagSpecial) != 0; } + + //! @brief Get whether the instruction is special type and it performs + //! memory access. + inline bool isSpecialMem() const + { return (_flags & kX86InstFlagSpecialMem) != 0; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Instruction code. + uint16_t _code; + //! @brief Instruction name index in x86InstName[] array. + uint16_t _nameIndex; + //! @brief Instruction group, used also by @c Compiler. + uint8_t _group; + //! @brief Instruction type flags. + uint8_t _flags; + + //! @brief First and second operand flags (some groups depends on these settings, used also by @c Compiler). + uint16_t _opFlags[2]; + //! @brief If instruction has only memory operand, this is register opcode. + uint16_t _opCodeR; + //! @brief Primary and secondary opcodes. + uint32_t _opCode[2]; +}; + +// ============================================================================ +// [AsmJit::x86InstInfo] +// ============================================================================ + +ASMJIT_VAR const X86InstInfo x86InstInfo[]; + +// ============================================================================ +// [AsmJit::kX86FuncConv] +// ============================================================================ + +//! @brief X86 function calling conventions. +//! +//! Calling convention is scheme how function arguments are passed into +//! function and how functions returns values. In assembler programming +//! it's needed to always comply with function calling conventions, because +//! even small inconsistency can cause undefined behavior or crash. +//! +//! List of calling conventions for 32-bit x86 mode: +//! - @c kX86FuncConvCDecl - Calling convention for C runtime. +//! - @c kX86FuncConvStdCall - Calling convention for WinAPI functions. +//! - @c kX86FuncConvMsThisCall - Calling convention for C++ members under +//! Windows (produced by MSVC and all MSVC compatible compilers). +//! - @c kX86FuncConvMsFastCall - Fastest calling convention that can be used +//! by MSVC compiler. +//! - @c kX86FuncConv_BORNANDFASTCALL - Borland fastcall convention. +//! - @c kX86FuncConvGccFastCall - GCC fastcall convention (2 register arguments). +//! - @c kX86FuncConvGccRegParm1 - GCC regparm(1) convention. +//! - @c kX86FuncConvGccRegParm2 - GCC regparm(2) convention. +//! - @c kX86FuncConvGccRegParm3 - GCC regparm(3) convention. +//! +//! List of calling conventions for 64-bit x86 mode (x64): +//! - @c kX86FuncConvX64W - Windows 64-bit calling convention (WIN64 ABI). +//! - @c kX86FuncConvX64U - Unix 64-bit calling convention (AMD64 ABI). +//! +//! There is also @c kX86FuncConvDefault that is defined to fit best to your +//! compiler. +//! +//! These types are used together with @c AsmJit::Compiler::newFunc() +//! method. +enum kX86FuncConv +{ + // -------------------------------------------------------------------------- + // [X64] + // -------------------------------------------------------------------------- + + //! @brief X64 calling convention for Windows platform (WIN64 ABI). + //! + //! For first four arguments are used these registers: + //! - 1. 32/64-bit integer or floating point argument - rcx/xmm0 + //! - 2. 32/64-bit integer or floating point argument - rdx/xmm1 + //! - 3. 32/64-bit integer or floating point argument - r8/xmm2 + //! - 4. 32/64-bit integer or floating point argument - r9/xmm3 + //! + //! Note first four arguments here means arguments at positions from 1 to 4 + //! (included). For example if second argument is not passed by register then + //! rdx/xmm1 register is unused. + //! + //! All other arguments are pushed on the stack in right-to-left direction. + //! Stack is aligned by 16 bytes. There is 32-byte shadow space on the stack + //! that can be used to save up to four 64-bit registers (probably designed to + //! be used to save first four arguments passed in registers). + //! + //! Arguments direction: + //! - Right to Left (except for first 4 parameters that's in registers) + //! + //! Stack is cleaned by: + //! - Caller. + //! + //! Return value: + //! - Integer types - RAX register. + //! - Floating points - XMM0 register. + //! + //! Stack is always aligned by 16 bytes. + //! + //! More information about this calling convention can be found on MSDN: + //! http://msdn.microsoft.com/en-us/library/9b372w95.aspx . + kX86FuncConvX64W = 1, + + //! @brief X64 calling convention for Unix platforms (AMD64 ABI). + //! + //! First six 32 or 64-bit integer arguments are passed in rdi, rsi, rdx, + //! rcx, r8, r9 registers. First eight floating point or XMM arguments + //! are passed in xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 registers. + //! This means that in registers can be transferred up to 14 arguments total. + //! + //! There is also RED ZONE below the stack pointer that can be used for + //! temporary storage. The red zone is the space from [rsp-128] to [rsp-8]. + //! + //! Arguments direction: + //! - Right to Left (Except for arguments passed in registers). + //! + //! Stack is cleaned by: + //! - Caller. + //! + //! Return value: + //! - Integer types - RAX register. + //! - Floating points - XMM0 register. + //! + //! Stack is always aligned by 16 bytes. + kX86FuncConvX64U = 2, + + // -------------------------------------------------------------------------- + // [X86] + // -------------------------------------------------------------------------- + + //! @brief Cdecl calling convention (used by C runtime). + //! + //! Compatible across MSVC and GCC. + //! + //! Arguments direction: + //! - Right to Left + //! + //! Stack is cleaned by: + //! - Caller. + kX86FuncConvCDecl = 3, + + //! @brief Stdcall calling convention (used by WinAPI). + //! + //! Compatible across MSVC and GCC. + //! + //! Arguments direction: + //! - Right to Left + //! + //! Stack is cleaned by: + //! - Callee. + //! + //! Return value: + //! - Integer types - EAX:EDX registers. + //! - Floating points - st(0) register. + kX86FuncConvStdCall = 4, + + //! @brief MSVC specific calling convention used by MSVC/Intel compilers + //! for struct/class methods. + //! + //! This is MSVC (and Intel) only calling convention used in Windows + //! world for C++ class methods. Implicit 'this' pointer is stored in + //! ECX register instead of storing it on the stack. + //! + //! Arguments direction: + //! - Right to Left (except this pointer in ECX) + //! + //! Stack is cleaned by: + //! - Callee. + //! + //! Return value: + //! - Integer types - EAX:EDX registers. + //! - Floating points - st(0) register. + //! + //! C++ class methods that have variable count of arguments uses different + //! calling convention called cdecl. + //! + //! @note This calling convention is always used by MSVC for class methods, + //! it's implicit and there is no way how to override it. + kX86FuncConvMsThisCall = 5, + + //! @brief MSVC specific fastcall. + //! + //! Two first parameters (evaluated from left-to-right) are in ECX:EDX + //! registers, all others on the stack in right-to-left order. + //! + //! Arguments direction: + //! - Right to Left (except to first two integer arguments in ECX:EDX) + //! + //! Stack is cleaned by: + //! - Callee. + //! + //! Return value: + //! - Integer types - EAX:EDX registers. + //! - Floating points - st(0) register. + //! + //! @note This calling convention differs to GCC one in stack cleaning + //! mechanism. + kX86FuncConvMsFastCall = 6, + + //! @brief Borland specific fastcall with 2 parameters in registers. + //! + //! Two first parameters (evaluated from left-to-right) are in ECX:EDX + //! registers, all others on the stack in left-to-right order. + //! + //! Arguments direction: + //! - Left to Right (except to first two integer arguments in ECX:EDX) + //! + //! Stack is cleaned by: + //! - Callee. + //! + //! Return value: + //! - Integer types - EAX:EDX registers. + //! - Floating points - st(0) register. + //! + //! @note Arguments on the stack are in left-to-right order that differs + //! to other fastcall conventions used in different compilers. + kX86FuncConvBorlandFastCall = 7, + + //! @brief GCC specific fastcall convention. + //! + //! Two first parameters (evaluated from left-to-right) are in ECX:EDX + //! registers, all others on the stack in right-to-left order. + //! + //! Arguments direction: + //! - Right to Left (except to first two integer arguments in ECX:EDX) + //! + //! Stack is cleaned by: + //! - Callee. + //! + //! Return value: + //! - Integer types - EAX:EDX registers. + //! - Floating points - st(0) register. + //! + //! @note This calling convention should be compatible to + //! @c kX86FuncConvMsFastCall. + kX86FuncConvGccFastCall = 8, + + //! @brief GCC specific regparm(1) convention. + //! + //! The first parameter (evaluated from left-to-right) is in EAX register, + //! all others on the stack in right-to-left order. + //! + //! Arguments direction: + //! - Right to Left (except to first one integer argument in EAX) + //! + //! Stack is cleaned by: + //! - Caller. + //! + //! Return value: + //! - Integer types - EAX:EDX registers. + //! - Floating points - st(0) register. + kX86FuncConvGccRegParm1 = 9, + + //! @brief GCC specific regparm(2) convention. + //! + //! Two first parameters (evaluated from left-to-right) are in EAX:EDX + //! registers, all others on the stack in right-to-left order. + //! + //! Arguments direction: + //! - Right to Left (except to first two integer arguments in EAX:EDX) + //! + //! Stack is cleaned by: + //! - Caller. + //! + //! Return value: + //! - Integer types - EAX:EDX registers. + //! - Floating points - st(0) register. + kX86FuncConvGccRegParm2 = 10, + + //! @brief GCC specific fastcall with 3 parameters in registers. + //! + //! Three first parameters (evaluated from left-to-right) are in + //! EAX:EDX:ECX registers, all others on the stack in right-to-left order. + //! + //! Arguments direction: + //! - Right to Left (except to first three integer arguments in EAX:EDX:ECX) + //! + //! Stack is cleaned by: + //! - Caller. + //! + //! Return value: + //! - Integer types - EAX:EDX registers. + //! - Floating points - st(0) register. + kX86FuncConvGccRegParm3 = 11, + + // -------------------------------------------------------------------------- + // [Detect] + // -------------------------------------------------------------------------- + + //! @def kX86FuncConvDefault + //! @brief Default calling convention for current platform / operating system. + + //! @def kX86FuncConvCompatFastCall + //! @brief Compatibility for __fastcall calling convention. + //! + //! @note This enumeration is always set to a value which is compatible to + //! current compilers __fastcall calling convention. In 64-bit mode the value + //! is compatible to @ref kX86FuncConvX64W or @ref kX86FuncConvX64U. + + //! @def kX86FuncConvCompatStdCall + //! @brief Compatibility for __stdcall calling convention. + //! + //! @note This enumeration is always set to a value which is compatible to + //! current compilers __stdcall calling convention. In 64-bit mode the value + //! is compatible to @ref kX86FuncConvX64W or @ref kX86FuncConvX64U. + + //! @def kX86FuncConvCompatCDecl + //! @brief Default C calling convention based on current compiler's settings. + +#if defined(ASMJIT_X86) + + kX86FuncConvDefault = kX86FuncConvCDecl, + +# if defined(_MSC_VER) + kX86FuncConvCompatFastCall = kX86FuncConvMsFastCall, +# elif defined(__GNUC__) + kX86FuncConvCompatFastCall = kX86FuncConvGccFastCall, +# elif defined(__BORLANDC__) + kX86FuncConvCompatFastCall = kX86FuncConvBorlandFastCall, +# else +# error "AsmJit::kX86FuncConvCompatFastCall not supported." +# endif + + kX86FuncConvCompatStdCall = kX86FuncConvStdCall, + kX86FuncConvCompatCDecl = kX86FuncConvCDecl + +#else + +# if defined(ASMJIT_WINDOWS) + kX86FuncConvDefault = kX86FuncConvX64W, +# else + kX86FuncConvDefault = kX86FuncConvX64U, +# endif + + kX86FuncConvCompatFastCall = kX86FuncConvDefault, + kX86FuncConvCompatStdCall = kX86FuncConvDefault, + kX86FuncConvCompatCDecl = kX86FuncConvDefault + +#endif // ASMJIT_X86 +}; + +// ============================================================================ +// [AsmJit::kX86FuncHint] +// ============================================================================ + +//! @brief X86 function hints. +enum kX86FuncHint +{ + //! @brief Use push/pop sequences instead of mov sequences in function prolog + //! and epilog. + kX86FuncHintPushPop = 8, + //! @brief Add emms instruction to the function epilog. + kX86FuncHintEmms = 9, + //! @brief Add sfence instruction to the function epilog. + kX86FuncHintSFence = 10, + //! @brief Add lfence instruction to the function epilog. + kX86FuncHintLFence = 11, + //! @brief Assume that stack is aligned to 16-bytes. + kX86FuncHintAssume16ByteAlignment = 12, + //! @brief Perform 16-byte stack alignmend by function. + kX86FuncHintPerform16ByteAlignment = 13 +}; + +// ============================================================================ +// [AsmJit::kX86FuncFlags] +// ============================================================================ + +//! @brief X86 function flags. +enum kX86FuncFlags +{ + //! @brief Whether to emit prolog / epilog sequence using push & pop + //! instructions (the default). + kX86FuncFlagPushPop = (1U << 8), + + //! @brief Whether to emit EMMS instruction in epilog (auto-detected). + kX86FuncFlagEmitEmms = (1U << 9), + + //! @brief Whether to emit SFence instruction in epilog (auto-detected). + //! + //! @note @ref kX86FuncFlagEmitSFence and @ref kX86FuncFlagEmitLFence + //! combination will result in emitting mfence. + kX86FuncFlagEmitSFence = (1U << 10), + + //! @brief Whether to emit LFence instruction in epilog (auto-detected). + //! + //! @note @ref kX86FuncFlagEmitSFence and @ref kX86FuncFlagEmitLFence + //! combination will result in emitting mfence. + kX86FuncFlagEmitLFence = (1U << 11), + + //! @brief Whether the function stack is aligned by 16-bytes by OS. + //! + //! This is always true for 64-bit mode and for linux. + kX86FuncFlagAssume16ByteAlignment = (1U << 12), + + //! @brief Whether the function stack (for variables) is aligned manually + //! by function to 16-bytes. + //! + //! This makes sense only if @ref kX86FuncFlagAssume16ByteAlignment is + //! false and MOVDQA instruction or other SSE/SSE2 instructions are used to + //! work with variables stored on the stack. + //! + //! Value is determined automatically by these factors, expectations are: + //! + //! 1. There is 16-byte wide variable which address was used (alloc, spill, + //! op). + //! 2. Function can't be naked. + kX86FuncFlagPerform16ByteAlignment = (1U << 13), + + //! @brief Whether the ESP register is adjusted by the stack size needed + //! to save registers and function variables. + //! + //! Esp is adjusted by 'sub' instruction in prolog and by add function in + //! epilog (only if function is not naked). + kX86FuncFlagIsEspAdjusted = (1U << 14) +}; + +// ============================================================================ +// [AsmJit::kX86CompilerInst] +// ============================================================================ + +//! @brief Instruction flags used by @ref X86CompilerInst item. +enum kX86CompilerInstFlag +{ + //! @brief Whether the instruction is special. + kX86CompilerInstFlagIsSpecial = (1U << 0), + //! @brief Whether the instruction is FPU. + kX86CompilerInstFlagIsFpu = (1U << 1), + //! @brief Whether the one of the operands is GPB.Lo register. + kX86CompilerInstFlagIsGpbLoUsed = (1U << 2), + //! @brief Whether the one of the operands is GPB.Hi register. + kX86CompilerInstFlagIsGpbHiUsed = (1U << 3), + + //! @brief Whether the jmp/jcc is likely to be taken. + kX86CompilerInstFlagIsTaken = (1U << 7) +}; + +// ============================================================================ +// [AsmJit::kX86VarClass] +// ============================================================================ + +//! @brief X86 variable class. +enum kX86VarClass +{ + //! @brief No class (used internally). + kX86VarClassNone = 0, + //! @brief General purpose register. + kX86VarClassGp = 1, + //! @brief X87 floating point. + kX86VarClassX87 = 2, + //! @brief MMX register. + kX86VarClassMm = 3, + //! @brief XMM register. + kX86VarClassXmm = 4, + + //! @brief Count of X86 variable classes. + kX86VarClassCount = 5 +}; + +// ============================================================================ +// [AsmJit::kX86VarFlags] +// ============================================================================ + +//! @brief X86 variable class. +enum kX86VarFlags +{ + //! @brief Variable contains single-precision floating-point(s). + kX86VarFlagSP = 0x10, + //! @brief Variable contains double-precision floating-point(s). + kX86VarFlagDP = 0x20, + //! @brief Variable is packed (for example float4x, double2x, ...). + kX86VarFlagPacked = 0x40 +}; + +// ============================================================================ +// [AsmJit::kX86VarType] +// ============================================================================ + +//! @brief X86 variable type. +enum kX86VarType +{ + // -------------------------------------------------------------------------- + // [Platform Dependent] + // -------------------------------------------------------------------------- + + //! @brief Variable is 32-bit general purpose register. + kX86VarTypeGpd = 0, + //! @brief Variable is 64-bit general purpose register. + kX86VarTypeGpq = 1, + + //! @var kX86VarTypeGpz + //! @brief Variable is system wide general purpose register (32-bit or 64-bit). +#if defined(ASMJIT_X86) + kX86VarTypeGpz = kX86VarTypeGpd, +#else + kX86VarTypeGpz = kX86VarTypeGpq, +#endif + + //! @brief Variable is X87 (FPU). + kX86VarTypeX87 = 2, + //! @brief Variable is X87 (FPU) SP-FP number (float). + kX86VarTypeX87SS = 3, + //! @brief Variable is X87 (FPU) DP-FP number (double). + kX86VarTypeX87SD = 4, + + //! @brief Variable is MM register / memory location. + kX86VarTypeMm = 5, + //! @brief Variable is XMM register / memory location. + kX86VarTypeXmm = 6, + + //! @brief Variable is SSE scalar SP-FP number. + kX86VarTypeXmmSS = 7, + //! @brief Variable is SSE packed SP-FP number (4 floats). + kX86VarTypeXmmPS = 8, + + //! @brief Variable is SSE2 scalar DP-FP number. + kX86VarTypeXmmSD = 9, + //! @brief Variable is SSE2 packed DP-FP number (2 doubles). + kX86VarTypeXmmPD = 10, + + //! @brief Count of variable types. + kX86VarTypeCount = 11, + + // -------------------------------------------------------------------------- + // [Platform Independent] + // -------------------------------------------------------------------------- + + //! @brief Variable is 32-bit integer. + kX86VarTypeInt32 = kX86VarTypeGpd, + //! @brief Variable is 64-bit integer. + kX86VarTypeInt64 = kX86VarTypeGpq, + //! @brief Variable is system dependent integer / pointer. + kX86VarTypeIntPtr = kX86VarTypeGpz, + +#if defined(ASMJIT_X86) + kX86VarTypeFloat = kX86VarTypeX87SS, + kX86VarTypeDouble = kX86VarTypeX87SD +#else + kX86VarTypeFloat = kX86VarTypeXmmSS, + kX86VarTypeDouble = kX86VarTypeXmmSD +#endif +}; + +// ============================================================================ +// [AsmJit::X86VarInfo] +// ============================================================================ + +//! @brief X86 variable information. +struct X86VarInfo +{ + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + //! @brief Get register code base, see @ref kX86RegCode. + inline uint32_t getCode() const + { return _code; } + + //! @brief Get register size in bytes. + inline uint32_t getSize() const + { return _size; } + + //! @brief Get variable class, see @ref kX86VarClass. + inline uint32_t getClass() const + { return _class; } + + //! @brief Get variable flags, see @ref kX86VarFlags. + inline uint32_t getFlags() const + { return _flags; } + + //! @brief Get variable type name. + inline const char* getName() const + { return _name; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Register code base, see @ref kX86RegCode. + uint32_t _code; + //! @brief Register size in bytes. + uint16_t _size; + //! @brief Variable class, see @ref kX86VarClass. + uint8_t _class; + //! @brief Variable flags, see @ref kX86VarFlags. + uint8_t _flags; + //! @brief Variable type name. + char _name[8]; +}; + +// ============================================================================ +// [AsmJit::x86VarInfo] +// ============================================================================ + +ASMJIT_VAR const X86VarInfo x86VarInfo[]; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_X86_X86DEFS_H diff --git a/desmume/src/utils/AsmJit/x86/x86func.cpp b/desmume/src/utils/AsmJit/x86/x86func.cpp new file mode 100644 index 000000000..1011d16a6 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86func.cpp @@ -0,0 +1,645 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../core/assert.h" +#include "../core/intutil.h" +#include "../core/stringutil.h" + +#include "../x86/x86defs.h" +#include "../x86/x86func.h" +#include "../x86/x86util.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::X86FuncDecl - Accessors] +// ============================================================================ + +uint32_t X86FuncDecl::findArgumentByRegCode(uint32_t regCode) const +{ + uint32_t type = regCode & kRegTypeMask; + uint32_t idx = regCode & kRegIndexMask; + + uint32_t clazz; + + switch (type) + { + case kX86RegTypeGpd: + case kX86RegTypeGpq: + clazz = kX86VarClassGp; + break; + + case kX86RegTypeX87: + clazz = kX86VarClassX87; + break; + + case kX86RegTypeMm: + clazz = kX86VarClassMm; + break; + + case kX86RegTypeXmm: + clazz = kX86VarClassXmm; + break; + + default: + return kInvalidValue; + } + + for (uint32_t i = 0; i < _argumentsCount; i++) + { + const FuncArg& arg = _arguments[i]; + + if (arg.getRegIndex() == idx && (X86Util::getVarClassFromVarType(arg.getVarType()) & clazz) != 0) + return i; + } + + return kInvalidValue; +} + +// ============================================================================ +// [AsmJit::X86FuncDecl - SetPrototype - InitCallingConvention] +// ============================================================================ + +static void X86FuncDecl_initCallingConvention(X86FuncDecl* self, uint32_t convention) +{ + uint32_t i; + + // -------------------------------------------------------------------------- + // [Inir] + // -------------------------------------------------------------------------- + + self->_convention = convention; + self->_calleePopsStack = false; + self->_argumentsDirection = kFuncArgsRTL; + + for (i = 0; i < ASMJIT_ARRAY_SIZE(self->_gpList); i++) + self->_gpList[i] = kRegIndexInvalid; + + for (i = 0; i < ASMJIT_ARRAY_SIZE(self->_xmmList); i++) + self->_xmmList[i] = kRegIndexInvalid; + + self->_gpListMask = 0x0; + self->_mmListMask = 0x0; + self->_xmmListMask = 0x0; + + self->_gpPreservedMask = 0x0; + self->_mmPreservedMask = 0x0; + self->_xmmPreservedMask = 0x0; + + // -------------------------------------------------------------------------- + // [X86 Calling Conventions] + // -------------------------------------------------------------------------- + +#if defined(ASMJIT_X86) + self->_gpPreservedMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexEbx) | + IntUtil::maskFromIndex(kX86RegIndexEsp) | + IntUtil::maskFromIndex(kX86RegIndexEbp) | + IntUtil::maskFromIndex(kX86RegIndexEsi) | + IntUtil::maskFromIndex(kX86RegIndexEdi)); + self->_xmmPreservedMask = 0; + + switch (convention) + { + // ------------------------------------------------------------------------ + // [CDecl] + // ------------------------------------------------------------------------ + + case kX86FuncConvCDecl: + break; + + // ------------------------------------------------------------------------ + // [StdCall] + // ------------------------------------------------------------------------ + + case kX86FuncConvStdCall: + self->_calleePopsStack = true; + break; + + // ------------------------------------------------------------------------ + // [MS-ThisCall] + // ------------------------------------------------------------------------ + + case kX86FuncConvMsThisCall: + self->_calleePopsStack = true; + + self->_gpList[0] = kX86RegIndexEcx; + + self->_gpListMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexEcx)); + break; + + // ------------------------------------------------------------------------ + // [MS-FastCall] + // ------------------------------------------------------------------------ + + case kX86FuncConvMsFastCall: + self->_calleePopsStack = true; + + self->_gpList[0] = kX86RegIndexEcx; + self->_gpList[1] = kX86RegIndexEdx; + + self->_gpListMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexEcx) | + IntUtil::maskFromIndex(kX86RegIndexEdx)); + break; + + // ------------------------------------------------------------------------ + // [Borland-FastCall] + // ------------------------------------------------------------------------ + + case kX86FuncConvBorlandFastCall: + self->_calleePopsStack = true; + self->_argumentsDirection = kFuncArgsLTR; + + self->_gpList[0] = kX86RegIndexEax; + self->_gpList[1] = kX86RegIndexEdx; + self->_gpList[2] = kX86RegIndexEcx; + + self->_gpListMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexEax) | + IntUtil::maskFromIndex(kX86RegIndexEdx) | + IntUtil::maskFromIndex(kX86RegIndexEcx)); + break; + + // ------------------------------------------------------------------------ + // [Gcc-FastCall] + // ------------------------------------------------------------------------ + + case kX86FuncConvGccFastCall: + self->_calleePopsStack = true; + + self->_gpList[0] = kX86RegIndexEcx; + self->_gpList[1] = kX86RegIndexEdx; + + self->_gpListMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexEcx) | + IntUtil::maskFromIndex(kX86RegIndexEdx)); + break; + + // ------------------------------------------------------------------------ + // [Gcc-Regparm(1)] + // ------------------------------------------------------------------------ + + case kX86FuncConvGccRegParm1: + self->_calleePopsStack = false; + + self->_gpList[0] = kX86RegIndexEax; + self->_gpListMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexEax)); + break; + + // ------------------------------------------------------------------------ + // [Gcc-Regparm(2)] + // ------------------------------------------------------------------------ + + case kX86FuncConvGccRegParm2: + self->_calleePopsStack = false; + + self->_gpList[0] = kX86RegIndexEax; + self->_gpList[1] = kX86RegIndexEdx; + + self->_gpListMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexEax) | + IntUtil::maskFromIndex(kX86RegIndexEdx)); + break; + + // ------------------------------------------------------------------------ + // [Gcc-Regparm(3)] + // ------------------------------------------------------------------------ + + case kX86FuncConvGccRegParm3: + self->_calleePopsStack = false; + + self->_gpList[0] = kX86RegIndexEax; + self->_gpList[1] = kX86RegIndexEdx; + self->_gpList[2] = kX86RegIndexEcx; + + self->_gpListMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexEax) | + IntUtil::maskFromIndex(kX86RegIndexEdx) | + IntUtil::maskFromIndex(kX86RegIndexEcx)); + break; + + // ------------------------------------------------------------------------ + // [Illegal] + // ------------------------------------------------------------------------ + + default: + // Illegal calling convention. + ASMJIT_ASSERT(0); + } +#endif // ASMJIT_X86 + + // -------------------------------------------------------------------------- + // [X64 Calling Conventions] + // -------------------------------------------------------------------------- + +#if defined(ASMJIT_X64) + switch (convention) + { + // ------------------------------------------------------------------------ + // [X64-Windows] + // ------------------------------------------------------------------------ + + case kX86FuncConvX64W: + self->_gpList[0] = kX86RegIndexRcx; + self->_gpList[1] = kX86RegIndexRdx; + self->_gpList[2] = kX86RegIndexR8; + self->_gpList[3] = kX86RegIndexR9; + + self->_xmmList[0] = kX86RegIndexXmm0; + self->_xmmList[1] = kX86RegIndexXmm1; + self->_xmmList[2] = kX86RegIndexXmm2; + self->_xmmList[3] = kX86RegIndexXmm3; + + self->_gpListMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexRcx ) | + IntUtil::maskFromIndex(kX86RegIndexRdx ) | + IntUtil::maskFromIndex(kX86RegIndexR8 ) | + IntUtil::maskFromIndex(kX86RegIndexR9 )); + + self->_xmmListMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexXmm0 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm1 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm2 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm3 )); + + self->_gpPreservedMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexRbx ) | + IntUtil::maskFromIndex(kX86RegIndexRsp ) | + IntUtil::maskFromIndex(kX86RegIndexRbp ) | + IntUtil::maskFromIndex(kX86RegIndexRsi ) | + IntUtil::maskFromIndex(kX86RegIndexRdi ) | + IntUtil::maskFromIndex(kX86RegIndexR12 ) | + IntUtil::maskFromIndex(kX86RegIndexR13 ) | + IntUtil::maskFromIndex(kX86RegIndexR14 ) | + IntUtil::maskFromIndex(kX86RegIndexR15 )); + + self->_xmmPreservedMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexXmm6 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm7 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm8 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm9 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm10) | + IntUtil::maskFromIndex(kX86RegIndexXmm11) | + IntUtil::maskFromIndex(kX86RegIndexXmm12) | + IntUtil::maskFromIndex(kX86RegIndexXmm13) | + IntUtil::maskFromIndex(kX86RegIndexXmm14) | + IntUtil::maskFromIndex(kX86RegIndexXmm15)); + break; + + // ------------------------------------------------------------------------ + // [X64-Unix] + // ------------------------------------------------------------------------ + + case kX86FuncConvX64U: + self->_gpList[0] = kX86RegIndexRdi; + self->_gpList[1] = kX86RegIndexRsi; + self->_gpList[2] = kX86RegIndexRdx; + self->_gpList[3] = kX86RegIndexRcx; + self->_gpList[4] = kX86RegIndexR8; + self->_gpList[5] = kX86RegIndexR9; + + self->_xmmList[0] = kX86RegIndexXmm0; + self->_xmmList[1] = kX86RegIndexXmm1; + self->_xmmList[2] = kX86RegIndexXmm2; + self->_xmmList[3] = kX86RegIndexXmm3; + self->_xmmList[4] = kX86RegIndexXmm4; + self->_xmmList[5] = kX86RegIndexXmm5; + self->_xmmList[6] = kX86RegIndexXmm6; + self->_xmmList[7] = kX86RegIndexXmm7; + + self->_gpListMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexRdi ) | + IntUtil::maskFromIndex(kX86RegIndexRsi ) | + IntUtil::maskFromIndex(kX86RegIndexRdx ) | + IntUtil::maskFromIndex(kX86RegIndexRcx ) | + IntUtil::maskFromIndex(kX86RegIndexR8 ) | + IntUtil::maskFromIndex(kX86RegIndexR9 )); + + self->_xmmListMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexXmm0 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm1 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm2 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm3 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm4 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm5 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm6 ) | + IntUtil::maskFromIndex(kX86RegIndexXmm7 )); + + self->_gpPreservedMask = static_cast( + IntUtil::maskFromIndex(kX86RegIndexRbx ) | + IntUtil::maskFromIndex(kX86RegIndexRsp ) | + IntUtil::maskFromIndex(kX86RegIndexRbp ) | + IntUtil::maskFromIndex(kX86RegIndexR12 ) | + IntUtil::maskFromIndex(kX86RegIndexR13 ) | + IntUtil::maskFromIndex(kX86RegIndexR14 ) | + IntUtil::maskFromIndex(kX86RegIndexR15 )); + break; + + // ------------------------------------------------------------------------ + // [Illegal] + // ------------------------------------------------------------------------ + + default: + // Illegal calling convention. + ASMJIT_ASSERT(0); + } +#endif // ASMJIT_X64 +} + +// ============================================================================ +// [AsmJit::X86FuncDecl - SetPrototype - InitDefinition] +// ============================================================================ + +static void X86FuncDecl_initDefinition(X86FuncDecl* self, + uint32_t returnType, const uint32_t* argumentsData, uint32_t argumentsCount) +{ + ASMJIT_ASSERT(argumentsCount <= kFuncArgsMax); + + // -------------------------------------------------------------------------- + // [Init] + // -------------------------------------------------------------------------- + + int32_t i = 0; + int32_t gpPos = 0; + int32_t xmmPos = 0; + int32_t stackOffset = 0; + + self->_returnType = returnType; + self->_argumentsCount = static_cast(argumentsCount); + + while (i < static_cast(argumentsCount)) + { + FuncArg& arg = self->_arguments[i]; + + arg._varType = static_cast(argumentsData[i]); + arg._regIndex = kRegIndexInvalid; + arg._stackOffset = kFuncStackInvalid; + + i++; + } + + while (i < kFuncArgsMax) + { + FuncArg& arg = self->_arguments[i]; + arg.reset(); + + i++; + } + + self->_argumentsStackSize = 0; + self->_gpArgumentsMask = 0x0; + self->_mmArgumentsMask = 0x0; + self->_xmmArgumentsMask = 0x0; + + if (self->_argumentsCount == 0) + return; + + // -------------------------------------------------------------------------- + // [X86 Calling Conventions (32-bit)] + // -------------------------------------------------------------------------- + +#if defined(ASMJIT_X86) + // Register arguments (Integer), always left-to-right. + for (i = 0; i != argumentsCount; i++) + { + FuncArg& arg = self->_arguments[i]; + uint32_t varType = arg.getVarType(); + + if (X86Util::isVarTypeInt(varType) && gpPos < 16 && self->_gpList[gpPos] != kRegIndexInvalid) + { + arg._regIndex = self->_gpList[gpPos++]; + self->_gpArgumentsMask |= static_cast(IntUtil::maskFromIndex(arg.getRegIndex())); + } + } + + // Stack arguments. + int32_t iStart = static_cast(argumentsCount - 1); + int32_t iEnd = -1; + int32_t iStep = -1; + + if (self->_argumentsDirection == kFuncArgsLTR) + { + iStart = 0; + iEnd = static_cast(argumentsCount); + iStep = 1; + } + + for (i = iStart; i != iEnd; i += iStep) + { + FuncArg& arg = self->_arguments[i]; + uint32_t varType = arg.getVarType(); + + if (arg.hasRegIndex()) + continue; + + if (X86Util::isVarTypeInt(varType)) + { + stackOffset -= 4; + arg._stackOffset = static_cast(stackOffset); + } + else if (X86Util::isVarTypeFloat(varType)) + { + int32_t size = static_cast(x86VarInfo[varType].getSize()); + stackOffset -= size; + arg._stackOffset = static_cast(stackOffset); + } + } +#endif // ASMJIT_X86 + + // -------------------------------------------------------------------------- + // [X64 Calling Conventions (64-bit)] + // -------------------------------------------------------------------------- + +#if defined(ASMJIT_X64) + // Windows 64-bit specific. + if (self->_convention == kX86FuncConvX64W) + { + int32_t max = argumentsCount < 4 ? argumentsCount : 4; + + // Register arguments (Integer / FP), always left-to-right. + for (i = 0; i != max; i++) + { + FuncArg& arg = self->_arguments[i]; + uint32_t varType = arg.getVarType(); + + if (X86Util::isVarTypeInt(varType)) + { + arg._regIndex = self->_gpList[i]; + self->_gpArgumentsMask |= static_cast(IntUtil::maskFromIndex(arg.getRegIndex())); + } + else if (X86Util::isVarTypeFloat(varType)) + { + arg._regIndex = self->_xmmList[i]; + self->_xmmArgumentsMask |= static_cast(IntUtil::maskFromIndex(arg.getRegIndex())); + } + } + + // Stack arguments (always right-to-left). + for (i = argumentsCount - 1; i != -1; i--) + { + FuncArg& arg = self->_arguments[i]; + uint32_t varType = arg.getVarType(); + + if (arg.isAssigned()) + continue; + + if (X86Util::isVarTypeInt(varType)) + { + stackOffset -= 8; // Always 8 bytes. + arg._stackOffset = stackOffset; + } + else if (X86Util::isVarTypeFloat(varType)) + { + int32_t size = static_cast(x86VarInfo[varType].getSize()); + stackOffset -= size; + arg._stackOffset = stackOffset; + } + } + + // 32 bytes shadow space (X64W calling convention specific). + stackOffset -= 4 * 8; + } + // Linux/Unix 64-bit (AMD64 calling convention). + else + { + // Register arguments (Integer), always left-to-right. + for (i = 0; i != static_cast(argumentsCount); i++) + { + FuncArg& arg = self->_arguments[i]; + uint32_t varType = arg.getVarType(); + + if (X86Util::isVarTypeInt(varType) && gpPos < 32 && self->_gpList[gpPos] != kRegIndexInvalid) + { + arg._regIndex = self->_gpList[gpPos++]; + self->_gpArgumentsMask |= static_cast(IntUtil::maskFromIndex(arg.getRegIndex())); + } + } + + // Register arguments (FP), always left-to-right. + for (i = 0; i != static_cast(argumentsCount); i++) + { + FuncArg& arg = self->_arguments[i]; + uint32_t varType = arg.getVarType(); + + if (X86Util::isVarTypeFloat(varType)) + { + arg._regIndex = self->_xmmList[xmmPos++]; + self->_xmmArgumentsMask |= static_cast(IntUtil::maskFromIndex(arg.getRegIndex())); + } + } + + // Stack arguments. + for (i = argumentsCount - 1; i != -1; i--) + { + FuncArg& arg = self->_arguments[i]; + uint32_t varType = arg.getVarType(); + + if (arg.isAssigned()) + continue; + + if (X86Util::isVarTypeInt(varType)) + { + stackOffset -= 8; + arg._stackOffset = static_cast(stackOffset); + } + else if (X86Util::isVarTypeFloat(varType)) + { + int32_t size = (int32_t)x86VarInfo[varType].getSize(); + + stackOffset -= size; + arg._stackOffset = static_cast(stackOffset); + } + } + } +#endif // ASMJIT_X64 + + // Modify stack offset (all function parameters will be in positive stack + // offset that is never zero). + for (i = 0; i < (int32_t)argumentsCount; i++) + { + FuncArg& arg = self->_arguments[i]; + if (!arg.hasRegIndex()) + { + arg._stackOffset += static_cast(static_cast(sizeof(uintptr_t)) - stackOffset); + } + } + + self->_argumentsStackSize = (uint32_t)(-stackOffset); +} + +void X86FuncDecl::setPrototype(uint32_t convention, uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount) +{ + // Limit maximum function arguments to kFuncArgsMax. + if (argumentsCount > kFuncArgsMax) + argumentsCount = kFuncArgsMax; + + X86FuncDecl_initCallingConvention(this, convention); + X86FuncDecl_initDefinition(this, returnType, arguments, argumentsCount); +} + +// ============================================================================ +// [AsmJit::X86FuncDecl - Reset] +// ============================================================================ + +void X86FuncDecl::reset() +{ + uint32_t i; + + // -------------------------------------------------------------------------- + // [Core] + // -------------------------------------------------------------------------- + + _returnType = kVarTypeInvalid; + _argumentsCount = 0; + + _reserved0[0] = 0; + _reserved0[1] = 0; + + for (i = 0; i < ASMJIT_ARRAY_SIZE(_arguments); i++) + _arguments[i].reset(); + + _argumentsStackSize = 0; + _gpArgumentsMask = 0x0; + _mmArgumentsMask = 0x0; + _xmmArgumentsMask = 0x0; + + // -------------------------------------------------------------------------- + // [Convention] + // -------------------------------------------------------------------------- + + _convention = kFuncConvNone; + _calleePopsStack = false; + _argumentsDirection = kFuncArgsRTL; + _reserved1 = 0; + + for (i = 0; i < ASMJIT_ARRAY_SIZE(_gpList); i++) + _gpList[i] = kRegIndexInvalid; + + for (i = 0; i < ASMJIT_ARRAY_SIZE(_xmmList); i++) + _xmmList[i] = kRegIndexInvalid; + + _gpListMask = 0x0; + _mmListMask = 0x0; + _xmmListMask = 0x0; + + _gpPreservedMask = 0x0; + _mmPreservedMask = 0x0; + _xmmPreservedMask = 0x0; +} + +} // AsmJit namespace + +// [Api-Begin] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/x86/x86func.h b/desmume/src/utils/AsmJit/x86/x86func.h new file mode 100644 index 000000000..661d3fa7e --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86func.h @@ -0,0 +1,257 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_X86_X86FUNC_H +#define _ASMJIT_X86_X86FUNC_H + +// [Dependencies - AsmJit] +#include "../core/defs.h" +#include "../core/func.h" + +#include "../x86/x86defs.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_X86 +//! @{ + +// ============================================================================ +// [AsmJit::TypeId] +// ============================================================================ + +ASMJIT_DECLARE_TYPE_CORE(kX86VarTypeIntPtr); +ASMJIT_DECLARE_TYPE_ID(void, kVarTypeInvalid); +ASMJIT_DECLARE_TYPE_ID(Void, kVarTypeInvalid); + +ASMJIT_DECLARE_TYPE_ID(int8_t, kX86VarTypeGpd); +ASMJIT_DECLARE_TYPE_ID(uint8_t, kX86VarTypeGpd); + +ASMJIT_DECLARE_TYPE_ID(int16_t, kX86VarTypeGpd); +ASMJIT_DECLARE_TYPE_ID(uint16_t, kX86VarTypeGpd); + +ASMJIT_DECLARE_TYPE_ID(int32_t, kX86VarTypeGpd); +ASMJIT_DECLARE_TYPE_ID(uint32_t, kX86VarTypeGpd); + +#if defined(ASMJIT_X64) +ASMJIT_DECLARE_TYPE_ID(int64_t, kX86VarTypeGpq); +ASMJIT_DECLARE_TYPE_ID(uint64_t, kX86VarTypeGpq); +#endif // ASMJIT_X64 + +ASMJIT_DECLARE_TYPE_ID(float, kX86VarTypeFloat); +ASMJIT_DECLARE_TYPE_ID(double, kX86VarTypeDouble); + +// ============================================================================ +// [AsmJit::X86FuncDecl] +// ============================================================================ + +//! @brief X86 function, including calling convention, arguments and their +//! register indices or stack positions. +struct X86FuncDecl : public FuncDecl +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref FunctionX86 instance. + inline X86FuncDecl() + { reset(); } + + // -------------------------------------------------------------------------- + // [Accessors - Core] + // -------------------------------------------------------------------------- + + //! @brief Get stack size needed for function arguments passed on the stack. + inline uint32_t getArgumentsStackSize() const + { return _argumentsStackSize; } + + //! @brief Get bit-mask of GP registers used to pass function arguments. + inline uint32_t getGpArgumentsMask() const + { return _gpArgumentsMask; } + + //! @brief Get bit-mask of MM registers used to pass function arguments. + inline uint32_t getMmArgumentsMask() const + { return _mmArgumentsMask; } + + //! @brief Get bit-mask of XMM registers used to pass function arguments. + inline uint32_t getXmmArgumentsMask() const + { return _xmmArgumentsMask; } + + // -------------------------------------------------------------------------- + // [Accessors - Convention] + // -------------------------------------------------------------------------- + + //! @brief Get function calling convention, see @c kX86FuncConv. + inline uint32_t getConvention() const + { return _convention; } + + //! @brief Get whether the callee pops the stack. + inline uint32_t getCalleePopsStack() const + { return _calleePopsStack; } + + //! @brief Get direction of arguments passed on the stack. + //! + //! Direction should be always @c kFuncArgsRTL. + //! + //! @note This is related to used calling convention, it's not affected by + //! number of function arguments or their types. + inline uint32_t getArgumentsDirection() const + { return _argumentsDirection; } + + //! @brief Get registers used to pass first integer parameters by current + //! calling convention. + //! + //! @note This is related to used calling convention, it's not affected by + //! number of function arguments or their types. + inline const uint8_t* getGpList() const + { return _gpList; } + + //! @brief Get registers used to pass first SP-FP or DP-FPparameters by + //! current calling convention. + //! + //! @note This is related to used calling convention, it's not affected by + //! number of function arguments or their types. + inline const uint8_t* getXmmList() const + { return _xmmList; } + + //! @brief Get bit-mask of GP registers which might be used for arguments. + inline uint32_t getGpListMask() const + { return _gpListMask; } + + //! @brief Get bit-mask of MM registers which might be used for arguments. + inline uint32_t getMmListMask() const + { return _mmListMask; } + + //! @brief Get bit-mask of XMM registers which might be used for arguments. + inline uint32_t getXmmListMask() const + { return _xmmListMask; } + + //! @brief Get bit-mask of general purpose registers that's preserved + //! (non-volatile). + //! + //! @note This is related to used calling convention, it's not affected by + //! number of function arguments or their types. + inline uint32_t getGpPreservedMask() const + { return _gpPreservedMask; } + + //! @brief Get bit-mask of MM registers that's preserved (non-volatile). + //! + //! @note No standardized calling function is not preserving MM registers. + //! This member is here for extension writers who need for some reason custom + //! calling convention that can be called through code generated by AsmJit + //! (or other runtime code generator). + inline uint32_t getMmPreservedMask() const + { return _mmPreservedMask; } + + //! @brief Get bit-mask of XMM registers that's preserved (non-volatile). + //! + //! @note This is related to used calling convention, it's not affected by + //! number of function arguments or their types. + inline uint32_t getXmmPreservedMask() const + { return _xmmPreservedMask; } + + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + //! @brief Find argument ID by the register code. + ASMJIT_API uint32_t findArgumentByRegCode(uint32_t regCode) const; + + // -------------------------------------------------------------------------- + // [SetPrototype] + // -------------------------------------------------------------------------- + + //! @brief Set function prototype. + //! + //! This will set function calling convention and setup arguments variables. + //! + //! @note This function will allocate variables, it can be called only once. + ASMJIT_API void setPrototype(uint32_t convention, uint32_t returnType, const uint32_t* arguments, uint32_t argumentsCount); + + // -------------------------------------------------------------------------- + // [Reset] + // -------------------------------------------------------------------------- + + ASMJIT_API void reset(); + + // -------------------------------------------------------------------------- + // [Members - Core] + // -------------------------------------------------------------------------- + + //! @brief Count of bytes consumed by arguments on the stack. + uint16_t _argumentsStackSize; + //! @brief Bitmask for GP registers used as passed function arguments. + uint16_t _gpArgumentsMask; + //! @brief Bitmask for MM registers used as passed function arguments. + uint16_t _mmArgumentsMask; + //! @brief Bitmask for XMM registers used as passed function arguments. + uint16_t _xmmArgumentsMask; + + // -------------------------------------------------------------------------- + // [Membes - Convention] + // + // This section doesn't depend on function arguments or return type. It + // depends only on function calling convention and it's filled according to + // that value. + // -------------------------------------------------------------------------- + + //! @brief Calling convention. + uint8_t _convention; + //! @brief Whether a callee pops stack. + uint8_t _calleePopsStack; + //! @brief Direction for arguments passed on the stack, see @c kFuncArgsDirection. + uint8_t _argumentsDirection; + //! @brief Reserved for future use #1 (alignment). + uint8_t _reserved1; + + //! @brief List of register IDs used for GP arguments (order is important). + //! + //! @note All registers in _gpList are also specified in @ref _gpListMask. + //! Unused fields are filled by @ref kRegIndexInvalid. + uint8_t _gpList[16]; + //! @brief List of register IDs used for XMM arguments (order is important). + //! + //! @note All registers in _gpList are also specified in @ref _xmmListMask. + //! Unused fields are filled by @ref kRegIndexInvalid. + uint8_t _xmmList[16]; + + //! @brief Bitmask for GP registers which might be used by arguments. + //! + //! @note All registers in _gpListMask are also specified in @ref _gpList. + uint16_t _gpListMask; + //! @brief Bitmask for MM registers which might be used by arguments. + uint16_t _mmListMask; + //! @brief Bitmask for XMM registers which might be used by arguments. + //! + //! @note All registers in _xmmListMask are also specified in @ref _xmmList. + uint16_t _xmmListMask; + + //! @brief Bitmask for GP registers preserved across the function call. + //! + //! @note Preserved register mask is complement to @ref _gpListMask. + uint16_t _gpPreservedMask; + //! @brief Bitmask for MM registers preserved across the function call. + //! + //! @note Preserved register mask is complement to @ref _mmListMask. + uint16_t _mmPreservedMask; + //! @brief Bitmask for XMM registers preserved across the function call. + //! + //! @note Preserved register mask is complement to @ref _xmmListMask. + uint16_t _xmmPreservedMask; +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_X86_X86FUNC_H diff --git a/desmume/src/utils/AsmJit/x86/x86operand.cpp b/desmume/src/utils/AsmJit/x86/x86operand.cpp new file mode 100644 index 000000000..be3aa1520 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86operand.cpp @@ -0,0 +1,385 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../x86/x86defs.h" +#include "../x86/x86operand.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::Registers - no_reg] +// ============================================================================ + +const GpReg no_reg(_Initialize(), kInvalidValue); + +// ============================================================================ +// [AsmJit::Registers - 8-bit] +// ============================================================================ + +const GpReg al(_Initialize(), kX86RegAl); +const GpReg cl(_Initialize(), kX86RegCl); +const GpReg dl(_Initialize(), kX86RegDl); +const GpReg bl(_Initialize(), kX86RegBl); + +#if defined(ASMJIT_X64) +const GpReg spl(_Initialize(), kX86RegSpl); +const GpReg bpl(_Initialize(), kX86RegBpl); +const GpReg sil(_Initialize(), kX86RegSil); +const GpReg dil(_Initialize(), kX86RegDil); + +const GpReg r8b(_Initialize(), kX86RegR8b); +const GpReg r9b(_Initialize(), kX86RegR9b); +const GpReg r10b(_Initialize(), kX86RegR10b); +const GpReg r11b(_Initialize(), kX86RegR11b); +const GpReg r12b(_Initialize(), kX86RegR12b); +const GpReg r13b(_Initialize(), kX86RegR13b); +const GpReg r14b(_Initialize(), kX86RegR14b); +const GpReg r15b(_Initialize(), kX86RegR15b); +#endif // ASMJIT_X64 + +const GpReg ah(_Initialize(), kX86RegAh); +const GpReg ch(_Initialize(), kX86RegCh); +const GpReg dh(_Initialize(), kX86RegDh); +const GpReg bh(_Initialize(), kX86RegBh); + +// ============================================================================ +// [AsmJit::Registers - 16-bit] +// ============================================================================ + +const GpReg ax(_Initialize(), kX86RegAx); +const GpReg cx(_Initialize(), kX86RegCx); +const GpReg dx(_Initialize(), kX86RegDx); +const GpReg bx(_Initialize(), kX86RegBx); +const GpReg sp(_Initialize(), kX86RegSp); +const GpReg bp(_Initialize(), kX86RegBp); +const GpReg si(_Initialize(), kX86RegSi); +const GpReg di(_Initialize(), kX86RegDi); + +#if defined(ASMJIT_X64) +const GpReg r8w(_Initialize(), kX86RegR8w); +const GpReg r9w(_Initialize(), kX86RegR9w); +const GpReg r10w(_Initialize(), kX86RegR10w); +const GpReg r11w(_Initialize(), kX86RegR11w); +const GpReg r12w(_Initialize(), kX86RegR12w); +const GpReg r13w(_Initialize(), kX86RegR13w); +const GpReg r14w(_Initialize(), kX86RegR14w); +const GpReg r15w(_Initialize(), kX86RegR15w); +#endif // ASMJIT_X64 + +// ============================================================================ +// [AsmJit::Registers - 32-bit] +// ============================================================================ + +const GpReg eax(_Initialize(), kX86RegEax); +const GpReg ecx(_Initialize(), kX86RegEcx); +const GpReg edx(_Initialize(), kX86RegEdx); +const GpReg ebx(_Initialize(), kX86RegEbx); +const GpReg esp(_Initialize(), kX86RegEsp); +const GpReg ebp(_Initialize(), kX86RegEbp); +const GpReg esi(_Initialize(), kX86RegEsi); +const GpReg edi(_Initialize(), kX86RegEdi); + +#if defined(ASMJIT_X64) +const GpReg r8d(_Initialize(), kX86RegR8d); +const GpReg r9d(_Initialize(), kX86RegR9d); +const GpReg r10d(_Initialize(), kX86RegR10d); +const GpReg r11d(_Initialize(), kX86RegR11d); +const GpReg r12d(_Initialize(), kX86RegR12d); +const GpReg r13d(_Initialize(), kX86RegR13d); +const GpReg r14d(_Initialize(), kX86RegR14d); +const GpReg r15d(_Initialize(), kX86RegR15d); +#endif // ASMJIT_X64 + +// ============================================================================ +// [AsmJit::Registers - 64-bit] +// ============================================================================ + +#if defined(ASMJIT_X64) +const GpReg rax(_Initialize(), kX86RegRax); +const GpReg rcx(_Initialize(), kX86RegRcx); +const GpReg rdx(_Initialize(), kX86RegRdx); +const GpReg rbx(_Initialize(), kX86RegRbx); +const GpReg rsp(_Initialize(), kX86RegRsp); +const GpReg rbp(_Initialize(), kX86RegRbp); +const GpReg rsi(_Initialize(), kX86RegRsi); +const GpReg rdi(_Initialize(), kX86RegRdi); + +const GpReg r8(_Initialize(), kX86RegR8); +const GpReg r9(_Initialize(), kX86RegR9); +const GpReg r10(_Initialize(), kX86RegR10); +const GpReg r11(_Initialize(), kX86RegR11); +const GpReg r12(_Initialize(), kX86RegR12); +const GpReg r13(_Initialize(), kX86RegR13); +const GpReg r14(_Initialize(), kX86RegR14); +const GpReg r15(_Initialize(), kX86RegR15); +#endif // ASMJIT_X64 + +// ============================================================================ +// [AsmJit::Registers - Native (AsmJit extension)] +// ============================================================================ + +const GpReg zax(_Initialize(), kX86RegZax); +const GpReg zcx(_Initialize(), kX86RegZcx); +const GpReg zdx(_Initialize(), kX86RegZdx); +const GpReg zbx(_Initialize(), kX86RegZbx); +const GpReg zsp(_Initialize(), kX86RegZsp); +const GpReg zbp(_Initialize(), kX86RegZbp); +const GpReg zsi(_Initialize(), kX86RegZsi); +const GpReg zdi(_Initialize(), kX86RegZdi); + +// ============================================================================ +// [AsmJit::Registers - MM] +// ============================================================================ + +const MmReg mm0(_Initialize(), kX86RegMm0); +const MmReg mm1(_Initialize(), kX86RegMm1); +const MmReg mm2(_Initialize(), kX86RegMm2); +const MmReg mm3(_Initialize(), kX86RegMm3); +const MmReg mm4(_Initialize(), kX86RegMm4); +const MmReg mm5(_Initialize(), kX86RegMm5); +const MmReg mm6(_Initialize(), kX86RegMm6); +const MmReg mm7(_Initialize(), kX86RegMm7); + +// ============================================================================ +// [AsmJit::Registers - XMM] +// ============================================================================ + +const XmmReg xmm0(_Initialize(), kX86RegXmm0); +const XmmReg xmm1(_Initialize(), kX86RegXmm1); +const XmmReg xmm2(_Initialize(), kX86RegXmm2); +const XmmReg xmm3(_Initialize(), kX86RegXmm3); +const XmmReg xmm4(_Initialize(), kX86RegXmm4); +const XmmReg xmm5(_Initialize(), kX86RegXmm5); +const XmmReg xmm6(_Initialize(), kX86RegXmm6); +const XmmReg xmm7(_Initialize(), kX86RegXmm7); + +#if defined(ASMJIT_X64) +const XmmReg xmm8(_Initialize(), kX86RegXmm8); +const XmmReg xmm9(_Initialize(), kX86RegXmm9); +const XmmReg xmm10(_Initialize(), kX86RegXmm10); +const XmmReg xmm11(_Initialize(), kX86RegXmm11); +const XmmReg xmm12(_Initialize(), kX86RegXmm12); +const XmmReg xmm13(_Initialize(), kX86RegXmm13); +const XmmReg xmm14(_Initialize(), kX86RegXmm14); +const XmmReg xmm15(_Initialize(), kX86RegXmm15); +#endif // ASMJIT_X64 + +// ============================================================================ +// [AsmJit::Registers - Segment] +// ============================================================================ + +const SegmentReg cs(_Initialize(), kX86RegCs); +const SegmentReg ss(_Initialize(), kX86RegSs); +const SegmentReg ds(_Initialize(), kX86RegDs); +const SegmentReg es(_Initialize(), kX86RegEs); +const SegmentReg fs(_Initialize(), kX86RegFs); +const SegmentReg gs(_Initialize(), kX86RegGs); + +// ============================================================================ +// [AsmJit::Var] +// ============================================================================ + +Mem _BaseVarMem(const Var& var, uint32_t size) +{ + Mem m; //(_DontInitialize()); + + m._mem.op = kOperandMem; + m._mem.size = static_cast(size == kInvalidValue ? var.getSize() : size); + m._mem.type = kOperandMemNative; + m._mem.segment = kX86SegNone; + m._mem.sizePrefix = 0; + m._mem.shift = 0; + + m._mem.id = var.getId(); + m._mem.base = kInvalidValue; + m._mem.index = kInvalidValue; + + m._mem.target = NULL; + m._mem.displacement = 0; + + return m; +} + + +Mem _BaseVarMem(const Var& var, uint32_t size, sysint_t disp) +{ + Mem m; //(_DontInitialize()); + + m._mem.op = kOperandMem; + m._mem.size = static_cast(size == kInvalidValue ? var.getSize() : size); + m._mem.type = kOperandMemNative; + m._mem.segment = kX86SegNone; + m._mem.sizePrefix = 0; + m._mem.shift = 0; + + m._mem.id = var.getId(); + + m._mem.base = kInvalidValue; + m._mem.index = kInvalidValue; + + m._mem.target = NULL; + m._mem.displacement = disp; + + return m; +} + +Mem _BaseVarMem(const Var& var, uint32_t size, const GpVar& index, uint32_t shift, sysint_t disp) +{ + Mem m; //(_DontInitialize()); + + m._mem.op = kOperandMem; + m._mem.size = static_cast(size == kInvalidValue ? var.getSize() : size); + m._mem.type = kOperandMemNative; + m._mem.segment = kX86SegNone; + m._mem.sizePrefix = 0; + m._mem.shift = shift; + + m._mem.id = var.getId(); + + m._mem.base = kInvalidValue; + m._mem.index = index.getId(); + + m._mem.target = NULL; + m._mem.displacement = disp; + + return m; +} + +// ============================================================================ +// [AsmJit::Mem - ptr[]] +// ============================================================================ + +Mem ptr(const Label& label, sysint_t disp, uint32_t size) +{ + return Mem(label, disp, size); +} + +Mem ptr(const Label& label, const GpReg& index, uint32_t shift, sysint_t disp, uint32_t size) +{ + Mem m(label, disp, size); + + m._mem.index = index.getRegIndex(); + m._mem.shift = shift; + + return m; +} + +Mem ptr(const Label& label, const GpVar& index, uint32_t shift, sysint_t disp, uint32_t size) +{ + Mem m(label, disp, size); + + m._mem.index = index.getId(); + m._mem.shift = shift; + + return m; +} + +// ============================================================================ +// [AsmJit::Mem - ptr[] - Absolute Addressing] +// ============================================================================ + +ASMJIT_API Mem ptr_abs(void* target, sysint_t disp, uint32_t size) +{ + Mem m; + + m._mem.size = size; + m._mem.type = kOperandMemAbsolute; + m._mem.segment = kX86SegNone; + + m._mem.target = target; + m._mem.displacement = disp; + + return m; +} + +ASMJIT_API Mem ptr_abs(void* target, const GpReg& index, uint32_t shift, sysint_t disp, uint32_t size) +{ + Mem m;// (_DontInitialize()); + + m._mem.op = kOperandMem; + m._mem.size = size; + m._mem.type = kOperandMemAbsolute; + m._mem.segment = kX86SegNone; + +#if defined(ASMJIT_X86) + m._mem.sizePrefix = index.getSize() != 4; +#else + m._mem.sizePrefix = index.getSize() != 8; +#endif + + m._mem.shift = shift; + + m._mem.id = kInvalidValue; + m._mem.base = kInvalidValue; + m._mem.index = index.getRegIndex(); + + m._mem.target = target; + m._mem.displacement = disp; + + return m; +} + +ASMJIT_API Mem ptr_abs(void* target, const GpVar& index, uint32_t shift, sysint_t disp, uint32_t size) +{ + Mem m;// (_DontInitialize()); + + m._mem.op = kOperandMem; + m._mem.size = size; + m._mem.type = kOperandMemAbsolute; + m._mem.segment = kX86SegNone; + +#if defined(ASMJIT_X86) + m._mem.sizePrefix = index.getSize() != 4; +#else + m._mem.sizePrefix = index.getSize() != 8; +#endif + + m._mem.shift = shift; + + m._mem.id = kInvalidValue; + m._mem.base = kInvalidValue; + m._mem.index = index.getId(); + + m._mem.target = target; + m._mem.displacement = disp; + + return m; +} + +// ============================================================================ +// [AsmJit::Mem - ptr[base + displacement]] +// ============================================================================ + +Mem ptr(const GpReg& base, sysint_t disp, uint32_t size) +{ + return Mem(base, disp, size); +} + +Mem ptr(const GpReg& base, const GpReg& index, uint32_t shift, sysint_t disp, uint32_t size) +{ + return Mem(base, index, shift, disp, size); +} + +Mem ptr(const GpVar& base, sysint_t disp, uint32_t size) +{ + return Mem(base, disp, size); +} + +Mem ptr(const GpVar& base, const GpVar& index, uint32_t shift, sysint_t disp, uint32_t size) +{ + return Mem(base, index, shift, disp, size); +} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/x86/x86operand.h b/desmume/src/utils/AsmJit/x86/x86operand.h new file mode 100644 index 000000000..7d591e771 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86operand.h @@ -0,0 +1,1828 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_X86_X86OPERAND_H +#define _ASMJIT_X86_X86OPERAND_H + +// [Dependencies - AsmJit] +#include "../core/defs.h" +#include "../core/operand.h" + +#include "../x86/x86defs.h" + +namespace AsmJit { + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +struct GpReg; +struct GpVar; +struct Mem; +struct MmReg; +struct MmVar; +struct Var; +struct X87Reg; +struct X87Var; +struct XmmReg; +struct XmmVar; + +struct SegmentReg; + +//! @addtogroup AsmJit_X86 +//! @{ + +// ============================================================================ +// [AsmJit::MmData] +// ============================================================================ + +//! @brief Structure used for MMX specific data (64-bit). +//! +//! This structure can be used to load / store data from / to MMX register. +union MmData +{ + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + //! @brief Set all eight signed 8-bit integers. + inline void setSB( + int8_t x0, int8_t x1, int8_t x2, int8_t x3, int8_t x4, int8_t x5, int8_t x6, int8_t x7) + { + sb[0] = x0; sb[1] = x1; sb[2] = x2; sb[3] = x3; sb[4] = x4; sb[5] = x5; sb[6] = x6; sb[7] = x7; + } + + //! @brief Set all eight unsigned 8-bit integers. + inline void setUB( + uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7) + { + ub[0] = x0; ub[1] = x1; ub[2] = x2; ub[3] = x3; ub[4] = x4; ub[5] = x5; ub[6] = x6; ub[7] = x7; + } + + //! @brief Set all four signed 16-bit integers. + inline void setSW( + int16_t x0, int16_t x1, int16_t x2, int16_t x3) + { + sw[0] = x0; sw[1] = x1; sw[2] = x2; sw[3] = x3; + } + + //! @brief Set all four unsigned 16-bit integers. + inline void setUW( + uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3) + { + uw[0] = x0; uw[1] = x1; uw[2] = x2; uw[3] = x3; + } + + //! @brief Set all two signed 32-bit integers. + inline void setSD( + int32_t x0, int32_t x1) + { + sd[0] = x0; sd[1] = x1; + } + + //! @brief Set all two unsigned 32-bit integers. + inline void setUD( + uint32_t x0, uint32_t x1) + { + ud[0] = x0; ud[1] = x1; + } + + //! @brief Set signed 64-bit integer. + inline void setSQ( + int64_t x0) + { + sq[0] = x0; + } + + //! @brief Set unsigned 64-bit integer. + inline void setUQ( + uint64_t x0) + { + uq[0] = x0; + } + + //! @brief Set all two SP-FP values. + inline void setSF( + float x0, float x1) + { + sf[0] = x0; sf[1] = x1; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Array of eight signed 8-bit integers. + int8_t sb[8]; + //! @brief Array of eight unsigned 8-bit integers. + uint8_t ub[8]; + //! @brief Array of four signed 16-bit integers. + int16_t sw[4]; + //! @brief Array of four unsigned 16-bit integers. + uint16_t uw[4]; + //! @brief Array of two signed 32-bit integers. + int32_t sd[2]; + //! @brief Array of two unsigned 32-bit integers. + uint32_t ud[2]; + //! @brief Array of one signed 64-bit integer. + int64_t sq[1]; + //! @brief Array of one unsigned 64-bit integer. + uint64_t uq[1]; + + //! @brief Array of two SP-FP values. + float sf[2]; +}; + +// ============================================================================ +// [AsmJit::XmmData] +// ============================================================================ + +//! @brief Structure used for SSE specific data (128-bit). +//! +//! This structure can be used to load / store data from / to SSE register. +//! +//! @note Always align SSE data to 16-bytes. +union XmmData +{ + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + //! @brief Set all sixteen signed 8-bit integers. + inline void setSB( + int8_t x0, int8_t x1, int8_t x2 , int8_t x3 , int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , + int8_t x8, int8_t x9, int8_t x10, int8_t x11, int8_t x12, int8_t x13, int8_t x14, int8_t x15) + { + sb[0] = x0; sb[1] = x1; sb[ 2] = x2 ; sb[3 ] = x3 ; sb[4 ] = x4 ; sb[5 ] = x5 ; sb[6 ] = x6 ; sb[7 ] = x7 ; + sb[8] = x8; sb[9] = x9; sb[10] = x10; sb[11] = x11; sb[12] = x12; sb[13] = x13; sb[14] = x14; sb[15] = x15; + } + + //! @brief Set all sixteen unsigned 8-bit integers. + inline void setUB( + uint8_t x0, uint8_t x1, uint8_t x2 , uint8_t x3 , uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , + uint8_t x8, uint8_t x9, uint8_t x10, uint8_t x11, uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15) + { + ub[0] = x0; ub[1] = x1; ub[ 2] = x2 ; ub[3 ] = x3 ; ub[4 ] = x4 ; ub[5 ] = x5 ; ub[6 ] = x6 ; ub[7 ] = x7 ; + ub[8] = x8; ub[9] = x9; ub[10] = x10; ub[11] = x11; ub[12] = x12; ub[13] = x13; ub[14] = x14; ub[15] = x15; + } + + //! @brief Set all eight signed 16-bit integers. + inline void setSW( + int16_t x0, int16_t x1, int16_t x2, int16_t x3, int16_t x4, int16_t x5, int16_t x6, int16_t x7) + { + sw[0] = x0; sw[1] = x1; sw[2] = x2; sw[3] = x3; sw[4] = x4; sw[5] = x5; sw[6] = x6; sw[7] = x7; + } + + //! @brief Set all eight unsigned 16-bit integers. + inline void setUW( + uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7) + { + uw[0] = x0; uw[1] = x1; uw[2] = x2; uw[3] = x3; uw[4] = x4; uw[5] = x5; uw[6] = x6; uw[7] = x7; + } + + //! @brief Set all four signed 32-bit integers. + inline void setSD( + int32_t x0, int32_t x1, int32_t x2, int32_t x3) + { + sd[0] = x0; sd[1] = x1; sd[2] = x2; sd[3] = x3; + } + + //! @brief Set all four unsigned 32-bit integers. + inline void setUD( + uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) + { + ud[0] = x0; ud[1] = x1; ud[2] = x2; ud[3] = x3; + } + + //! @brief Set all two signed 64-bit integers. + inline void setSQ( + int64_t x0, int64_t x1) + { + sq[0] = x0; sq[1] = x1; + } + + //! @brief Set all two unsigned 64-bit integers. + inline void setUQ( + uint64_t x0, uint64_t x1) + { + uq[0] = x0; uq[1] = x1; + } + + //! @brief Set all four SP-FP floats. + inline void setSF( + float x0, float x1, float x2, float x3) + { + sf[0] = x0; sf[1] = x1; sf[2] = x2; sf[3] = x3; + } + + //! @brief Set all two DP-FP floats. + inline void setDF( + double x0, double x1) + { + df[0] = x0; df[1] = x1; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Array of sixteen signed 8-bit integers. + int8_t sb[16]; + //! @brief Array of sixteen unsigned 8-bit integers. + uint8_t ub[16]; + //! @brief Array of eight signed 16-bit integers. + int16_t sw[8]; + //! @brief Array of eight unsigned 16-bit integers. + uint16_t uw[8]; + //! @brief Array of four signed 32-bit integers. + int32_t sd[4]; + //! @brief Array of four unsigned 32-bit integers. + uint32_t ud[4]; + //! @brief Array of two signed 64-bit integers. + int64_t sq[2]; + //! @brief Array of two unsigned 64-bit integers. + uint64_t uq[2]; + + //! @brief Array of four 32-bit single precision floating points. + float sf[4]; + //! @brief Array of two 64-bit double precision floating points. + double df[2]; +}; + +// ============================================================================ +// [AsmJit::GpReg] +// ============================================================================ + +//! @brief General purpose register. +//! +//! This class is for all general purpose registers (64, 32, 16 and 8-bit). +struct GpReg : public Reg +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create non-initialized general purpose register. + inline GpReg() : Reg(kInvalidValue, 0) {} + //! @brief Create a reference to @a other general purpose register. + inline GpReg(const GpReg& other) : Reg(other) {} + +#if !defined(ASMJIT_NODOC) + inline GpReg(const _DontInitialize& dontInitialize) : Reg(dontInitialize) {} + inline GpReg(const _Initialize&, uint32_t code) : Reg(code, static_cast(1U << ((code & kRegTypeMask) >> 12))) {} +#endif // ASMJIT_NODOC + + // -------------------------------------------------------------------------- + // [Reg Specific] + // -------------------------------------------------------------------------- + + //! @brief Set register code to @a code. + inline GpReg& setCode(uint32_t code) + { + _reg.code = code; + return *this; + } + + //! @brief Set register size to @a size. + inline GpReg& setSize(uint32_t size) + { + _reg.size = static_cast(size); + return *this; + } + + // -------------------------------------------------------------------------- + // [GpReg Specific] + // -------------------------------------------------------------------------- + + //! @brief Get whether the general purpose register is BYTE (8-bit) type. + inline bool isGpb() const { return (_reg.code & kRegTypeMask) <= kX86RegTypeGpbHi; } + //! @brief Get whether the general purpose register is LO-BYTE (8-bit) type. + inline bool isGpbLo() const { return (_reg.code & kRegTypeMask) == kX86RegTypeGpbLo; } + //! @brief Get whether the general purpose register is HI-BYTE (8-bit) type. + inline bool isGpbHi() const { return (_reg.code & kRegTypeMask) == kX86RegTypeGpbHi; } + + //! @brief Get whether the general purpose register is WORD (16-bit) type. + inline bool isGpw() const { return (_reg.code & kRegTypeMask) == kX86RegTypeGpw; } + //! @brief Get whether the general purpose register is DWORD (32-bit) type. + //! + //! This is default type for 32-bit platforms. + inline bool isGpd() const { return (_reg.code & kRegTypeMask) == kX86RegTypeGpd; } + //! @brief Get whether the general purpose register is QWORD (64-bit) type. + //! + //! This is default type for 64-bit platforms. + inline bool isGpq() const { return (_reg.code & kRegTypeMask) == kX86RegTypeGpq; } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline GpReg& operator=(const GpReg& other) { _copy(other); return *this; } + inline bool operator==(const GpReg& other) const { return getRegCode() == other.getRegCode(); } + inline bool operator!=(const GpReg& other) const { return getRegCode() != other.getRegCode(); } +#endif // ASMJIT_NODOC +}; + +// ============================================================================ +// [AsmJit::X87Reg] +// ============================================================================ + +//! @brief 80-bit x87 floating point register. +//! +//! To create instance of x87 register, use @c st() function. +struct X87Reg : public Reg +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create non-initialized x87 register. + inline X87Reg() : Reg(kInvalidValue, 10) {} + //! @brief Create a reference to @a other x87 register. + inline X87Reg(const X87Reg& other) : Reg(other) {} + +#if !defined(ASMJIT_NODOC) + inline X87Reg(const _DontInitialize& dontInitialize) : Reg(dontInitialize) {} + inline X87Reg(const _Initialize&, uint32_t code) : Reg(code | kX86RegTypeX87, 10) {} +#endif // ASMJIT_NODOC + + // -------------------------------------------------------------------------- + // [Reg Specific] + // -------------------------------------------------------------------------- + + //! @brief Set register code to @a code. + inline X87Reg& setCode(uint32_t code) + { + _reg.code = code; + return *this; + } + + //! @brief Set register size to @a size. + inline X87Reg& setSize(uint32_t size) + { + _reg.size = static_cast(size); + return *this; + } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline X87Reg& operator=(const X87Reg& other) { _copy(other); return *this; } + inline bool operator==(const X87Reg& other) const { return getRegCode() == other.getRegCode(); } + inline bool operator!=(const X87Reg& other) const { return getRegCode() != other.getRegCode(); } +#endif // ASMJIT_NODOC +}; + +// ============================================================================ +// [AsmJit::MmReg] +// ============================================================================ + +//! @brief 64-bit MMX register. +struct MmReg : public Reg +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create non-initialized MM register. + inline MmReg() : Reg(kInvalidValue, 8) {} + //! @brief Create a reference to @a other MM register. + inline MmReg(const MmReg& other) : Reg(other) {} + +#if !defined(ASMJIT_NODOC) + inline MmReg(const _DontInitialize& dontInitialize) : Reg(dontInitialize) {} + inline MmReg(const _Initialize&, uint32_t code) : Reg(code, 8) {} +#endif // ASMJIT_NODOC + + // -------------------------------------------------------------------------- + // [Reg Specific] + // -------------------------------------------------------------------------- + + //! @brief Set register code to @a code. + inline MmReg& setCode(uint32_t code) + { + _reg.code = code; + return *this; + } + + //! @brief Set register size to @a size. + inline MmReg& setSize(uint32_t size) + { + _reg.size = static_cast(size); + return *this; + } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline MmReg& operator=(const MmReg& other) { _copy(other); return *this; } + inline bool operator==(const MmReg& other) const { return getRegCode() == other.getRegCode(); } + inline bool operator!=(const MmReg& other) const { return getRegCode() != other.getRegCode(); } +#endif // ASMJIT_NODOC +}; + +// ============================================================================ +// [AsmJit::XmmReg] +// ============================================================================ + +//! @brief 128-bit SSE register. +struct XmmReg : public Reg +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create non-initialized XMM register. + inline XmmReg() : Reg(kInvalidValue, 16) {} + //! @brief Create a reference to @a other XMM register. + inline XmmReg(const _Initialize&, uint32_t code) : Reg(code, 16) {} + +#if !defined(ASMJIT_NODOC) + inline XmmReg(const _DontInitialize& dontInitialize) : Reg(dontInitialize) {} + inline XmmReg(const XmmReg& other) : Reg(other) {} +#endif // ASMJIT_NODOC + + // -------------------------------------------------------------------------- + // [Reg Specific] + // -------------------------------------------------------------------------- + + //! @brief Set register code to @a code. + inline XmmReg& setCode(uint32_t code) + { + _reg.code = code; + return *this; + } + + //! @brief Set register size to @a size. + inline XmmReg& setSize(uint32_t size) + { + _reg.size = static_cast(size); + return *this; + } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline XmmReg& operator=(const XmmReg& other) { _copy(other); return *this; } + inline bool operator==(const XmmReg& other) const { return getRegCode() == other.getRegCode(); } + inline bool operator!=(const XmmReg& other) const { return getRegCode() != other.getRegCode(); } +#endif // ASMJIT_NODOC +}; + +// ============================================================================ +// [AsmJit::SegmentReg] +// ============================================================================ + +//! @brief Segment register. +struct SegmentReg : public Reg +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create non-initialized segment register. + inline SegmentReg() : Reg(kInvalidValue, 2) {} + //! @brief Create a reference to @a other segment register. + inline SegmentReg(const _Initialize&, uint32_t code) : Reg(code, 2) {} + +#if !defined(ASMJIT_NODOC) + inline SegmentReg(const _DontInitialize& dontInitialize) : Reg(dontInitialize) {} + inline SegmentReg(const SegmentReg& other) : Reg(other) {} +#endif // ASMJIT_NODOC + + // -------------------------------------------------------------------------- + // [Reg Specific] + // -------------------------------------------------------------------------- + + //! @brief Set register code to @a code. + inline SegmentReg& setCode(uint32_t code) + { + _reg.code = code; + return *this; + } + + //! @brief Set register size to @a size. + inline SegmentReg& setSize(uint32_t size) + { + _reg.size = static_cast(size); + return *this; + } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline SegmentReg& operator=(const SegmentReg& other) { _copy(other); return *this; } + inline bool operator==(const SegmentReg& other) const { return getRegCode() == other.getRegCode(); } + inline bool operator!=(const SegmentReg& other) const { return getRegCode() != other.getRegCode(); } +#endif // ASMJIT_NODOC +}; + +// ============================================================================ +// [AsmJit::Registers - no_reg] +// ============================================================================ + +//! @brief No register, can be used only in @c Mem operand. +ASMJIT_VAR const GpReg no_reg; + +// ============================================================================ +// [AsmJit::Registers - 8-bit] +// ============================================================================ + +//! @brief 8-bit General purpose register. +ASMJIT_VAR const GpReg al; +//! @brief 8-bit General purpose register. +ASMJIT_VAR const GpReg cl; +//! @brief 8-bit General purpose register. +ASMJIT_VAR const GpReg dl; +//! @brief 8-bit General purpose register. +ASMJIT_VAR const GpReg bl; + +#if defined(ASMJIT_X64) +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg spl; +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg bpl; +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg sil; +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg dil; + +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r8b; +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r9b; +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r10b; +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r11b; +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r12b; +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r13b; +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r14b; +//! @brief 8-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r15b; +#endif // ASMJIT_X64 + +//! @brief 8-bit General purpose register. +ASMJIT_VAR const GpReg ah; +//! @brief 8-bit General purpose register. +ASMJIT_VAR const GpReg ch; +//! @brief 8-bit General purpose register. +ASMJIT_VAR const GpReg dh; +//! @brief 8-bit General purpose register. +ASMJIT_VAR const GpReg bh; + +// ============================================================================ +// [AsmJit::Registers - 16-bit] +// ============================================================================ + +//! @brief 16-bit General purpose register. +ASMJIT_VAR const GpReg ax; +//! @brief 16-bit General purpose register. +ASMJIT_VAR const GpReg cx; +//! @brief 16-bit General purpose register. +ASMJIT_VAR const GpReg dx; +//! @brief 16-bit General purpose register. +ASMJIT_VAR const GpReg bx; +//! @brief 16-bit General purpose register. +ASMJIT_VAR const GpReg sp; +//! @brief 16-bit General purpose register. +ASMJIT_VAR const GpReg bp; +//! @brief 16-bit General purpose register. +ASMJIT_VAR const GpReg si; +//! @brief 16-bit General purpose register. +ASMJIT_VAR const GpReg di; + +#if defined(ASMJIT_X64) +//! @brief 16-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r8w; +//! @brief 16-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r9w; +//! @brief 16-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r10w; +//! @brief 16-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r11w; +//! @brief 16-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r12w; +//! @brief 16-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r13w; +//! @brief 16-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r14w; +//! @brief 16-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r15w; +#endif // ASMJIT_X64 + +// ============================================================================ +// [AsmJit::Registers - 32-bit] +// ============================================================================ + +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg eax; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg ecx; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg edx; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg ebx; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg esp; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg ebp; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg esi; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg edi; + +#if defined(ASMJIT_X64) +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg r8d; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg r9d; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg r10d; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg r11d; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg r12d; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg r13d; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg r14d; +//! @brief 32-bit General purpose register. +ASMJIT_VAR const GpReg r15d; +#endif // ASMJIT_X64 + +// ============================================================================ +// [AsmJit::Registers - 64-bit] +// ============================================================================ + +#if defined(ASMJIT_X64) +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg rax; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg rcx; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg rdx; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg rbx; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg rsp; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg rbp; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg rsi; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg rdi; + +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r8; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r9; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r10; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r11; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r12; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r13; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r14; +//! @brief 64-bit General purpose register (64-bit mode only). +ASMJIT_VAR const GpReg r15; +#endif // ASMJIT_X64 + +// ============================================================================ +// [AsmJit::Registers - Native (AsmJit extension)] +// ============================================================================ + +//! @brief 32-bit or 64-bit General purpose register. +ASMJIT_VAR const GpReg zax; +//! @brief 32-bit or 64-bit General purpose register. +ASMJIT_VAR const GpReg zcx; +//! @brief 32-bit or 64-bit General purpose register. +ASMJIT_VAR const GpReg zdx; +//! @brief 32-bit or 64-bit General purpose register. +ASMJIT_VAR const GpReg zbx; +//! @brief 32-bit or 64-bit General purpose register. +ASMJIT_VAR const GpReg zsp; +//! @brief 32-bit or 64-bit General purpose register. +ASMJIT_VAR const GpReg zbp; +//! @brief 32-bit or 64-bit General purpose register. +ASMJIT_VAR const GpReg zsi; +//! @brief 32-bit or 64-bit General purpose register. +ASMJIT_VAR const GpReg zdi; + +// ============================================================================ +// [AsmJit::Registers - MM] +// ============================================================================ + +//! @brief 64-bit MM register. +ASMJIT_VAR const MmReg mm0; +//! @brief 64-bit MM register. +ASMJIT_VAR const MmReg mm1; +//! @brief 64-bit MM register. +ASMJIT_VAR const MmReg mm2; +//! @brief 64-bit MM register. +ASMJIT_VAR const MmReg mm3; +//! @brief 64-bit MM register. +ASMJIT_VAR const MmReg mm4; +//! @brief 64-bit MM register. +ASMJIT_VAR const MmReg mm5; +//! @brief 64-bit MM register. +ASMJIT_VAR const MmReg mm6; +//! @brief 64-bit MM register. +ASMJIT_VAR const MmReg mm7; + +// ============================================================================ +// [AsmJit::Registers - XMM] +// ============================================================================ + +//! @brief 128-bit XMM register. +ASMJIT_VAR const XmmReg xmm0; +//! @brief 128-bit XMM register. +ASMJIT_VAR const XmmReg xmm1; +//! @brief 128-bit XMM register. +ASMJIT_VAR const XmmReg xmm2; +//! @brief 128-bit XMM register. +ASMJIT_VAR const XmmReg xmm3; +//! @brief 128-bit XMM register. +ASMJIT_VAR const XmmReg xmm4; +//! @brief 128-bit XMM register. +ASMJIT_VAR const XmmReg xmm5; +//! @brief 128-bit XMM register. +ASMJIT_VAR const XmmReg xmm6; +//! @brief 128-bit XMM register. +ASMJIT_VAR const XmmReg xmm7; + +#if defined(ASMJIT_X64) +//! @brief 128-bit XMM register (64-bit mode only). +ASMJIT_VAR const XmmReg xmm8; +//! @brief 128-bit XMM register (64-bit mode only). +ASMJIT_VAR const XmmReg xmm9; +//! @brief 128-bit XMM register (64-bit mode only). +ASMJIT_VAR const XmmReg xmm10; +//! @brief 128-bit XMM register (64-bit mode only). +ASMJIT_VAR const XmmReg xmm11; +//! @brief 128-bit XMM register (64-bit mode only). +ASMJIT_VAR const XmmReg xmm12; +//! @brief 128-bit XMM register (64-bit mode only). +ASMJIT_VAR const XmmReg xmm13; +//! @brief 128-bit XMM register (64-bit mode only). +ASMJIT_VAR const XmmReg xmm14; +//! @brief 128-bit XMM register (64-bit mode only). +ASMJIT_VAR const XmmReg xmm15; +#endif // ASMJIT_X64 + +// ============================================================================ +// [AsmJit::Registers - Segment] +// ============================================================================ + +//! @brief CS segment register. +ASMJIT_VAR const SegmentReg cs; +//! @brief SS segment register. +ASMJIT_VAR const SegmentReg ss; +//! @brief DS segment register. +ASMJIT_VAR const SegmentReg ds; +//! @brief ES segment register. +ASMJIT_VAR const SegmentReg es; +//! @brief FS segment register. +ASMJIT_VAR const SegmentReg fs; +//! @brief GS segment register. +ASMJIT_VAR const SegmentReg gs; + +// ============================================================================ +// [AsmJit::Registers - Register From Index] +// ============================================================================ + +//! @brief Get general purpose register of byte size. +static inline GpReg gpb_lo(uint32_t index) +{ return GpReg(_Initialize(), static_cast(index | kX86RegTypeGpbLo)); } + +//! @brief Get general purpose register of byte size. +static inline GpReg gpb_hi(uint32_t index) +{ return GpReg(_Initialize(), static_cast(index | kX86RegTypeGpbHi)); } + +//! @brief Get general purpose register of word size. +static inline GpReg gpw(uint32_t index) +{ return GpReg(_Initialize(), static_cast(index | kX86RegTypeGpw)); } + +//! @brief Get general purpose register of dword size. +static inline GpReg gpd(uint32_t index) +{ return GpReg(_Initialize(), static_cast(index | kX86RegTypeGpd)); } + +#if defined(ASMJIT_X64) +//! @brief Get general purpose register of qword size (64-bit only). +static inline GpReg gpq(uint32_t index) +{ return GpReg(_Initialize(), static_cast(index | kX86RegTypeGpq)); } +#endif + +//! @brief Get general purpose dword/qword register (depending to architecture). +static inline GpReg gpz(uint32_t index) +{ return GpReg(_Initialize(), static_cast(index | kX86RegTypeGpz)); } + +//! @brief Get MMX (MM) register . +static inline MmReg mm(uint32_t index) +{ return MmReg(_Initialize(), static_cast(index | kX86RegTypeMm)); } + +//! @brief Get SSE (XMM) register. +static inline XmmReg xmm(uint32_t index) +{ return XmmReg(_Initialize(), static_cast(index | kX86RegTypeXmm)); } + +//! @brief Get x87 register with index @a i. +static inline X87Reg st(uint32_t i) +{ + ASMJIT_ASSERT(i < 8); + return X87Reg(_Initialize(), static_cast(i)); +} + +// ============================================================================ +// [AsmJit::Mem] +// ============================================================================ + +//! @brief Memory operand. +struct Mem : public Operand +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + inline Mem() : + Operand(_DontInitialize()) + { + _mem.op = kOperandMem; + _mem.size = 0; + _mem.type = kOperandMemNative; + _mem.segment = kX86SegNone; + _mem.sizePrefix = 0; + _mem.shift = 0; + + _mem.id = kInvalidValue; + _mem.base = kInvalidValue; + _mem.index = kInvalidValue; + + _mem.target = NULL; + _mem.displacement = 0; + } + + inline Mem(const Label& label, sysint_t displacement, uint32_t size = 0) : + Operand(_DontInitialize()) + { + _mem.op = kOperandMem; + _mem.size = (uint8_t)size; + _mem.type = kOperandMemLabel; + _mem.segment = kX86SegNone; + _mem.sizePrefix = 0; + _mem.shift = 0; + + _mem.id = kInvalidValue; + _mem.base = reinterpret_cast(label)._base.id; + _mem.index = kInvalidValue; + + _mem.target = NULL; + _mem.displacement = displacement; + } + + inline Mem(const GpReg& base, sysint_t displacement, uint32_t size = 0) : + Operand(_DontInitialize()) + { + _mem.op = kOperandMem; + _mem.size = (uint8_t)size; + _mem.type = kOperandMemNative; + _mem.segment = kX86SegNone; + +#if defined(ASMJIT_X86) + _mem.sizePrefix = base.getSize() != 4; +#else + _mem.sizePrefix = base.getSize() != 8; +#endif + + _mem.shift = 0; + + _mem.id = kInvalidValue; + _mem.base = base.getRegCode() & kRegIndexMask; + _mem.index = kInvalidValue; + + _mem.target = NULL; + _mem.displacement = displacement; + } + + inline Mem(const GpVar& base, sysint_t displacement, uint32_t size = 0) : + Operand(_DontInitialize()) + { + _mem.op = kOperandMem; + _mem.size = (uint8_t)size; + _mem.type = kOperandMemNative; + _mem.segment = kX86SegNone; + +#if defined(ASMJIT_X86) + _mem.sizePrefix = (reinterpret_cast(base)._var.size) != 4; +#else + _mem.sizePrefix = (reinterpret_cast(base)._var.size) != 8; +#endif + + _mem.shift = 0; + + _mem.id = kInvalidValue; + _mem.base = reinterpret_cast(base).getId(); + _mem.index = kInvalidValue; + + _mem.target = NULL; + _mem.displacement = displacement; + } + + inline Mem(const GpReg& base, const GpReg& index, uint32_t shift, sysint_t displacement, uint32_t size = 0) : + Operand(_DontInitialize()) + { + ASMJIT_ASSERT(shift <= 3); + + _mem.op = kOperandMem; + _mem.size = (uint8_t)size; + _mem.type = kOperandMemNative; + _mem.segment = kX86SegNone; + +#if defined(ASMJIT_X86) + _mem.sizePrefix = (base.getSize() | index.getSize()) != 4; +#else + _mem.sizePrefix = (base.getSize() | index.getSize()) != 8; +#endif + + _mem.shift = (uint8_t)shift; + + _mem.id = kInvalidValue; + _mem.base = base.getRegIndex(); + _mem.index = index.getRegIndex(); + + _mem.target = NULL; + _mem.displacement = displacement; + } + + inline Mem(const GpVar& base, const GpVar& index, uint32_t shift, sysint_t displacement, uint32_t size = 0) : + Operand(_DontInitialize()) + { + ASMJIT_ASSERT(shift <= 3); + + _mem.op = kOperandMem; + _mem.size = (uint8_t)size; + _mem.type = kOperandMemNative; + _mem.segment = kX86SegNone; + +#if defined(ASMJIT_X86) + _mem.sizePrefix = (reinterpret_cast(base )._var.size | + reinterpret_cast(index)._var.size ) != 4; +#else + _mem.sizePrefix = (reinterpret_cast(base )._var.size | + reinterpret_cast(index)._var.size ) != 8; +#endif + + _mem.shift = (uint8_t)shift; + + _mem.id = kInvalidValue; + _mem.base = reinterpret_cast(base).getId(); + _mem.index = reinterpret_cast(index).getId(); + + _mem.target = NULL; + _mem.displacement = displacement; + } + + inline Mem(const Mem& other) : + Operand(other) + { + } + + inline Mem(const _DontInitialize& dontInitialize) : + Operand(dontInitialize) + { + } + + // -------------------------------------------------------------------------- + // [Mem Specific] + // -------------------------------------------------------------------------- + + //! @brief Get type of memory operand, see @c kOperandMemType. + inline uint32_t getMemType() const + { return _mem.type; } + + //! @brief Get memory operand segment, see @c kX86Seg. + inline uint32_t getSegment() const + { return _mem.segment; } + + //! @brief Set memory operand segment, see @c kX86Seg. + inline Mem& setSegment(uint32_t seg) + { + _mem.segment = static_cast(seg); + return *this; + } + + //! @brief Set memory operand segment, see @c kX86Seg. + inline Mem& setSegment(const SegmentReg& seg) + { + _mem.segment = static_cast(seg.getRegIndex()); + return *this; + } + + //! @brief Get whether the memory operand has segment override prefix. + inline bool hasSegment() const + { return _mem.segment >= kX86SegCount; } + + //! @brief Get whether the memory operand has base register. + inline bool hasBase() const + { return _mem.base != kInvalidValue; } + + //! @brief Get whether the memory operand has index. + inline bool hasIndex() const + { return _mem.index != kInvalidValue; } + + //! @brief Get whether the memory operand has shift used. + inline bool hasShift() const + { return _mem.shift != 0; } + + //! @brief Get memory operand base register or @c kInvalidValue. + inline uint32_t getBase() const + { return _mem.base; } + + //! @brief Get memory operand index register or @c kInvalidValue. + inline uint32_t getIndex() const + { return _mem.index; } + + //! @brief Get memory operand index scale (0, 1, 2 or 3). + inline uint32_t getShift() const + { return _mem.shift; } + + //! @brief Get whether to use size-override prefix. + //! + //! @note This is useful only for MOV and LEA type of instructions. + inline bool getSizePrefix() const + { return _mem.sizePrefix; } + + //! @brief Set whether to use size-override prefix. + inline Mem& setSizePrefix(bool b) + { + _mem.sizePrefix = b; + return *this; + } + + //! @brief Get absolute target address. + //! + //! @note You should always check if operand contains address by @c getMemType(). + inline void* getTarget() const + { return _mem.target; } + + //! @brief Set absolute target address. + inline Mem& setTarget(void* target) + { + _mem.target = target; + return *this; + } + + //! @brief Set memory operand size. + inline Mem& setSize(uint32_t size) + { + _mem.size = size; + return *this; + } + + //! @brief Get memory operand relative displacement. + inline sysint_t getDisplacement() const + { return _mem.displacement; } + + //! @brief Set memory operand relative displacement. + inline Mem& setDisplacement(sysint_t displacement) + { + _mem.displacement = displacement; + return *this; + } + + //! @brief Adjust memory operand relative displacement by @a displacement. + inline Mem& adjust(sysint_t displacement) + { + _mem.displacement += displacement; + return *this; + } + + //! @brief Get new memory operand adjusted by @a displacement. + inline Mem adjusted(sysint_t displacement) const + { + Mem result(*this); + result.adjust(displacement); + return result; + } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline Mem& operator=(const Mem& other) + { + _copy(other); + return *this; + } + + inline bool operator==(const Mem& other) const + { + return _bin.u32[0] == other._bin.u32[0] && + _bin.u32[1] == other._bin.u32[1] && + _bin.u32[2] == other._bin.u32[2] && + _bin.u32[3] == other._bin.u32[3] && + _bin.uptr[0] == other._bin.uptr[0] && + _bin.uptr[1] == other._bin.uptr[1]; + } + + inline bool operator!=(const Mem& other) const + { + return !(*this == other); + } +#endif // ASMJIT_NODOC +}; + +// ============================================================================ +// [AsmJit::Var] +// ============================================================================ + +ASMJIT_API Mem _BaseVarMem(const Var& var, uint32_t size); +ASMJIT_API Mem _BaseVarMem(const Var& var, uint32_t size, sysint_t disp); +ASMJIT_API Mem _BaseVarMem(const Var& var, uint32_t size, const GpVar& index, uint32_t shift, sysint_t disp); + +//! @brief Base class for all variables. +struct Var : public Operand +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline Var(const _DontInitialize& dontInitialize) : + Operand(dontInitialize) + { + } +#endif // ASMJIT_NODOC + + inline Var() : + Operand(_DontInitialize()) + { + _var.op = kOperandVar; + _var.size = 0; + _var.regCode = kInvalidValue; + _var.varType = kInvalidValue; + _var.id = kInvalidValue; + } + + inline Var(const Var& other) : + Operand(other) + { + } + + // -------------------------------------------------------------------------- + // [Type] + // -------------------------------------------------------------------------- + + inline uint32_t getVarType() const + { return _var.varType; } + + inline bool isGpVar() const + { return _var.varType <= kX86VarTypeGpq; } + + inline bool isX87Var() const + { return _var.varType >= kX86VarTypeX87 && _var.varType <= kX86VarTypeX87SD; } + + inline bool isMmVar() const + { return _var.varType == kX86VarTypeMm; } + + inline bool isXmmVar() const + { return _var.varType >= kX86VarTypeXmm && _var.varType <= kX86VarTypeXmmPD; } + + // -------------------------------------------------------------------------- + // [Memory Cast] + // -------------------------------------------------------------------------- + + //! @brief Cast this variable to memory operand. + //! + //! @note Size of operand depends on native variable type, you can use other + //! variants if you want specific one. + inline Mem m() const + { return _BaseVarMem(*this, kInvalidValue); } + + //! @overload. + inline Mem m(sysint_t disp) const + { return _BaseVarMem(*this, kInvalidValue, disp); } + + //! @overload. + inline Mem m(const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) const + { return _BaseVarMem(*this, kInvalidValue, index, shift, disp); } + + //! @brief Cast this variable to 8-bit memory operand. + inline Mem m8() const + { return _BaseVarMem(*this, 1); } + + //! @overload. + inline Mem m8(sysint_t disp) const + { return _BaseVarMem(*this, 1, disp); } + + //! @overload. + inline Mem m8(const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) const + { return _BaseVarMem(*this, 1, index, shift, disp); } + + //! @brief Cast this variable to 16-bit memory operand. + inline Mem m16() const + { return _BaseVarMem(*this, 2); } + + //! @overload. + inline Mem m16(sysint_t disp) const + { return _BaseVarMem(*this, 2, disp); } + + //! @overload. + inline Mem m16(const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) const + { return _BaseVarMem(*this, 2, index, shift, disp); } + + //! @brief Cast this variable to 32-bit memory operand. + inline Mem m32() const + { return _BaseVarMem(*this, 4); } + + //! @overload. + inline Mem m32(sysint_t disp) const + { return _BaseVarMem(*this, 4, disp); } + + //! @overload. + inline Mem m32(const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) const + { return _BaseVarMem(*this, 4, index, shift, disp); } + + //! @brief Cast this variable to 64-bit memory operand. + inline Mem m64() const + { return _BaseVarMem(*this, 8); } + + //! @overload. + inline Mem m64(sysint_t disp) const + { return _BaseVarMem(*this, 8, disp); } + + //! @overload. + inline Mem m64(const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) const + { return _BaseVarMem(*this, 8, index, shift, disp); } + + //! @brief Cast this variable to 80-bit memory operand (long double). + inline Mem m80() const + { return _BaseVarMem(*this, 10); } + + //! @overload. + inline Mem m80(sysint_t disp) const + { return _BaseVarMem(*this, 10, disp); } + + //! @overload. + inline Mem m80(const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) const + { return _BaseVarMem(*this, 10, index, shift, disp); } + + //! @brief Cast this variable to 128-bit memory operand. + inline Mem m128() const + { return _BaseVarMem(*this, 16); } + + //! @overload. + inline Mem m128(sysint_t disp) const + { return _BaseVarMem(*this, 16, disp); } + + //! @overload. + inline Mem m128(const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) const + { return _BaseVarMem(*this, 16, index, shift, disp); } + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline Var& operator=(const Var& other) + { _copy(other); return *this; } + + inline bool operator==(const Var& other) const { return _base.id == other._base.id && _var.regCode == other._var.regCode; } + inline bool operator!=(const Var& other) const { return _base.id != other._base.id || _var.regCode != other._var.regCode; } +#endif // ASMJIT_NODOC + + // -------------------------------------------------------------------------- + // [Private] + // -------------------------------------------------------------------------- + +protected: + inline Var(const Var& other, uint32_t regCode, uint32_t size) : + Operand(_DontInitialize()) + { + _var.op = kOperandVar; + _var.size = (uint8_t)size; + _var.id = other._base.id; + _var.regCode = regCode; + _var.varType = other._var.varType; + } +}; + +// ============================================================================ +// [AsmJit::X87Var] +// ============================================================================ + +//! @brief X87 Variable operand. +struct X87Var : public Var +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + inline X87Var(const _DontInitialize& dontInitialize) : + Var(dontInitialize) + { + } + + inline X87Var() : + Var(_DontInitialize()) + { + _var.op = kOperandVar; + _var.size = 12; + _var.id = kInvalidValue; + + _var.regCode = kX86RegTypeX87; + _var.varType = kX86VarTypeX87; + } + + inline X87Var(const X87Var& other) : + Var(other) {} + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline X87Var& operator=(const X87Var& other) + { _copy(other); return *this; } + + inline bool operator==(const X87Var& other) const { return _base.id == other._base.id; } + inline bool operator!=(const X87Var& other) const { return _base.id != other._base.id; } +#endif // ASMJIT_NODOC +}; + +// ============================================================================ +// [AsmJit::GpVar] +// ============================================================================ + +//! @brief GP variable operand. +struct GpVar : public Var +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create new uninitialized @c GpVar instance (internal constructor). + inline GpVar(const _DontInitialize& dontInitialize) : + Var(dontInitialize) + { + } + + //! @brief Create new uninitialized @c GpVar instance. + inline GpVar() : + Var(_DontInitialize()) + { + _var.op = kOperandVar; + _var.size = sizeof(sysint_t); + _var.id = kInvalidValue; + + _var.regCode = kX86RegTypeGpz; + _var.varType = kX86VarTypeGpz; + } + + //! @brief Create new @c GpVar instance using @a other. + //! + //! Note this will not create a different variable, use @c Compiler::newGpVar() + //! if you want to do so. This is only copy-constructor that allows to store + //! the same variable in different places. + inline GpVar(const GpVar& other) : + Var(other) {} + + // -------------------------------------------------------------------------- + // [GpVar Specific] + // -------------------------------------------------------------------------- + + //! @brief Get whether this variable is general purpose BYTE register. + inline bool isGpb() const { return (_var.regCode & kRegTypeMask) <= kX86RegTypeGpbHi; } + //! @brief Get whether this variable is general purpose BYTE.LO register. + inline bool isGpbLo() const { return (_var.regCode & kRegTypeMask) == kX86RegTypeGpbLo; } + //! @brief Get whether this variable is general purpose BYTE.HI register. + inline bool isGpbHi() const { return (_var.regCode & kRegTypeMask) == kX86RegTypeGpbHi; } + + //! @brief Get whether this variable is general purpose WORD register. + inline bool isGpw() const { return (_var.regCode & kRegTypeMask) == kX86RegTypeGpw; } + //! @brief Get whether this variable is general purpose DWORD register. + inline bool isGpd() const { return (_var.regCode & kRegTypeMask) == kX86RegTypeGpd; } + //! @brief Get whether this variable is general purpose QWORD (only 64-bit) register. + inline bool isGpq() const { return (_var.regCode & kRegTypeMask) == kX86RegTypeGpq; } + + // -------------------------------------------------------------------------- + // [GpVar Cast] + // -------------------------------------------------------------------------- + + //! @brief Cast this variable to 8-bit (LO) part of variable + inline GpVar r8() const { return GpVar(*this, kX86RegTypeGpbLo, 1); } + //! @brief Cast this variable to 8-bit (LO) part of variable + inline GpVar r8Lo() const { return GpVar(*this, kX86RegTypeGpbLo, 1); } + //! @brief Cast this variable to 8-bit (HI) part of variable + inline GpVar r8Hi() const { return GpVar(*this, kX86RegTypeGpbHi, 1); } + + //! @brief Cast this variable to 16-bit part of variable + inline GpVar r16() const { return GpVar(*this, kX86RegTypeGpw, 2); } + //! @brief Cast this variable to 32-bit part of variable + inline GpVar r32() const { return GpVar(*this, kX86RegTypeGpd, 4); } +#if defined(ASMJIT_X64) + //! @brief Cast this variable to 64-bit part of variable + inline GpVar r64() const { return GpVar(*this, kX86RegTypeGpq, 8); } +#endif // ASMJIT_X64 + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline GpVar& operator=(const GpVar& other) + { _copy(other); return *this; } + + inline bool operator==(const GpVar& other) const { return _base.id == other._base.id && _var.regCode == other._var.regCode; } + inline bool operator!=(const GpVar& other) const { return _base.id != other._base.id || _var.regCode != other._var.regCode; } +#endif // ASMJIT_NODOC + + // -------------------------------------------------------------------------- + // [Private] + // -------------------------------------------------------------------------- + +protected: + inline GpVar(const GpVar& other, uint32_t regCode, uint32_t size) : + Var(other, regCode, size) + { + } +}; + +// ============================================================================ +// [AsmJit::MmVar] +// ============================================================================ + +//! @brief MM variable operand. +struct MmVar : public Var +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create new uninitialized @c MmVar instance (internal constructor). + inline MmVar(const _DontInitialize& dontInitialize) : + Var(dontInitialize) + { + } + + //! @brief Create new uninitialized @c MmVar instance. + inline MmVar() : + Var(_DontInitialize()) + { + _var.op = kOperandVar; + _var.size = 8; + _var.id = kInvalidValue; + + _var.regCode = kX86RegTypeMm; + _var.varType = kX86VarTypeMm; + } + + //! @brief Create new @c MmVar instance using @a other. + //! + //! Note this will not create a different variable, use @c Compiler::newMmVar() + //! if you want to do so. This is only copy-constructor that allows to store + //! the same variable in different places. + inline MmVar(const MmVar& other) : + Var(other) {} + + // -------------------------------------------------------------------------- + // [MmVar Cast] + // -------------------------------------------------------------------------- + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline MmVar& operator=(const MmVar& other) + { _copy(other); return *this; } + + inline bool operator==(const MmVar& other) const { return _base.id == other._base.id; } + inline bool operator!=(const MmVar& other) const { return _base.id != other._base.id; } +#endif // ASMJIT_NODOC +}; + +// ============================================================================ +// [AsmJit::XmmVar] +// ============================================================================ + +//! @brief XMM Variable operand. +struct XmmVar : public Var +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + inline XmmVar(const _DontInitialize& dontInitialize) : + Var(dontInitialize) + { + } + + inline XmmVar() : + Var(_DontInitialize()) + { + _var.op = kOperandVar; + _var.size = 16; + _var.id = kInvalidValue; + + _var.regCode = kX86RegTypeXmm; + _var.varType = kX86VarTypeXmm; + } + + inline XmmVar(const XmmVar& other) : + Var(other) {} + + // -------------------------------------------------------------------------- + // [XmmVar Access] + // -------------------------------------------------------------------------- + + // -------------------------------------------------------------------------- + // [Operator Overload] + // -------------------------------------------------------------------------- + +#if !defined(ASMJIT_NODOC) + inline XmmVar& operator=(const XmmVar& other) + { _copy(other); return *this; } + + inline bool operator==(const XmmVar& other) const { return _base.id == other._base.id; } + inline bool operator!=(const XmmVar& other) const { return _base.id != other._base.id; } +#endif // ASMJIT_NODOC +}; + +// ============================================================================ +// [AsmJit::Mem - [label + displacement]] +// ============================================================================ + +//! @brief Create a custom pointer operand. +ASMJIT_API Mem ptr(const Label& label, sysint_t disp = 0, uint32_t size = 0); +//! @brief Create a byte pointer operand. +static inline Mem byte_ptr(const Label& label, sysint_t disp = 0) { return ptr(label, disp, kSizeByte); } +//! @brief Create a word pointer operand. +static inline Mem word_ptr(const Label& label, sysint_t disp = 0) { return ptr(label, disp, kSizeWord); } +//! @brief Create a dword pointer operand. +static inline Mem dword_ptr(const Label& label, sysint_t disp = 0) { return ptr(label, disp, kSizeDWord); } +//! @brief Create a qword pointer operand. +static inline Mem qword_ptr(const Label& label, sysint_t disp = 0) { return ptr(label, disp, kSizeQWord); } +//! @brief Create a tword pointer operand. +static inline Mem tword_ptr(const Label& label, sysint_t disp = 0) { return ptr(label, disp, kSizeTWord); } +//! @brief Create a dqword pointer operand. +static inline Mem dqword_ptr(const Label& label, sysint_t disp = 0) { return ptr(label, disp, kSizeDQWord); } +//! @brief Create a mmword pointer operand. +static inline Mem mmword_ptr(const Label& label, sysint_t disp = 0) { return ptr(label, disp, kSizeQWord); } +//! @brief Create a xmmword pointer operand. +static inline Mem xmmword_ptr(const Label& label, sysint_t disp = 0) { return ptr(label, disp, kSizeDQWord); } +//! @brief Create an intptr_t pointer operand. +static inline Mem sysint_ptr(const Label& label, sysint_t disp = 0) { return ptr(label, disp, sizeof(sysint_t)); } + +// ============================================================================ +// [AsmJit::Mem - [label + index << shift + displacement]] +// ============================================================================ + +//! @brief Create a custom pointer operand. +ASMJIT_API Mem ptr(const Label& label, const GpReg& index, uint32_t shift, sysint_t disp = 0, uint32_t size = 0); +//! @brief Create a byte pointer operand. +static inline Mem byte_ptr(const Label& label, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeByte); } +//! @brief Create a word pointer operand. +static inline Mem word_ptr(const Label& label, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeWord); } +//! @brief Create a dword pointer operand. +static inline Mem dword_ptr(const Label& label, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeDWord); } +//! @brief Create a qword pointer operand. +static inline Mem qword_ptr(const Label& label, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeQWord); } +//! @brief Create a tword pointer operand. +static inline Mem tword_ptr(const Label& label, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeTWord); } +//! @brief Create a dqword pointer operand. +static inline Mem dqword_ptr(const Label& label, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeDQWord); } +//! @brief Create a mmword pointer operand. +static inline Mem mmword_ptr(const Label& label, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeQWord); } +//! @brief Create a xmmword pointer operand. +static inline Mem xmmword_ptr(const Label& label, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeDQWord); } +//! @brief Create an intptr_t pointer operand. +static inline Mem sysint_ptr(const Label& label, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, sizeof(sysint_t)); } + +//! @brief Create a custom pointer operand. +ASMJIT_API Mem ptr(const Label& label, const GpVar& index, uint32_t shift, sysint_t disp = 0, uint32_t size = 0); +//! @brief Create a byte pointer operand. +static inline Mem byte_ptr(const Label& label, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeByte); } +//! @brief Create a word pointer operand. +static inline Mem word_ptr(const Label& label, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeWord); } +//! @brief Create a dword pointer operand. +static inline Mem dword_ptr(const Label& label, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeDWord); } +//! @brief Create a qword pointer operand. +static inline Mem qword_ptr(const Label& label, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeQWord); } +//! @brief Create a tword pointer operand. +static inline Mem tword_ptr(const Label& label, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeTWord); } +//! @brief Create a dqword pointer operand. +static inline Mem dqword_ptr(const Label& label, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeDQWord); } +//! @brief Create a mmword pointer operand. +static inline Mem mmword_ptr(const Label& label, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeQWord); } +//! @brief Create a xmmword pointer operand. +static inline Mem xmmword_ptr(const Label& label, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, kSizeDQWord); } +//! @brief Create an intptr_t pointer operand. +static inline Mem sysint_ptr(const Label& label, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr(label, index, shift, disp, sizeof(sysint_t)); } + +// ============================================================================ +// [AsmJit::Mem - segment[target + displacement] +// ============================================================================ + +//! @brief Create a custom pointer operand. +ASMJIT_API Mem ptr_abs(void* target, sysint_t disp = 0, uint32_t size = 0); +//! @brief Create a byte pointer operand. +static inline Mem byte_ptr_abs(void* target, sysint_t disp = 0) { return ptr_abs(target, disp, kSizeByte); } +//! @brief Create a word pointer operand. +static inline Mem word_ptr_abs(void* target, sysint_t disp = 0) { return ptr_abs(target, disp, kSizeWord); } +//! @brief Create a dword pointer operand. +static inline Mem dword_ptr_abs(void* target, sysint_t disp = 0) { return ptr_abs(target, disp, kSizeDWord); } +//! @brief Create a qword pointer operand. +static inline Mem qword_ptr_abs(void* target, sysint_t disp = 0) { return ptr_abs(target, disp, kSizeQWord); } +//! @brief Create a tword pointer operand (used for 80-bit floating points). +static inline Mem tword_ptr_abs(void* target, sysint_t disp = 0) { return ptr_abs(target, disp, kSizeTWord); } +//! @brief Create a dqword pointer operand. +static inline Mem dqword_ptr_abs(void* target, sysint_t disp = 0) { return ptr_abs(target, disp, kSizeDQWord); } +//! @brief Create a mmword pointer operand. +static inline Mem mmword_ptr_abs(void* target, sysint_t disp = 0) { return ptr_abs(target, disp, kSizeQWord); } +//! @brief Create a xmmword pointer operand. +static inline Mem xmmword_ptr_abs(void* target, sysint_t disp = 0) { return ptr_abs(target, disp, kSizeDQWord); } +//! @brief Create an intptr_t pointer operand. +static inline Mem sysint_ptr_abs(void* target, sysint_t disp = 0) { return ptr_abs(target, disp, sizeof(sysint_t)); } + +// ============================================================================ +// [AsmJit::Mem - segment[target + index << shift + displacement] +// ============================================================================ + +//! @brief Create a custom pointer operand. +ASMJIT_API Mem ptr_abs(void* target, const GpReg& index, uint32_t shift, sysint_t disp = 0, uint32_t size = 0); +//! @brief Create a byte pointer operand. +static inline Mem byte_ptr_abs(void* target, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeByte); } +//! @brief Create a word pointer operand. +static inline Mem word_ptr_abs(void* target, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeWord); } +//! @brief Create a dword pointer operand. +static inline Mem dword_ptr_abs(void* target, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeDWord); } +//! @brief Create a qword pointer operand. +static inline Mem qword_ptr_abs(void* target, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeQWord); } +//! @brief Create a tword pointer operand. +static inline Mem tword_ptr_abs(void* target, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeTWord); } +//! @brief Create a dqword pointer operand. +static inline Mem dqword_ptr_abs(void* target, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeDQWord); } +//! @brief Create a mmword pointer operand. +static inline Mem mmword_ptr_abs(void* target, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeQWord); } +//! @brief Create a xmmword pointer operand. +static inline Mem xmmword_ptr_abs(void* target, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeDQWord); } +//! @brief Create an intptr_t pointer operand. +static inline Mem sysint_ptr_abs(void* target, const GpReg& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, sizeof(sysint_t)); } + +//! @brief Create a custom pointer operand. +ASMJIT_API Mem ptr_abs(void* target, const GpVar& index, uint32_t shift, sysint_t disp = 0, uint32_t size = 0); +//! @brief Create a byte pointer operand. +static inline Mem byte_ptr_abs(void* target, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeByte); } +//! @brief Create a word pointer operand. +static inline Mem word_ptr_abs(void* target, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeWord); } +//! @brief Create a dword pointer operand. +static inline Mem dword_ptr_abs(void* target, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeDWord); } +//! @brief Create a qword pointer operand. +static inline Mem qword_ptr_abs(void* target, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeQWord); } +//! @brief Create a tword pointer operand. +static inline Mem tword_ptr_abs(void* target, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeTWord); } +//! @brief Create a dqword pointer operand. +static inline Mem dqword_ptr_abs(void* target, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeDQWord); } +//! @brief Create a mmword pointer operand. +static inline Mem mmword_ptr_abs(void* target, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeQWord); } +//! @brief Create a xmmword pointer operand. +static inline Mem xmmword_ptr_abs(void* target, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, kSizeDQWord); } +//! @brief Create an intptr_t pointer operand. +static inline Mem sysint_ptr_abs(void* target, const GpVar& index, uint32_t shift, sysint_t disp = 0) { return ptr_abs(target, index, shift, disp, sizeof(sysint_t)); } + +// ============================================================================ +// [AsmJit::Mem - ptr[base + displacement]] +// ============================================================================ + +//! @brief Create a custom pointer operand. +ASMJIT_API Mem ptr(const GpReg& base, sysint_t disp = 0, uint32_t size = 0); +//! @brief Create a byte pointer operand. +static inline Mem byte_ptr(const GpReg& base, sysint_t disp = 0) { return ptr(base, disp, kSizeByte); } +//! @brief Create a word pointer operand. +static inline Mem word_ptr(const GpReg& base, sysint_t disp = 0) { return ptr(base, disp, kSizeWord); } +//! @brief Create a dword pointer operand. +static inline Mem dword_ptr(const GpReg& base, sysint_t disp = 0) { return ptr(base, disp, kSizeDWord); } +//! @brief Create a qword pointer operand. +static inline Mem qword_ptr(const GpReg& base, sysint_t disp = 0) { return ptr(base, disp, kSizeQWord); } +//! @brief Create a tword pointer operand. +static inline Mem tword_ptr(const GpReg& base, sysint_t disp = 0) { return ptr(base, disp, kSizeTWord); } +//! @brief Create a dqword pointer operand. +static inline Mem dqword_ptr(const GpReg& base, sysint_t disp = 0) { return ptr(base, disp, kSizeDQWord); } +//! @brief Create a mmword pointer operand. +static inline Mem mmword_ptr(const GpReg& base, sysint_t disp = 0) { return ptr(base, disp, kSizeQWord); } +//! @brief Create a xmmword pointer operand. +static inline Mem xmmword_ptr(const GpReg& base, sysint_t disp = 0) { return ptr(base, disp, kSizeDQWord); } +//! @brief Create an intptr_t pointer operand. +static inline Mem sysint_ptr(const GpReg& base, sysint_t disp = 0) { return ptr(base, disp, sizeof(sysint_t)); } + +//! @brief Create a custom pointer operand. +ASMJIT_API Mem ptr(const GpVar& base, sysint_t disp = 0, uint32_t size = 0); +//! @brief Create a byte pointer operand. +static inline Mem byte_ptr(const GpVar& base, sysint_t disp = 0) { return ptr(base, disp, kSizeByte); } +//! @brief Create a word pointer operand. +static inline Mem word_ptr(const GpVar& base, sysint_t disp = 0) { return ptr(base, disp, kSizeWord); } +//! @brief Create a dword pointer operand. +static inline Mem dword_ptr(const GpVar& base, sysint_t disp = 0) { return ptr(base, disp, kSizeDWord); } +//! @brief Create a qword pointer operand. +static inline Mem qword_ptr(const GpVar& base, sysint_t disp = 0) { return ptr(base, disp, kSizeQWord); } +//! @brief Create a tword pointer operand. +static inline Mem tword_ptr(const GpVar& base, sysint_t disp = 0) { return ptr(base, disp, kSizeTWord); } +//! @brief Create a dqword pointer operand. +static inline Mem dqword_ptr(const GpVar& base, sysint_t disp = 0) { return ptr(base, disp, kSizeDQWord); } +//! @brief Create a mmword pointer operand. +static inline Mem mmword_ptr(const GpVar& base, sysint_t disp = 0) { return ptr(base, disp, kSizeQWord); } +//! @brief Create a xmmword pointer operand. +static inline Mem xmmword_ptr(const GpVar& base, sysint_t disp = 0) { return ptr(base, disp, kSizeDQWord); } +//! @brief Create an intptr_t pointer operand. +static inline Mem sysint_ptr(const GpVar& base, sysint_t disp = 0) { return ptr(base, disp, sizeof(sysint_t)); } + +// ============================================================================ +// [AsmJit::Mem - ptr[base + (index << shift) + displacement]] +// ============================================================================ + +//! @brief Create a custom pointer operand. +ASMJIT_API Mem ptr(const GpReg& base, const GpReg& index, uint32_t shift = 0, sysint_t disp = 0, uint32_t size = 0); +//! @brief Create a byte pointer operand. +static inline Mem byte_ptr(const GpReg& base, const GpReg& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeByte); } +//! @brief Create a word pointer operand. +static inline Mem word_ptr(const GpReg& base, const GpReg& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeWord); } +//! @brief Create a dword pointer operand. +static inline Mem dword_ptr(const GpReg& base, const GpReg& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeDWord); } +//! @brief Create a qword pointer operand. +static inline Mem qword_ptr(const GpReg& base, const GpReg& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeQWord); } +//! @brief Create a tword pointer operand. +static inline Mem tword_ptr(const GpReg& base, const GpReg& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeTWord); } +//! @brief Create a dqword pointer operand. +static inline Mem dqword_ptr(const GpReg& base, const GpReg& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeDQWord); } +//! @brief Create a mmword pointer operand. +static inline Mem mmword_ptr(const GpReg& base, const GpReg& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeQWord); } +//! @brief Create a xmmword pointer operand. +static inline Mem xmmword_ptr(const GpReg& base, const GpReg& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeDQWord); } +//! @brief Create an intptr_t pointer operand. +static inline Mem sysint_ptr(const GpReg& base, const GpReg& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, sizeof(sysint_t)); } + +//! @brief Create a custom pointer operand. +ASMJIT_API Mem ptr(const GpVar& base, const GpVar& index, uint32_t shift = 0, sysint_t disp = 0, uint32_t size = 0); +//! @brief Create a byte pointer operand. +static inline Mem byte_ptr(const GpVar& base, const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeByte); } +//! @brief Create a word pointer operand. +static inline Mem word_ptr(const GpVar& base, const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeWord); } +//! @brief Create a dword pointer operand. +static inline Mem dword_ptr(const GpVar& base, const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeDWord); } +//! @brief Create a qword pointer operand. +static inline Mem qword_ptr(const GpVar& base, const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeQWord); } +//! @brief Create a tword pointer operand. +static inline Mem tword_ptr(const GpVar& base, const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeTWord); } +//! @brief Create a dqword pointer operand. +static inline Mem dqword_ptr(const GpVar& base, const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeDQWord); } +//! @brief Create a mmword pointer operand. +static inline Mem mmword_ptr(const GpVar& base, const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeQWord); } +//! @brief Create a xmmword pointer operand. +static inline Mem xmmword_ptr(const GpVar& base, const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, kSizeDQWord); } +//! @brief Create an intptr_t pointer operand. +static inline Mem sysint_ptr(const GpVar& base, const GpVar& index, uint32_t shift = 0, sysint_t disp = 0) { return ptr(base, index, shift, disp, sizeof(sysint_t)); } + +// ============================================================================ +// [AsmJit::Macros] +// ============================================================================ + +//! @brief Create Shuffle Constant for MMX/SSE shuffle instrutions. +//! @param z First component position, number at interval [0, 3] inclusive. +//! @param x Second component position, number at interval [0, 3] inclusive. +//! @param y Third component position, number at interval [0, 3] inclusive. +//! @param w Fourth component position, number at interval [0, 3] inclusive. +//! +//! Shuffle constants can be used to make immediate value for these intrinsics: +//! - @ref X86Assembler::pshufw() +//! - @ref X86Assembler::pshufd() +//! - @ref X86Assembler::pshufhw() +//! - @ref X86Assembler::pshuflw() +//! - @ref X86Assembler::shufps() +static inline uint8_t mm_shuffle(uint8_t z, uint8_t y, uint8_t x, uint8_t w) +{ return (z << 6) | (y << 4) | (x << 2) | w; } + +//! @} + +} // AsmJit namespace + +// [Guard] +#endif // _ASMJIT_X86_X86OPERAND_H diff --git a/desmume/src/utils/AsmJit/x86/x86util.cpp b/desmume/src/utils/AsmJit/x86/x86util.cpp new file mode 100644 index 000000000..a0e667614 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86util.cpp @@ -0,0 +1,138 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +#define ASMJIT_EXPORTS + +// [Dependencies - AsmJit] +#include "../x86/x86defs.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +// ============================================================================ +// [AsmJit::_x86UtilJccFromCond] +// ============================================================================ + +const uint32_t _x86UtilJccFromCond[20] = +{ + kX86InstJO, + kX86InstJNO, + kX86InstJB, + kX86InstJAE, + kX86InstJE, + kX86InstJNE, + kX86InstJBE, + kX86InstJA, + kX86InstJS, + kX86InstJNS, + kX86InstJPE, + kX86InstJPO, + kX86InstJL, + kX86InstJGE, + kX86InstJLE, + kX86InstJG, + + kInstNone, + kInstNone, + kInstNone, + kInstNone +}; + +// ============================================================================ +// [AsmJit::_x86UtilMovccFromCond] +// ============================================================================ + +const uint32_t _x86UtilMovccFromCond[20] = +{ + kX86InstCMovO, + kX86InstCMovNO, + kX86InstCMovB, + kX86InstCMovAE, + kX86InstCMovE, + kX86InstCMovNE, + kX86InstCMovBE, + kX86InstCMovA, + kX86InstCMovS, + kX86InstCMovNS, + kX86InstCMovPE, + kX86InstCMovPO, + kX86InstCMovL, + kX86InstCMovGE, + kX86InstCMovLE, + kX86InstCMovG, + + kInstNone, + kInstNone, + kInstNone, + kInstNone +}; + +// ============================================================================ +// [AsmJit::_x86UtilSetccFromCond] +// ============================================================================ + +const uint32_t _x86UtilSetccFromCond[20] = +{ + kX86InstSetO, + kX86InstSetNO, + kX86InstSetB, + kX86InstSetAE, + kX86InstSetE, + kX86InstSetNE, + kX86InstSetBE, + kX86InstSetA, + kX86InstSetS, + kX86InstSetNS, + kX86InstSetPE, + kX86InstSetPO, + kX86InstSetL, + kX86InstSetGE, + kX86InstSetLE, + kX86InstSetG, + + kInstNone, + kInstNone, + kInstNone, + kInstNone +}; + +// ============================================================================ +// [AsmJit::_x86UtilReversedCond] +// ============================================================================ + +const uint32_t _x86UtilReversedCond[20] = +{ + /* x86CondO -> */ kX86CondO, + /* x86CondNO -> */ kX86CondNO, + /* x86CondB -> */ kX86CondA, + /* x86CondAE -> */ kX86CondBE, + /* x86CondE -> */ kX86CondE, + /* x86CondNE -> */ kX86CondNE, + /* x86CondBE -> */ kX86CondAE, + /* x86CondA -> */ kX86CondB, + /* x86CondS -> */ kX86CondS, + /* x86CondNS -> */ kX86CondNS, + /* x86CondPE -> */ kX86CondPE, + /* x86CondPO -> */ kX86CondPO, + + /* x86CondL -> */ kX86CondG, + /* x86CondGE -> */ kX86CondLE, + + /* x86CondLE -> */ kX86CondGE, + /* x86CondG -> */ kX86CondL, + + /* kX86CondFpuUnordered -> */ kX86CondFpuUnordered, + /* kX86CondFpuNotUnordered -> */ kX86CondFpuNotUnordered, + + 0x12, + 0x13 +}; + +} // AsmJit namespace + +#include "../core/apiend.h" diff --git a/desmume/src/utils/AsmJit/x86/x86util.h b/desmume/src/utils/AsmJit/x86/x86util.h new file mode 100644 index 000000000..7e289a0b2 --- /dev/null +++ b/desmume/src/utils/AsmJit/x86/x86util.h @@ -0,0 +1,122 @@ +// [AsmJit] +// Complete JIT Assembler for C++ Language. +// +// [License] +// Zlib - See COPYING file in this package. + +// [Guard] +#ifndef _ASMJIT_X86_X86UTIL_H +#define _ASMJIT_X86_X86UTIL_H + +// [Dependencies - AsmJit] +#include "../x86/x86defs.h" +#include "../x86/x86operand.h" + +// [Api-Begin] +#include "../core/apibegin.h" + +namespace AsmJit { + +//! @addtogroup AsmJit_X86 +//! @{ + +// ============================================================================ +// [AsmJit::X86Util] +// ============================================================================ + +//! @brief Map condition code to "jcc" group of instructions. +ASMJIT_VAR const uint32_t _x86UtilJccFromCond[20]; +//! @brief Map condition code to "cmovcc" group of instructions. +ASMJIT_VAR const uint32_t _x86UtilMovccFromCond[20]; +//! @brief Map condition code to "setcc" group of instructions. +ASMJIT_VAR const uint32_t _x86UtilSetccFromCond[20]; +//! @brief Map condition code to reversed condition code. +ASMJIT_VAR const uint32_t _x86UtilReversedCond[20]; + +struct X86Util +{ + // -------------------------------------------------------------------------- + // [Condition Codes] + // -------------------------------------------------------------------------- + + //! @brief Get the equivalent of negated condition code. + static inline uint32_t getNegatedCond(uint32_t cond) + { + return static_cast(cond ^ static_cast(cond < kX86CondNone)); + } + + //! @brief Corresponds to transposing the operands of a comparison. + static inline uint32_t getReversedCond(uint32_t cond) + { + ASMJIT_ASSERT(static_cast(cond) < ASMJIT_ARRAY_SIZE(_x86UtilReversedCond)); + return _x86UtilReversedCond[cond]; + } + + //! @brief Translate condition code @a cc to jcc instruction code. + //! @sa @c kX86InstCode, @c kX86InstJ. + static inline uint32_t getJccInstFromCond(uint32_t cond) + { + ASMJIT_ASSERT(static_cast(cond) < ASMJIT_ARRAY_SIZE(_x86UtilJccFromCond)); + return _x86UtilJccFromCond[cond]; + } + + //! @brief Translate condition code @a cc to cmovcc instruction code. + //! @sa @c kX86InstCode, @c kX86InstCMov. + static inline uint32_t getCMovccInstFromCond(uint32_t cond) + { + ASMJIT_ASSERT(static_cast(cond) < ASMJIT_ARRAY_SIZE(_x86UtilMovccFromCond)); + return _x86UtilMovccFromCond[cond]; + } + + //! @brief Translate condition code @a cc to setcc instruction code. + //! @sa @c kX86InstCode, @c kX86InstSet. + static inline uint32_t getSetccInstFromCond(uint32_t cond) + { + ASMJIT_ASSERT(static_cast(cond) < ASMJIT_ARRAY_SIZE(_x86UtilSetccFromCond)); + return _x86UtilSetccFromCond[cond]; + } + + // -------------------------------------------------------------------------- + // [Variables] + // -------------------------------------------------------------------------- + + static inline uint32_t getVarClassFromVarType(uint32_t varType) + { + ASMJIT_ASSERT(varType < kX86VarTypeCount); + return x86VarInfo[varType].getClass(); + } + + static inline uint32_t getVarSizeFromVarType(uint32_t varType) + { + ASMJIT_ASSERT(varType < kX86VarTypeCount); + return x86VarInfo[varType].getSize(); + } + + static inline uint32_t getRegCodeFromVarType(uint32_t varType, uint32_t regIndex) + { + ASMJIT_ASSERT(varType < kX86VarTypeCount); + return x86VarInfo[varType].getCode() | regIndex; + } + + static inline bool isVarTypeInt(uint32_t varType) + { + ASMJIT_ASSERT(varType < kX86VarTypeCount); + return (x86VarInfo[varType].getClass() & kX86VarClassGp) != 0; + } + + static inline bool isVarTypeFloat(uint32_t varType) + { + ASMJIT_ASSERT(varType < kX86VarTypeCount); + return (x86VarInfo[varType].getFlags() & (kX86VarFlagSP | kX86VarFlagDP)) != 0; + } +}; + +//! @} + +} // AsmJit namespace + +// [Api-End] +#include "../core/apiend.h" + +// [Guard] +#endif // _ASMJIT_X86_X86UTIL_H diff --git a/desmume/src/windows/DeSmuME_2005.vcproj b/desmume/src/windows/DeSmuME_2005.vcproj index 9d56651c6..1245c9633 100644 --- a/desmume/src/windows/DeSmuME_2005.vcproj +++ b/desmume/src/windows/DeSmuME_2005.vcproj @@ -1887,141 +1887,289 @@ Name="AsmJit" > - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(ProjectName)_x64_release - $(ProjectName)_x64_release - $(ProjectName)_x64_release + $(ProjectName)_x64_debug + $(ProjectName)_x64_dev+ $(ProjectName)_release - $(ProjectName)_release - $(ProjectName)_release + $(ProjectName)_debug + $(ProjectName)_dev+ @@ -443,19 +443,35 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -707,27 +723,45 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -886,7 +920,6 @@ - diff --git a/desmume/src/windows/DeSmuME_2010.vcxproj.filters b/desmume/src/windows/DeSmuME_2010.vcxproj.filters index d2398965a..e9bf0480b 100644 --- a/desmume/src/windows/DeSmuME_2010.vcxproj.filters +++ b/desmume/src/windows/DeSmuME_2010.vcxproj.filters @@ -64,6 +64,12 @@ {24398c49-4650-412e-b46f-4725ad4f5b11} + + {82c38db3-d06d-44b5-a9a4-be3c002d0db0} + + + {0d620905-0dcf-47a4-bac2-91f307aa9994} + @@ -480,45 +486,6 @@ Windows - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - Core @@ -720,6 +687,93 @@ Windows\fex\unrar + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + @@ -1122,69 +1176,6 @@ Windows - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - - - Core\utils\AsmJit - Core @@ -1386,6 +1377,123 @@ Windows + + Core\utils\AsmJit + + + Core\utils\AsmJit + + + Core\utils\AsmJit + + + Core\utils\AsmJit + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + @@ -1403,12 +1511,6 @@ Core\filter - - Core\utils\AsmJit - - - Core\utils\AsmJit - Windows\fex\7z @@ -1436,6 +1538,9 @@ Windows\fex\unrar + + Core\utils\AsmJit + diff --git a/desmume/src/windows/DeSmuME_Intel.sln b/desmume/src/windows/DeSmuME_2012.sln similarity index 53% rename from desmume/src/windows/DeSmuME_Intel.sln rename to desmume/src/windows/DeSmuME_2012.sln index b26560563..e435d71c3 100644 --- a/desmume/src/windows/DeSmuME_Intel.sln +++ b/desmume/src/windows/DeSmuME_2012.sln @@ -1,28 +1,26 @@  -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{EAF909A5-FA59-4C3D-9431-0FCC20D5BCF9}") = "DeSmuME_Intel", "DeSmuME_Intel.icproj", "{61FB2DAF-A8E9-4CCC-ADF4-B824B4F00187}" +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DeSmuME_VS2012", "DeSmuME_2012.vcxproj", "{9F5F72A1-D3A5-4918-B460-E076B16D10A9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 + Dev+|Win32 = Dev+|Win32 + Dev+|x64 = Dev+|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {61FB2DAF-A8E9-4CCC-ADF4-B824B4F00187}.Debug|Win32.ActiveCfg = Debug|Win32 - {61FB2DAF-A8E9-4CCC-ADF4-B824B4F00187}.Debug|Win32.Build.0 = Debug|Win32 - {61FB2DAF-A8E9-4CCC-ADF4-B824B4F00187}.Debug|x64.ActiveCfg = Debug|x64 - {61FB2DAF-A8E9-4CCC-ADF4-B824B4F00187}.Debug|x64.Build.0 = Debug|x64 - {61FB2DAF-A8E9-4CCC-ADF4-B824B4F00187}.Release|Win32.ActiveCfg = Release|Win32 - {61FB2DAF-A8E9-4CCC-ADF4-B824B4F00187}.Release|Win32.Build.0 = Release|Win32 - {61FB2DAF-A8E9-4CCC-ADF4-B824B4F00187}.Release|x64.ActiveCfg = Release|x64 - {61FB2DAF-A8E9-4CCC-ADF4-B824B4F00187}.Release|x64.Build.0 = Release|x64 {9F5F72A1-D3A5-4918-B460-E076B16D10A9}.Debug|Win32.ActiveCfg = Debug|Win32 {9F5F72A1-D3A5-4918-B460-E076B16D10A9}.Debug|Win32.Build.0 = Debug|Win32 {9F5F72A1-D3A5-4918-B460-E076B16D10A9}.Debug|x64.ActiveCfg = Debug|x64 {9F5F72A1-D3A5-4918-B460-E076B16D10A9}.Debug|x64.Build.0 = Debug|x64 + {9F5F72A1-D3A5-4918-B460-E076B16D10A9}.Dev+|Win32.ActiveCfg = Dev+|Win32 + {9F5F72A1-D3A5-4918-B460-E076B16D10A9}.Dev+|Win32.Build.0 = Dev+|Win32 + {9F5F72A1-D3A5-4918-B460-E076B16D10A9}.Dev+|x64.ActiveCfg = Dev+|x64 + {9F5F72A1-D3A5-4918-B460-E076B16D10A9}.Dev+|x64.Build.0 = Dev+|x64 {9F5F72A1-D3A5-4918-B460-E076B16D10A9}.Release|Win32.ActiveCfg = Release|Win32 {9F5F72A1-D3A5-4918-B460-E076B16D10A9}.Release|Win32.Build.0 = Release|Win32 {9F5F72A1-D3A5-4918-B460-E076B16D10A9}.Release|x64.ActiveCfg = Release|x64 diff --git a/desmume/src/windows/DeSmuME_2012.vcxproj b/desmume/src/windows/DeSmuME_2012.vcxproj new file mode 100644 index 000000000..aa8090cae --- /dev/null +++ b/desmume/src/windows/DeSmuME_2012.vcxproj @@ -0,0 +1,944 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Dev+ + Win32 + + + Dev+ + x64 + + + Release + Win32 + + + Release + x64 + + + + DeSmuME_VS2012 + {9F5F72A1-D3A5-4918-B460-E076B16D10A9} + DeSmuME + + + + Application + v110 + false + + + Application + v110 + true + + + Application + v110 + + + Application + v110 + false + + + Application + v110 + true + + + Application + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + $(SolutionDir)\__bins\ + $(SolutionDir)\.VS2012\$(Configuration)\$(Platform)\ + $(ProjectName)_debug + + + $(SolutionDir)\__bins\ + $(SolutionDir)\.VS2012\$(Configuration)\$(Platform)\ + $(ProjectName)_x64_debug + + + $(SolutionDir)\__bins\ + $(SolutionDir)\.VS2012\$(Configuration)\$(Platform)\ + $(ProjectName)_release + + + $(SolutionDir)\__bins\ + $(SolutionDir)\.VS2012\$(Configuration)\$(Platform)\ + $(ProjectName)_x64_release + + + $(SolutionDir)\__bins\ + $(SolutionDir)\.VS2012\$(Configuration)\$(Platform)\ + $(ProjectName)_dev+ + + + $(SolutionDir)\__bins\ + $(SolutionDir)\.VS2012\$(Configuration)\$(Platform)\ + $(ProjectName)_x64_dev+ + + + + defaultconfig\SubWCRev.bat + + + /MP %(AdditionalOptions) + Disabled + Default + false + Neither + false + false + .;..;lua\include;glib-2.20.1\build;glib-2.20.1\build\glib;.\zlib123;.\zziplib;.\winpcap;userconfig;defaultconfig;.\agg\include;.\agg\examples;.\wx\include;%(AdditionalIncludeDirectories) + DEBUG;_CRT_SECURE_NO_DEPRECATE;GLIB_STATIC_COMPILATION;WIN32;BETA_VERSION;NOMINMAX;HAVE_LIBZ;%(PreprocessorDefinitions) + Sync + EnableFastChecks + true + StreamingSIMDExtensions2 + Fast + EditAndContinue + Cdecl + Default + + + directx-win32-ddraw-dinput8-dsound-dxerr8-dxguid.lib;libelf_libdwarf-vc8-Win32.lib;lua51.lib;glib-vc8-Win32.lib;zlib-vc8-Win32.lib;agg-2.5.lib;vfw32.lib;winmm.lib;opengl32.lib;glu32.lib;ws2_32.lib;user32.lib;gdi32.lib;shell32.lib;comdlg32.lib;shlwapi.lib;comctl32.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName)_debug.exe + .\zlib123;agg;.libs;.libs\win32;%(AdditionalLibraryDirectories) + lua51.dll;%(DelayLoadDLLs) + true + true + false + + + + DeSmuME_x86.manifest;%(AdditionalManifestFiles) + + + + + defaultconfig\SubWCRev.bat + + + X64 + + + /MP %(AdditionalOptions) + Disabled + Default + false + Neither + false + false + .;..;lua\include;glib-2.20.1\build;glib-2.20.1\build\glib;.\zlib123;.\zziplib;.\winpcap;userconfig;defaultconfig;.\agg\include;.\agg\examples;.\wx\include;%(AdditionalIncludeDirectories) + DEBUG;_CRT_SECURE_NO_DEPRECATE;GLIB_STATIC_COMPILATION;WIN32;BETA_VERSION;NOMINMAX;HAVE_LIBZ;%(PreprocessorDefinitions) + Sync + EnableFastChecks + true + NotSet + Fast + ProgramDatabase + Cdecl + Default + + + directx-x64-ddraw-dinput8-dsound-dxerr8-dxguid.lib;libelf_libdwarf-vc8-x64.lib;lua51.lib;glib-vc8-x64.lib;zlib-vc8-x64.lib;agg-2.5-x64.lib;vfw32.lib;winmm.lib;opengl32.lib;glu32.lib;ws2_32.lib;user32.lib;gdi32.lib;shell32.lib;comdlg32.lib;shlwapi.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName)_x64_debug.exe + .\zlib123;agg;.libs\x64;.libs;%(AdditionalLibraryDirectories) + lua51.dll;%(DelayLoadDLLs) + true + true + false + + MachineX64 + + + DeSmuME_x64.manifest;%(AdditionalManifestFiles) + + + + + defaultconfig\SubWCRev.bat + + + /MP %(AdditionalOptions) + MaxSpeed + AnySuitable + true + Speed + true + true + true + .;..;lua\include;glib-2.20.1\build;glib-2.20.1\build\glib;.\zlib123;.\zziplib;.\winpcap;userconfig;defaultconfig;.\agg\include;.\agg\examples;.\wx\include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;GLIB_STATIC_COMPILATION;WIN32;HAVE_LIBZ;NOMINMAX;RELEASE;NDEBUG;%(PreprocessorDefinitions) + true + Sync + Default + false + StreamingSIMDExtensions2 + Fast + Level1 + ProgramDatabase + Cdecl + Default + + + directx-win32-ddraw-dinput8-dsound-dxerr8-dxguid.lib;libelf_libdwarf-vc8-Win32.lib;lua51.lib;glib-vc8-Win32.lib;zlib-vc8-Win32.lib;agg-2.5.lib;vfw32.lib;winmm.lib;opengl32.lib;glu32.lib;ws2_32.lib;user32.lib;gdi32.lib;shell32.lib;comdlg32.lib;shlwapi.lib;comctl32.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName)_release.exe + .\zlib123;agg;.libs;.libs\win32;%(AdditionalLibraryDirectories) + lua51.dll;%(DelayLoadDLLs) + true + true + false + + false + + + DeSmuME_x86.manifest;%(AdditionalManifestFiles) + + + + + defaultconfig\SubWCRev.bat + + + X64 + + + /MP %(AdditionalOptions) + MaxSpeed + AnySuitable + true + Speed + true + true + true + .;..;lua\include;glib-2.20.1\build;glib-2.20.1\build\glib;.\zlib123;.\zziplib;.\winpcap;userconfig;defaultconfig;.\agg\include;.\agg\examples;.\wx\include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;GLIB_STATIC_COMPILATION;WIN32;HAVE_LIBZ;NOMINMAX;RELEASE;NDEBUG;%(PreprocessorDefinitions) + true + Sync + Default + false + NotSet + Fast + Level1 + ProgramDatabase + Cdecl + Default + + + directx-x64-ddraw-dinput8-dsound-dxerr8-dxguid.lib;libelf_libdwarf-vc8-x64.lib;lua51.lib;glib-vc8-x64.lib;zlib-vc8-x64.lib;agg-2.5-x64.lib;vfw32.lib;winmm.lib;opengl32.lib;glu32.lib;ws2_32.lib;user32.lib;gdi32.lib;shell32.lib;comdlg32.lib;shlwapi.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName)_x64_release.exe + .\zlib123;agg;.libs\x64;.libs;%(AdditionalLibraryDirectories) + lua51.dll;%(DelayLoadDLLs) + true + true + false + + MachineX64 + false + + + DeSmuME_x64.manifest;%(AdditionalManifestFiles) + + + + + defaultconfig\SubWCRev.bat + + + /MP %(AdditionalOptions) + Full + AnySuitable + true + Speed + true + true + false + .;..;lua\include;glib-2.20.1\build;glib-2.20.1\build\glib;.\zlib123;.\zziplib;.\winpcap;userconfig;defaultconfig;.\agg\include;.\agg\examples;.\wx\include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;GLIB_STATIC_COMPILATION;WIN32;HAVE_LIBZ;NOMINMAX;RELEASE;NDEBUG;FASTBUILD;DEVELOPER;%(PreprocessorDefinitions) + true + Sync + Default + false + StreamingSIMDExtensions2 + Fast + Level1 + ProgramDatabase + Cdecl + Default + + + directx-win32-ddraw-dinput8-dsound-dxerr8-dxguid.lib;libelf_libdwarf-vc8-Win32.lib;lua51.lib;glib-vc8-Win32.lib;zlib-vc8-Win32.lib;agg-2.5.lib;vfw32.lib;winmm.lib;opengl32.lib;glu32.lib;ws2_32.lib;user32.lib;gdi32.lib;shell32.lib;comdlg32.lib;shlwapi.lib;comctl32.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName)_dev+.exe + .\zlib123;agg;.libs;.libs\win32;%(AdditionalLibraryDirectories) + lua51.dll;%(DelayLoadDLLs) + true + true + + false + + false + + + DeSmuME_x86.manifest;%(AdditionalManifestFiles) + + + + + defaultconfig\SubWCRev.bat + + + X64 + + + /MP %(AdditionalOptions) + MaxSpeed + AnySuitable + true + Speed + true + true + false + .;..;lua\include;glib-2.20.1\build;glib-2.20.1\build\glib;.\zlib123;.\zziplib;.\winpcap;userconfig;defaultconfig;.\agg\include;.\agg\examples;.\wx\include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;GLIB_STATIC_COMPILATION;WIN32;HAVE_LIBZ;NOMINMAX;RELEASE;NDEBUG;DEVELOPER;%(PreprocessorDefinitions) + true + Sync + Default + false + NotSet + Fast + Level1 + ProgramDatabase + Cdecl + Default + + + directx-x64-ddraw-dinput8-dsound-dxerr8-dxguid.lib;libelf_libdwarf-vc8-x64.lib;lua51.lib;glib-vc8-x64.lib;zlib-vc8-x64.lib;agg-2.5-x64.lib;vfw32.lib;winmm.lib;opengl32.lib;glu32.lib;ws2_32.lib;user32.lib;gdi32.lib;shell32.lib;comdlg32.lib;shlwapi.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName)_x64_dev+.exe + .\zlib123;agg;.libs\x64;.libs;%(AdditionalLibraryDirectories) + lua51.dll;%(DelayLoadDLLs) + true + true + + false + + MachineX64 + false + + + DeSmuME_x64.manifest;%(AdditionalManifestFiles) + + + + + + + + + + + + Cdecl + Cdecl + Cdecl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(IntDir)decrypt\ + $(IntDir)decrypt\ + $(IntDir)decrypt\ + $(IntDir)decrypt\ + $(IntDir)decrypt\ + $(IntDir)decrypt\ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + un7z_and_touch.bat directx\directx.7z .libs\directx* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\directx.tag;%(Outputs) + un7z_and_touch.bat directx\directx.7z .libs\directx* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\directx.tag;%(Outputs) + un7z_and_touch.bat directx\directx.7z .libs\directx* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\directx.tag;%(Outputs) + un7z_and_touch.bat directx\directx.7z .libs\directx* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\directx.tag;%(Outputs) + un7z_and_touch.bat directx\directx.7z .libs\directx* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\directx.tag;%(Outputs) + + + un7z_and_touch.bat glib-2.20.1\glib-2.20.1.7z .libs\glib* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\glib-vc8.tag;%(Outputs) + un7z_and_touch.bat glib-2.20.1\glib-2.20.1.7z .libs\glib* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\glib-vc8.tag;%(Outputs) + un7z_and_touch.bat glib-2.20.1\glib-2.20.1.7z .libs\glib* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\glib-vc8.tag;%(Outputs) + un7z_and_touch.bat glib-2.20.1\glib-2.20.1.7z .libs\glib* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\glib-vc8.tag;%(Outputs) + un7z_and_touch.bat glib-2.20.1\glib-2.20.1.7z .libs\glib* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\glib-vc8.tag;%(Outputs) + + + un7z_and_touch.bat libelf_libdwarf\libelf_libdwarf.7z .libs\libelf_libdwarf* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\libelf_libdwarf.tag;%(Outputs) + un7z_and_touch.bat libelf_libdwarf\libelf_libdwarf.7z .libs\libelf_libdwarf* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\libelf_libdwarf.tag;%(Outputs) + un7z_and_touch.bat libelf_libdwarf\libelf_libdwarf.7z .libs\libelf_libdwarf* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\libelf_libdwarf.tag;%(Outputs) + un7z_and_touch.bat libelf_libdwarf\libelf_libdwarf.7z .libs\libelf_libdwarf* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\libelf_libdwarf.tag;%(Outputs) + un7z_and_touch.bat libelf_libdwarf\libelf_libdwarf.7z .libs\libelf_libdwarf* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\libelf_libdwarf.tag;%(Outputs) + un7z_and_touch.bat libelf_libdwarf\libelf_libdwarf.7z .libs\libelf_libdwarf* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\libelf_libdwarf.tag;%(Outputs) + + + un7z_and_touch.bat lua\lua.7z .libs\win32\lua* .libs\x64\lua* .libs\lua.tag + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\lua.tag;%(Outputs) + un7z_and_touch.bat lua\lua.7z .libs\win32\lua* .libs\x64\lua* .libs\lua.tag + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\lua.tag;%(Outputs) + un7z_and_touch.bat lua\lua.7z .libs\win32\lua* .libs\x64\lua* .libs\lua.tag + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\lua.tag;%(Outputs) + un7z_and_touch.bat lua\lua.7z .libs\win32\lua* .libs\x64\lua* .libs\lua.tag + + .libs\lua.tag;%(Outputs) + un7z_and_touch.bat lua\lua.7z .libs\win32\lua* .libs\x64\lua* .libs\lua.tag + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\lua.tag;%(Outputs) + un7z_and_touch.bat lua\lua.7z .libs\win32\lua* .libs\x64\lua* .libs\lua.tag + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\lua.tag;%(Outputs) + + + un7z_and_touch.bat wx\wx.7z .libs\wx* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\wx.tag;%(Outputs) + un7z_and_touch.bat wx\wx.7z .libs\wx* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\wx.tag;%(Outputs) + un7z_and_touch.bat wx\wx.7z .libs\wx* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\wx.tag;%(Outputs) + un7z_and_touch.bat wx\wx.7z .libs\wx* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\wx.tag;%(Outputs) + un7z_and_touch.bat wx\wx.7z .libs\wx* + + 7z.exe;un7z_and_touch.bat;%(AdditionalInputs) + .libs\wx.tag;%(Outputs) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/desmume/src/windows/DeSmuME_2012.vcxproj.filters b/desmume/src/windows/DeSmuME_2012.vcxproj.filters new file mode 100644 index 000000000..d2b106cfc --- /dev/null +++ b/desmume/src/windows/DeSmuME_2012.vcxproj.filters @@ -0,0 +1,1341 @@ + + + + + {7c82633b-ee33-4cd0-b47d-487a417edeab} + + + {8aa1dcea-23d0-456b-9be5-8338072c77cf} + + + {e6128d2d-eb64-460b-8bb2-4ee12e38466e} + + + {abcc1413-bf8e-4d2e-9bc7-332ac9269fde} + + + {d4f8903c-7f78-4416-883c-42ad17e5cb25} + + + {b7dff57f-b8e1-4d98-a6c5-3031e0763b76} + + + {2b7b810e-c016-4e26-84b2-c36829d93f87} + + + {e7a10a39-f561-4884-b884-f2282fbf8905} + + + {8051838e-4194-425a-b471-880788a7fb18} + + + {d23031b8-70eb-4035-89ad-cba21cc6b570} + + + {485cef5d-6bf9-434c-81ee-b8c3d188e2e0} + + + {19289bbe-161a-4431-931b-ac9fa1ab6fde} + + + {46c55ff6-0bd2-4715-ba89-aead8b466220} + + + {d089f491-2c1b-4006-9f3d-d23ab756613f} + + + {841d24f1-7f40-48a3-bde6-d546d7903ade} + + + {798a6649-7ea2-4dde-a8bc-9e36cf4a4975} + + + {ec682647-9bb7-4315-99a4-4f9398db61ad} + + + {321e6567-acbd-4dc4-a5c6-6cd8fe445d53} + + + {4c97f223-843f-4975-b774-4d0c887cfd37} + + + {4d7483df-e22e-4e77-9ae8-8446c04d335d} + + + {04ea2049-7954-4d44-a631-6562f02e467e} + + + {40f6aa8b-2cce-48bf-b89d-0cad473f16e2} + + + {191da306-49b9-43b4-a4d9-d91dd3a18db8} + + + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core\addons + + + Core\addons + + + Core\addons + + + Core\addons + + + Core\addons + + + Core\addons + + + Core\addons + + + Core\addons + + + Core\addons + + + Core\addons + + + Core\addons + + + Core\addons + + + Core\gdbstub + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils\decrypt + + + Core\utils\decrypt + + + Core\utils\decrypt + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\tinyxml + + + Core\utils\tinyxml + + + Core\utils\tinyxml + + + Core\utils\tinyxml + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\metaspu + + + Core\metaspu + + + Core\metaspu + + + Core\metaspu\win32 + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\wxdlg + + + Core\filter + + + Core\filter + + + Core\filter + + + Core\filter + + + Core\filter + + + Core\filter + + + Core\filter + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows\File_Extractor + + + Windows\File_Extractor + + + Windows\File_Extractor + + + Windows\File_Extractor + + + Windows\File_Extractor + + + Windows\File_Extractor + + + Windows\File_Extractor + + + Windows\File_Extractor + + + Windows\File_Extractor + + + Windows\File_Extractor + + + Windows\File_Extractor + + + Windows\File_Extractor + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\7-Zip + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\File_Extractor\unrar + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core + + + Core\gdbstub + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils + + + Core\utils\decrypt + + + Core\utils\decrypt + + + Core\utils\decrypt + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\libfat + + + Core\utils\tinyxml + + + Core\utils\tinyxml + + + Core\utils\AsmJit + + + Core\utils\AsmJit + + + Core\utils\AsmJit + + + Core\utils\AsmJit + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\core + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\utils\AsmJit\x86 + + + Core\metaspu + + + Core\metaspu + + + Core\metaspu\win32 + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\metaspu\SoundTouch + + + Core\wxdlg + + + Core\filter + + + Core\filter + + + Core\filter + + + Core\filter + + + Core\filter + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows + + + Windows\userconfig + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + Windows\tools + + + + + Core + + + Core + + + Core\filter + + + + + Core\utils\AsmJit + + + + + Windows\resources + + + Windows\resources + + + + + + + + + + + + + Windows\resources + + + + + Windows\libs + + + Windows\libs + + + Windows\libs + + + Windows\libs + + + Windows\libs + + + \ No newline at end of file diff --git a/desmume/src/windows/DeSmuME_Intel.icproj b/desmume/src/windows/DeSmuME_Intel.icproj deleted file mode 100644 index b13907d6b..000000000 --- a/desmume/src/windows/DeSmuME_Intel.icproj +++ /dev/null @@ -1,788 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/desmume/src/windows/DeSmuME_Intel.vcproj b/desmume/src/windows/DeSmuME_Intel.vcproj deleted file mode 100644 index 61b5ce7c9..000000000 --- a/desmume/src/windows/DeSmuME_Intel.vcproj +++ /dev/null @@ -1,1386 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -