summaryrefslogtreecommitdiffstats
path: root/libpixelflinger/codeflinger/x86/libenc/encoder.inl
diff options
context:
space:
mode:
Diffstat (limited to 'libpixelflinger/codeflinger/x86/libenc/encoder.inl')
-rw-r--r--libpixelflinger/codeflinger/x86/libenc/encoder.inl863
1 files changed, 863 insertions, 0 deletions
diff --git a/libpixelflinger/codeflinger/x86/libenc/encoder.inl b/libpixelflinger/codeflinger/x86/libenc/encoder.inl
new file mode 100644
index 0000000..ec72097
--- /dev/null
+++ b/libpixelflinger/codeflinger/x86/libenc/encoder.inl
@@ -0,0 +1,863 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Alexander V. Astapchuk
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+
+extern const RegName map_of_regno_2_regname[];
+extern const OpndSize map_of_EncoderOpndSize_2_RealOpndSize[];
+extern const Mnemonic map_of_alu_opcode_2_mnemonic[];
+extern const Mnemonic map_of_shift_opcode_2_mnemonic[];
+
+// S_ stands for 'Signed'
+extern const Mnemonic S_map_of_condition_code_2_branch_mnemonic[];
+// U_ stands for 'Unsigned'
+extern const Mnemonic U_map_of_condition_code_2_branch_mnemonic[];
+
+inline static RegName map_reg(Reg_No r) {
+ assert(r >= 0 && r <= n_reg);
+ return map_of_regno_2_regname[r];
+}
+
+inline static OpndSize map_size(Opnd_Size o_size) {
+ assert(o_size >= 0 && o_size <= n_size);
+ return map_of_EncoderOpndSize_2_RealOpndSize[o_size];
+}
+
+inline static Mnemonic map_alu(ALU_Opcode alu) {
+ assert(alu >= 0 && alu < n_alu);
+ return map_of_alu_opcode_2_mnemonic[alu];
+}
+
+inline static Mnemonic map_shift(Shift_Opcode shc) {
+ assert(shc >= 0 && shc < n_shift);
+ return map_of_shift_opcode_2_mnemonic[shc];
+}
+
+inline bool fit8(int64 val) {
+ return (CHAR_MIN <= val) && (val <= CHAR_MAX);
+}
+
+inline bool fit32(int64 val) {
+ return (INT_MIN <= val) && (val <= INT_MAX);
+}
+
+inline static void add_r(EncoderBase::Operands & args, const R_Opnd & r, Opnd_Size sz, OpndExt ext = OpndExt_None) {
+ RegName reg = map_reg(r.reg_no());
+ if (sz != n_size) {
+ OpndSize size = map_size(sz);
+ if (size != getRegSize(reg)) {
+ reg = getAliasReg(reg, size);
+ }
+ }
+ args.add(EncoderBase::Operand(reg, ext));
+}
+
+inline static void add_m(EncoderBase::Operands & args, const M_Opnd & m, Opnd_Size sz, OpndExt ext = OpndExt_None) {
+ assert(n_size != sz);
+ args.add(EncoderBase::Operand(map_size(sz),
+ map_reg(m.base().reg_no()), map_reg(m.index().reg_no()),
+ (unsigned)m.scale().get_value(), (int)m.disp().get_value(), ext));
+}
+
+inline static void add_rm(EncoderBase::Operands & args, const RM_Opnd & rm, Opnd_Size sz, OpndExt ext = OpndExt_None) {
+ rm.is_reg() ? add_r(args, (R_Opnd &)rm, sz, ext) : add_m(args, (M_Opnd &)rm, sz, ext);
+}
+
+inline static void add_xmm(EncoderBase::Operands & args, const XMM_Opnd & xmm, bool dbl) {
+ // Gregory -
+ // XMM registers indexes in Reg_No enum are shifted by xmm0_reg, their indexes
+ // don't start with 0, so it is necessary to subtract xmm0_reg index from
+ // xmm.get_idx() value
+ assert(xmm.get_idx() >= xmm0_reg);
+ return args.add((RegName)( (dbl ? RegName_XMM0D : RegName_XMM0S) + xmm.get_idx() -
+ xmm0_reg));
+}
+
+inline static void add_fp(EncoderBase::Operands & args, unsigned i, bool dbl) {
+ return args.add((RegName)( (dbl ? RegName_FP0D : RegName_FP0S) + i));
+}
+
+inline static void add_imm(EncoderBase::Operands & args, const Imm_Opnd & imm) {
+ assert(n_size != imm.get_size());
+ args.add(EncoderBase::Operand(map_size(imm.get_size()), imm.get_value(),
+ imm.is_signed() ? OpndExt_Signed : OpndExt_Zero));
+}
+
+ENCODER_DECLARE_EXPORT char * prefix(char * stream, InstrPrefix p) {
+ *stream = (char)p;
+ return stream + 1;
+}
+
+// stack push and pop instructions
+ENCODER_DECLARE_EXPORT char * push(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_PUSH, args);
+}
+
+ENCODER_DECLARE_EXPORT char * push(char * stream, const Imm_Opnd & imm) {
+ EncoderBase::Operands args;
+#ifdef _EM64T_
+ add_imm(args, imm);
+#else
+ // we need this workaround to be compatible with the former ia32 encoder implementation
+ add_imm(args, Imm_Opnd(size_32, imm.get_value()));
+#endif
+ return EncoderBase::encode(stream, Mnemonic_PUSH, args);
+}
+
+ENCODER_DECLARE_EXPORT char * pop(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_POP, args);
+}
+
+// cmpxchg or xchg
+ENCODER_DECLARE_EXPORT char * cmpxchg(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_r(args, r, sz);
+ RegName implicitReg = getAliasReg(RegName_EAX, map_size(sz));
+ args.add(implicitReg);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CMPXCHG, args);
+}
+
+ENCODER_DECLARE_EXPORT char * xchg(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_r(args, r, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_XCHG, args);
+}
+
+// inc(rement), dec(rement), not, neg(ate) instructions
+ENCODER_DECLARE_EXPORT char * inc(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_INC, args);
+}
+
+ENCODER_DECLARE_EXPORT char * dec(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_DEC, args);
+}
+
+ENCODER_DECLARE_EXPORT char * _not(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_NOT, args);
+}
+
+ENCODER_DECLARE_EXPORT char * neg(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_NEG, args);
+}
+
+ENCODER_DECLARE_EXPORT char * nop(char * stream) {
+ EncoderBase::Operands args;
+ return (char*)EncoderBase::encode(stream, Mnemonic_NOP, args);
+}
+
+ENCODER_DECLARE_EXPORT char * int3(char * stream) {
+ EncoderBase::Operands args;
+ return (char*)EncoderBase::encode(stream, Mnemonic_INT3, args);
+}
+
+// alu instructions: add, or, adc, sbb, and, sub, xor, cmp
+ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, map_alu(opc), args);
+};
+
+ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const M_Opnd & m, const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, m, sz);
+ add_rm(args, r, sz);
+ return (char*)EncoderBase::encode(stream, map_alu(opc), args);
+}
+
+ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, r, sz);
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, map_alu(opc), args);
+}
+
+// test instruction
+ENCODER_DECLARE_EXPORT char * test(char * stream, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ assert(imm.get_size() <= sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_TEST, args);
+}
+
+ENCODER_DECLARE_EXPORT char * test(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_r(args, r, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_TEST, args);
+}
+
+// shift instructions: shl, shr, sar, shld, shrd
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, map_shift(shc), args);
+}
+
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ args.add(RegName_CL);
+ return (char*)EncoderBase::encode(stream, map_shift(shc), args);
+}
+
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm,
+ const R_Opnd & r, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ assert(shc == shld_opc || shc == shrd_opc);
+ add_rm(args, rm, sz);
+ add_r(args, r, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, map_shift(shc), args);
+}
+
+ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm,
+ const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ assert(shc == shld_opc || shc == shrd_opc);
+ add_rm(args, rm, sz);
+ add_r(args, r, sz);
+ args.add(RegName_CL);
+ return (char*)EncoderBase::encode(stream, map_shift(shc), args);
+}
+
+// multiply instructions: mul, imul
+ENCODER_DECLARE_EXPORT char * mul(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ args.add(RegName_EDX);
+ args.add(RegName_EAX);
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MUL, args);
+}
+
+ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_IMUL, args);
+}
+
+ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_IMUL, args);
+}
+
+ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const RM_Opnd & rm,
+ const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_rm(args, rm, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_IMUL, args);
+}
+
+// divide instructions: div, idiv
+ENCODER_DECLARE_EXPORT char * idiv(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+#ifdef _EM64T_
+ add_r(args, rdx_opnd, sz);
+ add_r(args, rax_opnd, sz);
+#else
+ add_r(args, edx_opnd, sz);
+ add_r(args, eax_opnd, sz);
+#endif
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_IDIV, args);
+}
+
+ENCODER_DECLARE_EXPORT char * div(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+#ifdef _EM64T_
+ add_r(args, rdx_opnd, sz);
+ add_r(args, rax_opnd, sz);
+#else
+ add_r(args, edx_opnd, sz);
+ add_r(args, eax_opnd, sz);
+#endif
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_DIV, args);
+}
+
+// data movement: mov
+ENCODER_DECLARE_EXPORT char * mov(char * stream, const M_Opnd & m, const R_Opnd & r, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_m(args, m, sz);
+ add_r(args, r, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOV, args);
+}
+
+ENCODER_DECLARE_EXPORT char * mov(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOV, args);
+}
+
+ENCODER_DECLARE_EXPORT char * mov(char * stream, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOV, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movd(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, size_32);
+ add_xmm(args, xmm, false);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVD, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movd(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, false);
+ add_rm(args, rm, size_32);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVD, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movq(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, size_64);
+ add_xmm(args, xmm, true);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVQ, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movq(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, true);
+ add_rm(args, rm, size_64);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVQ, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movsx(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, n_size);
+ add_rm(args, rm, sz, OpndExt_Signed);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVSX, args);
+}
+
+ENCODER_DECLARE_EXPORT char * movzx(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, n_size);
+ // movzx r64, r/m32 is not available on em64t
+ // mov r32, r/m32 should zero out upper bytes
+ assert(sz <= size_16);
+ add_rm(args, rm, sz, OpndExt_Zero);
+ return (char*)EncoderBase::encode(stream, Mnemonic_MOVZX, args);
+}
+
+// sse mov
+ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MOVSD : Mnemonic_MOVSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const M_Opnd & mem, const XMM_Opnd & xmm, bool dbl) {
+ EncoderBase::Operands args;
+ add_m(args, mem, dbl ? size_64 : size_32);
+ add_xmm(args, xmm, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MOVSD : Mnemonic_MOVSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MOVSD : Mnemonic_MOVSS, args );
+}
+
+// sse add, sub, mul, div
+ENCODER_DECLARE_EXPORT char * sse_add(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_ADDSD : Mnemonic_ADDSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_add(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_ADDSD : Mnemonic_ADDSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_sub(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_SUBSD : Mnemonic_SUBSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_sub(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_SUBSD : Mnemonic_SUBSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_mul( char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MULSD : Mnemonic_MULSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_mul(char * stream, const XMM_Opnd& xmm0, const XMM_Opnd& xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MULSD : Mnemonic_MULSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_div(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_DIVSD : Mnemonic_DIVSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_div(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_DIVSD : Mnemonic_DIVSS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_xor(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, true);
+ add_xmm(args, xmm1, true);
+ return (char*)EncoderBase::encode(stream, Mnemonic_PXOR, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_compare(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, true);
+ add_xmm(args, xmm1, true);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_COMISD : Mnemonic_COMISS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_compare(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_COMISD : Mnemonic_COMISS, args);
+}
+
+// sse conversions
+ENCODER_DECLARE_EXPORT char * sse_cvt_si(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm, dbl);
+ add_m(args, mem, size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTSI2SD : Mnemonic_CVTSI2SS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_cvtt2si(char * stream, const R_Opnd & reg, const M_Opnd & mem, bool dbl) {
+ EncoderBase::Operands args;
+ add_rm(args, reg, size_32);
+ add_m(args, mem, dbl ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTTSD2SI : Mnemonic_CVTTSS2SI, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_cvtt2si(char * stream, const R_Opnd & reg, const XMM_Opnd & xmm, bool dbl) {
+ EncoderBase::Operands args;
+ add_rm(args, reg, size_32);
+ add_xmm(args, xmm, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTTSD2SI : Mnemonic_CVTTSS2SI, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_cvt_fp2dq(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTTPD2DQ : Mnemonic_CVTTPS2DQ, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_cvt_dq2fp(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, dbl);
+ add_xmm(args, xmm1, dbl);
+ return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTDQ2PD : Mnemonic_CVTDQ2PS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_d2s(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem64) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, false);
+ add_m(args, mem64, size_64);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CVTSD2SS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_d2s(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, false);
+ add_xmm(args, xmm1, true);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CVTSD2SS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_s2d(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem32) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, true);
+ add_m(args, mem32, size_32);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CVTSS2SD, args);
+}
+
+ENCODER_DECLARE_EXPORT char * sse_s2d(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1) {
+ EncoderBase::Operands args;
+ add_xmm(args, xmm0, true);
+ add_xmm(args, xmm1, false);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CVTSS2SD, args);
+}
+
+// condition operations
+ENCODER_DECLARE_EXPORT char *cmov(char * stream, ConditionCode cc, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, (Mnemonic)(Mnemonic_CMOVcc + cc), args);
+}
+
+ENCODER_DECLARE_EXPORT char * setcc(char * stream, ConditionCode cc, const RM_Opnd & rm8) {
+ EncoderBase::Operands args;
+ add_rm(args, rm8, size_8);
+ return (char*)EncoderBase::encode(stream, (Mnemonic)(Mnemonic_SETcc + cc), args);
+}
+
+// load effective address: lea
+ENCODER_DECLARE_EXPORT char * lea(char * stream, const R_Opnd & r, const M_Opnd & m, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_r(args, r, sz);
+ add_m(args, m, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_LEA, args);
+}
+
+ENCODER_DECLARE_EXPORT char * cdq(char * stream) {
+ EncoderBase::Operands args;
+ args.add(RegName_EDX);
+ args.add(RegName_EAX);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CDQ, args);
+}
+
+ENCODER_DECLARE_EXPORT char * wait(char * stream) {
+ return (char*)EncoderBase::encode(stream, Mnemonic_WAIT, EncoderBase::Operands());
+}
+
+// control-flow instructions
+
+// loop
+ENCODER_DECLARE_EXPORT char * loop(char * stream, const Imm_Opnd & imm) {
+ EncoderBase::Operands args;
+ assert(imm.get_size() == size_8);
+ args.add(RegName_ECX);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_LOOP, args);
+}
+
+// jump
+ENCODER_DECLARE_EXPORT char * jump8(char * stream, const Imm_Opnd & imm) {
+ EncoderBase::Operands args;
+ assert(imm.get_size() == size_8);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_JMP, args);
+}
+
+ENCODER_DECLARE_EXPORT char * jump32(char * stream, const Imm_Opnd & imm) {
+ EncoderBase::Operands args;
+ assert(imm.get_size() == size_32);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_JMP, args);
+}
+
+ENCODER_DECLARE_EXPORT char * jump(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_JMP, args);
+}
+
+/**
+ * @note On EM64T: if target lies beyond 2G (does not fit into 32 bit
+ * offset) then generates indirect jump using RAX (whose content is
+ * destroyed).
+ */
+ENCODER_DECLARE_EXPORT char * jump(char * stream, char * target) {
+#ifdef _EM64T_
+ int64 offset = target - stream;
+ // sub 2 bytes for the short version
+ offset -= 2;
+ if (fit8(offset)) {
+ // use 8-bit signed relative form
+ return jump8(stream, Imm_Opnd(size_8, offset));
+ } else if (fit32(offset)) {
+ // sub 5 (3 + 2)bytes for the long version
+ offset -= 3;
+ // use 32-bit signed relative form
+ return jump32(stream, Imm_Opnd(size_32, offset));
+ }
+ // need to use absolute indirect jump
+ stream = mov(stream, rax_opnd, Imm_Opnd(size_64, (int64)target), size_64);
+ return jump(stream, rax_opnd, size_64);
+#else
+ I_32 offset = target - stream;
+ // sub 2 bytes for the short version
+ offset -= 2;
+ if (fit8(offset)) {
+ // use 8-bit signed relative form
+ return jump8(stream, Imm_Opnd(size_8, offset));
+ }
+ // sub 5 (3 + 2) bytes for the long version
+ offset -= 3;
+ // use 32-bit signed relative form
+ return jump32(stream, Imm_Opnd(size_32, offset));
+#endif
+}
+
+// branch
+ENCODER_DECLARE_EXPORT char * branch8(char * stream, ConditionCode cond,
+ const Imm_Opnd & imm,
+ InstrPrefix pref)
+{
+ if (pref != no_prefix) {
+ assert(pref == hint_branch_taken_prefix || pref == hint_branch_taken_prefix);
+ stream = prefix(stream, pref);
+ }
+ Mnemonic m = (Mnemonic)(Mnemonic_Jcc + cond);
+ EncoderBase::Operands args;
+ assert(imm.get_size() == size_8);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, m, args);
+}
+
+ENCODER_DECLARE_EXPORT char * branch32(char * stream, ConditionCode cond,
+ const Imm_Opnd & imm,
+ InstrPrefix pref)
+{
+ if (pref != no_prefix) {
+ assert(pref == hint_branch_taken_prefix || pref == hint_branch_taken_prefix);
+ stream = prefix(stream, pref);
+ }
+ Mnemonic m = (Mnemonic)(Mnemonic_Jcc + cond);
+ EncoderBase::Operands args;
+ assert(imm.get_size() == size_32);
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, m, args);
+}
+
+/*
+ENCODER_DECLARE_EXPORT char * branch(char * stream, ConditionCode cc, const char * target, InstrPrefix prefix) {
+// sub 2 bytes for the short version
+int64 offset = stream-target-2;
+if( fit8(offset) ) {
+return branch8(stream, cc, Imm_Opnd(size_8, (char)offset), is_signed);
+}
+return branch32(stream, cc, Imm_Opnd(size_32, (int)offset), is_signed);
+}
+*/
+
+// call
+ENCODER_DECLARE_EXPORT char * call(char * stream, const Imm_Opnd & imm)
+{
+ EncoderBase::Operands args;
+ add_imm(args, imm);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CALL, args);
+}
+
+ENCODER_DECLARE_EXPORT char * call(char * stream, const RM_Opnd & rm,
+ Opnd_Size sz)
+{
+ EncoderBase::Operands args;
+ add_rm(args, rm, sz);
+ return (char*)EncoderBase::encode(stream, Mnemonic_CALL, args);
+}
+
+/**
+* @note On EM64T: if target lies beyond 2G (does not fit into 32 bit
+* offset) then generates indirect jump using RAX (whose content is
+* destroyed).
+*/
+ENCODER_DECLARE_EXPORT char * call(char * stream, const char * target)
+{
+#ifdef _EM64T_
+ int64 offset = target - stream;
+ if (fit32(offset)) {
+ offset -= 5; // sub 5 bytes for this instruction
+ Imm_Opnd imm(size_32, offset);
+ return call(stream, imm);
+ }
+ // need to use absolute indirect call
+ stream = mov(stream, rax_opnd, Imm_Opnd(size_64, (int64)target), size_64);
+ return call(stream, rax_opnd, size_64);
+#else
+ I_32 offset = target - stream;
+ offset -= 5; // sub 5 bytes for this instruction
+ Imm_Opnd imm(size_32, offset);
+ return call(stream, imm);
+#endif
+}
+
+// return instruction
+ENCODER_DECLARE_EXPORT char * ret(char * stream)
+{
+ EncoderBase::Operands args;
+ return (char*)EncoderBase::encode(stream, Mnemonic_RET, args);
+}
+
+ENCODER_DECLARE_EXPORT char * ret(char * stream, const Imm_Opnd & imm)
+{
+ EncoderBase::Operands args;
+ // TheManual says imm can be 16-bit only
+ //assert(imm.get_size() <= size_16);
+ args.add(EncoderBase::Operand(map_size(size_16), imm.get_value()));
+ return (char*)EncoderBase::encode(stream, Mnemonic_RET, args);
+}
+
+ENCODER_DECLARE_EXPORT char * ret(char * stream, unsigned short pop)
+{
+ // TheManual says it can only be imm16
+ EncoderBase::Operands args(EncoderBase::Operand(OpndSize_16, pop, OpndExt_Zero));
+ return (char*)EncoderBase::encode(stream, Mnemonic_RET, args);
+}
+
+// floating-point instructions
+ENCODER_DECLARE_EXPORT char * fld(char * stream, const M_Opnd & m,
+ bool is_double) {
+ EncoderBase::Operands args;
+ // a fake FP register as operand
+ add_fp(args, 0, is_double);
+ add_m(args, m, is_double ? size_64 : size_32);
+ return (char*)EncoderBase::encode(stream, Mnemonic_FLD, args);
+}
+
+ENCODER_DECLARE_EXPORT char * fist(char * stream, const M_Opnd & mem,
+ bool is_long, bool pop_stk)
+{
+ EncoderBase::Operands args;
+ if (pop_stk) {
+ add_m(args, mem, is_long ? size_64 : size_32);
+ // a fake FP register as operand
+ add_fp(args, 0, is_long);
+ return (char*)EncoderBase::encode(stream, Mnemonic_FISTP, args);
+ }
+ // only 32-bit operands are supported
+ assert(is_long == false);
+ add_m(args, mem, size_32);
+ add_fp(args, 0, false);
+ return (char*)EncoderBase::encode(stream, Mnemonic_FIST, args);
+}
+
+ENCODER_DECLARE_EXPORT char * fst(char * stream, const M_Opnd & m,
+ bool is_double, bool pop_stk)
+{
+ EncoderBase::Operands args;
+ add_m(args, m, is_double ? size_64 : size_32);
+ // a fake FP register as operand
+ add_fp(args, 0, is_double);
+ return (char*)EncoderBase::encode(stream,
+ pop_stk ? Mnemonic_FSTP : Mnemonic_FST,
+ args);
+}
+
+ENCODER_DECLARE_EXPORT char * fst(char * stream, unsigned i, bool pop_stk)
+{
+ EncoderBase::Operands args;
+ add_fp(args, i, true);
+ return (char*)EncoderBase::encode(stream,
+ pop_stk ? Mnemonic_FSTP : Mnemonic_FST,
+ args);
+}
+
+ENCODER_DECLARE_EXPORT char * fldcw(char * stream, const M_Opnd & mem) {
+ EncoderBase::Operands args;
+ add_m(args, mem, size_16);
+ return (char*)EncoderBase::encode(stream, Mnemonic_FLDCW, args);
+}
+
+ENCODER_DECLARE_EXPORT char * fnstcw(char * stream, const M_Opnd & mem) {
+ EncoderBase::Operands args;
+ add_m(args, mem, size_16);
+ return (char*)EncoderBase::encode(stream, Mnemonic_FNSTCW, args);
+}
+
+ENCODER_DECLARE_EXPORT char * fnstsw(char * stream)
+{
+ return (char*)EncoderBase::encode(stream, Mnemonic_FNSTCW,
+ EncoderBase::Operands());
+}
+
+// string operations
+ENCODER_DECLARE_EXPORT char * set_d(char * stream, bool set) {
+ EncoderBase::Operands args;
+ return (char*)EncoderBase::encode(stream,
+ set ? Mnemonic_STD : Mnemonic_CLD,
+ args);
+}
+
+ENCODER_DECLARE_EXPORT char * scas(char * stream, unsigned char prefix)
+{
+ EncoderBase::Operands args;
+ if (prefix != no_prefix) {
+ assert(prefix == prefix_repnz || prefix == prefix_repz);
+ *stream = prefix;
+ ++stream;
+ }
+ return (char*)EncoderBase::encode(stream, Mnemonic_SCAS, args);
+}
+
+ENCODER_DECLARE_EXPORT char * stos(char * stream, unsigned char prefix)
+{
+ if (prefix != no_prefix) {
+ assert(prefix == prefix_rep);
+ *stream = prefix;
+ ++stream;
+ }
+
+ EncoderBase::Operands args;
+ return (char*)EncoderBase::encode(stream, Mnemonic_STOS, args);
+}
+
+// Intrinsic FP math functions
+
+ENCODER_DECLARE_EXPORT char * fprem(char * stream) {
+ return (char*)EncoderBase::encode(stream, Mnemonic_FPREM,
+ EncoderBase::Operands());
+}
+
+ENCODER_DECLARE_EXPORT char * fprem1(char * stream) {
+ return (char*)EncoderBase::encode(stream, Mnemonic_FPREM1,
+ EncoderBase::Operands());
+}