/*---------------------------------------------------------*/
/* --- CLEAN HELPERS --- */
-extern UInt calculate_eflags_all ( UInt cc_op, UInt cc_res, UInt cc_aux );
-extern UInt calculate_eflags_c ( UInt cc_op, UInt cc_res, UInt cc_aux );
+
+extern UInt calculate_eflags_all ( UInt cc_op,
+ UInt cc_dep1, UInt cc_dep2, UInt cc_ndep );
+
+extern UInt calculate_eflags_c ( UInt cc_op,
+ UInt cc_dep1, UInt cc_dep2, UInt cc_ndep );
+
extern UInt calculate_condition ( UInt/*Condcode*/ cond,
- UInt cc_op, UInt cc_res, UInt cc_aux );
+ UInt cc_op,
+ UInt cc_dep1, UInt cc_dep2, UInt cc_ndep );
+
extern UInt calculate_FXAM ( UInt tag, ULong dbl );
+
extern ULong calculate_RCR ( UInt arg, UInt rot_amt, UInt eflags_in, UInt sz );
/* --- DIRTY HELPERS --- */
+
extern ULong loadF80le ( UInt );
+
extern void storeF80le ( UInt, ULong );
+
extern void dirtyhelper_CPUID ( VexGuestX86State* );
#define FC_MASK_C1 (1 << 9)
#define FC_MASK_C0 (1 << 8)
-/* %EFLAGS thunk descriptors. This encoding is slightly non-obvious,
- for the benefit of Memcheck. The intention is to make RES be the
- actual operation result -- or, in the case of multiply longs, at
- least have a complete data dependency on the real result. That
- means that the AUX field needs to carry -- in the case of {S,U}MULL
- -- a value which allows the real result to be recovered from the
- RES field.
-
- Note, for cases in which some or all of the old flags are also an
- input (INC, DEC, ROL, ROR) we could have chosen to xor in the old
- flags into the RES field. The effect would be that Memcheck then
- considers the result of the operation to also be dependent on the
- definedness of the old flags. This seems a step too far -- if the
- compiler creates conditional jumps/moves partially dependent on
- flags it is unsure of the definedness of -- then it is generating
- buggy code. So we don't do this.
-
- In short, we need to roll into the RES field all inputs to the
- computation that we want Memcheck to think have a bearing on the
- definedness of the result. We then tell Memcheck that only the RES
- field needs to have its definedness tracked, and the AUX and OP
- fields can be ignored. The upshot is that we need to put in the
- AUX field whatever info is needed to actually compute the flags
- given the potentially strange mixture of stuff in the RES field.
+/* %EFLAGS thunk descriptors. A four-word thunk is used to record
+ details of the most recent flag-setting operation, so the flags can
+ be computed later if needed. It is possible to do this a little
+ more efficiently using a 3-word thunk, but that makes it impossible
+ to describe the flag data dependencies sufficiently accurately for
+ Memcheck. Hence 4 words are used, with minimal loss of efficiency.
+
+ The four words are:
+
+ CC_OP, which describes the operation.
+
+ CC_DEP1 and CC_DEP2. These are arguments to the operation.
+ We want Memcheck to believe that the resulting flags are
+ data-dependent on both CC_DEP1 and CC_DEP2, hence the
+ name DEP.
+
+ CC_NDEP. This is a 3rd argument to the operation which is
+ sometimes needed. We arrange things so that Memcheck does
+ not believe the resulting flags are data-dependent on CC_NDEP
+ ("not dependent").
+
+ To make Memcheck believe that (the definedness of) the encoded
+ flags depends only on (the definedness of) CC_DEP1 and CC_DEP2
+ requires two things:
+
+ (1) In the guest state layout info (x86guest_layout), CC_OP and
+ CC_NDEP are marked as always defined.
+
+ (2) When passing the thunk components to an evaluation function
+ (calculate_condition, calculate_eflags, calculate_eflags_c) the
+ IRCallee's mcx_mask must be set so as to exclude from
+ consideration all passed args except CC_DEP1 and CC_DEP2.
+
+ Strictly speaking only (2) is necessary for correctness. However,
+ (1) helps efficiency in that since (2) means we never ask about the
+ definedness of CC_OP or CC_NDEP, we may as well not even bother to
+ track their definedness.
+
+ When building the thunk, it is always necessary to write words into
+ CC_DEP1 and CC_DEP2, even if those args are not used given the
+ CC_OP field (eg, CC_DEP2 is not used if CC_OP is CC_LOGIC1/2/4).
+ This is important because otherwise Memcheck could give false
+ positives as it does not understand the relationship between the
+ CC_OP field and CC_DEP1 and CC_DEP2, and so believes that the
+ definedness of the stored flags always depends on both CC_DEP1 and
+ CC_DEP2.
+
+ However, it is only necessary to set CC_NDEP when the CC_OP value
+ requires it, because Memcheck ignores CC_NDEP, and the evaluation
+ functions do understand the CC_OP fields and will only examine
+ CC_NDEP for suitable values of CC_OP.
+
+ A summary of the field usages is:
+
+ Operation DEP1 DEP2 NDEP
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ add/sub/mul first arg second arg unused
+
+ adc/sbb first arg (second arg)
+ XOR old_carry old_carry
+
+ and/or/xor result zero unused
+
+ inc/dec result zero old_carry
+
+ shl/shr/sar result subshifted- unused
+ result
+
+ rol/ror result zero old_flags
+
+ copy old_flags zero unused.
+
+
+ Therefore Memcheck will believe the following:
+
+ * add/sub/mul -- definedness of result flags depends on definedness
+ of both args.
+
+ * adc/sbb -- definedness of result flags depends on definedness of
+ both args and definedness of the old C flag. Because only two
+ DEP fields are available, the old C flag is XOR'd into the second
+ arg so that Memcheck sees the data dependency on it. That means
+ the NDEP field must contain a second copy of the old C flag
+ so that the evaluation functions can correctly recover the second
+ arg.
+
+ * and/or/xor are straightforward -- definedness of result flags
+ depends on definedness of result value.
+
+ * inc/dec -- definedness of result flags depends only on
+ definedness of result. This isn't really true -- it also depends
+ on the old C flag. However, we don't want Memcheck to see that,
+ and so the old C flag must be passed in NDEP and not in DEP2.
+ It's inconceivable that a compiler would generate code that puts
+ the C flag in an undefined state, then does an inc/dec, which
+ leaves C unchanged, and then makes a conditional jump/move based
+ on C. So our fiction seems a good approximation.
+
+ * shl/shr/sar -- straightforward, again, definedness of result
+ flags depends on definedness of result value. The subshifted
+ value (value shifted one less) is also needed, but its
+ definedness is the same as the definedness of the shifted value.
+
+ * rol/ror -- these only set O and C, and leave A Z C P alone.
+ However it seems prudent (as per inc/dec) to say the definedness
+ of all resulting flags depends on the definedness of the result,
+ hence the old flags must go in as NDEP and not DEP2.
+
+ * rcl/rcr are too difficult to do in-line, and so are done by a
+ helper function. They are not part of this scheme. The helper
+ function takes the value to be rotated, the rotate amount and the
+ old flags, and returns the new flags and the rotated value.
+ Since the helper's mcx_mask does not have any set bits, Memcheck
+ will lazily propagate undefinedness from any of the 3 args into
+ both results (flags and actual value).
*/
enum {
- CC_OP_COPY, /* RES = current flags, AUX = 0, do nothing */
+ CC_OP_COPY, /* DEP1 = current flags, DEP2 = 0, NDEP = unused */
+ /* just copy DEP1 to output */
- CC_OP_ADDB, /* RES = argL+argR, AUX = argR */
- CC_OP_ADDW,
+ CC_OP_ADDB, /* 1 */
+ CC_OP_ADDW, /* 2 DEP1 = argL, DEP2 = argR, NDEP = unused */
CC_OP_ADDL, /* 3 */
- CC_OP_ADCB, /* RES = argL+argR, AUX = argR */
- CC_OP_ADCW,
- CC_OP_ADCL, /* 6 */
+ CC_OP_SUBB, /* 4 */
+ CC_OP_SUBW, /* 5 DEP1 = argL, DEP2 = argR, NDEP = unused */
+ CC_OP_SUBL, /* 6 */
- CC_OP_SUBB, /* RES = argL-argR, AUX = argR */
- CC_OP_SUBW,
- CC_OP_SUBL, /* 9 */
+ CC_OP_ADCB, /* 7 */
+ CC_OP_ADCW, /* 8 DEP1 = argL, DEP2 = argR ^ oldCarry, NDEP = oldCarry */
+ CC_OP_ADCL, /* 9 */
- CC_OP_SBBB, /* RES = argL-argR, AUX = argR */
- CC_OP_SBBW,
+ CC_OP_SBBB, /* 10 */
+ CC_OP_SBBW, /* 11 DEP1 = argL, DEP2 = argR ^ oldCarry, NDEP = oldCarry */
CC_OP_SBBL, /* 12 */
- CC_OP_LOGICB, /* RES = and/or/xor(argL,argR), AUX = 0 */
- CC_OP_LOGICW,
+ CC_OP_LOGICB, /* 13 */
+ CC_OP_LOGICW, /* 14 DEP1 = result, DEP2 = 0, NDEP = unused */
CC_OP_LOGICL, /* 15 */
- CC_OP_INCB, /* RES = arg+1, AUX = old C flag (0 or 1) */
- CC_OP_INCW,
+ CC_OP_INCB, /* 16 */
+ CC_OP_INCW, /* 17 DEP1 = result, DEP2 = 0, NDEP = oldCarry (0 or 1) */
CC_OP_INCL, /* 18 */
- CC_OP_DECB, /* RES = arg-1, AUX = old C flag (0 or 1) */
- CC_OP_DECW,
+ CC_OP_DECB, /* 19 */
+ CC_OP_DECW, /* 20 DEP1 = result, DEP2 = 0, NDEP = oldCarry (0 or 1) */
CC_OP_DECL, /* 21 */
- CC_OP_SHLB, /* RES = res, AUX = res' */
- CC_OP_SHLW, /* where res' is like res but shifted one bit less */
+ CC_OP_SHLB, /* 22 DEP1 = res, DEP2 = res', NDEP = unused */
+ CC_OP_SHLW, /* 23 where res' is like res but shifted one bit less */
CC_OP_SHLL, /* 24 */
- CC_OP_SARB, /* RES = res, AUX = res' */
- CC_OP_SARW, /* where res' is like res but shifted one bit less */
- CC_OP_SARL, /* 27 */
+ CC_OP_SHRB, /* 25 DEP1 = res, DEP2 = res', NDEP = unused */
+ CC_OP_SHRW, /* 26 where res' is like res but shifted one bit less */
+ CC_OP_SHRL, /* 27 */
- CC_OP_ROLB, /* RES = res, AUX = old flags */
- CC_OP_ROLW,
+ CC_OP_ROLB, /* 28 */
+ CC_OP_ROLW, /* 29 DEP1 = res, DEP2 = 0, NDEP = old flags */
CC_OP_ROLL, /* 30 */
- CC_OP_RORB, /* RES = res, AUX = old flags */
- CC_OP_RORW,
+ CC_OP_RORB, /* 31 */
+ CC_OP_RORW, /* 32 DEP1 = res, DEP2 = 0, NDEP = old flags */
CC_OP_RORL, /* 33 */
- CC_OP_UMULB, /* RES = hiHalf(result) ^ loHalf(result) */
- CC_OP_UMULW, /* AUX = loHalf(result) */
+ CC_OP_UMULB, /* 34 */
+ CC_OP_UMULW, /* 35 DEP1 = argL, DEP2 = argR, NDEP = unused */
CC_OP_UMULL, /* 36 */
- CC_OP_SMULB, /* RES = hiHalf(result) ^ loHalf(result) */
- CC_OP_SMULW, /* AUX = loHalf(result) */
+ CC_OP_SMULB, /* 37 */
+ CC_OP_SMULW, /* 38 DEP1 = argL, DEP2 = argR, NDEP = unused */
CC_OP_SMULL, /* 39 */
CC_OP_NUMBER
: (__data_bits==16 ? 0xFFFF \
: 0xFFFFFFFF); \
/* const */ UInt SIGN_MASK = 1 << (__data_bits - 1); \
- /* const */ UInt CC_RES = cc_res_formal; \
- /* const */ UInt CC_AUX = cc_aux_formal; \
- /* Three bogus assignments, which hopefully gcc can */ \
+ /* const */ UInt CC_DEP1 = cc_dep1_formal; \
+ /* const */ UInt CC_DEP2 = cc_dep2_formal; \
+ /* const */ UInt CC_NDEP = cc_ndep_formal; \
+ /* Four 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_AUX = CC_AUX;
+ CC_DEP2 = CC_DEP2; \
+ CC_NDEP = CC_NDEP;
/*-------------------------------------------------------------*/
PREAMBLE(DATA_BITS); \
Int cf, pf, af, zf, sf, of; \
Int argL, argR, res; \
- argL = CC_RES - CC_AUX; \
- argR = CC_AUX; \
- res = CC_RES; \
+ argL = CC_DEP1; \
+ argR = CC_DEP2; \
+ res = argL + argR; \
cf = (DATA_UTYPE)res < (DATA_UTYPE)argL; \
pf = parity_table[(UChar)res]; \
af = (res ^ argL ^ argR) & 0x10; \
/*-------------------------------------------------------------*/
-#define ACTIONS_ADC(DATA_BITS,DATA_UTYPE) \
+#define ACTIONS_SUB(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
Int cf, pf, af, zf, sf, of; \
Int argL, argR, res; \
- argL = CC_RES - CC_AUX - 1; \
- argR = CC_AUX; \
- res = CC_RES; \
- cf = (DATA_UTYPE)res <= (DATA_UTYPE)argL; \
+ argL = CC_DEP1; \
+ argR = CC_DEP2; \
+ res = argL - argR; \
+ cf = (DATA_UTYPE)argL < (DATA_UTYPE)argR; \
pf = parity_table[(UChar)res]; \
af = (res ^ argL ^ argR) & 0x10; \
zf = ((DATA_UTYPE)res == 0) << 6; \
sf = lshift(res, 8 - DATA_BITS) & 0x80; \
- of = lshift((argL ^ argR ^ -1) & (argL ^ res), \
- 12 - DATA_BITS) & CC_MASK_O; \
+ of = lshift((argL ^ argR) & (argL ^ res), \
+ 12 - DATA_BITS) & CC_MASK_O; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
-#define ACTIONS_SUB(DATA_BITS,DATA_UTYPE) \
+#define ACTIONS_ADC(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
Int cf, pf, af, zf, sf, of; \
- Int argL, argR, res; \
- argL = CC_RES + CC_AUX; \
- argR = CC_AUX; \
- res = CC_RES; \
- cf = (DATA_UTYPE)argL < (DATA_UTYPE)argR; \
+ Int argL, argR, oldC, res; \
+ oldC = CC_NDEP & CC_MASK_C; \
+ argL = CC_DEP1; \
+ argR = CC_DEP2 ^ oldC; \
+ res = (argL + argR) + oldC; \
+ if (oldC) \
+ cf = (DATA_UTYPE)res <= (DATA_UTYPE)argL; \
+ else \
+ cf = (DATA_UTYPE)res < (DATA_UTYPE)argL; \
pf = parity_table[(UChar)res]; \
af = (res ^ argL ^ argR) & 0x10; \
zf = ((DATA_UTYPE)res == 0) << 6; \
sf = lshift(res, 8 - DATA_BITS) & 0x80; \
- of = lshift((argL ^ argR) & (argL ^ res), \
- 12 - DATA_BITS) & CC_MASK_O; \
+ of = lshift((argL ^ argR ^ -1) & (argL ^ res), \
+ 12 - DATA_BITS) & CC_MASK_O; \
return cf | pf | af | zf | sf | of; \
}
{ \
PREAMBLE(DATA_BITS); \
Int cf, pf, af, zf, sf, of; \
- Int argL, argR, res; \
- argL = CC_RES + CC_AUX + 1; \
- argR = CC_AUX; \
- res = CC_RES; \
- cf = (DATA_UTYPE)argL <= (DATA_UTYPE)argR; \
+ Int argL, argR, oldC, res; \
+ oldC = CC_NDEP & CC_MASK_C; \
+ argL = CC_DEP1; \
+ argR = CC_DEP2 ^ oldC; \
+ res = (argL - argR) - oldC; \
+ if (oldC) \
+ cf = (DATA_UTYPE)argL <= (DATA_UTYPE)argR; \
+ else \
+ cf = (DATA_UTYPE)argL < (DATA_UTYPE)argR; \
pf = parity_table[(UChar)res]; \
af = (res ^ argL ^ argR) & 0x10; \
zf = ((DATA_UTYPE)res == 0) << 6; \
PREAMBLE(DATA_BITS); \
Int cf, pf, af, zf, sf, of; \
cf = 0; \
- pf = parity_table[(UChar)CC_RES]; \
+ pf = parity_table[(UChar)CC_DEP1]; \
af = 0; \
- zf = ((DATA_UTYPE)CC_RES == 0) << 6; \
- sf = lshift(CC_RES, 8 - DATA_BITS) & 0x80; \
+ zf = ((DATA_UTYPE)CC_DEP1 == 0) << 6; \
+ sf = lshift(CC_DEP1, 8 - DATA_BITS) & 0x80; \
of = 0; \
return cf | pf | af | zf | sf | of; \
}
{ \
PREAMBLE(DATA_BITS); \
Int cf, pf, af, zf, sf, of; \
- Int argL, argR; \
- argL = CC_RES - 1; \
+ Int argL, argR, res; \
+ res = CC_DEP1; \
+ argL = res - 1; \
argR = 1; \
- cf = CC_AUX & CC_MASK_C; \
- pf = parity_table[(UChar)CC_RES]; \
- af = (CC_RES ^ argL ^ argR) & 0x10; \
- zf = ((DATA_UTYPE)CC_RES == 0) << 6; \
- sf = lshift(CC_RES, 8 - DATA_BITS) & 0x80; \
- of = ((CC_RES & DATA_MASK) == SIGN_MASK) << 11; \
+ cf = CC_NDEP & CC_MASK_C; \
+ pf = parity_table[(UChar)res]; \
+ af = (res ^ argL ^ argR) & 0x10; \
+ zf = ((DATA_UTYPE)res == 0) << 6; \
+ sf = lshift(res, 8 - DATA_BITS) & 0x80; \
+ of = ((res & DATA_MASK) == SIGN_MASK) << 11; \
return cf | pf | af | zf | sf | of; \
}
{ \
PREAMBLE(DATA_BITS); \
Int cf, pf, af, zf, sf, of; \
- Int argL, argR; \
- argL = CC_RES + 1; \
+ Int argL, argR, res; \
+ res = CC_DEP1; \
+ argL = res + 1; \
argR = 1; \
- cf = CC_AUX & CC_MASK_C; \
- pf = parity_table[(UChar)CC_RES]; \
- af = (CC_RES ^ argL ^ argR) & 0x10; \
- zf = ((DATA_UTYPE)CC_RES == 0) << 6; \
- sf = lshift(CC_RES, 8 - DATA_BITS) & 0x80; \
- of = ((CC_RES & DATA_MASK) \
+ cf = CC_NDEP & CC_MASK_C; \
+ pf = parity_table[(UChar)res]; \
+ af = (res ^ argL ^ argR) & 0x10; \
+ zf = ((DATA_UTYPE)res == 0) << 6; \
+ sf = lshift(res, 8 - DATA_BITS) & 0x80; \
+ of = ((res & DATA_MASK) \
== ((UInt)SIGN_MASK - 1)) << 11; \
return cf | pf | af | zf | sf | of; \
}
{ \
PREAMBLE(DATA_BITS); \
Int cf, pf, af, zf, sf, of; \
- cf = (CC_AUX >> (DATA_BITS - 1)) & CC_MASK_C; \
- pf = parity_table[(UChar)CC_RES]; \
+ cf = (CC_DEP2 >> (DATA_BITS - 1)) & CC_MASK_C; \
+ pf = parity_table[(UChar)CC_DEP1]; \
af = 0; /* undefined */ \
- zf = ((DATA_UTYPE)CC_RES == 0) << 6; \
- sf = lshift(CC_RES, 8 - DATA_BITS) & 0x80; \
+ zf = ((DATA_UTYPE)CC_DEP1 == 0) << 6; \
+ sf = lshift(CC_DEP1, 8 - DATA_BITS) & 0x80; \
/* of is defined if shift count == 1 */ \
- of = lshift(CC_AUX ^ CC_RES, 12 - DATA_BITS) & CC_MASK_O; \
+ of = lshift(CC_DEP2 ^ CC_DEP1, 12 - DATA_BITS) & CC_MASK_O; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
-#define ACTIONS_SAR(DATA_BITS,DATA_UTYPE) \
+#define ACTIONS_SHR(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
Int cf, pf, af, zf, sf, of; \
- cf = CC_AUX & 1; \
- pf = parity_table[(UChar)CC_RES]; \
+ cf = CC_DEP2 & 1; \
+ pf = parity_table[(UChar)CC_DEP1]; \
af = 0; /* undefined */ \
- zf = ((DATA_UTYPE)CC_RES == 0) << 6; \
- sf = lshift(CC_RES, 8 - DATA_BITS) & 0x80; \
+ zf = ((DATA_UTYPE)CC_DEP1 == 0) << 6; \
+ sf = lshift(CC_DEP1, 8 - DATA_BITS) & 0x80; \
/* of is defined if shift count == 1 */ \
- of = lshift(CC_AUX ^ CC_RES, 12 - DATA_BITS) & CC_MASK_O; \
+ of = lshift(CC_DEP2 ^ CC_DEP1, 12 - DATA_BITS) & CC_MASK_O; \
return cf | pf | af | zf | sf | of; \
}
/*-------------------------------------------------------------*/
/* ROL: cf' = lsb(result). of' = msb(result) ^ lsb(result). */
-/* DST = result, SRC = old flags */
+/* DEP1 = result, NDEP = old flags */
#define ACTIONS_ROL(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
Int fl \
- = (CC_AUX & ~(CC_MASK_O | CC_MASK_C)) \
- | (CC_MASK_C & CC_RES) \
- | (CC_MASK_O & (lshift(CC_RES, 11-(DATA_BITS-1)) \
- ^ lshift(CC_RES, 11))); \
+ = (CC_NDEP & ~(CC_MASK_O | CC_MASK_C)) \
+ | (CC_MASK_C & CC_DEP1) \
+ | (CC_MASK_O & (lshift(CC_DEP1, 11-(DATA_BITS-1)) \
+ ^ lshift(CC_DEP1, 11))); \
return fl; \
}
/*-------------------------------------------------------------*/
/* ROR: cf' = msb(result). of' = msb(result) ^ msb-1(result). */
-/* DST = result, SRC = old flags */
+/* DEP1 = result, NDEP = old flags */
#define ACTIONS_ROR(DATA_BITS,DATA_UTYPE) \
{ \
PREAMBLE(DATA_BITS); \
Int fl \
- = (CC_AUX & ~(CC_MASK_O | CC_MASK_C)) \
- | (CC_MASK_C & (CC_RES >> (DATA_BITS-1))) \
- | (CC_MASK_O & (lshift(CC_RES, 11-(DATA_BITS-1)) \
- ^ lshift(CC_RES, 11-(DATA_BITS-1)+1))); \
+ = (CC_NDEP & ~(CC_MASK_O | CC_MASK_C)) \
+ | (CC_MASK_C & (CC_DEP1 >> (DATA_BITS-1))) \
+ | (CC_MASK_O & (lshift(CC_DEP1, 11-(DATA_BITS-1)) \
+ ^ lshift(CC_DEP1, 11-(DATA_BITS-1)+1))); \
return fl; \
}
/*-------------------------------------------------------------*/
-#define ACTIONS_UMUL(DATA_BITS,DATA_UTYPE) \
-{ \
- PREAMBLE(DATA_BITS); \
- Int cf, pf, af, zf, sf, of; \
- DATA_UTYPE resHi = DATA_MASK & (CC_RES ^ CC_AUX); \
- DATA_UTYPE resLo = DATA_MASK & CC_AUX; \
- cf = (resHi != 0); \
- pf = parity_table[(UChar)resLo]; \
- af = 0; /* undefined */ \
- zf = (resLo == 0) << 6; \
- sf = lshift(resLo, 8 - DATA_BITS) & 0x80; \
- of = cf << 11; \
- return cf | pf | af | zf | sf | of; \
+#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_DEP1) \
+ * ((DATA_UTYPE)CC_DEP2); \
+ DATA_U2TYPE rr = ((DATA_U2TYPE)((DATA_UTYPE)CC_DEP1)) \
+ * ((DATA_U2TYPE)((DATA_UTYPE)CC_DEP2)); \
+ hi = (DATA_UTYPE)(rr >>/*u*/ DATA_BITS); \
+ cf = (hi != 0); \
+ pf = parity_table[(UChar)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) \
-{ \
- PREAMBLE(DATA_BITS); \
- Int cf, pf, af, zf, sf, of; \
- DATA_STYPE resHi = DATA_MASK & (CC_RES ^ CC_AUX); \
- DATA_STYPE resLo = DATA_MASK & CC_AUX; \
- cf = (resHi != (resLo >>/*s*/ (DATA_BITS-1))); \
- pf = parity_table[(UChar)resLo]; \
- af = 0; /* undefined */ \
- zf = (resLo == 0) << 6; \
- sf = lshift(resLo, 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_DEP1) \
+ * ((DATA_STYPE)CC_DEP2); \
+ DATA_S2TYPE rr = ((DATA_S2TYPE)((DATA_STYPE)CC_DEP1)) \
+ * ((DATA_S2TYPE)((DATA_STYPE)CC_DEP2)); \
+ hi = (DATA_STYPE)(rr >>/*s*/ DATA_BITS); \
+ cf = (hi != (lo >>/*s*/ (DATA_BITS-1))); \
+ pf = parity_table[(UChar)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];
/* CALLED FROM GENERATED CODE: CLEAN HELPER */
/* Calculate all the 6 flags from the supplied thunk parameters. */
-UInt calculate_eflags_all ( UInt cc_op, UInt cc_res_formal, UInt cc_aux_formal )
+UInt calculate_eflags_all ( UInt cc_op,
+ UInt cc_dep1_formal,
+ UInt cc_dep2_formal,
+ UInt cc_ndep_formal )
{
# if PROFILE_EFLAGS
n_calc_all++;
# endif
switch (cc_op) {
case CC_OP_COPY:
- return cc_res_formal
+ return cc_dep1_formal
& (CC_MASK_O | CC_MASK_S | CC_MASK_Z
| CC_MASK_A | CC_MASK_C | CC_MASK_P);
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_SHRB: ACTIONS_SHR( 8, UChar );
+ case CC_OP_SHRW: ACTIONS_SHR( 16, UShort );
+ case CC_OP_SHRL: ACTIONS_SHR( 32, UInt );
case CC_OP_ROLB: ACTIONS_ROL( 8, UChar );
case CC_OP_ROLW: ACTIONS_ROL( 16, UShort );
case CC_OP_RORW: ACTIONS_ROR( 16, UShort );
case CC_OP_RORL: ACTIONS_ROR( 32, UInt );
- case CC_OP_UMULB: ACTIONS_UMUL( 8, UChar );
- case CC_OP_UMULW: ACTIONS_UMUL( 16, UShort );
- case CC_OP_UMULL: ACTIONS_UMUL( 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 );
- case CC_OP_SMULW: ACTIONS_SMUL( 16, Short );
- case CC_OP_SMULL: ACTIONS_SMUL( 32, Int );
+ 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_res_formal, cc_res_formal );
+ vex_printf("calculate_eflags_all( %d, 0x%x, 0x%x, 0x%x )\n",
+ cc_op, cc_dep1_formal, cc_dep2_formal, cc_ndep_formal );
vpanic("calculate_eflags_all");
}
}
/* CALLED FROM GENERATED CODE: CLEAN HELPER */
/* Calculate just the carry flag from the supplied thunk parameters. */
-UInt calculate_eflags_c ( UInt cc_op, UInt cc_res, UInt cc_aux )
+UInt calculate_eflags_c ( UInt cc_op,
+ UInt cc_dep1,
+ UInt cc_dep2,
+ UInt cc_ndep )
{
/* Fast-case some common ones. */
switch (cc_op) {
n_calc_c++;
# endif
- return calculate_eflags_all(cc_op,cc_res,cc_aux) & CC_MASK_C;
+ return calculate_eflags_all(cc_op,cc_dep1,cc_dep2,cc_ndep) & CC_MASK_C;
}
/* CALLED FROM GENERATED CODE: CLEAN HELPER */
/* returns 1 or 0 */
/*static*/ UInt calculate_condition ( UInt/*Condcode*/ cond,
- UInt cc_op, UInt cc_res, UInt cc_aux )
+ UInt cc_op,
+ UInt cc_dep1,
+ UInt cc_dep2,
+ UInt cc_ndep )
{
- UInt eflags = calculate_eflags_all(cc_op, cc_res, cc_aux);
+ UInt eflags = calculate_eflags_all(cc_op, cc_dep1, cc_dep2, cc_ndep);
UInt of,sf,zf,cf,pf;
UInt inv = cond & 1;
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_res, cc_aux );
+ vex_printf("calculate_condition( %d, %d, 0x%x, 0x%x, 0x%x )\n",
+ cond, cc_op, cc_dep1, cc_dep2, cc_ndep );
vpanic("calculate_condition");
}
}
&= (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_AUX = 0;
- vex_state->guest_CC_RES = eflags_native;
+ vex_state->guest_CC_OP = CC_OP_COPY;
+ vex_state->guest_CC_DEP1 = eflags_native;
+ vex_state->guest_CC_DEP2 = 0;
+ vex_state->guest_CC_NDEP = 0; /* unnecessary paranoia */
}
{
UInt eflags = calculate_eflags_all(
vex_state->guest_CC_OP,
- vex_state->guest_CC_RES,
- vex_state->guest_CC_AUX
+ vex_state->guest_CC_DEP1,
+ vex_state->guest_CC_DEP2,
+ vex_state->guest_CC_NDEP
);
UInt dflag = vex_state->guest_DFLAG;
vassert(dflag == 1 || dflag == 0xFFFFFFFF);
vex_state->guest_ESI = 0;
vex_state->guest_EDI = 0;
- vex_state->guest_CC_OP = CC_OP_COPY;
- vex_state->guest_CC_RES = 0;
- vex_state->guest_CC_AUX = 0;
- vex_state->guest_DFLAG = 1; /* forwards */
- vex_state->guest_IDFLAG = 0;
+ vex_state->guest_CC_OP = CC_OP_COPY;
+ vex_state->guest_CC_DEP1 = 0;
+ vex_state->guest_CC_DEP2 = 0;
+ vex_state->guest_CC_NDEP = 0;
+ vex_state->guest_DFLAG = 1; /* forwards */
+ vex_state->guest_IDFLAG = 0;
vex_state->guest_EIP = 0;
/* Describe any sections to be regarded by Memcheck as
'always-defined'. */
.n_alwaysDefd = 15,
- /* flags thunk: OP and AUX are always defd; only RES isn't.
- See detailed comment in gdefs.h on meaning of thunk
- fields. */
+ /* flags thunk: OP and NDEP are always defd, whereas DEP1
+ and DEP2 have to be tracked. See detailed comment in
+ gdefs.h on meaning of thunk fields. */
.alwaysDefd[0] = ALWAYSDEFD(guest_CC_OP),
- .alwaysDefd[1] = ALWAYSDEFD(guest_CC_AUX),
+ .alwaysDefd[1] = ALWAYSDEFD(guest_CC_NDEP),
.alwaysDefd[2] = ALWAYSDEFD(guest_DFLAG),
.alwaysDefd[3] = ALWAYSDEFD(guest_IDFLAG),
/*--- Offsets of various parts of the x86 guest state. ---*/
/*------------------------------------------------------------*/
-#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
-#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
-#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
-#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
-#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
-#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
-#define OFFB_EIP offsetof(VexGuestX86State,guest_EIP)
-#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
-#define OFFB_CC_RES offsetof(VexGuestX86State,guest_CC_RES)
-#define OFFB_CC_AUX offsetof(VexGuestX86State,guest_CC_AUX)
-#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
-#define OFFB_IDFLAG offsetof(VexGuestX86State,guest_IDFLAG)
-#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
-#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
-#define OFFB_FPUCW offsetof(VexGuestX86State,guest_FPUCW)
+#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
+#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
+#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
+#define OFFB_EBX offsetof(VexGuestX86State,guest_EBX)
+#define OFFB_ECX offsetof(VexGuestX86State,guest_ECX)
+#define OFFB_EDX offsetof(VexGuestX86State,guest_EDX)
+#define OFFB_EIP offsetof(VexGuestX86State,guest_EIP)
+
+#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
+#define OFFB_CC_DEP1 offsetof(VexGuestX86State,guest_CC_DEP1)
+#define OFFB_CC_DEP2 offsetof(VexGuestX86State,guest_CC_DEP2)
+#define OFFB_CC_NDEP offsetof(VexGuestX86State,guest_CC_NDEP)
+
+#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
+#define OFFB_IDFLAG offsetof(VexGuestX86State,guest_IDFLAG)
+#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
+#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
+#define OFFB_FPUCW offsetof(VexGuestX86State,guest_FPUCW)
/*------------------------------------------------------------*/
{
Int adj;
vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
-
- switch (op8) {
- case Iop_MullS8:
- return ty==Ity_I8 ? Iop_MullS8
- : (ty==Ity_I16 ? Iop_MullS16 : Iop_MullS32);
- case Iop_16HIto8:
- return ty==Ity_I8 ? Iop_16HIto8
- : (ty==Ity_I16 ? Iop_32HIto16 : Iop_64HIto32);
- case Iop_16to8:
- return ty==Ity_I8 ? Iop_16to8
- : (ty==Ity_I16 ? Iop_32to16 : Iop_64to32);
- default:
- break;
- }
-
vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
|| op8 == Iop_Mul8
|| op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
vpanic("mkWidenOp(x86,guest)");
}
-static IRType doubleLengthType ( IRType ty )
-{
- switch (ty) {
- case Ity_I8: return Ity_I16;
- case Ity_I16: return Ity_I32;
- case Ity_I32: return Ity_I64;
- default: vpanic("doubleLengthType(x86,guest)");
- }
-}
/*------------------------------------------------------------*/
/*--- Helpers for %eflags. ---*/
/* -------------- Evaluating the flags-thunk. -------------- */
/* Build IR to calculate all the eflags from stored
- CC_OP/CC_RES/CC_AUX. Returns an expression :: Ity_I32. */
+ CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
+ Ity_I32. */
static IRExpr* mk_calculate_eflags_all ( void )
{
IRExpr** args
- = mkIRExprVec_3( IRExpr_Get(OFFB_CC_OP, Ity_I32),
- IRExpr_Get(OFFB_CC_RES, Ity_I32),
- IRExpr_Get(OFFB_CC_AUX, Ity_I32) );
+ = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
+ IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
+ IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
+ IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
IRExpr* call
= mkIRExprCCall(
Ity_I32,
"calculate_eflags_all", &calculate_eflags_all,
args
);
- /* Exclude OP and AUX from definedness checking. We're only
- interested in RES. */
- call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<2);
+ /* Exclude OP and NDEP from definedness checking. We're only
+ interested in DEP1 and DEP2. */
+ call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
return call;
}
/* Build IR to calculate some particular condition from stored
- CC_OP/CC_RES/CC_AUX. Returns an expression :: Ity_Bit. */
+ CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression ::
+ Ity_Bit. */
static IRExpr* mk_calculate_condition ( Condcode cond )
{
IRExpr** args
- = mkIRExprVec_4( mkU32(cond),
+ = mkIRExprVec_5( mkU32(cond),
IRExpr_Get(OFFB_CC_OP, Ity_I32),
- IRExpr_Get(OFFB_CC_RES, Ity_I32),
- IRExpr_Get(OFFB_CC_AUX, Ity_I32) );
+ IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
+ IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
+ IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
IRExpr* call
= mkIRExprCCall(
Ity_I32,
"calculate_condition", &calculate_condition,
args
);
- /* Exclude the requested condition, OP and AUX from definedness
- checking. We're only interested in RES. */
- call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1 << 3);
+ /* Exclude the requested condition, OP and NDEP from definedness
+ checking. We're only interested in DEP1 and DEP2. */
+ call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
return unop(Iop_32to1, call);
}
/* Build IR to calculate just the carry flag from stored
- CC_OP/CC_RES/CC_AUX. Returns an expression :: Ity_I32. */
+ CC_OP/CC_DEP1/CC_DEP2/CC_NDEP. Returns an expression :: Ity_I32. */
static IRExpr* mk_calculate_eflags_c ( void )
{
IRExpr** args
- = mkIRExprVec_3( IRExpr_Get(OFFB_CC_OP, Ity_I32),
- IRExpr_Get(OFFB_CC_RES, Ity_I32),
- IRExpr_Get(OFFB_CC_AUX, Ity_I32) );
+ = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP, Ity_I32),
+ IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
+ IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
+ IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
IRExpr* call
= mkIRExprCCall(
Ity_I32,
"calculate_eflags_c", &calculate_eflags_c,
args
);
- /* Exclude OP and AUX from definedness checking. We're only
- interested in RES. */
- call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<2);
+ /* Exclude OP and NDEP from definedness checking. We're only
+ interested in DEP1 and DEP2. */
+ call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
return call;
}
return op8 == Iop_Add8 || op8 == Iop_Sub8;
}
+static Bool isLogic ( IROp op8 )
+{
+ return op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8;
+}
+
/* U-widen 8/16/32 bit int expr to 32. */
static IRExpr* widenUto32 ( IRExpr* e )
{
}
-/* Set the flags thunk for add/sub operations.. The supplied op is
+/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
auto-sized up to the real op. */
-static void setFlags_RES_AUX ( IROp op8,
- IRTemp res,
- IRTemp aux,
- IRType ty )
+static
+void setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
{
Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
case Iop_Add8: ccOp += CC_OP_ADDB; break;
case Iop_Sub8: ccOp += CC_OP_SUBB; break;
default: ppIROp(op8);
- vpanic("setFlags_RES_AUX(x86)");
+ vpanic("setFlags_DEP1_DEP2(x86)");
}
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
- stmt( IRStmt_Put( OFFB_CC_RES, widenUto32(mkexpr(res))) );
- stmt( IRStmt_Put( OFFB_CC_AUX, widenUto32(mkexpr(aux))) );
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
+ stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
+ stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
}
-/* For and/or/xor, only the result is important. However, put zero in
- CC_AUX since we're paranoid. */
+/* Set the OP and DEP1 fields only, and write zero to DEP2. */
-static void setFlags_LOGIC ( IROp op8,
- IRTemp res,
- IRType ty )
+static
+void setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
{
Int ccOp = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
case Iop_And8:
case Iop_Xor8: ccOp += CC_OP_LOGICB; break;
default: ppIROp(op8);
- vpanic("setFlags_LOGIC(x86)");
+ vpanic("setFlags_DEP1(x86)");
}
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
- stmt( IRStmt_Put( OFFB_CC_RES, widenUto32(mkexpr(res))) );
- stmt( IRStmt_Put( OFFB_CC_AUX, mkU32(0)) );
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
+ stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
+ stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
}
result. Except if the shift amount is zero, the thunk is left
unchanged. */
-static void setFlags_RES_RESus ( IROp op32,
- IRTemp res,
- IRTemp resUS,
- IRType ty,
- IRTemp guard )
+static void setFlags_DEP1_DEP2_shift ( IROp op32,
+ IRTemp res,
+ IRTemp resUS,
+ IRType ty,
+ IRTemp guard )
{
Int ccOp = ty==Ity_I8 ? 2 : (ty==Ity_I16 ? 1 : 0);
vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
vassert(guard);
+ /* Both kinds of right shifts are handled by the same thunk
+ operation. */
switch (op32) {
case Iop_Shr32:
- case Iop_Sar32: ccOp = CC_OP_SARL - ccOp; break;
+ case Iop_Sar32: ccOp = CC_OP_SHRL - ccOp; break;
case Iop_Shl32: ccOp = CC_OP_SHLL - ccOp; break;
default: ppIROp(op32);
- vpanic("setFlags_RES_RESus(x86)");
+ vpanic("setFlags_DEP1_DEP2_shift(x86)");
}
- /* RES contains the result, AUX contains the undershifted value. */
+ /* DEP1 contains the result, DEP2 contains the undershifted value. */
stmt( IRStmt_Put( OFFB_CC_OP,
IRExpr_Mux0X( mkexpr(guard),
IRExpr_Get(OFFB_CC_OP,Ity_I32),
mkU32(ccOp))) );
- stmt( IRStmt_Put( OFFB_CC_RES,
+ stmt( IRStmt_Put( OFFB_CC_DEP1,
IRExpr_Mux0X( mkexpr(guard),
- IRExpr_Get(OFFB_CC_RES,Ity_I32),
+ IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
widenUto32(mkexpr(res)))) );
- stmt( IRStmt_Put( OFFB_CC_AUX,
+ stmt( IRStmt_Put( OFFB_CC_DEP2,
IRExpr_Mux0X( mkexpr(guard),
- IRExpr_Get(OFFB_CC_AUX,Ity_I32),
+ IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
widenUto32(mkexpr(resUS)))) );
}
-/* For the inc/dec case, we store in RES the result value and in AUX
+/* For the inc/dec case, we store in DEP1 the result value and in NDEP
the former value of the carry flag, which unfortunately we have to
compute. */
vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
/* This has to come first, because calculating the C flag
- may require reading all three OFFB_CC fields. */
- stmt( IRStmt_Put( OFFB_CC_AUX, mk_calculate_eflags_c()) );
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
- stmt( IRStmt_Put( OFFB_CC_RES, mkexpr(res)) );
+ may require reading all four thunk fields. */
+ stmt( IRStmt_Put( OFFB_CC_NDEP, mk_calculate_eflags_c()) );
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(ccOp)) );
+ stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(res)) );
+ stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
}
-/* For multiplies, RES is the xor of the upper and lower halves of the
- result, and AUX is the lower half. See long comment in gdefs.h for
- explanation of the weirdness involving Xor. */
+/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
+ two arguments. */
static
-void setFlags_MUL ( IRType ty, IRTemp resHi, IRTemp resLo, UInt base_op )
+void setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, UInt base_op )
{
switch (ty) {
- case Ity_I8:
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
- stmt( IRStmt_Put( OFFB_CC_AUX, unop(Iop_8Uto32,mkexpr(resLo)) ) );
- stmt( IRStmt_Put( OFFB_CC_RES,
- unop(Iop_8Uto32,
- binop(Iop_Xor8, mkexpr(resHi), mkexpr(resLo))) ));
- break;
- case Ity_I16:
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
- stmt( IRStmt_Put( OFFB_CC_AUX, unop(Iop_16Uto32,mkexpr(resLo)) ) );
- stmt( IRStmt_Put( OFFB_CC_RES,
- unop(Iop_16Uto32,
- binop(Iop_Xor16, mkexpr(resHi), mkexpr(resLo))) ));
- break;
- case Ity_I32:
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
- stmt( IRStmt_Put( OFFB_CC_AUX, mkexpr(resLo) ) );
- stmt( IRStmt_Put( OFFB_CC_RES,
- binop(Iop_Xor32, mkexpr(resHi), mkexpr(resLo)) ));
- break;
- default:
- vpanic("setFlags_MUL(x86)");
+ case Ity_I8:
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+0) ) );
+ break;
+ case Ity_I16:
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+1) ) );
+ break;
+ case Ity_I32:
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(base_op+2) ) );
+ break;
+ default:
+ vpanic("setFlags_MUL(x86)");
}
+ stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
}
/* -------------- Helpers for ADD/SUB with carry. -------------- */
/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
- appropriately. Depends critically on the relative ordering of
- CC_OP_ADD{B,W,L} vs CC_OP_ADC{B,W,L}.
+ appropriately.
*/
static void helper_ADC ( Int sz,
IRTemp tres, IRTemp ta1, IRTemp ta2 )
{
UInt thunkOp;
- IRExpr* thunkExpr;
- IRType ty = szToITy(sz);
- IRTemp oldc = newTemp(Ity_I32);
- IROp plus = mkSizedOp(ty,Iop_Add8);
+ IRType ty = szToITy(sz);
+ IRTemp oldc = newTemp(Ity_I32);
+ IRTemp oldcn = newTemp(ty);
+ IROp plus = mkSizedOp(ty, Iop_Add8);
+ IROp xor = mkSizedOp(ty, Iop_Xor8);
+
+ vassert(sz == 1 || sz == 2 || sz == 4);
+ thunkOp = sz==4 ? CC_OP_ADCL : (sz==2 ? CC_OP_ADCW : CC_OP_ADCB);
/* oldc = old carry flag, 0 or 1 */
- assign( oldc, binop(Iop_And32,
- mk_calculate_eflags_c(),
- mkU32(1)) );
+ assign( oldc, binop(Iop_And32,
+ mk_calculate_eflags_c(),
+ mkU32(1)) );
- assign(tres, binop(plus,
- binop(plus,mkexpr(ta1),mkexpr(ta2)),
- narrowTo(ty,mkexpr(oldc))));
+ assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
- vassert(sz == 1 || sz == 2 || sz == 4);
- thunkOp = sz==4 ? CC_OP_ADDL : (sz==2 ? CC_OP_ADDW : CC_OP_ADDB);
-
- /* This dynamically calculates the thunk op number.
- 3 * the old carry flag is added, so (eg) it gives
- CC_OP_ADDL if old carry was zero, and CC_OP_ADCL if
- old carry was one. */
- thunkExpr = binop(Iop_Add32,
- mkU32(thunkOp),
- binop(Iop_Mul32, mkexpr(oldc), mkU32(3)));
-
- stmt( IRStmt_Put( OFFB_CC_OP, thunkExpr ) );
- stmt( IRStmt_Put( OFFB_CC_RES, mkexpr(tres) ) );
- stmt( IRStmt_Put( OFFB_CC_AUX, mkexpr(ta2) ) );
+ assign( tres, binop(plus,
+ binop(plus,mkexpr(ta1),mkexpr(ta2)),
+ mkexpr(oldcn)) );
+
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
+ stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
+ stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2), mkexpr(oldcn)) ) );
+ stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
}
/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
- appropriately. Depends critically on the relative ordering of
- CC_OP_SUB{B,W,L} vs CC_OP_SBB{B,W,L}.
+ appropriately.
*/
static void helper_SBB ( Int sz,
IRTemp tres, IRTemp ta1, IRTemp ta2 )
{
UInt thunkOp;
- IRExpr* thunkExpr;
- IRType ty = szToITy(sz);
- IRTemp oldc = newTemp(Ity_I32);
- IROp minus = mkSizedOp(ty,Iop_Sub8);
+ IRType ty = szToITy(sz);
+ IRTemp oldc = newTemp(Ity_I32);
+ IRTemp oldcn = newTemp(ty);
+ IROp minus = mkSizedOp(ty, Iop_Sub8);
+ IROp xor = mkSizedOp(ty, Iop_Xor8);
+
+ vassert(sz == 1 || sz == 2 || sz == 4);
+ thunkOp = sz==4 ? CC_OP_SBBL : (sz==2 ? CC_OP_SBBW : CC_OP_SBBB);
/* oldc = old carry flag, 0 or 1 */
assign( oldc, binop(Iop_And32,
mk_calculate_eflags_c(),
mkU32(1)) );
- assign(tres, binop(minus,
- binop(minus,mkexpr(ta1),mkexpr(ta2)),
- narrowTo(ty,mkexpr(oldc))));
+ assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
- vassert(sz == 1 || sz == 2 || sz == 4);
- thunkOp = sz==4 ? CC_OP_SUBL : (sz==2 ? CC_OP_SUBW : CC_OP_SUBB);
-
- /* This dynamically calculates the thunk op number.
- 3 * the old carry flag is added, so (eg) it gives
- CC_OP_SUBL if old carry was zero, and CC_OP_SBBL if
- old carry was one. */
- thunkExpr = binop(Iop_Add32,
- mkU32(thunkOp),
- binop(Iop_Mul32, mkexpr(oldc), mkU32(3)));
-
- stmt( IRStmt_Put( OFFB_CC_OP, thunkExpr ) );
- stmt( IRStmt_Put( OFFB_CC_RES, mkexpr(tres) ) );
- stmt( IRStmt_Put( OFFB_CC_AUX, mkexpr(ta2) ) );
+ assign( tres, binop(minus,
+ binop(minus,mkexpr(ta1),mkexpr(ta2)),
+ mkexpr(oldcn)) );
+
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(thunkOp) ) );
+ stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(ta1) ) );
+ stmt( IRStmt_Put( OFFB_CC_DEP2, binop(xor, mkexpr(ta2), mkexpr(oldcn)) ) );
+ stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
}
/* reg := 0 */
putIReg(size, ge_reg, mkU(ty,0));
/* Flags: C,A,O=0, Z=1, S=0, P=1 */
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
- stmt( IRStmt_Put( OFFB_CC_RES, mkU32(CC_MASK_Z|CC_MASK_P) ));
- stmt( IRStmt_Put( OFFB_CC_AUX, mkU32(0) ));
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP1, mkU32(CC_MASK_Z|CC_MASK_P) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
DIP("xor%c %s, %s\n", nameISize(size),
nameIReg(size,ge_reg), nameIReg(size,ge_reg) );
}
} else {
assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
if (isAddSub(op8))
- setFlags_RES_AUX(op8, dst1, src, ty);
+ setFlags_DEP1_DEP2(op8, dst0, src, ty);
else
- setFlags_LOGIC(op8, dst1, ty);
+ setFlags_DEP1(op8, dst1, ty);
if (keep)
putIReg(size, gregOfRM(rm), mkexpr(dst1));
}
} else {
assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
if (isAddSub(op8))
- setFlags_RES_AUX(op8, dst1, src, ty);
+ setFlags_DEP1_DEP2(op8, dst0, src, ty);
else
- setFlags_LOGIC(op8, dst1, ty);
+ setFlags_DEP1(op8, dst1, ty);
if (keep)
putIReg(size, gregOfRM(rm), mkexpr(dst1));
}
} else {
assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
if (isAddSub(op8))
- setFlags_RES_AUX(op8, dst1, src, ty);
+ setFlags_DEP1_DEP2(op8, dst0, src, ty);
else
- setFlags_LOGIC(op8, dst1, ty);
+ setFlags_DEP1(op8, dst1, ty);
if (keep)
putIReg(size, eregOfRM(rm), mkexpr(dst1));
}
} else {
assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
if (isAddSub(op8))
- setFlags_RES_AUX(op8, dst1, src, ty);
+ setFlags_DEP1_DEP2(op8, dst0, src, ty);
else
- setFlags_LOGIC(op8, dst1, ty);
+ setFlags_DEP1(op8, dst1, ty);
if (keep)
storeLE(mkexpr(addr), mkexpr(dst1));
}
assign(src, mkU(ty,lit));
assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
if (isAddSub(op8))
- setFlags_RES_AUX(op8, dst1, src, ty);
+ setFlags_DEP1_DEP2(op8, dst0, src, ty);
else
- setFlags_LOGIC(op8, dst1, ty);
+ if (isLogic(op8))
+ setFlags_DEP1(op8, dst1, ty);
+ else
+ vpanic("dis_op_imm_A(x86,guest)");
if (keep)
putIReg(size, R_EAX, mkexpr(dst1));
} else {
assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
if (isAddSub(op8))
- setFlags_RES_AUX(op8, dst1, src, ty);
+ setFlags_DEP1_DEP2(op8, dst0, src, ty);
else
- setFlags_LOGIC(op8, dst1, ty);
+ setFlags_DEP1(op8, dst1, ty);
}
if (gregOfRM(modrm) < 7)
} else {
assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
if (isAddSub(op8))
- setFlags_RES_AUX(op8, dst1, src, ty);
+ setFlags_DEP1_DEP2(op8, dst0, src, ty);
else
- setFlags_LOGIC(op8, dst1, ty);
+ setFlags_DEP1(op8, dst1, ty);
}
if (gregOfRM(modrm) < 7)
);
/* new eflags in hi half r64; new value in lo half r64 */
assign( dst1, narrowTo(ty, unop(Iop_64to32, mkexpr(r64))) );
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
- stmt( IRStmt_Put( OFFB_CC_RES, unop(Iop_64HIto32, mkexpr(r64)) ));
- stmt( IRStmt_Put( OFFB_CC_AUX, mkU32(0) ));
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP1, unop(Iop_64HIto32, mkexpr(r64)) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
}
if (isShift) {
mkU8(31))) );
/* Build the flags thunk. */
- setFlags_RES_RESus(op32, res32, res32ss, ty, shift_amt);
+ setFlags_DEP1_DEP2_shift(op32, res32, res32ss, ty, shift_amt);
/* Narrow the result back down. */
assign( dst1, narrowTo(ty, mkexpr(res32)) );
assign(oldFlags, mk_calculate_eflags_all());
- /* CC_RES is the rotated value. CC_AUX is flags before. */
+ /* CC_DEP1 is the rotated value. CC_NDEP is flags before. */
stmt( IRStmt_Put( OFFB_CC_OP,
IRExpr_Mux0X( mkexpr(rot_amt32),
IRExpr_Get(OFFB_CC_OP,Ity_I32),
mkU32(ccOp))) );
- stmt( IRStmt_Put( OFFB_CC_RES,
+ stmt( IRStmt_Put( OFFB_CC_DEP1,
IRExpr_Mux0X( mkexpr(rot_amt32),
- IRExpr_Get(OFFB_CC_RES,Ity_I32),
+ IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
widenUto32(mkexpr(dst1)))) );
- stmt( IRStmt_Put( OFFB_CC_AUX,
+ stmt( IRStmt_Put( OFFB_CC_DEP2,
+ IRExpr_Mux0X( mkexpr(rot_amt32),
+ IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
+ mkU32(0))) );
+ stmt( IRStmt_Put( OFFB_CC_NDEP,
IRExpr_Mux0X( mkexpr(rot_amt32),
- IRExpr_Get(OFFB_CC_AUX,Ity_I32),
+ IRExpr_Get(OFFB_CC_NDEP,Ity_I32),
mkexpr(oldFlags))) );
} /* if (isRotate) */
IRTemp resLo = newTemp(Ity_I32);
IROp mulOp = syned ? Iop_MullS32 : Iop_MullU32;
UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
+ setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
assign( resLo, unop(Iop_64to32,mkexpr(res64)));
- setFlags_MUL ( Ity_I32, resHi, resLo, tBaseOp );
putIReg(4, R_EDX, mkexpr(resHi));
putIReg(4, R_EAX, mkexpr(resLo));
break;
IRTemp resLo = newTemp(Ity_I16);
IROp mulOp = syned ? Iop_MullS16 : Iop_MullU16;
UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
+ setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
assign( resLo, unop(Iop_32to16,mkexpr(res32)));
- setFlags_MUL ( Ity_I16, resHi, resLo, tBaseOp );
putIReg(2, R_EDX, mkexpr(resHi));
putIReg(2, R_EAX, mkexpr(resLo));
break;
IRTemp resLo = newTemp(Ity_I8);
IROp mulOp = syned ? Iop_MullS8 : Iop_MullU8;
UInt tBaseOp = syned ? CC_OP_SMULB : CC_OP_UMULB;
+ setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
assign( resLo, unop(Iop_16to8,mkexpr(res16)));
- setFlags_MUL ( Ity_I8, resHi, resLo, tBaseOp );
putIReg(2, R_EAX, mkexpr(res16));
break;
}
assign(dst1, binop(mkSizedOp(ty,Iop_And8),
getIReg(sz,eregOfRM(modrm)),
mkU(ty,d32)));
- setFlags_LOGIC( Iop_And8, dst1, ty );
+ setFlags_DEP1( Iop_And8, dst1, ty );
DIP("test%c $0x%x, %s\n", nameISize(sz), d32,
nameIReg(sz, eregOfRM(modrm)));
break;
assign(dst0, mkU(ty,0));
assign(src, getIReg(sz,eregOfRM(modrm)));
assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
- setFlags_RES_AUX(Iop_Sub8, dst1, src, ty);
+ setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
putIReg(sz, eregOfRM(modrm), mkexpr(dst1));
DIP("neg%c %s\n", nameISize(sz), nameIReg(sz, eregOfRM(modrm)));
break;
dst1 = newTemp(ty);
assign(dst1, binop(mkSizedOp(ty,Iop_And8),
mkexpr(t1), mkU(ty,d32)));
- setFlags_LOGIC( Iop_And8, dst1, ty );
+ setFlags_DEP1( Iop_And8, dst1, ty );
DIP("test%c $0x%x, %s\n", nameISize(sz), d32, dis_buf);
break;
}
assign(dst0, mkU(ty,0));
assign(src, mkexpr(t1));
assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0), mkexpr(src)));
- setFlags_RES_AUX(Iop_Sub8, dst1, src, ty);
+ setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
storeLE( mkexpr(addr), mkexpr(dst1) );
DIP("neg%c %s\n", nameISize(sz), dis_buf);
break;
IRType ty = szToITy(sz);
IRTemp tdv = newTemp(ty); /* (EDI) */
IRTemp tsv = newTemp(ty); /* (ESI) */
- IRTemp res = newTemp(ty);
+ //IRTemp res = newTemp(ty);
IRTemp td = newTemp(Ity_I32); /* EDI */
IRTemp ts = newTemp(Ity_I32); /* ESI */
//uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, tsv);
//setFlagsFromUOpcode(cb, SUB);
- assign( res, binop(mkSizedOp(ty, Iop_Sub8), mkexpr(tsv), mkexpr(tdv)) );
- setFlags_RES_AUX ( Iop_Sub8, res, tdv, ty );
+ //assign( res, binop(mkSizedOp(ty, Iop_Sub8), mkexpr(tsv), mkexpr(tdv)) );
+ setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
//uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
//uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, ts);
IRTemp ta = newTemp(ty); /* EAX */
IRTemp td = newTemp(Ity_I32); /* EDI */
IRTemp tdv = newTemp(ty); /* (EDI) */
- IRTemp res = newTemp(ty);
+ //IRTemp res = newTemp(ty);
//uInstr2(cb, GET, sz, ArchReg, R_EAX, TempReg, ta);
assign( ta, getIReg(sz, R_EAX) );
//uInstr2(cb, SUB, sz, TempReg, tdv, TempReg, ta);
//setFlagsFromUOpcode(cb, SUB);
- assign( res, binop(mkSizedOp(ty, Iop_Sub8), mkexpr(ta), mkexpr(tdv)) );
- setFlags_RES_AUX ( Iop_Sub8, res, tdv, ty );
+ //assign( res, binop(mkSizedOp(ty, Iop_Sub8), mkexpr(ta), mkexpr(tdv)) );
+ setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
//uInstr2(cb, ADD, 4, TempReg, t_inc, TempReg, td);
//uInstr2(cb, PUT, 4, TempReg, td, ArchReg, R_EDI);
/*--- Arithmetic, etc. ---*/
/*------------------------------------------------------------*/
-/* (I)MUL E, G. Supplied eip points to the modR/M byte. */
+/* IMUL E, G. Supplied eip points to the modR/M byte. */
static
UInt dis_mul_E_G ( UChar sorb,
Int size,
- UInt delta0,
- Bool syned )
+ UInt delta0 )
{
Int alen;
UChar dis_buf[50];
IRType ty = szToITy(size);
IRTemp te = newTemp(ty);
IRTemp tg = newTemp(ty);
- IRTemp resHi = newTemp(ty);
IRTemp resLo = newTemp(ty);
- IRTemp res2L = newTemp(doubleLengthType(ty));
-
- vassert(syned);
assign( tg, getIReg(size, gregOfRM(rm)) );
if (epartIsReg(rm)) {
assign( te, loadLE(ty,mkexpr(addr)) );
}
- assign( res2L, binop( mkSizedOp(ty, syned ? Iop_MullS8 : Iop_MullU8),
- mkexpr(te), mkexpr(tg) ));
- assign( resHi, unop( mkSizedOp(ty, Iop_16HIto8), mkexpr(res2L) ));
- assign( resLo, unop( mkSizedOp(ty, Iop_16to8), mkexpr(res2L) ));
+ setFlags_MUL ( ty, te, tg, CC_OP_SMULB );
- setFlags_MUL ( ty, resHi, resLo, syned ? CC_OP_SMULB : CC_OP_UMULB );
+ assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
putIReg(size, gregOfRM(rm), mkexpr(resLo) );
if (epartIsReg(rm)) {
- DIP("%smul%c %s, %s\n", syned ? "i" : "",
- nameISize(size),
- nameIReg(size,eregOfRM(rm)),
- nameIReg(size,gregOfRM(rm)));
+ DIP("imul%c %s, %s\n", nameISize(size),
+ nameIReg(size,eregOfRM(rm)),
+ nameIReg(size,gregOfRM(rm)));
return 1+delta0;
} else {
- DIP("%smul%c %s, %s\n", syned ? "i" : "",
- nameISize(size),
- dis_buf, nameIReg(size,gregOfRM(rm)));
+ DIP("imul%c %s, %s\n", nameISize(size),
+ dis_buf, nameIReg(size,gregOfRM(rm)));
return alen+delta0;
}
}
IRType ty = szToITy(size);
IRTemp te = newTemp(ty);
IRTemp tl = newTemp(ty);
- IRTemp resHi = newTemp(ty);
IRTemp resLo = newTemp(ty);
- IRTemp res2L = newTemp(doubleLengthType(ty));
vassert(size == 1 || size == 2 || size == 4);
assign(tl, mkU(ty,d32));
- assign( res2L, binop( mkSizedOp(ty, Iop_MullS8),
- mkexpr(te), mkexpr(tl) ));
- assign( resHi, unop( mkSizedOp(ty, Iop_16HIto8), mkexpr(res2L) ));
- assign( resLo, unop( mkSizedOp(ty, Iop_16to8), mkexpr(res2L) ));
+ assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
- setFlags_MUL ( ty, resHi, resLo, CC_OP_SMULB );
+ setFlags_MUL ( ty, te, tl, CC_OP_SMULB );
putIReg(size, gregOfRM(rm), mkexpr(resLo));
Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
documentation implies A and S are unchanged.
*/
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
- stmt( IRStmt_Put( OFFB_CC_AUX, mkU32(0) ));
- stmt( IRStmt_Put( OFFB_CC_RES,
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP1,
binop( Iop_And32,
binop(Iop_CmpF64, get_ST(0), get_ST(i)),
mkU32(0x45)
binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
mask))) );
- setFlags_RES_RESus ( left_shift ? Iop_Shl32 : Iop_Sar32,
- tmpRes, tmpSubSh, ty, tmpSH );
+ setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl32 : Iop_Sar32,
+ tmpRes, tmpSubSh, ty, tmpSH );
/* Put result back. */
}
/* Side effect done; now get selected bit into Carry flag */
- /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
- stmt( IRStmt_Put( OFFB_CC_AUX, mkU32(0) ));
+ /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
stmt( IRStmt_Put(
- OFFB_CC_RES,
+ OFFB_CC_DEP1,
binop(Iop_And32,
binop(Iop_Shr32,
unop(Iop_8Uto32, mkexpr(t_fetched)),
/* Flags: Z is 1 iff source value is zero. All others
are undefined -- we force them to zero. */
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
- stmt( IRStmt_Put( OFFB_CC_AUX, mkU32(0) ));
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
stmt( IRStmt_Put(
- OFFB_CC_RES,
+ OFFB_CC_DEP1,
IRExpr_Mux0X( mkexpr(src8),
/* src==0 */
mkU32(CC_MASK_Z),
(calculate_flags_all() & CC_MASK_O) -- retain the old O flag
| (%AH & (CC_MASK_S|CC_MASK_Z|CC_MASK_A|CC_MASK_P|CC_MASK_C)
*/
- UInt mask_SZACP = CC_MASK_S|CC_MASK_Z|CC_MASK_A|CC_MASK_P|CC_MASK_C;
+ UInt mask_SZACP = CC_MASK_S|CC_MASK_Z|CC_MASK_A|CC_MASK_C|CC_MASK_P;
IRTemp oldflags = newTemp(Ity_I32);
assign( oldflags, mk_calculate_eflags_all() );
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
- stmt( IRStmt_Put( OFFB_CC_AUX, mkU32(0) ));
- stmt( IRStmt_Put( OFFB_CC_RES,
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP1,
binop(Iop_Or32,
binop(Iop_And32, mkexpr(oldflags), mkU32(CC_MASK_O)),
binop(Iop_And32,
IRType ty = szToITy(size);
IRTemp acc = newTemp(ty);
IRTemp src = newTemp(ty);
- IRTemp res = newTemp(ty);
+ //IRTemp res = newTemp(ty);
IRTemp dest = newTemp(ty);
IRTemp dest2 = newTemp(ty);
IRTemp acc2 = newTemp(ty);
assign( src, getIReg(size, gregOfRM(rm)) );
assign( acc, getIReg(size, R_EAX) );
- assign( res, binop( mkSizedOp(ty,Iop_Sub8), mkexpr(acc), mkexpr(dest) ));
- setFlags_RES_AUX(Iop_Sub8, res, dest, ty);
+ //assign( res, binop( mkSizedOp(ty,Iop_Sub8), mkexpr(acc), mkexpr(dest) ));
+ setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
assign( cond8, unop(Iop_1Uto8, mk_calculate_condition(CondZ)) );
assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
assign( acc2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
assign( tmpd, loadLE(ty, mkexpr(addr)) );
assign( tmpt0, getIReg(sz, gregOfRM(rm)) );
assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8), mkexpr(tmpd), mkexpr(tmpt0)) );
- setFlags_RES_AUX( Iop_Add8, tmpt1, tmpt0, ty );
+ setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
storeLE( mkexpr(addr), mkexpr(tmpt1) );
putIReg(sz, gregOfRM(rm), mkexpr(tmpd));
DIP("xadd%c %s, %s\n",
putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(t2), mkU32(sz)));
/* t1 is the flag word. Mask out everything except OSZACP and
set the flags thunk to CC_OP_COPY. */
- stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
- stmt( IRStmt_Put( OFFB_CC_AUX, mkU32(0) ));
- stmt( IRStmt_Put( OFFB_CC_RES,
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU32(CC_OP_COPY) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
+ stmt( IRStmt_Put( OFFB_CC_DEP1,
binop(Iop_And32,
mkexpr(t1),
mkU32( CC_MASK_C | CC_MASK_P | CC_MASK_A
/* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
case 0xAF: /* IMUL Ev, Gv */
- delta = dis_mul_E_G ( sorb, sz, delta, True );
+ delta = dis_mul_E_G ( sorb, sz, delta );
break;
/* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */