blob: a3d3d2dad383736246430967ad45f7c923f0a68e [file] [log] [blame]
/*---------------------------------------------------------------*/
/*--- ---*/
/*--- This file (guest-x86/ghelpers.c) is ---*/
/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
/*--- ---*/
/*---------------------------------------------------------------*/
#include "libvex_basictypes.h"
#include "libvex_guest_x86.h"
#include "libvex_ir.h"
#include "main/vex_util.h"
#include "guest-x86/gdefs.h"
/* --- Forwardses --- */
UInt calculate_eflags_all ( UInt cc_op, UInt cc_src, UInt cc_dst );
static UInt calculate_eflags_c ( UInt cc_op, UInt cc_src, UInt cc_dst );
static UInt calculate_condition ( UInt/*Condcode*/ cond,
UInt cc_op, UInt cc_src, UInt cc_dst );
static UInt calculate_FXAM ( UInt tag, ULong dbl );
static ULong loadF80le ( UInt );
static void storeF80le ( UInt, ULong );
/* This file contains helper functions for x86 guest code.
Calls to these functions are generated by the back end.
These calls are of course in the host machine code and
this file will be compiled to host machine code, so that
all makes sense.
x86guest_findhelper() is the only exported function.
Only change the signatures of these helper functions very
carefully. If you change the signature here, you'll have to change
the parameters passed to it in the IR calls constructed by
x86toIR.c.
Some of this code/logic is derived from QEMU, which is copyright
Fabrice Bellard, licensed under the LGPL. It is used with
permission.
*/
/* Set to 1 to get detailed profiling info about use of the flag
machinery. */
#define PROFILE_EFLAGS 0
typedef UChar uint8_t;
typedef UInt uint32_t;
#define CC_O CC_MASK_O
#define CC_P CC_MASK_P
#define CC_C CC_MASK_C
static const uint8_t parity_table[256] = {
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
};
/* n must be a constant to be efficient */
inline static Int lshift ( Int x, Int n )
{
if (n >= 0)
return x << n;
else
return x >> (-n);
}
#define PREAMBLE(__data_bits) \
/* const */ UInt DATA_MASK \
= __data_bits==8 ? 0xFF \
: (__data_bits==16 ? 0xFFFF \
: 0xFFFFFFFF); \
/* const */ UInt SIGN_MASK = 1 << (__data_bits - 1); \
/* const */ UInt CC_DST = cc_dst_formal; \
/* const */ UInt CC_SRC = cc_src_formal; \
/* Three bogus assignments, which hopefully gcc can */ \
/* optimise away, and which stop it complaining about */ \
/* unused variables. */ \
SIGN_MASK = SIGN_MASK; \
DATA_MASK = DATA_MASK; \
CC_SRC = CC_SRC;
/*-------------------------------------------------------------*/
#define ACTIONS_ADD(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
int cf, pf, af, zf, sf, of; \
int src1, src2, dst; \
src1 = CC_SRC; \
src2 = CC_DST; \
dst = src1 + src2; \
cf = (DATA_UTYPE)dst < (DATA_UTYPE)src1; \
pf = parity_table[(uint8_t)dst]; \
af = (dst ^ src1 ^ src2) & 0x10; \
zf = ((DATA_UTYPE)dst == 0) << 6; \
sf = lshift(dst, 8 - DATA_BITS) & 0x80; \
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), \
12 - DATA_BITS) & CC_O; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
#define ACTIONS_ADC(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
int cf, pf, af, zf, sf, of; \
int src1, src2, dst; \
src1 = CC_SRC; \
src2 = CC_DST; \
dst = src1 + src2 + 1; \
cf = (DATA_UTYPE)dst <= (DATA_UTYPE)src1; \
pf = parity_table[(uint8_t)dst]; \
af = (dst ^ src1 ^ src2) & 0x10; \
zf = ((DATA_UTYPE)dst == 0) << 6; \
sf = lshift(dst, 8 - DATA_BITS) & 0x80; \
of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), \
12 - DATA_BITS) & CC_O; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
#define ACTIONS_SUB(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
int cf, pf, af, zf, sf, of; \
int src1, src2, dst; \
src1 = CC_DST; \
src2 = CC_SRC; \
dst = src1 - src2; \
cf = (DATA_UTYPE)src1 < (DATA_UTYPE)src2; \
pf = parity_table[(uint8_t)dst]; \
af = (dst ^ src1 ^ src2) & 0x10; \
zf = ((DATA_UTYPE)dst == 0) << 6; \
sf = lshift(dst, 8 - DATA_BITS) & 0x80; \
of = lshift((src1 ^ src2) & (src1 ^ dst), \
12 - DATA_BITS) & CC_O; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
#define ACTIONS_SBB(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
int cf, pf, af, zf, sf, of; \
int src1, src2, dst; \
src1 = CC_DST; \
src2 = CC_SRC; \
dst = (src1 - src2) - 1; \
cf = (DATA_UTYPE)src1 <= (DATA_UTYPE)src2; \
pf = parity_table[(uint8_t)dst]; \
af = (dst ^ src1 ^ src2) & 0x10; \
zf = ((DATA_UTYPE)dst == 0) << 6; \
sf = lshift(dst, 8 - DATA_BITS) & 0x80; \
of = lshift((src1 ^ src2) & (src1 ^ dst), \
12 - DATA_BITS) & CC_O; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
#define ACTIONS_LOGIC(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
int cf, pf, af, zf, sf, of; \
cf = 0; \
pf = parity_table[(uint8_t)CC_DST]; \
af = 0; \
zf = ((DATA_UTYPE)CC_DST == 0) << 6; \
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; \
of = 0; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
#define ACTIONS_INC(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
int cf, pf, af, zf, sf, of; \
int src1, src2; \
src1 = CC_DST - 1; \
src2 = 1; \
cf = CC_SRC; \
pf = parity_table[(uint8_t)CC_DST]; \
af = (CC_DST ^ src1 ^ src2) & 0x10; \
zf = ((DATA_UTYPE)CC_DST == 0) << 6; \
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; \
of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
#define ACTIONS_DEC(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
int cf, pf, af, zf, sf, of; \
int src1, src2; \
src1 = CC_DST + 1; \
src2 = 1; \
cf = CC_SRC; \
pf = parity_table[(uint8_t)CC_DST]; \
af = (CC_DST ^ src1 ^ src2) & 0x10; \
zf = ((DATA_UTYPE)CC_DST == 0) << 6; \
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; \
of = ((CC_DST & DATA_MASK) \
== ((uint32_t)SIGN_MASK - 1)) << 11; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
#define ACTIONS_SHL(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
int cf, pf, af, zf, sf, of; \
cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C; \
pf = parity_table[(uint8_t)CC_DST]; \
af = 0; /* undefined */ \
zf = ((DATA_UTYPE)CC_DST == 0) << 6; \
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; \
/* of is defined if shift count == 1 */ \
of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
#define ACTIONS_SAR(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
int cf, pf, af, zf, sf, of; \
cf = CC_SRC & 1; \
pf = parity_table[(uint8_t)CC_DST]; \
af = 0; /* undefined */ \
zf = ((DATA_UTYPE)CC_DST == 0) << 6; \
sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; \
/* of is defined if shift count == 1 */ \
of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
/* ROL: cf' = lsb(result). of' = msb(result) ^ lsb(result). */
/* DST = result, SRC = old flags */
#define ACTIONS_ROL(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
int fl \
= (CC_SRC & ~(CC_O | CC_C)) \
| (CC_C & CC_DST) \
| (CC_O & (lshift(CC_DST, 11-(DATA_BITS-1)) \
^ lshift(CC_DST, 11))); \
return fl; \
}
/*-------------------------------------------------------------*/
/* ROR: cf' = msb(result). of' = msb(result) ^ msb-1(result). */
/* DST = result, SRC = old flags */
#define ACTIONS_ROR(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
int fl \
= (CC_SRC & ~(CC_O | CC_C)) \
| (CC_C & (CC_DST >> (DATA_BITS-1))) \
| (CC_O & (lshift(CC_DST, 11-(DATA_BITS-1)) \
^ lshift(CC_DST, 11-(DATA_BITS-1)+1))); \
return fl; \
}
/*-------------------------------------------------------------*/
#define ACTIONS_UMUL(DATA_BITS,DATA_UTYPE,DATA_U2TYPE) \
{ \
PREAMBLE(DATA_BITS); \
int cf, pf, af, zf, sf, of; \
DATA_UTYPE hi; \
DATA_UTYPE lo = ((DATA_UTYPE)CC_SRC) * ((DATA_UTYPE)CC_DST);\
DATA_U2TYPE rr = ((DATA_U2TYPE)((DATA_UTYPE)CC_SRC)) \
* ((DATA_U2TYPE)((DATA_UTYPE)CC_DST)); \
hi = (DATA_UTYPE)(rr >>/*u*/ DATA_BITS); \
cf = (hi != 0); \
pf = parity_table[(uint8_t)lo]; \
af = 0; /* undefined */ \
zf = (lo == 0) << 6; \
sf = lshift(lo, 8 - DATA_BITS) & 0x80; \
of = cf << 11; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
#define ACTIONS_SMUL(DATA_BITS,DATA_STYPE,DATA_S2TYPE) \
{ \
PREAMBLE(DATA_BITS); \
int cf, pf, af, zf, sf, of; \
DATA_STYPE hi; \
DATA_STYPE lo = ((DATA_STYPE)CC_SRC) * ((DATA_STYPE)CC_DST);\
DATA_S2TYPE rr = ((DATA_S2TYPE)((DATA_STYPE)CC_SRC)) \
* ((DATA_S2TYPE)((DATA_STYPE)CC_DST)); \
hi = (DATA_STYPE)(rr >>/*s*/ DATA_BITS); \
cf = (hi != (lo >>/*s*/ (DATA_BITS-1))); \
pf = parity_table[(uint8_t)lo]; \
af = 0; /* undefined */ \
zf = (lo == 0) << 6; \
sf = lshift(lo, 8 - DATA_BITS) & 0x80; \
of = cf << 11; \
return cf | pf | af | zf | sf | of; \
}
#define CC_SHIFT_C 0
#define CC_SHIFT_P 2
#define CC_SHIFT_A 4
#define CC_SHIFT_Z 6
#define CC_SHIFT_S 7
#define CC_SHIFT_O 11
#if PROFILE_EFLAGS
static UInt tabc[CC_OP_NUMBER];
static UInt tab[CC_OP_NUMBER][16];
static Bool initted = False;
static UInt n_calc_cond = 0;
static UInt n_calc_all = 0;
static UInt n_calc_c = 0;
static void showCounts ( void )
{
Int op, co;
Char ch;
vex_printf("\nALL=%d COND=%d C=%d\n",
n_calc_all-n_calc_cond-n_calc_c, n_calc_cond, n_calc_c);
vex_printf(" CARRY O NO B NB Z NZ BE NBE"
" S NS P NP L NL LE NLE\n");
vex_printf(" ----------------------------------------------"
"----------------------------------------\n");
for (op = 0; op < CC_OP_NUMBER; op++) {
ch = ' ';
if (op > 0 && (op-1) % 3 == 2)
ch = 'L';
vex_printf("%2d%c: ", op, ch);
vex_printf("%6d ", tabc[op]);
for (co = 0; co < 16; co++) {
Int n = tab[op][co];
if (n >= 1000) {
vex_printf(" %3dK", n / 1000);
} else
if (n >= 0) {
vex_printf(" %3d ", n );
} else {
vex_printf(" ");
}
}
vex_printf("\n");
}
vex_printf("\n");
}
static void initCounts ( void )
{
Int op, co;
initted = True;
for (op = 0; op < CC_OP_NUMBER; op++) {
tabc[op] = 0;
for (co = 0; co < 16; co++)
tab[op][co] = 0;
}
}
#endif /* PROFILE_EFLAGS */
/* CALLED FROM GENERATED CODE */
/* Calculate all the 6 flags from the supplied thunk parameters. */
/*static*/
UInt calculate_eflags_all ( UInt cc_op, UInt cc_src_formal, UInt cc_dst_formal )
{
# if PROFILE_EFLAGS
n_calc_all++;
# endif
switch (cc_op) {
case CC_OP_COPY:
return cc_src_formal
& (CC_MASK_O | CC_MASK_S | CC_MASK_Z
| CC_MASK_A | CC_MASK_C | CC_MASK_P);
case CC_OP_ADDB: ACTIONS_ADD( 8, UChar );
case CC_OP_ADDW: ACTIONS_ADD( 16, UShort );
case CC_OP_ADDL: ACTIONS_ADD( 32, UInt );
case CC_OP_ADCB: ACTIONS_ADC( 8, UChar );
case CC_OP_ADCW: ACTIONS_ADC( 16, UShort );
case CC_OP_ADCL: ACTIONS_ADC( 32, UInt );
case CC_OP_SUBB: ACTIONS_SUB( 8, UChar );
case CC_OP_SUBW: ACTIONS_SUB( 16, UShort );
case CC_OP_SUBL: ACTIONS_SUB( 32, UInt );
case CC_OP_SBBB: ACTIONS_SBB( 8, UChar );
case CC_OP_SBBW: ACTIONS_SBB( 16, UShort );
case CC_OP_SBBL: ACTIONS_SBB( 32, UInt );
case CC_OP_LOGICB: ACTIONS_LOGIC( 8, UChar );
case CC_OP_LOGICW: ACTIONS_LOGIC( 16, UShort );
case CC_OP_LOGICL: ACTIONS_LOGIC( 32, UInt );
case CC_OP_INCB: ACTIONS_INC( 8, UChar );
case CC_OP_INCW: ACTIONS_INC( 16, UShort );
case CC_OP_INCL: ACTIONS_INC( 32, UInt );
case CC_OP_DECB: ACTIONS_DEC( 8, UChar );
case CC_OP_DECW: ACTIONS_DEC( 16, UShort );
case CC_OP_DECL: ACTIONS_DEC( 32, UInt );
case CC_OP_SHLB: ACTIONS_SHL( 8, UChar );
case CC_OP_SHLW: ACTIONS_SHL( 16, UShort );
case CC_OP_SHLL: ACTIONS_SHL( 32, UInt );
case CC_OP_SARB: ACTIONS_SAR( 8, UChar );
case CC_OP_SARW: ACTIONS_SAR( 16, UShort );
case CC_OP_SARL: ACTIONS_SAR( 32, UInt );
case CC_OP_ROLB: ACTIONS_ROL( 8, UChar );
case CC_OP_ROLW: ACTIONS_ROL( 16, UShort );
case CC_OP_ROLL: ACTIONS_ROL( 32, UInt );
case CC_OP_RORB: ACTIONS_ROR( 8, UChar );
case CC_OP_RORW: ACTIONS_ROR( 16, UShort );
case CC_OP_RORL: ACTIONS_ROR( 32, UInt );
case CC_OP_UMULB: ACTIONS_UMUL( 8, UChar, UShort );
case CC_OP_UMULW: ACTIONS_UMUL( 16, UShort, UInt );
case CC_OP_UMULL: ACTIONS_UMUL( 32, UInt, ULong );
case CC_OP_SMULB: ACTIONS_SMUL( 8, Char, Short );
case CC_OP_SMULW: ACTIONS_SMUL( 16, Short, Int );
case CC_OP_SMULL: ACTIONS_SMUL( 32, Int, Long );
default:
/* shouldn't really make these calls from generated code */
vex_printf("calculate_eflags_all( %d, 0x%x, 0x%x )\n",
cc_op, cc_src_formal, cc_dst_formal );
vpanic("calculate_eflags_all");
}
}
/* CALLED FROM GENERATED CODE */
/* Calculate just the carry flag from the supplied thunk parameters. */
static UInt calculate_eflags_c ( UInt cc_op, UInt cc_src, UInt cc_dst )
{
/* Fast-case some common ones. */
if (cc_op == CC_OP_LOGICL)
return 0;
if (cc_op == CC_OP_DECL)
return cc_src;
if (cc_op == CC_OP_SUBL)
return ( ((UInt)cc_src) < ((UInt)cc_dst) ) & CC_MASK_C;
# if PROFILE_EFLAGS
if (!initted)
initCounts();
tabc[cc_op]++;
n_calc_c++;
# endif
return calculate_eflags_all(cc_op,cc_src,cc_dst) & CC_MASK_C;
}
/* CALLED FROM GENERATED CODE */
/* returns 1 or 0 */
/*static*/ UInt calculate_condition ( UInt/*Condcode*/ cond,
UInt cc_op, UInt cc_src, UInt cc_dst )
{
UInt eflags = calculate_eflags_all(cc_op, cc_src, cc_dst);
UInt of,sf,zf,cf,pf;
UInt inv = cond & 1;
# if PROFILE_EFLAGS
if (!initted)
initCounts();
tab[cc_op][cond]++;
n_calc_cond++;
if (0 == ((n_calc_all+n_calc_c) & 0x3FFF)) showCounts();
# endif
switch (cond) {
case CondNO:
case CondO: /* OF == 1 */
of = eflags >> CC_SHIFT_O;
return 1 & (inv ^ of);
case CondNZ:
case CondZ: /* ZF == 1 */
zf = eflags >> CC_SHIFT_Z;
return 1 & (inv ^ zf);
case CondNB:
case CondB: /* CF == 1 */
cf = eflags >> CC_SHIFT_C;
return 1 & (inv ^ cf);
break;
case CondNBE:
case CondBE: /* (CF or ZF) == 1 */
cf = eflags >> CC_SHIFT_C;
zf = eflags >> CC_SHIFT_Z;
return 1 & (inv ^ (cf | zf));
break;
case CondNS:
case CondS: /* SF == 1 */
sf = eflags >> CC_SHIFT_S;
return 1 & (inv ^ sf);
case CondNP:
case CondP: /* PF == 1 */
pf = eflags >> CC_SHIFT_P;
return 1 & (inv ^ pf);
case CondNL:
case CondL: /* (SF xor OF) == 1 */
sf = eflags >> CC_SHIFT_S;
of = eflags >> CC_SHIFT_O;
return 1 & (inv ^ (sf ^ of));
break;
case CondNLE:
case CondLE: /* ((SF xor OF) or ZF) == 1 */
sf = eflags >> CC_SHIFT_S;
of = eflags >> CC_SHIFT_O;
zf = eflags >> CC_SHIFT_Z;
return 1 & (inv ^ ((sf ^ of) | zf));
break;
default:
/* shouldn't really make these calls from generated code */
vex_printf("calculate_condition( %d, %d, 0x%x, 0x%x )\n",
cond, cc_op, cc_src, cc_dst );
vpanic("calculate_condition");
}
}
Addr64 x86guest_findhelper ( Char* function_name )
{
if (vex_streq(function_name, "calculate_condition"))
return (Addr64)(Addr32)(& calculate_condition);
if (vex_streq(function_name, "calculate_eflags_c"))
return (Addr64)(Addr32)(& calculate_eflags_c);
if (vex_streq(function_name, "calculate_eflags_all"))
return (Addr64)(Addr32)(& calculate_eflags_all);
if (vex_streq(function_name, "calculate_FXAM"))
return (Addr64)(Addr32)(& calculate_FXAM);
if (vex_streq(function_name, "storeF80le"))
return (Addr64)(Addr32)(& storeF80le);
if (vex_streq(function_name, "loadF80le"))
return (Addr64)(Addr32)(& loadF80le);
vex_printf("\nx86 guest: can't find helper: %s\n", function_name);
vpanic("x86guest_findhelper");
}
/* Used by the optimiser to try specialisations. Returns an
equivalent expression, or NULL if none. */
static Bool isU32 ( IRExpr* e, UInt n )
{
return e->tag == Iex_Const
&& e->Iex.Const.con->tag == Ico_U32
&& e->Iex.Const.con->Ico.U32 == n;
}
IRExpr* x86guest_spechelper ( Char* function_name,
IRExpr** args )
{
# define unop(_op,_a1) IRExpr_Unop((_op),(_a1))
# define binop(_op,_a1,_a2) IRExpr_Binop((_op),(_a1),(_a2))
# define mkU32(_n) IRExpr_Const(IRConst_U32(_n))
Int i, arity = 0;
for (i = 0; args[i]; i++)
arity++;
# if 0
vex_printf("spec request:\n");
vex_printf(" %s ", function_name);
for (i = 0; i < arity; i++) {
vex_printf(" ");
ppIRExpr(args[i]);
}
vex_printf("\n");
# endif
if (vex_streq(function_name, "calculate_eflags_c")) {
/* specialise calls to above "calculate_eflags_c" function */
IRExpr *cc_op, *cc_src, *cc_dst;
vassert(arity == 3);
cc_op = args[0];
cc_src = args[1];
cc_dst = args[2];
if (isU32(cc_op, CC_OP_LOGICL)) {
/* cflag after logic is zero */
return mkU32(0);
}
if (isU32(cc_op, CC_OP_DECL) || isU32(cc_op, CC_OP_INCL)) {
/* If the thunk is dec or inc, the cflag is supplied as CC_SRC. */
return cc_src;
}
if (isU32(cc_op, CC_OP_SUBL)) {
/* C after sub denotes unsigned less than */
return unop(Iop_1Uto32,
binop(Iop_CmpLT32U, cc_dst, cc_src));
}
# if 0
if (cc_op->tag == Iex_Const) {
vex_printf("CFLAG "); ppIRExpr(cc_op); vex_printf("\n");
}
# endif
return NULL;
}
if (vex_streq(function_name, "calculate_condition")) {
/* specialise calls to above "calculate condition" function */
IRExpr *cond, *cc_op, *cc_src, *cc_dst;
vassert(arity == 4);
cond = args[0];
cc_op = args[1];
cc_src = args[2];
cc_dst = args[3];
/*---------------- SUBL ----------------*/
if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondZ)) {
/* long sub/cmp, then Z --> test dst==src */
return unop(Iop_1Uto32,
binop(Iop_CmpEQ32, cc_dst, cc_src));
}
if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondL)) {
/* long sub/cmp, then L (signed less than)
--> test dst <s src */
return unop(Iop_1Uto32,
binop(Iop_CmpLT32S, cc_dst, cc_src));
}
if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondLE)) {
/* long sub/cmp, then LE (signed less than or equal)
--> test dst <=s src */
return unop(Iop_1Uto32,
binop(Iop_CmpLE32S, cc_dst, cc_src));
}
if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondBE)) {
/* long sub/cmp, then BE (unsigned less than or equal)
--> test dst <=u src */
return unop(Iop_1Uto32,
binop(Iop_CmpLE32U, cc_dst, cc_src));
}
if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondB)) {
/* long sub/cmp, then B (unsigned less than)
--> test dst <u src */
return unop(Iop_1Uto32,
binop(Iop_CmpLT32U, cc_dst, cc_src));
}
/*---------------- SUBW ----------------*/
if (isU32(cc_op, CC_OP_SUBW) && isU32(cond, CondZ)) {
/* byte sub/cmp, then Z --> test dst==src */
return unop(Iop_1Uto32,
binop(Iop_CmpEQ16,
unop(Iop_32to16,cc_dst),
unop(Iop_32to16,cc_src)));
}
/*---------------- SUBB ----------------*/
if (isU32(cc_op, CC_OP_SUBB) && isU32(cond, CondZ)) {
/* byte sub/cmp, then Z --> test dst==src */
return unop(Iop_1Uto32,
binop(Iop_CmpEQ8,
unop(Iop_32to8,cc_dst),
unop(Iop_32to8,cc_src)));
}
if (isU32(cc_op, CC_OP_SUBB) && isU32(cond, CondNZ)) {
/* byte sub/cmp, then Z --> test dst!=src */
return unop(Iop_1Uto32,
binop(Iop_CmpNE8,
unop(Iop_32to8,cc_dst),
unop(Iop_32to8,cc_src)));
}
if (isU32(cc_op, CC_OP_SUBB) && isU32(cond, CondNBE)) {
/* long sub/cmp, then NBE (unsigned greater than)
--> test src <=u dst */
return unop(Iop_1Uto32,
binop(Iop_CmpLT32U,
binop(Iop_And32,cc_src,mkU32(0xFF)),
binop(Iop_And32,cc_dst,mkU32(0xFF))));
}
/*---------------- LOGICL ----------------*/
if (isU32(cc_op, CC_OP_LOGICL) && isU32(cond, CondZ)) {
/* long and/or/xor, then Z --> test dst==0 */
return unop(Iop_1Uto32,binop(Iop_CmpEQ32, cc_dst, mkU32(0)));
}
if (isU32(cc_op, CC_OP_LOGICL) && isU32(cond, CondS)) {
/* long and/or/xor, then S --> test dst <s 0 */
return unop(Iop_1Uto32,binop(Iop_CmpLT32S, cc_dst, mkU32(0)));
}
if (isU32(cc_op, CC_OP_LOGICL) && isU32(cond, CondLE)) {
/* long and/or/xor, then LE
This is pretty subtle. LOGIC sets SF and ZF according to the
result and makes OF be zero. LE computes (SZ ^ OF) | ZF, but
OF is zero, so this reduces to SZ | ZF -- which will be 1 iff
the result is <=signed 0. Hence ...
*/
return unop(Iop_1Uto32,binop(Iop_CmpLE32S, cc_dst, mkU32(0)));
}
/*---------------- LOGICB ----------------*/
if (isU32(cc_op, CC_OP_LOGICB) && isU32(cond, CondZ)) {
/* byte and/or/xor, then Z --> test dst==0 */
return unop(Iop_1Uto32,
binop(Iop_CmpEQ32, binop(Iop_And32,cc_dst,mkU32(255)),
mkU32(0)));
}
/*---------------- DECL ----------------*/
if (isU32(cc_op, CC_OP_DECL) && isU32(cond, CondZ)) {
/* dec L, then Z --> test dst == 0 */
return unop(Iop_1Uto32,binop(Iop_CmpEQ32, cc_dst, mkU32(0)));
}
if (isU32(cc_op, CC_OP_DECL) && isU32(cond, CondS)) {
/* dec L, then S --> compare DST <s 0 */
return unop(Iop_1Uto32,binop(Iop_CmpLT32S, cc_dst, mkU32(0)));
}
return NULL;
}
# undef unop
# undef binop
# undef mkU32
return NULL;
}
/*-----------------------------------------------------------*/
/*--- Utility functions for x87 FPU conversions. ---*/
/*-----------------------------------------------------------*/
/* 80 and 64-bit floating point formats:
80-bit:
S 0 0-------0 zero
S 0 0X------X denormals
S 1-7FFE 1X------X normals (all normals have leading 1)
S 7FFF 10------0 infinity
S 7FFF 10X-----X snan
S 7FFF 11X-----X qnan
S is the sign bit. For runs X----X, at least one of the Xs must be
nonzero. Exponent is 15 bits, fractional part is 63 bits, and
there is an explicitly represented leading 1, and a sign bit,
giving 80 in total.
64-bit avoids the confusion of an explicitly represented leading 1
and so is simpler:
S 0 0------0 zero
S 0 X------X denormals
S 1-7FE any normals
S 7FF 0------0 infinity
S 7FF 0X-----X snan
S 7FF 1X-----X qnan
Exponent is 11 bits, fractional part is 52 bits, and there is a
sign bit, giving 64 in total.
*/
static inline Bool host_is_little_endian ( void )
{
UInt x = 0x76543210;
UChar* p = (UChar*)(&x);
return (*p == 0x10);
}
static UInt calculate_FXAM ( UInt tag, ULong dbl )
{
Bool mantissaIsZero;
Int bexp;
UChar sign;
UInt c1;
UChar* f64;
if (!host_is_little_endian()) {
vassert(0);
}
/* vex_printf("calculate_FXAM ( %d, %llx ) .. ", tag, dbl ); */
f64 = (UChar*)(&dbl);
sign = (f64[7] >> 7) & 1;
/* First off, if the tag indicates the register was empty,
return 1,0,sign,1 */
if (tag == 0) {
/* vex_printf("Empty\n"); */
return FC_MASK_C3 | 0 | sign | FC_MASK_C0;
}
bexp = (f64[7] << 4) | ((f64[6] >> 4) & 0x0F);
bexp &= 0x7FF;
c1 = ((UInt)sign) << 9;
mantissaIsZero
= (f64[6] & 0x0F) == 0
&& (f64[5] | f64[4] | f64[3] | f64[2] | f64[1] | f64[0]) == 0;
/* If both exponent and mantissa are zero, the value is zero.
Return 1,0,sign,0. */
if (bexp == 0 && mantissaIsZero) {
/* vex_printf("Zero\n"); */
return FC_MASK_C3 | 0 | sign | 0;
}
/* If exponent is zero but mantissa isn't, it's a denormal.
Return 1,1,sign,0. */
if (bexp == 0 && !mantissaIsZero) {
/* vex_printf("Denormal\n"); */
return FC_MASK_C3 | FC_MASK_C2 | sign | 0;
}
/* If the exponent is 7FF and the mantissa is zero, this is an infinity.
Return 0,1,sign,1. */
if (bexp == 0x7FF && mantissaIsZero) {
/* vex_printf("Inf\n"); */
return 0 | FC_MASK_C2 | sign | FC_MASK_C0;
}
/* If the exponent is 7FF and the mantissa isn't zero, this is a NaN.
Return 0,0,sign,1. */
if (bexp == 0x7FF && !mantissaIsZero) {
/* vex_printf("NaN\n"); */
return 0 | 0 | sign | FC_MASK_C0;
}
/* Uh, ok, we give up. It must be a normal finite number.
Return 0,1,sign,0.
*/
/* vex_printf("normal\n"); */
return 0 | FC_MASK_C2 | sign | 0;
}
/* Convert a IEEE754 double (64-bit) into an x87 extended double
(80-bit), mimicing the hardware fairly closely. Both numbers are
stored little-endian. Limitations, all of which could be fixed,
given some level of hassle:
* Does not handle double precision denormals. As a result, values
with magnitudes less than 1e-308 are flushed to zero when they
need not be.
* Identity of NaNs is not preserved.
See comments in the code for more details.
*/
static void convert_f64le_to_f80le ( /*IN*/UChar* f64, /*OUT*/UChar* f80 )
{
Bool isInf;
Int bexp;
UChar sign;
sign = (f64[7] >> 7) & 1;
bexp = (f64[7] << 4) | ((f64[6] >> 4) & 0x0F);
bexp &= 0x7FF;
/* If the exponent is zero, either we have a zero or a denormal.
Produce a zero. This is a hack in that it forces denormals to
zero. Could do better. */
if (bexp == 0) {
f80[9] = sign << 7;
f80[8] = f80[7] = f80[6] = f80[5] = f80[4]
= f80[3] = f80[2] = f80[1] = f80[0] = 0;
return;
}
/* If the exponent is 7FF, this is either an Infinity, a SNaN or
QNaN, as determined by examining bits 51:0, thus:
0 ... 0 Inf
0X ... X SNaN
1X ... X QNaN
where at least one of the Xs is not zero.
*/
if (bexp == 0x7FF) {
isInf = (f64[6] & 0x0F) == 0
&& f64[5] == 0 && f64[4] == 0 && f64[3] == 0
&& f64[2] == 0 && f64[1] == 0 && f64[0] == 0;
if (isInf) {
/* Produce an appropriately signed infinity:
S 1--1 (15) 1 0--0 (63)
*/
f80[9] = (sign << 7) | 0x7F;
f80[8] = 0xFF;
f80[7] = 0x80;
f80[6] = f80[5] = f80[4] = f80[3]
= f80[2] = f80[1] = f80[0] = 0;
return;
}
/* So it's either a QNaN or SNaN. Distinguish by considering
bit 51. Note, this destroys all the trailing bits
(identity?) of the NaN. IEEE754 doesn't require preserving
these (it only requires that there be one QNaN value and one
SNaN value), but x87 does seem to have some ability to
preserve them. Anyway, here, the NaN's identity is
destroyed. Could be improved. */
if (f64[6] & 8) {
/* QNaN. Make a QNaN:
S 1--1 (15) 1 1--1 (63)
*/
f80[9] = (sign << 7) | 0x7F;
f80[8] = 0xFF;
f80[7] = 0xFF;
f80[6] = f80[5] = f80[4] = f80[3]
= f80[2] = f80[1] = f80[0] = 0xFF;
} else {
/* SNaN. Make a SNaN:
S 1--1 (15) 0 1--1 (63)
*/
f80[9] = (sign << 7) | 0x7F;
f80[8] = 0xFF;
f80[7] = 0x7F;
f80[6] = f80[5] = f80[4] = f80[3]
= f80[2] = f80[1] = f80[0] = 0xFF;
}
return;
}
/* It's not a zero, denormal, infinity or nan. So it must be a
normalised number. Rebias the exponent and build the new
number. */
bexp += (16383 - 1023);
f80[9] = (sign << 7) | ((bexp >> 8) & 0xFF);
f80[8] = bexp & 0xFF;
f80[7] = (1 << 7) | ((f64[6] << 3) & 0x78) | ((f64[5] >> 5) & 7);
f80[6] = ((f64[5] << 3) & 0xF8) | ((f64[4] >> 5) & 7);
f80[5] = ((f64[4] << 3) & 0xF8) | ((f64[3] >> 5) & 7);
f80[4] = ((f64[3] << 3) & 0xF8) | ((f64[2] >> 5) & 7);
f80[3] = ((f64[2] << 3) & 0xF8) | ((f64[1] >> 5) & 7);
f80[2] = ((f64[1] << 3) & 0xF8) | ((f64[0] >> 5) & 7);
f80[1] = ((f64[0] << 3) & 0xF8);
f80[0] = 0;
}
/////////////////////////////////////////////////////////////////
/* Convert a x87 extended double (80-bit) into an IEEE 754 double
(64-bit), mimicing the hardware fairly closely. Both numbers are
stored little-endian. Limitations, all of which could be fixed,
given some level of hassle:
* Does not create double precision denormals. As a result, values
with magnitudes less than 1e-308 are flushed to zero when they
need not be.
* Rounding following truncation could be a bit better.
* Identity of NaNs is not preserved.
See comments in the code for more details.
*/
static void convert_f80le_to_f64le ( /*IN*/UChar* f80, /*OUT*/UChar* f64 )
{
Bool isInf;
Int bexp;
UChar sign;
sign = (f80[9] >> 7) & 1;
bexp = (((UInt)f80[9]) << 8) | (UInt)f80[8];
bexp &= 0x7FFF;
/* If the exponent is zero, either we have a zero or a denormal.
But an extended precision denormal becomes a double precision
zero, so in either case, just produce the appropriately signed
zero. */
if (bexp == 0) {
f64[7] = sign << 7;
f64[6] = f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0;
return;
}
/* If the exponent is 7FFF, this is either an Infinity, a SNaN or
QNaN, as determined by examining bits 62:0, thus:
0 ... 0 Inf
0X ... X SNaN
1X ... X QNaN
where at least one of the Xs is not zero.
*/
if (bexp == 0x7FFF) {
isInf = (f80[7] & 0x7F) == 0
&& f80[6] == 0 && f80[5] == 0 && f80[4] == 0
&& f80[3] == 0 && f80[2] == 0 && f80[1] == 0 && f80[0] == 0;
if (isInf) {
if (0 == (f80[7] & 0x80))
goto wierd_NaN;
/* Produce an appropriately signed infinity:
S 1--1 (11) 0--0 (52)
*/
f64[7] = (sign << 7) | 0x7F;
f64[6] = 0xF0;
f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0;
return;
}
/* So it's either a QNaN or SNaN. Distinguish by considering
bit 62. Note, this destroys all the trailing bits
(identity?) of the NaN. IEEE754 doesn't require preserving
these (it only requires that there be one QNaN value and one
SNaN value), but x87 does seem to have some ability to
preserve them. Anyway, here, the NaN's identity is
destroyed. Could be improved. */
if (f80[8] & 0x40) {
/* QNaN. Make a QNaN:
S 1--1 (11) 1 1--1 (51)
*/
f64[7] = (sign << 7) | 0x7F;
f64[6] = 0xFF;
f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0xFF;
} else {
/* SNaN. Make a SNaN:
S 1--1 (11) 0 1--1 (51)
*/
f64[7] = (sign << 7) | 0x7F;
f64[6] = 0xF7;
f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0xFF;
}
return;
}
/* If it's not a Zero, NaN or Inf, and the integer part (bit 62) is
zero, the x87 FPU appears to consider the number denormalised
and converts it to a QNaN. */
if (0 == (f80[7] & 0x80)) {
wierd_NaN:
/* Strange hardware QNaN:
S 1--1 (11) 1 0--0 (51)
*/
/* On a PIII, these QNaNs always appear with sign==1. I have
no idea why. */
f64[7] = (1 /*sign*/ << 7) | 0x7F;
f64[6] = 0xF8;
f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0;
return;
}
/* It's not a zero, denormal, infinity or nan. So it must be a
normalised number. Rebias the exponent and consider. */
bexp -= (16383 - 1023);
if (bexp >= 0x7FF) {
/* It's too big for a double. Construct an infinity. */
f64[7] = (sign << 7) | 0x7F;
f64[6] = 0xF0;
f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0;
return;
}
if (bexp < 0) {
/* It's too small for a double. Construct a zero. Note, this
is a kludge since we could conceivably create a
denormalised number for bexp in -1 to -51, but we don't
bother. This means the conversion flushes values
approximately in the range 1e-309 to 1e-324 ish to zero
when it doesn't actually need to. This could be
improved. */
f64[7] = sign << 7;
f64[6] = f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0;
return;
}
/* Ok, it's a normalised number which is representable as a double.
Copy the exponent and mantissa into place. */
/*
for (i = 0; i < 52; i++)
write_bit_array ( f64,
i,
read_bit_array ( f80, i+11 ) );
*/
f64[0] = (f80[1] >> 3) | (f80[2] << 5);
f64[1] = (f80[2] >> 3) | (f80[3] << 5);
f64[2] = (f80[3] >> 3) | (f80[4] << 5);
f64[3] = (f80[4] >> 3) | (f80[5] << 5);
f64[4] = (f80[5] >> 3) | (f80[6] << 5);
f64[5] = (f80[6] >> 3) | (f80[7] << 5);
f64[6] = ((bexp << 4) & 0xF0) | ((f80[7] >> 3) & 0x0F);
f64[7] = (sign << 7) | ((bexp >> 4) & 0x7F);
/* Now consider any rounding that needs to happen as a result of
truncating the mantissa. */
if (f80[1] & 4) /* read_bit_array(f80, 10) == 1) */ {
/* Round upwards. This is a kludge. Once in every 64k
roundings (statistically) the bottom two bytes are both 0xFF
and so we don't round at all. Could be improved. */
if (f64[0] != 0xFF) {
f64[0]++;
}
else
if (f64[0] == 0xFF && f64[1] != 0xFF) {
f64[0] = 0;
f64[1]++;
}
/* else we don't round, but we should. */
}
}
/* CALLED FROM GENERATED CODE */
/* DIRTY HELPER (reads guest memory) */
static ULong loadF80le ( UInt addrU )
{
ULong f64;
convert_f80le_to_f64le ( (UChar*)addrU, (UChar*)&f64 );
return f64;
}
/* CALLED FROM GENERATED CODE */
/* DIRTY HELPER (writes guest memory) */
static void storeF80le ( UInt addrU, ULong f64 )
{
convert_f64le_to_f80le( (UChar*)&f64, (UChar*)addrU );
}
/*----------------------------------------------*/
/*--- The exported fns .. ---*/
/*----------------------------------------------*/
/* Layout of the real x87 state. */
typedef
struct {
UShort env[14];
UChar reg[80];
}
Fpu_State;
/* Offsets, in 16-bit ints, into the FPU environment (env) area. */
#define FP_ENV_CTRL 0
#define FP_ENV_STAT 2
#define FP_ENV_TAG 4
#define FP_ENV_IP 6 /* and 7 */
#define FP_ENV_CS 8
#define FP_ENV_OPOFF 10 /* and 11 */
#define FP_ENV_OPSEL 12
#define FP_REG(ii) (10*(7-(ii)))
/* VISIBLE TO LIBVEX CLIENT */
void x87_to_vex ( /*IN*/UChar* x87_state,
/*OUT*/VexGuestX86State* vex_state )
{
Int r;
UInt tag;
Double* vexRegs = (Double*)(&vex_state->guest_FPREG[0]);
UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
Fpu_State* x87 = (Fpu_State*)x87_state;
UInt ftop = (x87->env[FP_ENV_STAT] >> 11) & 7;
UInt tagw = x87->env[FP_ENV_TAG];
UInt fpucw = x87->env[FP_ENV_CTRL];
UInt c3210 = x87->env[FP_ENV_STAT] & 0x4700;
/* Copy registers and tags */
for (r = 0; r < 8; r++) {
tag = (tagw >> (2*r)) & 3;
if (tag == 3) {
/* register is empty */
vexRegs[r] = 0.0;
vexTags[r] = 0;
} else {
/* register is non-empty */
convert_f80le_to_f64le( &x87->reg[FP_REG(r)], (UChar*)&vexRegs[r] );
vexTags[r] = 1;
}
}
/* stack pointer */
vex_state->guest_FTOP = ftop;
/* control word */
vex_state->guest_FPUCW = fpucw;
/* status word */
vex_state->guest_FC3210 = c3210;
}
/* VISIBLE TO LIBVEX CLIENT */
void vex_to_x87 ( /*IN*/VexGuestX86State* vex_state,
/*OUT*/UChar* x87_state )
{
Int i, r;
UInt tagw;
Double* vexRegs = (Double*)(&vex_state->guest_FPREG[0]);
UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
Fpu_State* x87 = (Fpu_State*)x87_state;
UInt ftop = vex_state->guest_FTOP;
UInt c3210 = vex_state->guest_FC3210;
for (i = 0; i < 14; i++)
x87->env[i] = 0;
x87->env[1] = x87->env[3] = x87->env[5] = x87->env[13] = 0xFFFF;
x87->env[FP_ENV_CTRL] = (UShort)( vex_state->guest_FPUCW );
x87->env[FP_ENV_STAT] = ((ftop & 7) << 11) | (c3210 & 0x4700);
tagw = 0;
for (r = 0; r < 8; r++) {
if (vexTags[r] == 0) {
/* register is empty */
tagw |= (3 << (2*r));
convert_f64le_to_f80le( (UChar*)&vexRegs[r], &x87->reg[FP_REG(r)] );
} else {
/* register is full. */
tagw |= (0 << (2*r));
convert_f64le_to_f80le( (UChar*)&vexRegs[r], &x87->reg[FP_REG(r)] );
}
}
x87->env[FP_ENV_TAG] = tagw;
}
/* VISIBLE TO LIBVEX CLIENT */
void eflags_to_vex ( UInt eflags_native,
/*OUT*/VexGuestX86State* vex_state )
{
vex_state->guest_DFLAG
= (eflags_native & (1<<10)) ? 0xFFFFFFFF : 0x00000001;
/* Mask out everything except O S Z A C P. */
eflags_native
&= (CC_MASK_C | CC_MASK_P | CC_MASK_A
| CC_MASK_Z | CC_MASK_S | CC_MASK_O);
vex_state->guest_CC_OP = CC_OP_COPY;
vex_state->guest_CC_DST = 0;
vex_state->guest_CC_DST = eflags_native;
}
/* VISIBLE TO LIBVEX CLIENT */
UInt vex_to_eflags ( /*IN*/VexGuestX86State* vex_state )
{
UInt eflags = calculate_eflags_all(
vex_state->guest_CC_OP,
vex_state->guest_CC_SRC,
vex_state->guest_CC_DST
);
UInt dflag = vex_state->guest_DFLAG;
vassert(dflag == 1 || dflag == 0xFFFFFFFF);
if (dflag == 0xFFFFFFFF)
eflags |= (1<<10);
return eflags;
}
/* VISIBLE TO LIBVEX CLIENT */
void vex_initialise_x87 ( /* MOD*/VexGuestX86State* vex_state )
{
Int i;
for (i = 0; i < 8; i++) {
vex_state->guest_FPTAG[i] = 0; /* empty */
vex_state->guest_FPREG[i] = 0; /* IEEE754 64-bit zero */
}
vex_state->guest_FTOP = 0;
vex_state->guest_FC3210 = 0;
/* The default setting: all fp exceptions masked, rounding to
nearest, precision to 64 bits */
vex_state->guest_FPUCW = 0x03F7;
}
/*---------------------------------------------------------------*/
/*--- end guest-x86/ghelpers.c ---*/
/*---------------------------------------------------------------*/