1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17/**
18 * @author Alexander V. Astapchuk
19 */
20#include <stdio.h>
21#include <assert.h>
22#include <limits.h>
23
24extern const RegName map_of_regno_2_regname[];
25extern const OpndSize map_of_EncoderOpndSize_2_RealOpndSize[];
26extern const Mnemonic map_of_alu_opcode_2_mnemonic[];
27extern const Mnemonic map_of_shift_opcode_2_mnemonic[];
28
29// S_ stands for 'Signed'
30extern const Mnemonic S_map_of_condition_code_2_branch_mnemonic[];
31// U_ stands for 'Unsigned'
32extern const Mnemonic U_map_of_condition_code_2_branch_mnemonic[];
33
34inline static RegName map_reg(Reg_No r) {
35    assert(r >= 0 && r <= n_reg);
36    return map_of_regno_2_regname[r];
37}
38
39inline static OpndSize map_size(Opnd_Size o_size) {
40    assert(o_size >= 0 && o_size <= n_size);
41    return map_of_EncoderOpndSize_2_RealOpndSize[o_size];
42}
43
44inline static Mnemonic map_alu(ALU_Opcode alu) {
45    assert(alu >= 0 && alu < n_alu);
46    return map_of_alu_opcode_2_mnemonic[alu];
47}
48
49inline static Mnemonic map_shift(Shift_Opcode shc) {
50    assert(shc >= 0 && shc < n_shift);
51    return map_of_shift_opcode_2_mnemonic[shc];
52}
53
54inline bool fit8(int64 val) {
55    return (CHAR_MIN <= val) && (val <= CHAR_MAX);
56}
57
58inline bool fit32(int64 val) {
59    return (INT_MIN <= val) && (val <= INT_MAX);
60}
61
62inline static void add_r(EncoderBase::Operands & args, const R_Opnd & r, Opnd_Size sz, OpndExt ext = OpndExt_None) {
63    RegName reg = map_reg(r.reg_no());
64    if (sz != n_size) {
65        OpndSize size = map_size(sz);
66        if (size != getRegSize(reg)) {
67            reg = getAliasReg(reg, size);
68        }
69    }
70    args.add(EncoderBase::Operand(reg, ext));
71}
72
73inline static void add_m(EncoderBase::Operands & args, const M_Opnd & m, Opnd_Size sz, OpndExt ext = OpndExt_None) {
74        assert(n_size != sz);
75        args.add(EncoderBase::Operand(map_size(sz),
76            map_reg(m.base().reg_no()), map_reg(m.index().reg_no()),
77            (unsigned)m.scale().get_value(), (int)m.disp().get_value(), ext));
78}
79
80inline static void add_rm(EncoderBase::Operands & args, const RM_Opnd & rm, Opnd_Size sz, OpndExt ext = OpndExt_None) {
81    rm.is_reg() ? add_r(args, (R_Opnd &)rm, sz, ext) : add_m(args, (M_Opnd &)rm, sz, ext);
82}
83
84inline static void add_xmm(EncoderBase::Operands & args, const XMM_Opnd & xmm, bool dbl) {
85    // Gregory -
86    // XMM registers indexes in Reg_No enum are shifted by xmm0_reg, their indexes
87    // don't start with 0, so it is necessary to subtract xmm0_reg index from
88    // xmm.get_idx() value
89    assert(xmm.get_idx() >= xmm0_reg);
90    return args.add((RegName)( (dbl ? RegName_XMM0D : RegName_XMM0S) + xmm.get_idx() -
91            xmm0_reg));
92}
93
94inline static void add_fp(EncoderBase::Operands & args, unsigned i, bool dbl) {
95    return args.add((RegName)( (dbl ? RegName_FP0D : RegName_FP0S) + i));
96}
97
98inline static void add_imm(EncoderBase::Operands & args, const Imm_Opnd & imm) {
99    assert(n_size != imm.get_size());
100    args.add(EncoderBase::Operand(map_size(imm.get_size()), imm.get_value(),
101        imm.is_signed() ? OpndExt_Signed : OpndExt_Zero));
102}
103
104ENCODER_DECLARE_EXPORT char * prefix(char * stream, InstrPrefix p) {
105    *stream = (char)p;
106    return stream + 1;
107}
108
109// stack push and pop instructions
110ENCODER_DECLARE_EXPORT char * push(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
111    EncoderBase::Operands args;
112    add_rm(args, rm, sz);
113    return (char*)EncoderBase::encode(stream, Mnemonic_PUSH, args);
114}
115
116ENCODER_DECLARE_EXPORT char * push(char * stream, const Imm_Opnd & imm) {
117    EncoderBase::Operands args;
118#ifdef _EM64T_
119    add_imm(args, imm);
120#else
121    // we need this workaround to be compatible with the former ia32 encoder implementation
122    add_imm(args, Imm_Opnd(size_32, imm.get_value()));
123#endif
124    return EncoderBase::encode(stream, Mnemonic_PUSH, args);
125}
126
127ENCODER_DECLARE_EXPORT char * pop(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
128    EncoderBase::Operands args;
129    add_rm(args, rm, sz);
130    return (char*)EncoderBase::encode(stream, Mnemonic_POP, args);
131}
132
133// cmpxchg or xchg
134ENCODER_DECLARE_EXPORT char * cmpxchg(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz) {
135    EncoderBase::Operands args;
136    add_rm(args, rm, sz);
137    add_r(args, r, sz);
138    RegName implicitReg = getAliasReg(RegName_EAX, map_size(sz));
139    args.add(implicitReg);
140    return (char*)EncoderBase::encode(stream, Mnemonic_CMPXCHG, args);
141}
142
143ENCODER_DECLARE_EXPORT char * xchg(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz) {
144    EncoderBase::Operands args;
145    add_rm(args, rm, sz);
146    add_r(args, r, sz);
147    return (char*)EncoderBase::encode(stream, Mnemonic_XCHG, args);
148}
149
150// inc(rement), dec(rement), not, neg(ate) instructions
151ENCODER_DECLARE_EXPORT char * inc(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
152    EncoderBase::Operands args;
153    add_rm(args, rm, sz);
154    return (char*)EncoderBase::encode(stream, Mnemonic_INC, args);
155}
156
157ENCODER_DECLARE_EXPORT char * dec(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
158    EncoderBase::Operands args;
159    add_rm(args, rm, sz);
160    return (char*)EncoderBase::encode(stream, Mnemonic_DEC, args);
161}
162
163ENCODER_DECLARE_EXPORT char * _not(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
164    EncoderBase::Operands args;
165    add_rm(args, rm, sz);
166    return (char*)EncoderBase::encode(stream, Mnemonic_NOT, args);
167}
168
169ENCODER_DECLARE_EXPORT char * neg(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
170    EncoderBase::Operands args;
171    add_rm(args, rm, sz);
172    return (char*)EncoderBase::encode(stream, Mnemonic_NEG, args);
173}
174
175ENCODER_DECLARE_EXPORT char * nop(char * stream) {
176    EncoderBase::Operands args;
177    return (char*)EncoderBase::encode(stream, Mnemonic_NOP, args);
178}
179
180ENCODER_DECLARE_EXPORT char * int3(char * stream) {
181    EncoderBase::Operands args;
182    return (char*)EncoderBase::encode(stream, Mnemonic_INT3, args);
183}
184
185// alu instructions: add, or, adc, sbb, and, sub, xor, cmp
186ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
187    EncoderBase::Operands args;
188    add_rm(args, rm, sz);
189    add_imm(args, imm);
190    return (char*)EncoderBase::encode(stream, map_alu(opc), args);
191};
192
193ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const M_Opnd & m, const R_Opnd & r, Opnd_Size sz) {
194    EncoderBase::Operands args;
195    add_rm(args, m, sz);
196    add_rm(args, r, sz);
197    return (char*)EncoderBase::encode(stream, map_alu(opc), args);
198}
199
200ENCODER_DECLARE_EXPORT char * alu(char * stream, ALU_Opcode opc, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
201    EncoderBase::Operands args;
202    add_rm(args, r, sz);
203    add_rm(args, rm, sz);
204    return (char*)EncoderBase::encode(stream, map_alu(opc), args);
205}
206
207// test instruction
208ENCODER_DECLARE_EXPORT char * test(char * stream, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
209    EncoderBase::Operands args;
210    add_rm(args, rm, sz);
211    assert(imm.get_size() <= sz);
212    add_imm(args, imm);
213    return (char*)EncoderBase::encode(stream, Mnemonic_TEST, args);
214}
215
216ENCODER_DECLARE_EXPORT char * test(char * stream, const RM_Opnd & rm, const R_Opnd & r, Opnd_Size sz) {
217    EncoderBase::Operands args;
218    add_rm(args, rm, sz);
219    add_r(args, r, sz);
220    return (char*)EncoderBase::encode(stream, Mnemonic_TEST, args);
221}
222
223// shift instructions: shl, shr, sar, shld, shrd
224ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
225    EncoderBase::Operands args;
226    add_rm(args, rm, sz);
227    add_imm(args, imm);
228    return (char*)EncoderBase::encode(stream, map_shift(shc), args);
229}
230
231ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm, Opnd_Size sz) {
232    EncoderBase::Operands args;
233    add_rm(args, rm, sz);
234    args.add(RegName_CL);
235    return (char*)EncoderBase::encode(stream, map_shift(shc), args);
236}
237
238ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm,
239                            const R_Opnd & r, const Imm_Opnd & imm, Opnd_Size sz) {
240    EncoderBase::Operands args;
241    assert(shc == shld_opc || shc == shrd_opc);
242    add_rm(args, rm, sz);
243    add_r(args, r, sz);
244    add_imm(args, imm);
245    return (char*)EncoderBase::encode(stream, map_shift(shc), args);
246}
247
248ENCODER_DECLARE_EXPORT char * shift(char * stream, Shift_Opcode shc, const RM_Opnd & rm,
249                            const R_Opnd & r, Opnd_Size sz) {
250    EncoderBase::Operands args;
251    assert(shc == shld_opc || shc == shrd_opc);
252    add_rm(args, rm, sz);
253    add_r(args, r, sz);
254    args.add(RegName_CL);
255    return (char*)EncoderBase::encode(stream, map_shift(shc), args);
256}
257
258// multiply instructions: mul, imul
259ENCODER_DECLARE_EXPORT char * mul(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
260    EncoderBase::Operands args;
261    args.add(RegName_EDX);
262    args.add(RegName_EAX);
263    add_rm(args, rm, sz);
264    return (char*)EncoderBase::encode(stream, Mnemonic_MUL, args);
265}
266
267ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
268    EncoderBase::Operands args;
269    add_r(args, r, sz);
270    add_rm(args, rm, sz);
271    return (char*)EncoderBase::encode(stream, Mnemonic_IMUL, args);
272}
273
274ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const Imm_Opnd & imm, Opnd_Size sz) {
275    EncoderBase::Operands args;
276    add_r(args, r, sz);
277    add_imm(args, imm);
278    return (char*)EncoderBase::encode(stream, Mnemonic_IMUL, args);
279}
280
281ENCODER_DECLARE_EXPORT char * imul(char * stream, const R_Opnd & r, const RM_Opnd & rm,
282                           const Imm_Opnd & imm, Opnd_Size sz) {
283    EncoderBase::Operands args;
284    add_r(args, r, sz);
285    add_rm(args, rm, sz);
286    add_imm(args, imm);
287    return (char*)EncoderBase::encode(stream, Mnemonic_IMUL, args);
288}
289
290// divide instructions: div, idiv
291ENCODER_DECLARE_EXPORT char * idiv(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
292    EncoderBase::Operands args;
293#ifdef _EM64T_
294    add_r(args, rdx_opnd, sz);
295    add_r(args, rax_opnd, sz);
296#else
297    add_r(args, edx_opnd, sz);
298    add_r(args, eax_opnd, sz);
299#endif
300    add_rm(args, rm, sz);
301    return (char*)EncoderBase::encode(stream, Mnemonic_IDIV, args);
302}
303
304// data movement: mov
305ENCODER_DECLARE_EXPORT char * mov(char * stream, const M_Opnd & m, const R_Opnd & r, Opnd_Size sz) {
306    EncoderBase::Operands args;
307    add_m(args, m, sz);
308    add_r(args, r, sz);
309    return (char*)EncoderBase::encode(stream, Mnemonic_MOV, args);
310}
311
312ENCODER_DECLARE_EXPORT char * mov(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
313    EncoderBase::Operands args;
314    add_r(args, r, sz);
315    add_rm(args, rm, sz);
316    return (char*)EncoderBase::encode(stream, Mnemonic_MOV, args);
317}
318
319ENCODER_DECLARE_EXPORT char * mov(char * stream, const RM_Opnd & rm, const Imm_Opnd & imm, Opnd_Size sz) {
320    EncoderBase::Operands args;
321    add_rm(args, rm, sz);
322    add_imm(args, imm);
323    return (char*)EncoderBase::encode(stream, Mnemonic_MOV, args);
324}
325
326ENCODER_DECLARE_EXPORT char * movd(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm) {
327    EncoderBase::Operands args;
328    add_rm(args, rm, size_32);
329    add_xmm(args, xmm, false);
330    return (char*)EncoderBase::encode(stream, Mnemonic_MOVD, args);
331}
332
333ENCODER_DECLARE_EXPORT char * movd(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm) {
334    EncoderBase::Operands args;
335    add_xmm(args, xmm, false);
336    add_rm(args, rm, size_32);
337    return (char*)EncoderBase::encode(stream, Mnemonic_MOVD, args);
338}
339
340ENCODER_DECLARE_EXPORT char * movq(char * stream, const RM_Opnd & rm, const XMM_Opnd & xmm) {
341    EncoderBase::Operands args;
342    add_rm(args, rm, size_64);
343    add_xmm(args, xmm, true);
344    return (char*)EncoderBase::encode(stream, Mnemonic_MOVQ, args);
345}
346
347ENCODER_DECLARE_EXPORT char * movq(char * stream, const XMM_Opnd & xmm, const RM_Opnd & rm) {
348    EncoderBase::Operands args;
349    add_xmm(args, xmm, true);
350    add_rm(args, rm, size_64);
351    return (char*)EncoderBase::encode(stream, Mnemonic_MOVQ, args);
352}
353
354ENCODER_DECLARE_EXPORT char * movsx(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
355    EncoderBase::Operands args;
356    add_r(args, r, n_size);
357    add_rm(args, rm, sz, OpndExt_Signed);
358    return (char*)EncoderBase::encode(stream, Mnemonic_MOVSX, args);
359}
360
361ENCODER_DECLARE_EXPORT char * movzx(char * stream, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
362    EncoderBase::Operands args;
363    add_r(args, r, n_size);
364    // movzx r64, r/m32 is not available on em64t
365    // mov r32, r/m32 should zero out upper bytes
366    assert(sz <= size_16);
367    add_rm(args, rm, sz, OpndExt_Zero);
368    return (char*)EncoderBase::encode(stream, Mnemonic_MOVZX, args);
369}
370
371// sse mov
372ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
373    EncoderBase::Operands args;
374    add_xmm(args, xmm, dbl);
375    add_m(args, mem, dbl ? size_64 : size_32);
376    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MOVSD : Mnemonic_MOVSS, args);
377}
378
379ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const M_Opnd &  mem, const XMM_Opnd & xmm, bool dbl) {
380    EncoderBase::Operands args;
381    add_m(args, mem, dbl ? size_64 : size_32);
382    add_xmm(args, xmm, dbl);
383    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MOVSD : Mnemonic_MOVSS, args);
384}
385
386ENCODER_DECLARE_EXPORT char * sse_mov(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
387    EncoderBase::Operands args;
388    add_xmm(args, xmm0, dbl);
389    add_xmm(args, xmm1, dbl);
390    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MOVSD : Mnemonic_MOVSS, args );
391}
392
393// sse add, sub, mul, div
394ENCODER_DECLARE_EXPORT char * sse_add(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
395    EncoderBase::Operands args;
396    add_xmm(args, xmm, dbl);
397    add_m(args, mem, dbl ? size_64 : size_32);
398    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_ADDSD : Mnemonic_ADDSS, args);
399}
400
401ENCODER_DECLARE_EXPORT char * sse_add(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
402    EncoderBase::Operands args;
403    add_xmm(args, xmm0, dbl);
404    add_xmm(args, xmm1, dbl);
405    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_ADDSD : Mnemonic_ADDSS, args);
406}
407
408ENCODER_DECLARE_EXPORT char * sse_sub(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
409    EncoderBase::Operands args;
410    add_xmm(args, xmm, dbl);
411    add_m(args, mem, dbl ? size_64 : size_32);
412    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_SUBSD : Mnemonic_SUBSS, args);
413}
414
415ENCODER_DECLARE_EXPORT char * sse_sub(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
416    EncoderBase::Operands args;
417    add_xmm(args, xmm0, dbl);
418    add_xmm(args, xmm1, dbl);
419    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_SUBSD : Mnemonic_SUBSS, args);
420}
421
422ENCODER_DECLARE_EXPORT char * sse_mul( char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
423    EncoderBase::Operands args;
424    add_xmm(args, xmm, dbl);
425    add_m(args, mem, dbl ? size_64 : size_32);
426    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MULSD : Mnemonic_MULSS, args);
427}
428
429ENCODER_DECLARE_EXPORT char * sse_mul(char * stream, const XMM_Opnd& xmm0, const XMM_Opnd& xmm1, bool dbl) {
430    EncoderBase::Operands args;
431    add_xmm(args,  xmm0, dbl);
432    add_xmm(args,  xmm1, dbl);
433    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_MULSD : Mnemonic_MULSS, args);
434}
435
436ENCODER_DECLARE_EXPORT char * sse_div(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
437    EncoderBase::Operands args;
438    add_xmm(args, xmm, dbl);
439    add_m(args, mem, dbl ? size_64 : size_32);
440    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_DIVSD : Mnemonic_DIVSS, args);
441}
442
443ENCODER_DECLARE_EXPORT char * sse_div(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
444    EncoderBase::Operands args;
445    add_xmm(args, xmm0, dbl);
446    add_xmm(args, xmm1, dbl);
447    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_DIVSD : Mnemonic_DIVSS, args);
448}
449
450ENCODER_DECLARE_EXPORT char * sse_xor(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1) {
451    EncoderBase::Operands args;
452    add_xmm(args, xmm0, true);
453    add_xmm(args, xmm1, true);
454    return (char*)EncoderBase::encode(stream, Mnemonic_PXOR, args);
455}
456
457ENCODER_DECLARE_EXPORT char * sse_compare(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
458    EncoderBase::Operands args;
459    add_xmm(args, xmm0, true);
460    add_xmm(args, xmm1, true);
461    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_COMISD : Mnemonic_COMISS, args);
462}
463
464ENCODER_DECLARE_EXPORT char * sse_compare(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem, bool dbl) {
465    EncoderBase::Operands args;
466    add_xmm(args, xmm0, dbl);
467    add_m(args, mem, dbl ? size_64 : size_32);
468    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_COMISD : Mnemonic_COMISS, args);
469}
470
471// sse conversions
472ENCODER_DECLARE_EXPORT char * sse_cvt_si(char * stream, const XMM_Opnd & xmm, const M_Opnd & mem, bool dbl) {
473    EncoderBase::Operands args;
474    add_xmm(args, xmm, dbl);
475    add_m(args, mem, size_32);
476    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTSI2SD : Mnemonic_CVTSI2SS, args);
477}
478
479ENCODER_DECLARE_EXPORT char * sse_cvtt2si(char * stream, const R_Opnd & reg, const M_Opnd & mem, bool dbl) {
480    EncoderBase::Operands args;
481    add_rm(args, reg, size_32);
482    add_m(args, mem, dbl ? size_64 : size_32);
483    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTTSD2SI : Mnemonic_CVTTSS2SI, args);
484}
485
486ENCODER_DECLARE_EXPORT char * sse_cvtt2si(char * stream, const R_Opnd & reg, const XMM_Opnd & xmm, bool dbl) {
487    EncoderBase::Operands args;
488    add_rm(args, reg, size_32);
489    add_xmm(args, xmm, dbl);
490    return (char*)EncoderBase::encode(stream, dbl ? Mnemonic_CVTTSD2SI : Mnemonic_CVTTSS2SI, args);
491}
492
493ENCODER_DECLARE_EXPORT char * sse_cvt_fp2dq(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
494    EncoderBase::Operands args;
495    add_xmm(args, xmm0, dbl);
496    add_xmm(args, xmm1, dbl);
497    return (char*)EncoderBase::encode(stream, dbl ?  Mnemonic_CVTTPD2DQ : Mnemonic_CVTTPS2DQ, args);
498}
499
500ENCODER_DECLARE_EXPORT char * sse_cvt_dq2fp(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1, bool dbl) {
501    EncoderBase::Operands args;
502    add_xmm(args, xmm0, dbl);
503    add_xmm(args, xmm1, dbl);
504    return (char*)EncoderBase::encode(stream, dbl ?  Mnemonic_CVTDQ2PD : Mnemonic_CVTDQ2PS, args);
505}
506
507ENCODER_DECLARE_EXPORT char * sse_d2s(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem64) {
508    EncoderBase::Operands args;
509    add_xmm(args, xmm0, false);
510    add_m(args, mem64, size_64);
511    return (char*)EncoderBase::encode(stream, Mnemonic_CVTSD2SS, args);
512}
513
514ENCODER_DECLARE_EXPORT char * sse_d2s(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1) {
515    EncoderBase::Operands args;
516    add_xmm(args, xmm0, false);
517    add_xmm(args, xmm1, true);
518    return (char*)EncoderBase::encode(stream, Mnemonic_CVTSD2SS, args);
519}
520
521ENCODER_DECLARE_EXPORT char * sse_s2d(char * stream, const XMM_Opnd & xmm0, const M_Opnd & mem32) {
522    EncoderBase::Operands args;
523    add_xmm(args, xmm0, true);
524    add_m(args, mem32, size_32);
525    return (char*)EncoderBase::encode(stream, Mnemonic_CVTSS2SD, args);
526}
527
528ENCODER_DECLARE_EXPORT char * sse_s2d(char * stream, const XMM_Opnd & xmm0, const XMM_Opnd & xmm1) {
529    EncoderBase::Operands args;
530    add_xmm(args, xmm0, true);
531    add_xmm(args, xmm1, false);
532    return (char*)EncoderBase::encode(stream, Mnemonic_CVTSS2SD, args);
533}
534
535// condition operations
536ENCODER_DECLARE_EXPORT char *cmov(char * stream, ConditionCode cc, const R_Opnd & r, const RM_Opnd & rm, Opnd_Size sz) {
537    EncoderBase::Operands args;
538    add_r(args, r, sz);
539    add_rm(args, rm, sz);
540    return (char*)EncoderBase::encode(stream, (Mnemonic)(Mnemonic_CMOVcc + cc), args);
541}
542
543ENCODER_DECLARE_EXPORT char * setcc(char * stream, ConditionCode cc, const RM_Opnd & rm8) {
544    EncoderBase::Operands args;
545    add_rm(args, rm8, size_8);
546    return (char*)EncoderBase::encode(stream, (Mnemonic)(Mnemonic_SETcc + cc), args);
547}
548
549// load effective address: lea
550ENCODER_DECLARE_EXPORT char * lea(char * stream, const R_Opnd & r, const M_Opnd & m, Opnd_Size sz) {
551    EncoderBase::Operands args;
552    add_r(args, r, sz);
553    add_m(args, m, sz);
554    return (char*)EncoderBase::encode(stream, Mnemonic_LEA, args);
555}
556
557ENCODER_DECLARE_EXPORT char * cdq(char * stream) {
558    EncoderBase::Operands args;
559    args.add(RegName_EDX);
560    args.add(RegName_EAX);
561    return (char*)EncoderBase::encode(stream, Mnemonic_CDQ, args);
562}
563
564ENCODER_DECLARE_EXPORT char * wait(char * stream) {
565    return (char*)EncoderBase::encode(stream, Mnemonic_WAIT, EncoderBase::Operands());
566}
567
568// control-flow instructions
569
570// loop
571ENCODER_DECLARE_EXPORT char * loop(char * stream, const Imm_Opnd & imm) {
572    EncoderBase::Operands args;
573    assert(imm.get_size() == size_8);
574    args.add(RegName_ECX);
575    add_imm(args, imm);
576    return (char*)EncoderBase::encode(stream, Mnemonic_LOOP, args);
577}
578
579// jump
580ENCODER_DECLARE_EXPORT char * jump8(char * stream, const Imm_Opnd & imm) {
581    EncoderBase::Operands args;
582    assert(imm.get_size() == size_8);
583    add_imm(args, imm);
584    return (char*)EncoderBase::encode(stream, Mnemonic_JMP, args);
585}
586
587ENCODER_DECLARE_EXPORT char * jump32(char * stream, const Imm_Opnd & imm) {
588    EncoderBase::Operands args;
589    assert(imm.get_size() == size_32);
590    add_imm(args, imm);
591    return (char*)EncoderBase::encode(stream, Mnemonic_JMP, args);
592}
593
594ENCODER_DECLARE_EXPORT char * jump(char * stream, const RM_Opnd & rm, Opnd_Size sz) {
595    EncoderBase::Operands args;
596    add_rm(args, rm, sz);
597    return (char*)EncoderBase::encode(stream, Mnemonic_JMP, args);
598}
599
600/**
601 * @note On EM64T: if target lies beyond 2G (does not fit into 32 bit
602 *       offset) then generates indirect jump using RAX (whose content is
603 *       destroyed).
604 */
605ENCODER_DECLARE_EXPORT char * jump(char * stream, char * target) {
606#ifdef _EM64T_
607    int64 offset = target - stream;
608    // sub 2 bytes for the short version
609    offset -= 2;
610    if (fit8(offset)) {
611        // use 8-bit signed relative form
612        return jump8(stream, Imm_Opnd(size_8, offset));
613    } else if (fit32(offset)) {
614        // sub 5 (3 + 2)bytes for the long version
615        offset -= 3;
616        // use 32-bit signed relative form
617        return jump32(stream, Imm_Opnd(size_32, offset));
618    }
619    // need to use absolute indirect jump
620    stream = mov(stream, rax_opnd, Imm_Opnd(size_64, (int64)target), size_64);
621    return jump(stream, rax_opnd, size_64);
622#else
623    I_32 offset = target - stream;
624    // sub 2 bytes for the short version
625    offset -= 2;
626    if (fit8(offset)) {
627        // use 8-bit signed relative form
628        return jump8(stream, Imm_Opnd(size_8, offset));
629    }
630    // sub 5 (3 + 2) bytes for the long version
631    offset -= 3;
632    // use 32-bit signed relative form
633    return jump32(stream, Imm_Opnd(size_32, offset));
634#endif
635}
636
637// branch
638ENCODER_DECLARE_EXPORT char * branch8(char * stream, ConditionCode cond,
639                                      const Imm_Opnd & imm,
640                                      InstrPrefix pref)
641{
642    if (pref != no_prefix) {
643        assert(pref == hint_branch_taken_prefix || pref == hint_branch_taken_prefix);
644        stream = prefix(stream, pref);
645    }
646    Mnemonic m = (Mnemonic)(Mnemonic_Jcc + cond);
647    EncoderBase::Operands args;
648    assert(imm.get_size() == size_8);
649    add_imm(args, imm);
650    return (char*)EncoderBase::encode(stream, m, args);
651}
652
653ENCODER_DECLARE_EXPORT char * branch32(char * stream, ConditionCode cond,
654                                       const Imm_Opnd & imm,
655                                       InstrPrefix pref)
656{
657    if (pref != no_prefix) {
658        assert(pref == hint_branch_taken_prefix || pref == hint_branch_taken_prefix);
659        stream = prefix(stream, pref);
660    }
661    Mnemonic m = (Mnemonic)(Mnemonic_Jcc + cond);
662    EncoderBase::Operands args;
663    assert(imm.get_size() == size_32);
664    add_imm(args, imm);
665    return (char*)EncoderBase::encode(stream, m, args);
666}
667
668/*
669ENCODER_DECLARE_EXPORT char * branch(char * stream, ConditionCode cc, const char * target, InstrPrefix prefix) {
670// sub 2 bytes for the short version
671int64 offset = stream-target-2;
672if( fit8(offset) ) {
673return branch8(stream, cc, Imm_Opnd(size_8, (char)offset), is_signed);
674}
675return branch32(stream, cc, Imm_Opnd(size_32, (int)offset), is_signed);
676}
677*/
678
679// call
680ENCODER_DECLARE_EXPORT char * call(char * stream, const Imm_Opnd & imm)
681{
682    EncoderBase::Operands args;
683    add_imm(args, imm);
684    return (char*)EncoderBase::encode(stream, Mnemonic_CALL, args);
685}
686
687ENCODER_DECLARE_EXPORT char * call(char * stream, const RM_Opnd & rm,
688                                   Opnd_Size sz)
689{
690    EncoderBase::Operands args;
691    add_rm(args, rm, sz);
692    return (char*)EncoderBase::encode(stream, Mnemonic_CALL, args);
693}
694
695/**
696* @note On EM64T: if target lies beyond 2G (does not fit into 32 bit
697*       offset) then generates indirect jump using RAX (whose content is
698*       destroyed).
699*/
700ENCODER_DECLARE_EXPORT char * call(char * stream, const char * target)
701{
702#ifdef _EM64T_
703    int64 offset = target - stream;
704    if (fit32(offset)) {
705        offset -= 5; // sub 5 bytes for this instruction
706        Imm_Opnd imm(size_32, offset);
707        return call(stream, imm);
708    }
709    // need to use absolute indirect call
710    stream = mov(stream, rax_opnd, Imm_Opnd(size_64, (int64)target), size_64);
711    return call(stream, rax_opnd, size_64);
712#else
713    I_32 offset = target - stream;
714    offset -= 5; // sub 5 bytes for this instruction
715    Imm_Opnd imm(size_32, offset);
716    return call(stream, imm);
717#endif
718}
719
720// return instruction
721ENCODER_DECLARE_EXPORT char * ret(char * stream)
722{
723    EncoderBase::Operands args;
724    return (char*)EncoderBase::encode(stream, Mnemonic_RET, args);
725}
726
727ENCODER_DECLARE_EXPORT char * ret(char * stream, const Imm_Opnd & imm)
728{
729    EncoderBase::Operands args;
730    // TheManual says imm can be 16-bit only
731    //assert(imm.get_size() <= size_16);
732    args.add(EncoderBase::Operand(map_size(size_16), imm.get_value()));
733    return (char*)EncoderBase::encode(stream, Mnemonic_RET, args);
734}
735
736ENCODER_DECLARE_EXPORT char * ret(char * stream, unsigned short pop)
737{
738    // TheManual says it can only be imm16
739    EncoderBase::Operands args(EncoderBase::Operand(OpndSize_16, pop, OpndExt_Zero));
740    return (char*)EncoderBase::encode(stream, Mnemonic_RET, args);
741}
742
743// floating-point instructions
744ENCODER_DECLARE_EXPORT char * fld(char * stream, const M_Opnd & m,
745                                  bool is_double) {
746    EncoderBase::Operands args;
747    // a fake FP register as operand
748    add_fp(args, 0, is_double);
749    add_m(args, m, is_double ? size_64 : size_32);
750    return (char*)EncoderBase::encode(stream, Mnemonic_FLD, args);
751}
752
753ENCODER_DECLARE_EXPORT char * fist(char * stream, const M_Opnd & mem,
754                                   bool is_long, bool pop_stk)
755{
756    EncoderBase::Operands args;
757    if (pop_stk) {
758        add_m(args, mem, is_long ? size_64 : size_32);
759        // a fake FP register as operand
760        add_fp(args, 0, is_long);
761        return (char*)EncoderBase::encode(stream,  Mnemonic_FISTP, args);
762    }
763    // only 32-bit operands are supported
764    assert(is_long == false);
765    add_m(args, mem, size_32);
766    add_fp(args, 0, false);
767    return (char*)EncoderBase::encode(stream,  Mnemonic_FIST, args);
768}
769
770ENCODER_DECLARE_EXPORT char * fst(char * stream, const M_Opnd & m,
771                                  bool is_double, bool pop_stk)
772{
773    EncoderBase::Operands args;
774    add_m(args, m, is_double ? size_64 : size_32);
775    // a fake FP register as operand
776    add_fp(args, 0, is_double);
777    return (char*)EncoderBase::encode(stream,
778                                    pop_stk ? Mnemonic_FSTP : Mnemonic_FST,
779                                    args);
780}
781
782ENCODER_DECLARE_EXPORT char * fst(char * stream, unsigned i, bool pop_stk)
783{
784    EncoderBase::Operands args;
785    add_fp(args, i, true);
786    return (char*)EncoderBase::encode(stream,
787                                    pop_stk ? Mnemonic_FSTP : Mnemonic_FST,
788                                    args);
789}
790
791ENCODER_DECLARE_EXPORT char * fldcw(char * stream, const M_Opnd & mem) {
792    EncoderBase::Operands args;
793    add_m(args, mem, size_16);
794    return (char*)EncoderBase::encode(stream, Mnemonic_FLDCW, args);
795}
796
797ENCODER_DECLARE_EXPORT char * fnstcw(char * stream, const M_Opnd & mem) {
798    EncoderBase::Operands args;
799    add_m(args, mem, size_16);
800    return (char*)EncoderBase::encode(stream, Mnemonic_FNSTCW, args);
801}
802
803ENCODER_DECLARE_EXPORT char * fnstsw(char * stream)
804{
805    return (char*)EncoderBase::encode(stream, Mnemonic_FNSTCW,
806                                      EncoderBase::Operands());
807}
808
809// string operations
810ENCODER_DECLARE_EXPORT char * set_d(char * stream, bool set) {
811    EncoderBase::Operands args;
812    return (char*)EncoderBase::encode(stream,
813                                      set ? Mnemonic_STD : Mnemonic_CLD,
814                                      args);
815}
816
817ENCODER_DECLARE_EXPORT char * scas(char * stream, unsigned char prefix)
818{
819	EncoderBase::Operands args;
820    if (prefix != no_prefix) {
821        assert(prefix == prefix_repnz || prefix == prefix_repz);
822        *stream = prefix;
823        ++stream;
824    }
825    return (char*)EncoderBase::encode(stream, Mnemonic_SCAS, args);
826}
827
828ENCODER_DECLARE_EXPORT char * stos(char * stream, unsigned char prefix)
829{
830    if (prefix != no_prefix) {
831        assert(prefix == prefix_rep);
832        *stream = prefix;
833        ++stream;
834    }
835
836	EncoderBase::Operands args;
837	return (char*)EncoderBase::encode(stream, Mnemonic_STOS, args);
838}
839
840// Intrinsic FP math functions
841
842ENCODER_DECLARE_EXPORT char * fprem(char * stream) {
843    return (char*)EncoderBase::encode(stream, Mnemonic_FPREM,
844                                      EncoderBase::Operands());
845}
846
847ENCODER_DECLARE_EXPORT char * fprem1(char * stream) {
848    return (char*)EncoderBase::encode(stream, Mnemonic_FPREM1,
849                                      EncoderBase::Operands());
850}
851