blob: db5ca8a525b372e168ecf56f62e8ff33c487dcd5 [file] [log] [blame]
sewardj36ca5132004-07-24 13:12:23 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
sewardjc0ee2ed2004-07-27 10:29:41 +00004/*--- This file (guest-x86/ghelpers.c) is ---*/
sewardj36ca5132004-07-24 13:12:23 +00005/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*---------------------------------------------------------------*/
8
9#include "libvex_basictypes.h"
sewardj0c2cb622004-09-06 23:21:21 +000010#include "libvex_guest_x86.h"
sewardj36ca5132004-07-24 13:12:23 +000011#include "libvex_ir.h"
sewardj49651f42004-10-28 22:11:04 +000012#include "libvex.h"
sewardjc0ee2ed2004-07-27 10:29:41 +000013
14#include "main/vex_util.h"
15#include "guest-x86/gdefs.h"
sewardj36ca5132004-07-24 13:12:23 +000016
sewardjc4be80c2004-09-10 16:17:45 +000017
sewardj36ca5132004-07-24 13:12:23 +000018/* This file contains helper functions for x86 guest code.
19 Calls to these functions are generated by the back end.
20 These calls are of course in the host machine code and
21 this file will be compiled to host machine code, so that
22 all makes sense.
23
sewardj36ca5132004-07-24 13:12:23 +000024 Only change the signatures of these helper functions very
25 carefully. If you change the signature here, you'll have to change
26 the parameters passed to it in the IR calls constructed by
sewardj89050e52004-07-28 23:25:02 +000027 x86toIR.c.
28
29 Some of this code/logic is derived from QEMU, which is copyright
30 Fabrice Bellard, licensed under the LGPL. It is used with
31 permission.
sewardj36ca5132004-07-24 13:12:23 +000032*/
33
sewardj84ff0652004-08-23 16:16:08 +000034/* Set to 1 to get detailed profiling info about use of the flag
35 machinery. */
36#define PROFILE_EFLAGS 0
37
38
sewardjd44bc6e2004-10-26 12:39:24 +000039static const UChar parity_table[256] = {
sewardj9aebb0c2004-10-24 19:20:43 +000040 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
41 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
42 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
43 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
44 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
45 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
46 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
47 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
48 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
49 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
50 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
51 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
52 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
53 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
54 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
55 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
56 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
57 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
58 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
59 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
60 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
61 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
62 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
63 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
64 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
65 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
66 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
67 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
68 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
69 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
70 CC_MASK_P, 0, 0, CC_MASK_P, 0, CC_MASK_P, CC_MASK_P, 0,
71 0, CC_MASK_P, CC_MASK_P, 0, CC_MASK_P, 0, 0, CC_MASK_P,
sewardj14731f22004-07-25 01:24:28 +000072};
73
74/* n must be a constant to be efficient */
sewardjdf22c1c2004-10-16 22:59:59 +000075inline static Int lshift ( Int x, Int n )
sewardj14731f22004-07-25 01:24:28 +000076{
sewardjdf22c1c2004-10-16 22:59:59 +000077 if (n >= 0)
78 return x << n;
79 else
80 return x >> (-n);
sewardj14731f22004-07-25 01:24:28 +000081}
82
83
sewardjb9c5cf62004-08-24 15:10:38 +000084#define PREAMBLE(__data_bits) \
sewardjdf22c1c2004-10-16 22:59:59 +000085 /* const */ UInt DATA_MASK \
sewardjb9c5cf62004-08-24 15:10:38 +000086 = __data_bits==8 ? 0xFF \
87 : (__data_bits==16 ? 0xFFFF \
88 : 0xFFFFFFFF); \
sewardjdf22c1c2004-10-16 22:59:59 +000089 /* const */ UInt SIGN_MASK = 1 << (__data_bits - 1); \
sewardj2a2ba8b2004-11-08 13:14:06 +000090 /* const */ UInt CC_DEP1 = cc_dep1_formal; \
91 /* const */ UInt CC_DEP2 = cc_dep2_formal; \
92 /* const */ UInt CC_NDEP = cc_ndep_formal; \
93 /* Four bogus assignments, which hopefully gcc can */ \
sewardjdf22c1c2004-10-16 22:59:59 +000094 /* optimise away, and which stop it complaining about */ \
95 /* unused variables. */ \
96 SIGN_MASK = SIGN_MASK; \
97 DATA_MASK = DATA_MASK; \
sewardj2a2ba8b2004-11-08 13:14:06 +000098 CC_DEP2 = CC_DEP2; \
99 CC_NDEP = CC_NDEP;
sewardjdf22c1c2004-10-16 22:59:59 +0000100
sewardj14731f22004-07-25 01:24:28 +0000101
sewardjb9c5cf62004-08-24 15:10:38 +0000102/*-------------------------------------------------------------*/
sewardj89050e52004-07-28 23:25:02 +0000103
sewardjdf22c1c2004-10-16 22:59:59 +0000104#define ACTIONS_ADD(DATA_BITS,DATA_UTYPE) \
sewardjb9c5cf62004-08-24 15:10:38 +0000105{ \
106 PREAMBLE(DATA_BITS); \
sewardj948d48b2004-11-05 19:49:09 +0000107 Int cf, pf, af, zf, sf, of; \
108 Int argL, argR, res; \
sewardj2a2ba8b2004-11-08 13:14:06 +0000109 argL = CC_DEP1; \
110 argR = CC_DEP2; \
111 res = argL + argR; \
sewardj948d48b2004-11-05 19:49:09 +0000112 cf = (DATA_UTYPE)res < (DATA_UTYPE)argL; \
113 pf = parity_table[(UChar)res]; \
114 af = (res ^ argL ^ argR) & 0x10; \
115 zf = ((DATA_UTYPE)res == 0) << 6; \
116 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
117 of = lshift((argL ^ argR ^ -1) & (argL ^ res), \
sewardj9aebb0c2004-10-24 19:20:43 +0000118 12 - DATA_BITS) & CC_MASK_O; \
sewardjb9c5cf62004-08-24 15:10:38 +0000119 return cf | pf | af | zf | sf | of; \
sewardj89050e52004-07-28 23:25:02 +0000120}
121
sewardjb9c5cf62004-08-24 15:10:38 +0000122/*-------------------------------------------------------------*/
123
sewardjdf22c1c2004-10-16 22:59:59 +0000124#define ACTIONS_SUB(DATA_BITS,DATA_UTYPE) \
sewardjb9c5cf62004-08-24 15:10:38 +0000125{ \
126 PREAMBLE(DATA_BITS); \
sewardj948d48b2004-11-05 19:49:09 +0000127 Int cf, pf, af, zf, sf, of; \
128 Int argL, argR, res; \
sewardj2a2ba8b2004-11-08 13:14:06 +0000129 argL = CC_DEP1; \
130 argR = CC_DEP2; \
131 res = argL - argR; \
sewardj948d48b2004-11-05 19:49:09 +0000132 cf = (DATA_UTYPE)argL < (DATA_UTYPE)argR; \
133 pf = parity_table[(UChar)res]; \
134 af = (res ^ argL ^ argR) & 0x10; \
135 zf = ((DATA_UTYPE)res == 0) << 6; \
136 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
137 of = lshift((argL ^ argR) & (argL ^ res), \
sewardj9aebb0c2004-10-24 19:20:43 +0000138 12 - DATA_BITS) & CC_MASK_O; \
sewardjb9c5cf62004-08-24 15:10:38 +0000139 return cf | pf | af | zf | sf | of; \
sewardj2ef5f2a2004-08-24 01:46:34 +0000140}
141
sewardjb9c5cf62004-08-24 15:10:38 +0000142/*-------------------------------------------------------------*/
143
sewardj2a2ba8b2004-11-08 13:14:06 +0000144#define ACTIONS_ADC(DATA_BITS,DATA_UTYPE) \
145{ \
146 PREAMBLE(DATA_BITS); \
147 Int cf, pf, af, zf, sf, of; \
148 Int argL, argR, oldC, res; \
149 oldC = CC_NDEP & CC_MASK_C; \
150 argL = CC_DEP1; \
151 argR = CC_DEP2 ^ oldC; \
152 res = (argL + argR) + oldC; \
153 if (oldC) \
154 cf = (DATA_UTYPE)res <= (DATA_UTYPE)argL; \
155 else \
156 cf = (DATA_UTYPE)res < (DATA_UTYPE)argL; \
157 pf = parity_table[(UChar)res]; \
158 af = (res ^ argL ^ argR) & 0x10; \
159 zf = ((DATA_UTYPE)res == 0) << 6; \
160 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
161 of = lshift((argL ^ argR ^ -1) & (argL ^ res), \
162 12 - DATA_BITS) & CC_MASK_O; \
163 return cf | pf | af | zf | sf | of; \
164}
165
166/*-------------------------------------------------------------*/
167
sewardjdf22c1c2004-10-16 22:59:59 +0000168#define ACTIONS_SBB(DATA_BITS,DATA_UTYPE) \
sewardjb9c5cf62004-08-24 15:10:38 +0000169{ \
170 PREAMBLE(DATA_BITS); \
sewardj948d48b2004-11-05 19:49:09 +0000171 Int cf, pf, af, zf, sf, of; \
sewardj2a2ba8b2004-11-08 13:14:06 +0000172 Int argL, argR, oldC, res; \
173 oldC = CC_NDEP & CC_MASK_C; \
174 argL = CC_DEP1; \
175 argR = CC_DEP2 ^ oldC; \
176 res = (argL - argR) - oldC; \
177 if (oldC) \
178 cf = (DATA_UTYPE)argL <= (DATA_UTYPE)argR; \
179 else \
180 cf = (DATA_UTYPE)argL < (DATA_UTYPE)argR; \
sewardj948d48b2004-11-05 19:49:09 +0000181 pf = parity_table[(UChar)res]; \
182 af = (res ^ argL ^ argR) & 0x10; \
183 zf = ((DATA_UTYPE)res == 0) << 6; \
184 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
185 of = lshift((argL ^ argR) & (argL ^ res), \
sewardj9aebb0c2004-10-24 19:20:43 +0000186 12 - DATA_BITS) & CC_MASK_O; \
sewardjb9c5cf62004-08-24 15:10:38 +0000187 return cf | pf | af | zf | sf | of; \
sewardj2ef5f2a2004-08-24 01:46:34 +0000188}
189
sewardjb9c5cf62004-08-24 15:10:38 +0000190/*-------------------------------------------------------------*/
191
sewardjdf22c1c2004-10-16 22:59:59 +0000192#define ACTIONS_LOGIC(DATA_BITS,DATA_UTYPE) \
sewardjb9c5cf62004-08-24 15:10:38 +0000193{ \
194 PREAMBLE(DATA_BITS); \
sewardj948d48b2004-11-05 19:49:09 +0000195 Int cf, pf, af, zf, sf, of; \
sewardjb9c5cf62004-08-24 15:10:38 +0000196 cf = 0; \
sewardj2a2ba8b2004-11-08 13:14:06 +0000197 pf = parity_table[(UChar)CC_DEP1]; \
sewardjb9c5cf62004-08-24 15:10:38 +0000198 af = 0; \
sewardj2a2ba8b2004-11-08 13:14:06 +0000199 zf = ((DATA_UTYPE)CC_DEP1 == 0) << 6; \
200 sf = lshift(CC_DEP1, 8 - DATA_BITS) & 0x80; \
sewardjb9c5cf62004-08-24 15:10:38 +0000201 of = 0; \
202 return cf | pf | af | zf | sf | of; \
sewardj2ef5f2a2004-08-24 01:46:34 +0000203}
204
sewardjb9c5cf62004-08-24 15:10:38 +0000205/*-------------------------------------------------------------*/
206
sewardjdf22c1c2004-10-16 22:59:59 +0000207#define ACTIONS_INC(DATA_BITS,DATA_UTYPE) \
sewardjb9c5cf62004-08-24 15:10:38 +0000208{ \
209 PREAMBLE(DATA_BITS); \
sewardj948d48b2004-11-05 19:49:09 +0000210 Int cf, pf, af, zf, sf, of; \
sewardj2a2ba8b2004-11-08 13:14:06 +0000211 Int argL, argR, res; \
212 res = CC_DEP1; \
213 argL = res - 1; \
sewardj948d48b2004-11-05 19:49:09 +0000214 argR = 1; \
sewardj2a2ba8b2004-11-08 13:14:06 +0000215 cf = CC_NDEP & CC_MASK_C; \
216 pf = parity_table[(UChar)res]; \
217 af = (res ^ argL ^ argR) & 0x10; \
218 zf = ((DATA_UTYPE)res == 0) << 6; \
219 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
220 of = ((res & DATA_MASK) == SIGN_MASK) << 11; \
sewardjb9c5cf62004-08-24 15:10:38 +0000221 return cf | pf | af | zf | sf | of; \
sewardj2ef5f2a2004-08-24 01:46:34 +0000222}
223
sewardjb9c5cf62004-08-24 15:10:38 +0000224/*-------------------------------------------------------------*/
225
sewardjdf22c1c2004-10-16 22:59:59 +0000226#define ACTIONS_DEC(DATA_BITS,DATA_UTYPE) \
sewardjb9c5cf62004-08-24 15:10:38 +0000227{ \
228 PREAMBLE(DATA_BITS); \
sewardj948d48b2004-11-05 19:49:09 +0000229 Int cf, pf, af, zf, sf, of; \
sewardj2a2ba8b2004-11-08 13:14:06 +0000230 Int argL, argR, res; \
231 res = CC_DEP1; \
232 argL = res + 1; \
sewardj948d48b2004-11-05 19:49:09 +0000233 argR = 1; \
sewardj2a2ba8b2004-11-08 13:14:06 +0000234 cf = CC_NDEP & CC_MASK_C; \
235 pf = parity_table[(UChar)res]; \
236 af = (res ^ argL ^ argR) & 0x10; \
237 zf = ((DATA_UTYPE)res == 0) << 6; \
238 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
239 of = ((res & DATA_MASK) \
sewardjd44bc6e2004-10-26 12:39:24 +0000240 == ((UInt)SIGN_MASK - 1)) << 11; \
sewardjb9c5cf62004-08-24 15:10:38 +0000241 return cf | pf | af | zf | sf | of; \
sewardj2ef5f2a2004-08-24 01:46:34 +0000242}
243
sewardjb9c5cf62004-08-24 15:10:38 +0000244/*-------------------------------------------------------------*/
245
sewardjdf22c1c2004-10-16 22:59:59 +0000246#define ACTIONS_SHL(DATA_BITS,DATA_UTYPE) \
sewardjb9c5cf62004-08-24 15:10:38 +0000247{ \
248 PREAMBLE(DATA_BITS); \
sewardj948d48b2004-11-05 19:49:09 +0000249 Int cf, pf, af, zf, sf, of; \
sewardj2a2ba8b2004-11-08 13:14:06 +0000250 cf = (CC_DEP2 >> (DATA_BITS - 1)) & CC_MASK_C; \
251 pf = parity_table[(UChar)CC_DEP1]; \
sewardjb9c5cf62004-08-24 15:10:38 +0000252 af = 0; /* undefined */ \
sewardj2a2ba8b2004-11-08 13:14:06 +0000253 zf = ((DATA_UTYPE)CC_DEP1 == 0) << 6; \
254 sf = lshift(CC_DEP1, 8 - DATA_BITS) & 0x80; \
sewardjb9c5cf62004-08-24 15:10:38 +0000255 /* of is defined if shift count == 1 */ \
sewardj2a2ba8b2004-11-08 13:14:06 +0000256 of = lshift(CC_DEP2 ^ CC_DEP1, 12 - DATA_BITS) & CC_MASK_O; \
sewardjb9c5cf62004-08-24 15:10:38 +0000257 return cf | pf | af | zf | sf | of; \
sewardj2ef5f2a2004-08-24 01:46:34 +0000258}
259
sewardjb9c5cf62004-08-24 15:10:38 +0000260/*-------------------------------------------------------------*/
261
sewardj2a2ba8b2004-11-08 13:14:06 +0000262#define ACTIONS_SHR(DATA_BITS,DATA_UTYPE) \
sewardjb9c5cf62004-08-24 15:10:38 +0000263{ \
264 PREAMBLE(DATA_BITS); \
sewardj948d48b2004-11-05 19:49:09 +0000265 Int cf, pf, af, zf, sf, of; \
sewardj2a2ba8b2004-11-08 13:14:06 +0000266 cf = CC_DEP2 & 1; \
267 pf = parity_table[(UChar)CC_DEP1]; \
sewardjb9c5cf62004-08-24 15:10:38 +0000268 af = 0; /* undefined */ \
sewardj2a2ba8b2004-11-08 13:14:06 +0000269 zf = ((DATA_UTYPE)CC_DEP1 == 0) << 6; \
270 sf = lshift(CC_DEP1, 8 - DATA_BITS) & 0x80; \
sewardjb9c5cf62004-08-24 15:10:38 +0000271 /* of is defined if shift count == 1 */ \
sewardj2a2ba8b2004-11-08 13:14:06 +0000272 of = lshift(CC_DEP2 ^ CC_DEP1, 12 - DATA_BITS) & CC_MASK_O; \
sewardjb9c5cf62004-08-24 15:10:38 +0000273 return cf | pf | af | zf | sf | of; \
sewardj5f630352004-07-25 18:18:03 +0000274}
275
sewardjb9c5cf62004-08-24 15:10:38 +0000276/*-------------------------------------------------------------*/
277
sewardj8ee2de12004-07-29 22:22:31 +0000278/* ROL: cf' = lsb(result). of' = msb(result) ^ lsb(result). */
sewardj2a2ba8b2004-11-08 13:14:06 +0000279/* DEP1 = result, NDEP = old flags */
sewardjdf22c1c2004-10-16 22:59:59 +0000280#define ACTIONS_ROL(DATA_BITS,DATA_UTYPE) \
sewardjb9c5cf62004-08-24 15:10:38 +0000281{ \
282 PREAMBLE(DATA_BITS); \
sewardj948d48b2004-11-05 19:49:09 +0000283 Int fl \
sewardj2a2ba8b2004-11-08 13:14:06 +0000284 = (CC_NDEP & ~(CC_MASK_O | CC_MASK_C)) \
285 | (CC_MASK_C & CC_DEP1) \
286 | (CC_MASK_O & (lshift(CC_DEP1, 11-(DATA_BITS-1)) \
287 ^ lshift(CC_DEP1, 11))); \
sewardjb9c5cf62004-08-24 15:10:38 +0000288 return fl; \
sewardj8c7f1ab2004-07-29 20:31:09 +0000289}
290
sewardjb9c5cf62004-08-24 15:10:38 +0000291/*-------------------------------------------------------------*/
292
sewardj1813dbe2004-07-28 17:09:04 +0000293/* ROR: cf' = msb(result). of' = msb(result) ^ msb-1(result). */
sewardj2a2ba8b2004-11-08 13:14:06 +0000294/* DEP1 = result, NDEP = old flags */
sewardjdf22c1c2004-10-16 22:59:59 +0000295#define ACTIONS_ROR(DATA_BITS,DATA_UTYPE) \
sewardjb9c5cf62004-08-24 15:10:38 +0000296{ \
297 PREAMBLE(DATA_BITS); \
sewardj948d48b2004-11-05 19:49:09 +0000298 Int fl \
sewardj2a2ba8b2004-11-08 13:14:06 +0000299 = (CC_NDEP & ~(CC_MASK_O | CC_MASK_C)) \
300 | (CC_MASK_C & (CC_DEP1 >> (DATA_BITS-1))) \
301 | (CC_MASK_O & (lshift(CC_DEP1, 11-(DATA_BITS-1)) \
302 ^ lshift(CC_DEP1, 11-(DATA_BITS-1)+1))); \
sewardjb9c5cf62004-08-24 15:10:38 +0000303 return fl; \
sewardj1813dbe2004-07-28 17:09:04 +0000304}
305
sewardjb9c5cf62004-08-24 15:10:38 +0000306/*-------------------------------------------------------------*/
307
sewardj2a2ba8b2004-11-08 13:14:06 +0000308#define ACTIONS_UMUL(DATA_BITS,DATA_UTYPE,DATA_U2TYPE) \
309{ \
310 PREAMBLE(DATA_BITS); \
311 Int cf, pf, af, zf, sf, of; \
312 DATA_UTYPE hi; \
313 DATA_UTYPE lo = ((DATA_UTYPE)CC_DEP1) \
314 * ((DATA_UTYPE)CC_DEP2); \
315 DATA_U2TYPE rr = ((DATA_U2TYPE)((DATA_UTYPE)CC_DEP1)) \
316 * ((DATA_U2TYPE)((DATA_UTYPE)CC_DEP2)); \
317 hi = (DATA_UTYPE)(rr >>/*u*/ DATA_BITS); \
318 cf = (hi != 0); \
319 pf = parity_table[(UChar)lo]; \
320 af = 0; /* undefined */ \
321 zf = (lo == 0) << 6; \
322 sf = lshift(lo, 8 - DATA_BITS) & 0x80; \
323 of = cf << 11; \
324 return cf | pf | af | zf | sf | of; \
sewardj7ed22952004-07-29 00:09:58 +0000325}
sewardj741153c2004-07-25 23:39:13 +0000326
sewardjdf22c1c2004-10-16 22:59:59 +0000327/*-------------------------------------------------------------*/
328
sewardj2a2ba8b2004-11-08 13:14:06 +0000329#define ACTIONS_SMUL(DATA_BITS,DATA_STYPE,DATA_S2TYPE) \
330{ \
331 PREAMBLE(DATA_BITS); \
332 Int cf, pf, af, zf, sf, of; \
333 DATA_STYPE hi; \
334 DATA_STYPE lo = ((DATA_STYPE)CC_DEP1) \
335 * ((DATA_STYPE)CC_DEP2); \
336 DATA_S2TYPE rr = ((DATA_S2TYPE)((DATA_STYPE)CC_DEP1)) \
337 * ((DATA_S2TYPE)((DATA_STYPE)CC_DEP2)); \
338 hi = (DATA_STYPE)(rr >>/*s*/ DATA_BITS); \
339 cf = (hi != (lo >>/*s*/ (DATA_BITS-1))); \
340 pf = parity_table[(UChar)lo]; \
341 af = 0; /* undefined */ \
342 zf = (lo == 0) << 6; \
343 sf = lshift(lo, 8 - DATA_BITS) & 0x80; \
344 of = cf << 11; \
345 return cf | pf | af | zf | sf | of; \
sewardjdf22c1c2004-10-16 22:59:59 +0000346}
347
sewardj6e9964d2004-07-25 17:25:55 +0000348
sewardj84ff0652004-08-23 16:16:08 +0000349#if PROFILE_EFLAGS
350
351static UInt tabc[CC_OP_NUMBER];
352static UInt tab[CC_OP_NUMBER][16];
sewardj9eab5882004-08-25 16:38:30 +0000353static Bool initted = False;
sewardj84ff0652004-08-23 16:16:08 +0000354static UInt n_calc_cond = 0;
355static UInt n_calc_all = 0;
356static UInt n_calc_c = 0;
357
358static void showCounts ( void )
359{
360 Int op, co;
361 Char ch;
sewardj9eab5882004-08-25 16:38:30 +0000362 vex_printf("\nALL=%d COND=%d C=%d\n",
sewardj84ff0652004-08-23 16:16:08 +0000363 n_calc_all-n_calc_cond-n_calc_c, n_calc_cond, n_calc_c);
364 vex_printf(" CARRY O NO B NB Z NZ BE NBE"
365 " S NS P NP L NL LE NLE\n");
366 vex_printf(" ----------------------------------------------"
367 "----------------------------------------\n");
368 for (op = 0; op < CC_OP_NUMBER; op++) {
369
370 ch = ' ';
sewardj93d96e92004-11-08 17:39:55 +0000371 if (op > 0 && (op-1) % 3 == 0)
372 ch = 'B';
373 if (op > 0 && (op-1) % 3 == 1)
374 ch = 'W';
sewardj84ff0652004-08-23 16:16:08 +0000375 if (op > 0 && (op-1) % 3 == 2)
376 ch = 'L';
377
378 vex_printf("%2d%c: ", op, ch);
379 vex_printf("%6d ", tabc[op]);
380 for (co = 0; co < 16; co++) {
381 Int n = tab[op][co];
382 if (n >= 1000) {
383 vex_printf(" %3dK", n / 1000);
384 } else
385 if (n >= 0) {
386 vex_printf(" %3d ", n );
387 } else {
388 vex_printf(" ");
389 }
390 }
391 vex_printf("\n");
392 }
393 vex_printf("\n");
394}
395
396static void initCounts ( void )
397{
398 Int op, co;
399 initted = True;
400 for (op = 0; op < CC_OP_NUMBER; op++) {
401 tabc[op] = 0;
402 for (co = 0; co < 16; co++)
403 tab[op][co] = 0;
404 }
405}
406
407#endif /* PROFILE_EFLAGS */
408
sewardj9aebb0c2004-10-24 19:20:43 +0000409/* CALLED FROM GENERATED CODE: CLEAN HELPER */
sewardjb9c5cf62004-08-24 15:10:38 +0000410/* Calculate all the 6 flags from the supplied thunk parameters. */
sewardj2a2ba8b2004-11-08 13:14:06 +0000411UInt calculate_eflags_all ( UInt cc_op,
412 UInt cc_dep1_formal,
413 UInt cc_dep2_formal,
414 UInt cc_ndep_formal )
sewardj36ca5132004-07-24 13:12:23 +0000415{
sewardj84ff0652004-08-23 16:16:08 +0000416# if PROFILE_EFLAGS
417 n_calc_all++;
418# endif
sewardj36ca5132004-07-24 13:12:23 +0000419 switch (cc_op) {
sewardj1813dbe2004-07-28 17:09:04 +0000420 case CC_OP_COPY:
sewardj2a2ba8b2004-11-08 13:14:06 +0000421 return cc_dep1_formal
sewardjdf22c1c2004-10-16 22:59:59 +0000422 & (CC_MASK_O | CC_MASK_S | CC_MASK_Z
423 | CC_MASK_A | CC_MASK_C | CC_MASK_P);
sewardj14731f22004-07-25 01:24:28 +0000424
sewardj8c7f1ab2004-07-29 20:31:09 +0000425 case CC_OP_ADDB: ACTIONS_ADD( 8, UChar );
sewardja2384712004-07-29 14:36:40 +0000426 case CC_OP_ADDW: ACTIONS_ADD( 16, UShort );
sewardj8c7f1ab2004-07-29 20:31:09 +0000427 case CC_OP_ADDL: ACTIONS_ADD( 32, UInt );
sewardjafc57872004-07-25 18:00:18 +0000428
sewardj8c7f1ab2004-07-29 20:31:09 +0000429 case CC_OP_ADCB: ACTIONS_ADC( 8, UChar );
sewardja2384712004-07-29 14:36:40 +0000430 case CC_OP_ADCW: ACTIONS_ADC( 16, UShort );
sewardj8c7f1ab2004-07-29 20:31:09 +0000431 case CC_OP_ADCL: ACTIONS_ADC( 32, UInt );
sewardj741153c2004-07-25 23:39:13 +0000432
sewardj8c7f1ab2004-07-29 20:31:09 +0000433 case CC_OP_SUBB: ACTIONS_SUB( 8, UChar );
sewardja2384712004-07-29 14:36:40 +0000434 case CC_OP_SUBW: ACTIONS_SUB( 16, UShort );
sewardj8c7f1ab2004-07-29 20:31:09 +0000435 case CC_OP_SUBL: ACTIONS_SUB( 32, UInt );
sewardj5f630352004-07-25 18:18:03 +0000436
sewardj8c7f1ab2004-07-29 20:31:09 +0000437 case CC_OP_SBBB: ACTIONS_SBB( 8, UChar );
sewardja2384712004-07-29 14:36:40 +0000438 case CC_OP_SBBW: ACTIONS_SBB( 16, UShort );
sewardj8c7f1ab2004-07-29 20:31:09 +0000439 case CC_OP_SBBL: ACTIONS_SBB( 32, UInt );
sewardj750f4072004-07-26 22:39:11 +0000440
sewardj8c7f1ab2004-07-29 20:31:09 +0000441 case CC_OP_LOGICB: ACTIONS_LOGIC( 8, UChar );
sewardja2384712004-07-29 14:36:40 +0000442 case CC_OP_LOGICW: ACTIONS_LOGIC( 16, UShort );
sewardj8c7f1ab2004-07-29 20:31:09 +0000443 case CC_OP_LOGICL: ACTIONS_LOGIC( 32, UInt );
sewardj741153c2004-07-25 23:39:13 +0000444
sewardj8c7f1ab2004-07-29 20:31:09 +0000445 case CC_OP_INCB: ACTIONS_INC( 8, UChar );
sewardja2384712004-07-29 14:36:40 +0000446 case CC_OP_INCW: ACTIONS_INC( 16, UShort );
sewardj8c7f1ab2004-07-29 20:31:09 +0000447 case CC_OP_INCL: ACTIONS_INC( 32, UInt );
sewardj1813dbe2004-07-28 17:09:04 +0000448
sewardj8c7f1ab2004-07-29 20:31:09 +0000449 case CC_OP_DECB: ACTIONS_DEC( 8, UChar );
sewardja2384712004-07-29 14:36:40 +0000450 case CC_OP_DECW: ACTIONS_DEC( 16, UShort );
sewardj8c7f1ab2004-07-29 20:31:09 +0000451 case CC_OP_DECL: ACTIONS_DEC( 32, UInt );
sewardj1813dbe2004-07-28 17:09:04 +0000452
sewardj8c7f1ab2004-07-29 20:31:09 +0000453 case CC_OP_SHLB: ACTIONS_SHL( 8, UChar );
454 case CC_OP_SHLW: ACTIONS_SHL( 16, UShort );
455 case CC_OP_SHLL: ACTIONS_SHL( 32, UInt );
sewardja2384712004-07-29 14:36:40 +0000456
sewardj2a2ba8b2004-11-08 13:14:06 +0000457 case CC_OP_SHRB: ACTIONS_SHR( 8, UChar );
458 case CC_OP_SHRW: ACTIONS_SHR( 16, UShort );
459 case CC_OP_SHRL: ACTIONS_SHR( 32, UInt );
sewardj8c7f1ab2004-07-29 20:31:09 +0000460
461 case CC_OP_ROLB: ACTIONS_ROL( 8, UChar );
462 case CC_OP_ROLW: ACTIONS_ROL( 16, UShort );
463 case CC_OP_ROLL: ACTIONS_ROL( 32, UInt );
464
465 case CC_OP_RORB: ACTIONS_ROR( 8, UChar );
sewardja2384712004-07-29 14:36:40 +0000466 case CC_OP_RORW: ACTIONS_ROR( 16, UShort );
sewardj8c7f1ab2004-07-29 20:31:09 +0000467 case CC_OP_RORL: ACTIONS_ROR( 32, UInt );
sewardja2384712004-07-29 14:36:40 +0000468
sewardj2a2ba8b2004-11-08 13:14:06 +0000469 case CC_OP_UMULB: ACTIONS_UMUL( 8, UChar, UShort );
470 case CC_OP_UMULW: ACTIONS_UMUL( 16, UShort, UInt );
471 case CC_OP_UMULL: ACTIONS_UMUL( 32, UInt, ULong );
sewardj56296d82004-07-30 01:52:45 +0000472
sewardj2a2ba8b2004-11-08 13:14:06 +0000473 case CC_OP_SMULB: ACTIONS_SMUL( 8, Char, Short );
474 case CC_OP_SMULW: ACTIONS_SMUL( 16, Short, Int );
475 case CC_OP_SMULL: ACTIONS_SMUL( 32, Int, Long );
sewardj7ed22952004-07-29 00:09:58 +0000476
sewardj36ca5132004-07-24 13:12:23 +0000477 default:
478 /* shouldn't really make these calls from generated code */
sewardj2a2ba8b2004-11-08 13:14:06 +0000479 vex_printf("calculate_eflags_all( %d, 0x%x, 0x%x, 0x%x )\n",
480 cc_op, cc_dep1_formal, cc_dep2_formal, cc_ndep_formal );
sewardj36ca5132004-07-24 13:12:23 +0000481 vpanic("calculate_eflags_all");
482 }
483}
484
sewardjb9c5cf62004-08-24 15:10:38 +0000485
sewardj9aebb0c2004-10-24 19:20:43 +0000486/* CALLED FROM GENERATED CODE: CLEAN HELPER */
sewardjb9c5cf62004-08-24 15:10:38 +0000487/* Calculate just the carry flag from the supplied thunk parameters. */
sewardj2a2ba8b2004-11-08 13:14:06 +0000488UInt calculate_eflags_c ( UInt cc_op,
489 UInt cc_dep1,
490 UInt cc_dep2,
491 UInt cc_ndep )
sewardj36ca5132004-07-24 13:12:23 +0000492{
sewardj9eab5882004-08-25 16:38:30 +0000493 /* Fast-case some common ones. */
sewardj43c46952004-10-23 01:13:57 +0000494 switch (cc_op) {
495 case CC_OP_LOGICL: case CC_OP_LOGICW: case CC_OP_LOGICB:
496 return 0;
sewardj93d96e92004-11-08 17:39:55 +0000497 case CC_OP_SUBL:
498 return ((UInt)cc_dep1) < ((UInt)cc_dep2)
499 ? CC_MASK_C : 0;
500#if 0
501 case CC_OP_SUBB:
502 return ((UInt)(cc_dep1 & 0xFF)) < ((UInt)(cc_dep2 & 0xFF))
503 ? CC_MASK_C : 0;
504#endif
505#if 0
sewardj43c46952004-10-23 01:13:57 +0000506 case CC_OP_DECL:
507 return cc_src;
sewardj43c46952004-10-23 01:13:57 +0000508 case CC_OP_ADDL:
509 return ( ((UInt)cc_src + (UInt)cc_dst) < ((UInt)cc_src) )
510 ? CC_MASK_C : 0;
511 case CC_OP_SUBB:
512 return ( ((UInt)(cc_src & 0xFF)) > ((UInt)(cc_dst & 0xFF)) )
513 ? CC_MASK_C : 0;
sewardj948d48b2004-11-05 19:49:09 +0000514#endif
sewardj43c46952004-10-23 01:13:57 +0000515 default:
516 break;
517 }
sewardj9eab5882004-08-25 16:38:30 +0000518
sewardj84ff0652004-08-23 16:16:08 +0000519# if PROFILE_EFLAGS
520 if (!initted)
521 initCounts();
522 tabc[cc_op]++;
523
524 n_calc_c++;
525# endif
sewardj2a2ba8b2004-11-08 13:14:06 +0000526 return calculate_eflags_all(cc_op,cc_dep1,cc_dep2,cc_ndep) & CC_MASK_C;
sewardj36ca5132004-07-24 13:12:23 +0000527}
528
529
sewardj9aebb0c2004-10-24 19:20:43 +0000530/* CALLED FROM GENERATED CODE: CLEAN HELPER */
sewardj84ff0652004-08-23 16:16:08 +0000531/* returns 1 or 0 */
532/*static*/ UInt calculate_condition ( UInt/*Condcode*/ cond,
sewardj2a2ba8b2004-11-08 13:14:06 +0000533 UInt cc_op,
534 UInt cc_dep1,
535 UInt cc_dep2,
536 UInt cc_ndep )
sewardj84ff0652004-08-23 16:16:08 +0000537{
sewardj2a2ba8b2004-11-08 13:14:06 +0000538 UInt eflags = calculate_eflags_all(cc_op, cc_dep1, cc_dep2, cc_ndep);
sewardj84ff0652004-08-23 16:16:08 +0000539 UInt of,sf,zf,cf,pf;
540 UInt inv = cond & 1;
541
542# if PROFILE_EFLAGS
543 if (!initted)
544 initCounts();
545
546 tab[cc_op][cond]++;
547 n_calc_cond++;
548
sewardj93d96e92004-11-08 17:39:55 +0000549 if (0 == ((n_calc_all+n_calc_c) & 0x7FFFF)) showCounts();
sewardj84ff0652004-08-23 16:16:08 +0000550# endif
551
552 switch (cond) {
553 case CondNO:
554 case CondO: /* OF == 1 */
555 of = eflags >> CC_SHIFT_O;
556 return 1 & (inv ^ of);
557
558 case CondNZ:
559 case CondZ: /* ZF == 1 */
560 zf = eflags >> CC_SHIFT_Z;
561 return 1 & (inv ^ zf);
562
563 case CondNB:
564 case CondB: /* CF == 1 */
565 cf = eflags >> CC_SHIFT_C;
566 return 1 & (inv ^ cf);
567 break;
568
569 case CondNBE:
570 case CondBE: /* (CF or ZF) == 1 */
571 cf = eflags >> CC_SHIFT_C;
572 zf = eflags >> CC_SHIFT_Z;
573 return 1 & (inv ^ (cf | zf));
574 break;
575
576 case CondNS:
577 case CondS: /* SF == 1 */
578 sf = eflags >> CC_SHIFT_S;
579 return 1 & (inv ^ sf);
580
581 case CondNP:
582 case CondP: /* PF == 1 */
583 pf = eflags >> CC_SHIFT_P;
584 return 1 & (inv ^ pf);
585
586 case CondNL:
587 case CondL: /* (SF xor OF) == 1 */
588 sf = eflags >> CC_SHIFT_S;
589 of = eflags >> CC_SHIFT_O;
590 return 1 & (inv ^ (sf ^ of));
591 break;
592
593 case CondNLE:
594 case CondLE: /* ((SF xor OF) or ZF) == 1 */
595 sf = eflags >> CC_SHIFT_S;
596 of = eflags >> CC_SHIFT_O;
597 zf = eflags >> CC_SHIFT_Z;
598 return 1 & (inv ^ ((sf ^ of) | zf));
599 break;
600
601 default:
602 /* shouldn't really make these calls from generated code */
sewardj2a2ba8b2004-11-08 13:14:06 +0000603 vex_printf("calculate_condition( %d, %d, 0x%x, 0x%x, 0x%x )\n",
604 cond, cc_op, cc_dep1, cc_dep2, cc_ndep );
sewardj84ff0652004-08-23 16:16:08 +0000605 vpanic("calculate_condition");
606 }
607}
608
609
sewardj84ff0652004-08-23 16:16:08 +0000610/* Used by the optimiser to try specialisations. Returns an
611 equivalent expression, or NULL if none. */
612
613static Bool isU32 ( IRExpr* e, UInt n )
614{
615 return e->tag == Iex_Const
616 && e->Iex.Const.con->tag == Ico_U32
617 && e->Iex.Const.con->Ico.U32 == n;
618}
619
620IRExpr* x86guest_spechelper ( Char* function_name,
621 IRExpr** args )
622{
623# define unop(_op,_a1) IRExpr_Unop((_op),(_a1))
624# define binop(_op,_a1,_a2) IRExpr_Binop((_op),(_a1),(_a2))
625# define mkU32(_n) IRExpr_Const(IRConst_U32(_n))
626
627 Int i, arity = 0;
628 for (i = 0; args[i]; i++)
629 arity++;
630# if 0
631 vex_printf("spec request:\n");
632 vex_printf(" %s ", function_name);
633 for (i = 0; i < arity; i++) {
634 vex_printf(" ");
635 ppIRExpr(args[i]);
636 }
637 vex_printf("\n");
638# endif
sewardj93d96e92004-11-08 17:39:55 +0000639
640 /* --------- specialising "calculate_eflags_c" --------- */
641
sewardj84ff0652004-08-23 16:16:08 +0000642 if (vex_streq(function_name, "calculate_eflags_c")) {
643 /* specialise calls to above "calculate_eflags_c" function */
sewardj93d96e92004-11-08 17:39:55 +0000644 IRExpr *cc_op, *cc_dep1, *cc_dep2, *cc_ndep;
645 vassert(arity == 4);
646 cc_op = args[0];
647 cc_dep1 = args[1];
648 cc_dep2 = args[2];
649 cc_ndep = args[3];
sewardj84ff0652004-08-23 16:16:08 +0000650
sewardj93d96e92004-11-08 17:39:55 +0000651 if (isU32(cc_op, CC_OP_SUBL)) {
652 /* C after sub denotes unsigned less than */
653 return unop(Iop_1Uto32,
654 binop(Iop_CmpLT32U, cc_dep1, cc_dep2));
655 }
sewardj84ff0652004-08-23 16:16:08 +0000656 if (isU32(cc_op, CC_OP_LOGICL)) {
657 /* cflag after logic is zero */
658 return mkU32(0);
659 }
660 if (isU32(cc_op, CC_OP_DECL) || isU32(cc_op, CC_OP_INCL)) {
sewardj22419b82004-11-10 23:27:07 +0000661 /* If the thunk is dec or inc, the cflag is supplied as CC_NDEP. */
sewardje7bd0682004-11-10 23:25:37 +0000662 return cc_ndep;
sewardj84ff0652004-08-23 16:16:08 +0000663 }
sewardj84ff0652004-08-23 16:16:08 +0000664# if 0
665 if (cc_op->tag == Iex_Const) {
666 vex_printf("CFLAG "); ppIRExpr(cc_op); vex_printf("\n");
667 }
668# endif
669
670 return NULL;
671 }
672
sewardj93d96e92004-11-08 17:39:55 +0000673 /* --------- specialising "calculate_condition" --------- */
674
sewardj84ff0652004-08-23 16:16:08 +0000675 if (vex_streq(function_name, "calculate_condition")) {
676 /* specialise calls to above "calculate condition" function */
sewardj93d96e92004-11-08 17:39:55 +0000677 IRExpr *cond, *cc_op, *cc_dep1, *cc_dep2, *cc_ndep;
678 vassert(arity == 5);
679 cond = args[0];
680 cc_op = args[1];
681 cc_dep1 = args[2];
682 cc_dep2 = args[3];
683 cc_ndep = args[4];
sewardj84ff0652004-08-23 16:16:08 +0000684
sewardj46ccb512004-08-26 01:25:07 +0000685 /*---------------- SUBL ----------------*/
sewardj84ff0652004-08-23 16:16:08 +0000686
687 if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondZ)) {
sewardjb9c5cf62004-08-24 15:10:38 +0000688 /* long sub/cmp, then Z --> test dst==src */
689 return unop(Iop_1Uto32,
sewardj93d96e92004-11-08 17:39:55 +0000690 binop(Iop_CmpEQ32, cc_dep1, cc_dep2));
sewardj84ff0652004-08-23 16:16:08 +0000691 }
692
693 if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondL)) {
sewardjb9c5cf62004-08-24 15:10:38 +0000694 /* long sub/cmp, then L (signed less than)
695 --> test dst <s src */
sewardj84ff0652004-08-23 16:16:08 +0000696 return unop(Iop_1Uto32,
sewardj93d96e92004-11-08 17:39:55 +0000697 binop(Iop_CmpLT32S, cc_dep1, cc_dep2));
sewardj84ff0652004-08-23 16:16:08 +0000698 }
699
700 if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondLE)) {
sewardjb9c5cf62004-08-24 15:10:38 +0000701 /* long sub/cmp, then LE (signed less than or equal)
702 --> test dst <=s src */
sewardj84ff0652004-08-23 16:16:08 +0000703 return unop(Iop_1Uto32,
sewardj93d96e92004-11-08 17:39:55 +0000704 binop(Iop_CmpLE32S, cc_dep1, cc_dep2));
sewardj84ff0652004-08-23 16:16:08 +0000705 }
706
707 if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondBE)) {
sewardjb9c5cf62004-08-24 15:10:38 +0000708 /* long sub/cmp, then BE (unsigned less than or equal)
709 --> test dst <=u src */
sewardj84ff0652004-08-23 16:16:08 +0000710 return unop(Iop_1Uto32,
sewardj93d96e92004-11-08 17:39:55 +0000711 binop(Iop_CmpLE32U, cc_dep1, cc_dep2));
sewardj84ff0652004-08-23 16:16:08 +0000712 }
sewardj93d96e92004-11-08 17:39:55 +0000713#if 0
sewardjaf991de2004-08-24 23:50:56 +0000714 if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondB)) {
715 /* long sub/cmp, then B (unsigned less than)
716 --> test dst <u src */
717 return unop(Iop_1Uto32,
718 binop(Iop_CmpLT32U, cc_dst, cc_src));
719 }
sewardj7e6644c2004-11-10 12:10:23 +0000720#endif
sewardj46ccb512004-08-26 01:25:07 +0000721 /*---------------- SUBW ----------------*/
722
723 if (isU32(cc_op, CC_OP_SUBW) && isU32(cond, CondZ)) {
724 /* byte sub/cmp, then Z --> test dst==src */
725 return unop(Iop_1Uto32,
726 binop(Iop_CmpEQ16,
sewardj7e6644c2004-11-10 12:10:23 +0000727 unop(Iop_32to16,cc_dep1),
728 unop(Iop_32to16,cc_dep2)));
sewardj46ccb512004-08-26 01:25:07 +0000729 }
730
731 /*---------------- SUBB ----------------*/
sewardj7e6644c2004-11-10 12:10:23 +0000732
sewardj46ccb512004-08-26 01:25:07 +0000733 if (isU32(cc_op, CC_OP_SUBB) && isU32(cond, CondZ)) {
734 /* byte sub/cmp, then Z --> test dst==src */
735 return unop(Iop_1Uto32,
736 binop(Iop_CmpEQ8,
sewardj93d96e92004-11-08 17:39:55 +0000737 unop(Iop_32to8,cc_dep1),
738 unop(Iop_32to8,cc_dep2)));
sewardj46ccb512004-08-26 01:25:07 +0000739 }
740
741 if (isU32(cc_op, CC_OP_SUBB) && isU32(cond, CondNZ)) {
sewardj7e5b7cd2004-11-08 18:20:23 +0000742 /* byte sub/cmp, then NZ --> test dst!=src */
sewardj46ccb512004-08-26 01:25:07 +0000743 return unop(Iop_1Uto32,
744 binop(Iop_CmpNE8,
sewardj93d96e92004-11-08 17:39:55 +0000745 unop(Iop_32to8,cc_dep1),
746 unop(Iop_32to8,cc_dep2)));
sewardj46ccb512004-08-26 01:25:07 +0000747 }
sewardj22419b82004-11-10 23:27:07 +0000748
sewardj46ccb512004-08-26 01:25:07 +0000749 if (isU32(cc_op, CC_OP_SUBB) && isU32(cond, CondNBE)) {
750 /* long sub/cmp, then NBE (unsigned greater than)
751 --> test src <=u dst */
sewardj7e5b7cd2004-11-08 18:20:23 +0000752 /* Note, args are opposite way round from the usual */
sewardj46ccb512004-08-26 01:25:07 +0000753 return unop(Iop_1Uto32,
754 binop(Iop_CmpLT32U,
sewardj7e5b7cd2004-11-08 18:20:23 +0000755 binop(Iop_And32,cc_dep2,mkU32(0xFF)),
756 binop(Iop_And32,cc_dep1,mkU32(0xFF))));
sewardj46ccb512004-08-26 01:25:07 +0000757 }
758
759 /*---------------- LOGICL ----------------*/
760
761 if (isU32(cc_op, CC_OP_LOGICL) && isU32(cond, CondZ)) {
762 /* long and/or/xor, then Z --> test dst==0 */
sewardj93d96e92004-11-08 17:39:55 +0000763 return unop(Iop_1Uto32,binop(Iop_CmpEQ32, cc_dep1, mkU32(0)));
sewardj46ccb512004-08-26 01:25:07 +0000764 }
sewardj22419b82004-11-10 23:27:07 +0000765
sewardj46ccb512004-08-26 01:25:07 +0000766 if (isU32(cc_op, CC_OP_LOGICL) && isU32(cond, CondS)) {
767 /* long and/or/xor, then S --> test dst <s 0 */
sewardj7e6644c2004-11-10 12:10:23 +0000768 return unop(Iop_1Uto32,binop(Iop_CmpLT32S, cc_dep1, mkU32(0)));
sewardj46ccb512004-08-26 01:25:07 +0000769 }
sewardj22419b82004-11-10 23:27:07 +0000770
sewardj46ccb512004-08-26 01:25:07 +0000771 if (isU32(cc_op, CC_OP_LOGICL) && isU32(cond, CondLE)) {
772 /* long and/or/xor, then LE
773 This is pretty subtle. LOGIC sets SF and ZF according to the
774 result and makes OF be zero. LE computes (SZ ^ OF) | ZF, but
775 OF is zero, so this reduces to SZ | ZF -- which will be 1 iff
776 the result is <=signed 0. Hence ...
777 */
sewardj93d96e92004-11-08 17:39:55 +0000778 return unop(Iop_1Uto32,binop(Iop_CmpLE32S, cc_dep1, mkU32(0)));
sewardj46ccb512004-08-26 01:25:07 +0000779 }
780
781 /*---------------- LOGICB ----------------*/
782
783 if (isU32(cc_op, CC_OP_LOGICB) && isU32(cond, CondZ)) {
784 /* byte and/or/xor, then Z --> test dst==0 */
785 return unop(Iop_1Uto32,
sewardj93d96e92004-11-08 17:39:55 +0000786 binop(Iop_CmpEQ32, binop(Iop_And32,cc_dep1,mkU32(255)),
sewardj46ccb512004-08-26 01:25:07 +0000787 mkU32(0)));
788 }
789
790 /*---------------- DECL ----------------*/
791
sewardj84ff0652004-08-23 16:16:08 +0000792 if (isU32(cc_op, CC_OP_DECL) && isU32(cond, CondZ)) {
793 /* dec L, then Z --> test dst == 0 */
sewardj93d96e92004-11-08 17:39:55 +0000794 return unop(Iop_1Uto32,binop(Iop_CmpEQ32, cc_dep1, mkU32(0)));
sewardj84ff0652004-08-23 16:16:08 +0000795 }
sewardj22419b82004-11-10 23:27:07 +0000796
sewardjfae2ca72004-08-24 01:16:01 +0000797 if (isU32(cc_op, CC_OP_DECL) && isU32(cond, CondS)) {
798 /* dec L, then S --> compare DST <s 0 */
sewardj7e6644c2004-11-10 12:10:23 +0000799 return unop(Iop_1Uto32,binop(Iop_CmpLT32S, cc_dep1, mkU32(0)));
sewardjfae2ca72004-08-24 01:16:01 +0000800 }
801
sewardj84ff0652004-08-23 16:16:08 +0000802 return NULL;
803 }
804
805# undef unop
806# undef binop
807# undef mkU32
808
809 return NULL;
810}
811
sewardj36ca5132004-07-24 13:12:23 +0000812
sewardj0c2cb622004-09-06 23:21:21 +0000813/*-----------------------------------------------------------*/
814/*--- Utility functions for x87 FPU conversions. ---*/
815/*-----------------------------------------------------------*/
816
817
818/* 80 and 64-bit floating point formats:
819
820 80-bit:
821
822 S 0 0-------0 zero
823 S 0 0X------X denormals
824 S 1-7FFE 1X------X normals (all normals have leading 1)
825 S 7FFF 10------0 infinity
826 S 7FFF 10X-----X snan
827 S 7FFF 11X-----X qnan
828
829 S is the sign bit. For runs X----X, at least one of the Xs must be
830 nonzero. Exponent is 15 bits, fractional part is 63 bits, and
831 there is an explicitly represented leading 1, and a sign bit,
832 giving 80 in total.
833
834 64-bit avoids the confusion of an explicitly represented leading 1
835 and so is simpler:
836
837 S 0 0------0 zero
838 S 0 X------X denormals
839 S 1-7FE any normals
840 S 7FF 0------0 infinity
841 S 7FF 0X-----X snan
842 S 7FF 1X-----X qnan
843
844 Exponent is 11 bits, fractional part is 52 bits, and there is a
845 sign bit, giving 64 in total.
846*/
847
sewardjc4be80c2004-09-10 16:17:45 +0000848static inline Bool host_is_little_endian ( void )
849{
850 UInt x = 0x76543210;
851 UChar* p = (UChar*)(&x);
852 return (*p == 0x10);
853}
854
sewardj9aebb0c2004-10-24 19:20:43 +0000855/* CALLED FROM GENERATED CODE: CLEAN HELPER */
sewardj8ea867b2004-10-30 19:03:02 +0000856UInt calculate_FXAM ( UInt tag, ULong dbl )
sewardjc4be80c2004-09-10 16:17:45 +0000857{
858 Bool mantissaIsZero;
859 Int bexp;
860 UChar sign;
861 UInt c1;
862 UChar* f64;
863
sewardjf5e36672004-09-21 23:38:53 +0000864 if (!host_is_little_endian()) {
sewardjc4be80c2004-09-10 16:17:45 +0000865 vassert(0);
866 }
867
868 /* vex_printf("calculate_FXAM ( %d, %llx ) .. ", tag, dbl ); */
869
870 f64 = (UChar*)(&dbl);
871 sign = (f64[7] >> 7) & 1;
872
873 /* First off, if the tag indicates the register was empty,
874 return 1,0,sign,1 */
875 if (tag == 0) {
876 /* vex_printf("Empty\n"); */
877 return FC_MASK_C3 | 0 | sign | FC_MASK_C0;
878 }
879
880 bexp = (f64[7] << 4) | ((f64[6] >> 4) & 0x0F);
881 bexp &= 0x7FF;
882
883 c1 = ((UInt)sign) << 9;
884
885 mantissaIsZero
886 = (f64[6] & 0x0F) == 0
887 && (f64[5] | f64[4] | f64[3] | f64[2] | f64[1] | f64[0]) == 0;
888
889 /* If both exponent and mantissa are zero, the value is zero.
890 Return 1,0,sign,0. */
891 if (bexp == 0 && mantissaIsZero) {
892 /* vex_printf("Zero\n"); */
893 return FC_MASK_C3 | 0 | sign | 0;
894 }
895
896 /* If exponent is zero but mantissa isn't, it's a denormal.
897 Return 1,1,sign,0. */
898 if (bexp == 0 && !mantissaIsZero) {
899 /* vex_printf("Denormal\n"); */
900 return FC_MASK_C3 | FC_MASK_C2 | sign | 0;
901 }
902
903 /* If the exponent is 7FF and the mantissa is zero, this is an infinity.
904 Return 0,1,sign,1. */
905 if (bexp == 0x7FF && mantissaIsZero) {
906 /* vex_printf("Inf\n"); */
907 return 0 | FC_MASK_C2 | sign | FC_MASK_C0;
908 }
909
910 /* If the exponent is 7FF and the mantissa isn't zero, this is a NaN.
911 Return 0,0,sign,1. */
912 if (bexp == 0x7FF && !mantissaIsZero) {
913 /* vex_printf("NaN\n"); */
914 return 0 | 0 | sign | FC_MASK_C0;
915 }
916
917 /* Uh, ok, we give up. It must be a normal finite number.
918 Return 0,1,sign,0.
919 */
920 /* vex_printf("normal\n"); */
921 return 0 | FC_MASK_C2 | sign | 0;
922}
923
sewardj0c2cb622004-09-06 23:21:21 +0000924
925/* Convert a IEEE754 double (64-bit) into an x87 extended double
926 (80-bit), mimicing the hardware fairly closely. Both numbers are
927 stored little-endian. Limitations, all of which could be fixed,
928 given some level of hassle:
929
930 * Does not handle double precision denormals. As a result, values
931 with magnitudes less than 1e-308 are flushed to zero when they
932 need not be.
933
934 * Identity of NaNs is not preserved.
935
936 See comments in the code for more details.
937*/
938static void convert_f64le_to_f80le ( /*IN*/UChar* f64, /*OUT*/UChar* f80 )
939{
940 Bool isInf;
941 Int bexp;
942 UChar sign;
943
944 sign = (f64[7] >> 7) & 1;
945 bexp = (f64[7] << 4) | ((f64[6] >> 4) & 0x0F);
946 bexp &= 0x7FF;
947
948 /* If the exponent is zero, either we have a zero or a denormal.
949 Produce a zero. This is a hack in that it forces denormals to
950 zero. Could do better. */
951 if (bexp == 0) {
952 f80[9] = sign << 7;
953 f80[8] = f80[7] = f80[6] = f80[5] = f80[4]
954 = f80[3] = f80[2] = f80[1] = f80[0] = 0;
955 return;
956 }
957
958 /* If the exponent is 7FF, this is either an Infinity, a SNaN or
959 QNaN, as determined by examining bits 51:0, thus:
960 0 ... 0 Inf
961 0X ... X SNaN
962 1X ... X QNaN
963 where at least one of the Xs is not zero.
964 */
965 if (bexp == 0x7FF) {
966 isInf = (f64[6] & 0x0F) == 0
967 && f64[5] == 0 && f64[4] == 0 && f64[3] == 0
968 && f64[2] == 0 && f64[1] == 0 && f64[0] == 0;
969 if (isInf) {
970 /* Produce an appropriately signed infinity:
971 S 1--1 (15) 1 0--0 (63)
972 */
973 f80[9] = (sign << 7) | 0x7F;
974 f80[8] = 0xFF;
975 f80[7] = 0x80;
976 f80[6] = f80[5] = f80[4] = f80[3]
977 = f80[2] = f80[1] = f80[0] = 0;
978 return;
979 }
980 /* So it's either a QNaN or SNaN. Distinguish by considering
981 bit 51. Note, this destroys all the trailing bits
982 (identity?) of the NaN. IEEE754 doesn't require preserving
983 these (it only requires that there be one QNaN value and one
984 SNaN value), but x87 does seem to have some ability to
985 preserve them. Anyway, here, the NaN's identity is
986 destroyed. Could be improved. */
987 if (f64[6] & 8) {
988 /* QNaN. Make a QNaN:
989 S 1--1 (15) 1 1--1 (63)
990 */
991 f80[9] = (sign << 7) | 0x7F;
992 f80[8] = 0xFF;
993 f80[7] = 0xFF;
994 f80[6] = f80[5] = f80[4] = f80[3]
995 = f80[2] = f80[1] = f80[0] = 0xFF;
996 } else {
997 /* SNaN. Make a SNaN:
998 S 1--1 (15) 0 1--1 (63)
999 */
1000 f80[9] = (sign << 7) | 0x7F;
1001 f80[8] = 0xFF;
1002 f80[7] = 0x7F;
1003 f80[6] = f80[5] = f80[4] = f80[3]
1004 = f80[2] = f80[1] = f80[0] = 0xFF;
1005 }
1006 return;
1007 }
1008
1009 /* It's not a zero, denormal, infinity or nan. So it must be a
1010 normalised number. Rebias the exponent and build the new
1011 number. */
1012 bexp += (16383 - 1023);
1013
1014 f80[9] = (sign << 7) | ((bexp >> 8) & 0xFF);
1015 f80[8] = bexp & 0xFF;
1016 f80[7] = (1 << 7) | ((f64[6] << 3) & 0x78) | ((f64[5] >> 5) & 7);
1017 f80[6] = ((f64[5] << 3) & 0xF8) | ((f64[4] >> 5) & 7);
1018 f80[5] = ((f64[4] << 3) & 0xF8) | ((f64[3] >> 5) & 7);
1019 f80[4] = ((f64[3] << 3) & 0xF8) | ((f64[2] >> 5) & 7);
1020 f80[3] = ((f64[2] << 3) & 0xF8) | ((f64[1] >> 5) & 7);
1021 f80[2] = ((f64[1] << 3) & 0xF8) | ((f64[0] >> 5) & 7);
1022 f80[1] = ((f64[0] << 3) & 0xF8);
1023 f80[0] = 0;
1024}
1025
1026
1027/////////////////////////////////////////////////////////////////
1028
1029/* Convert a x87 extended double (80-bit) into an IEEE 754 double
1030 (64-bit), mimicing the hardware fairly closely. Both numbers are
1031 stored little-endian. Limitations, all of which could be fixed,
1032 given some level of hassle:
1033
1034 * Does not create double precision denormals. As a result, values
1035 with magnitudes less than 1e-308 are flushed to zero when they
1036 need not be.
1037
1038 * Rounding following truncation could be a bit better.
1039
1040 * Identity of NaNs is not preserved.
1041
1042 See comments in the code for more details.
1043*/
1044static void convert_f80le_to_f64le ( /*IN*/UChar* f80, /*OUT*/UChar* f64 )
1045{
1046 Bool isInf;
1047 Int bexp;
1048 UChar sign;
1049
1050 sign = (f80[9] >> 7) & 1;
1051 bexp = (((UInt)f80[9]) << 8) | (UInt)f80[8];
1052 bexp &= 0x7FFF;
1053
1054 /* If the exponent is zero, either we have a zero or a denormal.
1055 But an extended precision denormal becomes a double precision
1056 zero, so in either case, just produce the appropriately signed
1057 zero. */
1058 if (bexp == 0) {
1059 f64[7] = sign << 7;
1060 f64[6] = f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0;
1061 return;
1062 }
1063
1064 /* If the exponent is 7FFF, this is either an Infinity, a SNaN or
1065 QNaN, as determined by examining bits 62:0, thus:
1066 0 ... 0 Inf
1067 0X ... X SNaN
1068 1X ... X QNaN
1069 where at least one of the Xs is not zero.
1070 */
1071 if (bexp == 0x7FFF) {
1072 isInf = (f80[7] & 0x7F) == 0
1073 && f80[6] == 0 && f80[5] == 0 && f80[4] == 0
1074 && f80[3] == 0 && f80[2] == 0 && f80[1] == 0 && f80[0] == 0;
1075 if (isInf) {
1076 if (0 == (f80[7] & 0x80))
1077 goto wierd_NaN;
1078 /* Produce an appropriately signed infinity:
1079 S 1--1 (11) 0--0 (52)
1080 */
1081 f64[7] = (sign << 7) | 0x7F;
1082 f64[6] = 0xF0;
1083 f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0;
1084 return;
1085 }
1086 /* So it's either a QNaN or SNaN. Distinguish by considering
1087 bit 62. Note, this destroys all the trailing bits
1088 (identity?) of the NaN. IEEE754 doesn't require preserving
1089 these (it only requires that there be one QNaN value and one
1090 SNaN value), but x87 does seem to have some ability to
1091 preserve them. Anyway, here, the NaN's identity is
1092 destroyed. Could be improved. */
1093 if (f80[8] & 0x40) {
1094 /* QNaN. Make a QNaN:
1095 S 1--1 (11) 1 1--1 (51)
1096 */
1097 f64[7] = (sign << 7) | 0x7F;
1098 f64[6] = 0xFF;
1099 f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0xFF;
1100 } else {
1101 /* SNaN. Make a SNaN:
1102 S 1--1 (11) 0 1--1 (51)
1103 */
1104 f64[7] = (sign << 7) | 0x7F;
1105 f64[6] = 0xF7;
1106 f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0xFF;
1107 }
1108 return;
1109 }
1110
1111 /* If it's not a Zero, NaN or Inf, and the integer part (bit 62) is
1112 zero, the x87 FPU appears to consider the number denormalised
1113 and converts it to a QNaN. */
1114 if (0 == (f80[7] & 0x80)) {
1115 wierd_NaN:
1116 /* Strange hardware QNaN:
1117 S 1--1 (11) 1 0--0 (51)
1118 */
1119 /* On a PIII, these QNaNs always appear with sign==1. I have
1120 no idea why. */
1121 f64[7] = (1 /*sign*/ << 7) | 0x7F;
1122 f64[6] = 0xF8;
1123 f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0;
1124 return;
1125 }
1126
1127 /* It's not a zero, denormal, infinity or nan. So it must be a
1128 normalised number. Rebias the exponent and consider. */
1129 bexp -= (16383 - 1023);
1130 if (bexp >= 0x7FF) {
1131 /* It's too big for a double. Construct an infinity. */
1132 f64[7] = (sign << 7) | 0x7F;
1133 f64[6] = 0xF0;
1134 f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0;
1135 return;
1136 }
1137
1138 if (bexp < 0) {
1139 /* It's too small for a double. Construct a zero. Note, this
1140 is a kludge since we could conceivably create a
1141 denormalised number for bexp in -1 to -51, but we don't
1142 bother. This means the conversion flushes values
1143 approximately in the range 1e-309 to 1e-324 ish to zero
1144 when it doesn't actually need to. This could be
1145 improved. */
1146 f64[7] = sign << 7;
1147 f64[6] = f64[5] = f64[4] = f64[3] = f64[2] = f64[1] = f64[0] = 0;
1148 return;
1149 }
1150
1151 /* Ok, it's a normalised number which is representable as a double.
1152 Copy the exponent and mantissa into place. */
1153 /*
1154 for (i = 0; i < 52; i++)
1155 write_bit_array ( f64,
1156 i,
1157 read_bit_array ( f80, i+11 ) );
1158 */
1159 f64[0] = (f80[1] >> 3) | (f80[2] << 5);
1160 f64[1] = (f80[2] >> 3) | (f80[3] << 5);
1161 f64[2] = (f80[3] >> 3) | (f80[4] << 5);
1162 f64[3] = (f80[4] >> 3) | (f80[5] << 5);
1163 f64[4] = (f80[5] >> 3) | (f80[6] << 5);
1164 f64[5] = (f80[6] >> 3) | (f80[7] << 5);
1165
1166 f64[6] = ((bexp << 4) & 0xF0) | ((f80[7] >> 3) & 0x0F);
1167
1168 f64[7] = (sign << 7) | ((bexp >> 4) & 0x7F);
1169
1170 /* Now consider any rounding that needs to happen as a result of
1171 truncating the mantissa. */
1172 if (f80[1] & 4) /* read_bit_array(f80, 10) == 1) */ {
1173 /* Round upwards. This is a kludge. Once in every 64k
1174 roundings (statistically) the bottom two bytes are both 0xFF
1175 and so we don't round at all. Could be improved. */
1176 if (f64[0] != 0xFF) {
1177 f64[0]++;
1178 }
1179 else
1180 if (f64[0] == 0xFF && f64[1] != 0xFF) {
1181 f64[0] = 0;
1182 f64[1]++;
1183 }
1184 /* else we don't round, but we should. */
1185 }
1186}
1187
sewardj17442fe2004-09-20 14:54:28 +00001188/* CALLED FROM GENERATED CODE */
1189/* DIRTY HELPER (reads guest memory) */
sewardj8ea867b2004-10-30 19:03:02 +00001190ULong loadF80le ( UInt addrU )
sewardj17442fe2004-09-20 14:54:28 +00001191{
1192 ULong f64;
1193 convert_f80le_to_f64le ( (UChar*)addrU, (UChar*)&f64 );
1194 return f64;
1195}
1196
1197/* CALLED FROM GENERATED CODE */
1198/* DIRTY HELPER (writes guest memory) */
sewardj8ea867b2004-10-30 19:03:02 +00001199void storeF80le ( UInt addrU, ULong f64 )
sewardj17442fe2004-09-20 14:54:28 +00001200{
1201 convert_f64le_to_f80le( (UChar*)&f64, (UChar*)addrU );
1202}
1203
sewardj0c2cb622004-09-06 23:21:21 +00001204
1205/*----------------------------------------------*/
1206/*--- The exported fns .. ---*/
1207/*----------------------------------------------*/
1208
1209/* Layout of the real x87 state. */
1210
1211typedef
1212 struct {
1213 UShort env[14];
1214 UChar reg[80];
1215 }
1216 Fpu_State;
1217
1218/* Offsets, in 16-bit ints, into the FPU environment (env) area. */
1219#define FP_ENV_CTRL 0
1220#define FP_ENV_STAT 2
1221#define FP_ENV_TAG 4
1222#define FP_ENV_IP 6 /* and 7 */
1223#define FP_ENV_CS 8
1224#define FP_ENV_OPOFF 10 /* and 11 */
1225#define FP_ENV_OPSEL 12
1226#define FP_REG(ii) (10*(7-(ii)))
1227
1228
1229/* VISIBLE TO LIBVEX CLIENT */
sewardj76bdc802004-10-25 15:33:26 +00001230void LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state,
1231 /*OUT*/VexGuestX86State* vex_state )
sewardj0c2cb622004-09-06 23:21:21 +00001232{
1233 Int r;
1234 UInt tag;
sewardjf6dc3ce2004-10-19 01:03:46 +00001235 Double* vexRegs = (Double*)(&vex_state->guest_FPREG[0]);
1236 UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
sewardj0c2cb622004-09-06 23:21:21 +00001237 Fpu_State* x87 = (Fpu_State*)x87_state;
1238 UInt ftop = (x87->env[FP_ENV_STAT] >> 11) & 7;
1239 UInt tagw = x87->env[FP_ENV_TAG];
sewardj6e0dbda2004-09-08 19:06:34 +00001240 UInt fpucw = x87->env[FP_ENV_CTRL];
sewardjc4be80c2004-09-10 16:17:45 +00001241 UInt c3210 = x87->env[FP_ENV_STAT] & 0x4700;
sewardj0c2cb622004-09-06 23:21:21 +00001242
1243 /* Copy registers and tags */
1244 for (r = 0; r < 8; r++) {
1245 tag = (tagw >> (2*r)) & 3;
1246 if (tag == 3) {
1247 /* register is empty */
1248 vexRegs[r] = 0.0;
1249 vexTags[r] = 0;
1250 } else {
1251 /* register is non-empty */
1252 convert_f80le_to_f64le( &x87->reg[FP_REG(r)], (UChar*)&vexRegs[r] );
1253 vexTags[r] = 1;
1254 }
1255 }
1256
1257 /* stack pointer */
sewardjf6dc3ce2004-10-19 01:03:46 +00001258 vex_state->guest_FTOP = ftop;
sewardj0c2cb622004-09-06 23:21:21 +00001259
sewardj6e0dbda2004-09-08 19:06:34 +00001260 /* control word */
sewardjf6dc3ce2004-10-19 01:03:46 +00001261 vex_state->guest_FPUCW = fpucw;
sewardj3f868e52004-09-09 00:19:22 +00001262
1263 /* status word */
sewardjf6dc3ce2004-10-19 01:03:46 +00001264 vex_state->guest_FC3210 = c3210;
sewardj0c2cb622004-09-06 23:21:21 +00001265}
1266
sewardj6e0dbda2004-09-08 19:06:34 +00001267
sewardj0c2cb622004-09-06 23:21:21 +00001268/* VISIBLE TO LIBVEX CLIENT */
sewardj76bdc802004-10-25 15:33:26 +00001269void LibVEX_GuestX86_get_x87 ( /*IN*/VexGuestX86State* vex_state,
1270 /*OUT*/UChar* x87_state )
sewardj0c2cb622004-09-06 23:21:21 +00001271{
1272 Int i, r;
1273 UInt tagw;
sewardjf6dc3ce2004-10-19 01:03:46 +00001274 Double* vexRegs = (Double*)(&vex_state->guest_FPREG[0]);
1275 UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
sewardj0c2cb622004-09-06 23:21:21 +00001276 Fpu_State* x87 = (Fpu_State*)x87_state;
sewardjf6dc3ce2004-10-19 01:03:46 +00001277 UInt ftop = vex_state->guest_FTOP;
1278 UInt c3210 = vex_state->guest_FC3210;
sewardj0c2cb622004-09-06 23:21:21 +00001279
1280 for (i = 0; i < 14; i++)
1281 x87->env[i] = 0;
1282
1283 x87->env[1] = x87->env[3] = x87->env[5] = x87->env[13] = 0xFFFF;
sewardjf6dc3ce2004-10-19 01:03:46 +00001284 x87->env[FP_ENV_CTRL] = (UShort)( vex_state->guest_FPUCW );
sewardjc4be80c2004-09-10 16:17:45 +00001285 x87->env[FP_ENV_STAT] = ((ftop & 7) << 11) | (c3210 & 0x4700);
sewardj0c2cb622004-09-06 23:21:21 +00001286
1287 tagw = 0;
1288 for (r = 0; r < 8; r++) {
1289 if (vexTags[r] == 0) {
1290 /* register is empty */
1291 tagw |= (3 << (2*r));
1292 convert_f64le_to_f80le( (UChar*)&vexRegs[r], &x87->reg[FP_REG(r)] );
1293 } else {
1294 /* register is full. */
1295 tagw |= (0 << (2*r));
1296 convert_f64le_to_f80le( (UChar*)&vexRegs[r], &x87->reg[FP_REG(r)] );
1297 }
1298 }
1299 x87->env[FP_ENV_TAG] = tagw;
1300}
1301
1302
sewardjf6dc3ce2004-10-19 01:03:46 +00001303/* VISIBLE TO LIBVEX CLIENT */
sewardj76bdc802004-10-25 15:33:26 +00001304void LibVEX_GuestX86_put_eflags ( UInt eflags_native,
1305 /*OUT*/VexGuestX86State* vex_state )
sewardjf6dc3ce2004-10-19 01:03:46 +00001306{
1307 vex_state->guest_DFLAG
1308 = (eflags_native & (1<<10)) ? 0xFFFFFFFF : 0x00000001;
sewardj006a6a22004-10-26 00:50:52 +00001309 vex_state->guest_IDFLAG
1310 = (eflags_native & (1<<21)) ? 1 : 0;
sewardjf6dc3ce2004-10-19 01:03:46 +00001311
1312 /* Mask out everything except O S Z A C P. */
1313 eflags_native
1314 &= (CC_MASK_C | CC_MASK_P | CC_MASK_A
1315 | CC_MASK_Z | CC_MASK_S | CC_MASK_O);
1316
sewardj2a2ba8b2004-11-08 13:14:06 +00001317 vex_state->guest_CC_OP = CC_OP_COPY;
1318 vex_state->guest_CC_DEP1 = eflags_native;
1319 vex_state->guest_CC_DEP2 = 0;
1320 vex_state->guest_CC_NDEP = 0; /* unnecessary paranoia */
sewardjf6dc3ce2004-10-19 01:03:46 +00001321}
1322
1323
1324/* VISIBLE TO LIBVEX CLIENT */
sewardj76bdc802004-10-25 15:33:26 +00001325UInt LibVEX_GuestX86_get_eflags ( /*IN*/VexGuestX86State* vex_state )
sewardjf6dc3ce2004-10-19 01:03:46 +00001326{
1327 UInt eflags = calculate_eflags_all(
1328 vex_state->guest_CC_OP,
sewardj2a2ba8b2004-11-08 13:14:06 +00001329 vex_state->guest_CC_DEP1,
1330 vex_state->guest_CC_DEP2,
1331 vex_state->guest_CC_NDEP
sewardjf6dc3ce2004-10-19 01:03:46 +00001332 );
1333 UInt dflag = vex_state->guest_DFLAG;
1334 vassert(dflag == 1 || dflag == 0xFFFFFFFF);
1335 if (dflag == 0xFFFFFFFF)
1336 eflags |= (1<<10);
sewardj006a6a22004-10-26 00:50:52 +00001337 if (vex_state->guest_IDFLAG == 1)
1338 eflags |= (1<<21);
sewardjf6dc3ce2004-10-19 01:03:46 +00001339
1340 return eflags;
1341}
1342
sewardjdda7a4c2004-10-19 23:42:00 +00001343/* VISIBLE TO LIBVEX CLIENT */
sewardj76bdc802004-10-25 15:33:26 +00001344void LibVEX_GuestX86_initialise ( /*OUT*/VexGuestX86State* vex_state )
sewardjdda7a4c2004-10-19 23:42:00 +00001345{
1346 Int i;
sewardj76bdc802004-10-25 15:33:26 +00001347
1348 vex_state->guest_EAX = 0;
1349 vex_state->guest_ECX = 0;
1350 vex_state->guest_EDX = 0;
1351 vex_state->guest_EBX = 0;
1352 vex_state->guest_ESP = 0;
1353 vex_state->guest_EBP = 0;
1354 vex_state->guest_ESI = 0;
1355 vex_state->guest_EDI = 0;
1356
sewardj2a2ba8b2004-11-08 13:14:06 +00001357 vex_state->guest_CC_OP = CC_OP_COPY;
1358 vex_state->guest_CC_DEP1 = 0;
1359 vex_state->guest_CC_DEP2 = 0;
1360 vex_state->guest_CC_NDEP = 0;
1361 vex_state->guest_DFLAG = 1; /* forwards */
1362 vex_state->guest_IDFLAG = 0;
sewardj76bdc802004-10-25 15:33:26 +00001363
1364 vex_state->guest_EIP = 0;
1365
1366 vex_state->guest_FTOP = 0;
sewardjdda7a4c2004-10-19 23:42:00 +00001367 for (i = 0; i < 8; i++) {
1368 vex_state->guest_FPTAG[i] = 0; /* empty */
1369 vex_state->guest_FPREG[i] = 0; /* IEEE754 64-bit zero */
1370 }
sewardjdda7a4c2004-10-19 23:42:00 +00001371 /* The default setting: all fp exceptions masked, rounding to
1372 nearest, precision to 64 bits */
1373 vex_state->guest_FPUCW = 0x03F7;
sewardj76bdc802004-10-25 15:33:26 +00001374 vex_state->guest_FC3210 = 0;
1375
1376 vex_state->guest_CS = 0;
1377 vex_state->guest_DS = 0;
1378 vex_state->guest_ES = 0;
1379 vex_state->guest_FS = 0;
1380 vex_state->guest_GS = 0;
1381 vex_state->guest_SS = 0;
sewardjdda7a4c2004-10-19 23:42:00 +00001382}
sewardjf6dc3ce2004-10-19 01:03:46 +00001383
1384
sewardj9aebb0c2004-10-24 19:20:43 +00001385/*----------------------------------------------*/
1386/*--- Misc integer helpers ---*/
1387/*----------------------------------------------*/
1388
1389/* CALLED FROM GENERATED CODE: CLEAN HELPER */
1390/* Calculate both flags and value result for rotate right
1391 through the carry bit. Result in low 32 bits,
1392 new flags (OSZACP) in high 32 bits.
1393*/
sewardj8ea867b2004-10-30 19:03:02 +00001394ULong calculate_RCR ( UInt arg, UInt rot_amt, UInt eflags_in, UInt sz )
sewardj9aebb0c2004-10-24 19:20:43 +00001395{
1396 UInt tempCOUNT = rot_amt & 0x1F, cf=0, of=0, tempcf;
1397
1398 switch (sz) {
1399 case 4:
1400 cf = (eflags_in >> CC_SHIFT_C) & 1;
1401 of = ((arg >> 31) ^ cf) & 1;
1402 while (tempCOUNT > 0) {
1403 tempcf = arg & 1;
1404 arg = (arg >> 1) | (cf << 31);
1405 cf = tempcf;
1406 tempCOUNT--;
1407 }
1408 break;
1409 case 2:
1410 while (tempCOUNT >= 17) tempCOUNT -= 17;
1411 cf = (eflags_in >> CC_SHIFT_C) & 1;
1412 of = ((arg >> 15) ^ cf) & 1;
1413 while (tempCOUNT > 0) {
1414 tempcf = arg & 1;
1415 arg = ((arg >> 1) & 0x7FFF) | (cf << 15);
1416 cf = tempcf;
1417 tempCOUNT--;
1418 }
1419 break;
1420 case 1:
1421 while (tempCOUNT >= 9) tempCOUNT -= 9;
1422 cf = (eflags_in >> CC_SHIFT_C) & 1;
1423 of = ((arg >> 7) ^ cf) & 1;
1424 while (tempCOUNT > 0) {
1425 tempcf = arg & 1;
1426 arg = ((arg >> 1) & 0x7F) | (cf << 7);
1427 cf = tempcf;
1428 tempCOUNT--;
1429 }
1430 break;
1431 default:
1432 vpanic("calculate_RCR: invalid size");
1433 }
1434
1435 cf &= 1;
1436 of &= 1;
1437 eflags_in &= ~(CC_MASK_C | CC_MASK_O);
1438 eflags_in |= (cf << CC_SHIFT_C) | (of << CC_SHIFT_O);
1439
1440 return (((ULong)eflags_in) << 32) | ((ULong)arg);
1441}
1442
sewardj7cb49d72004-10-24 22:31:25 +00001443
1444/* CALLED FROM GENERATED CODE */
1445/* DIRTY HELPER (modifies guest state) */
1446/* Claim to be a P54C P133 (pre-MMX Pentium) */
sewardj8ea867b2004-10-30 19:03:02 +00001447void dirtyhelper_CPUID ( VexGuestX86State* st )
sewardj7cb49d72004-10-24 22:31:25 +00001448{
1449 if (st->guest_EAX == 0) {
1450 st->guest_EAX = 0x1;
1451 st->guest_EBX = 0x756e6547;
1452 st->guest_ECX = 0x6c65746e;
1453 st->guest_EDX = 0x49656e69;
1454 } else {
1455 st->guest_EAX = 0x52b;
1456 st->guest_EBX = 0x0;
1457 st->guest_ECX = 0x0;
1458 st->guest_EDX = 0x1bf;
1459 }
1460}
1461
sewardj8d2291c2004-10-25 14:50:21 +00001462/*-----------------------------------------------------------*/
1463/*--- Describing the x86 guest state, for the benefit ---*/
1464/*--- of iropt and instrumenters. ---*/
1465/*-----------------------------------------------------------*/
1466
1467/* Figure out if any part of the guest state contained in minoff
1468 .. maxoff requires precise memory exceptions. If in doubt return
1469 True (but this is generates significantly slower code).
1470
1471 We enforce precise exns for guest %ESP and %EIP only.
1472*/
1473Bool guest_x86_state_requires_precise_mem_exns ( Int minoff,
1474 Int maxoff)
1475{
1476 Int esp_min = offsetof(VexGuestX86State, guest_ESP);
1477 Int esp_max = esp_min + 4 - 1;
1478 Int eip_min = offsetof(VexGuestX86State, guest_EIP);
1479 Int eip_max = eip_min + 4 - 1;
1480
1481 if (maxoff < esp_min || minoff > esp_max) {
sewardjeeac8412004-11-02 00:26:55 +00001482 /* no overlap with esp */
sewardj8d2291c2004-10-25 14:50:21 +00001483 } else {
sewardjeeac8412004-11-02 00:26:55 +00001484 return True;
sewardj8d2291c2004-10-25 14:50:21 +00001485 }
1486
1487 if (maxoff < eip_min || minoff > eip_max) {
sewardjeeac8412004-11-02 00:26:55 +00001488 /* no overlap with eip */
sewardj8d2291c2004-10-25 14:50:21 +00001489 } else {
sewardjeeac8412004-11-02 00:26:55 +00001490 return True;
sewardj8d2291c2004-10-25 14:50:21 +00001491 }
1492
1493 return False;
1494}
1495
1496
sewardjeeac8412004-11-02 00:26:55 +00001497#define ALWAYSDEFD(field) \
1498 { offsetof(VexGuestX86State, field), \
1499 (sizeof ((VexGuestX86State*)0)->field) }
1500
1501VexGuestLayout
sewardj49651f42004-10-28 22:11:04 +00001502 x86guest_layout
sewardjeeac8412004-11-02 00:26:55 +00001503 = {
1504 /* Total size of the guest state, in bytes. */
1505 .total_sizeB = sizeof(VexGuestX86State),
1506
1507 /* Describe the stack pointer. */
1508 .offset_SP = offsetof(VexGuestX86State,guest_ESP),
1509 .sizeof_SP = 4,
1510
sewardjcf787902004-11-03 09:08:33 +00001511 /* Describe the instruction pointer. */
1512 .offset_IP = offsetof(VexGuestX86State,guest_EIP),
1513 .sizeof_IP = 4,
sewardjeeac8412004-11-02 00:26:55 +00001514
1515 /* Describe any sections to be regarded by Memcheck as
1516 'always-defined'. */
sewardj948d48b2004-11-05 19:49:09 +00001517 .n_alwaysDefd = 15,
sewardj2a2ba8b2004-11-08 13:14:06 +00001518 /* flags thunk: OP and NDEP are always defd, whereas DEP1
1519 and DEP2 have to be tracked. See detailed comment in
1520 gdefs.h on meaning of thunk fields. */
sewardjeeac8412004-11-02 00:26:55 +00001521 .alwaysDefd[0] = ALWAYSDEFD(guest_CC_OP),
sewardj2a2ba8b2004-11-08 13:14:06 +00001522 .alwaysDefd[1] = ALWAYSDEFD(guest_CC_NDEP),
sewardjb128ebe2004-11-06 12:21:23 +00001523
1524 .alwaysDefd[2] = ALWAYSDEFD(guest_DFLAG),
1525 .alwaysDefd[3] = ALWAYSDEFD(guest_IDFLAG),
1526 .alwaysDefd[4] = ALWAYSDEFD(guest_EIP),
1527 .alwaysDefd[5] = ALWAYSDEFD(guest_FTOP),
1528 .alwaysDefd[6] = ALWAYSDEFD(guest_FPTAG),
1529 .alwaysDefd[7] = ALWAYSDEFD(guest_FPUCW),
1530 .alwaysDefd[8] = ALWAYSDEFD(guest_FC3210),
1531 .alwaysDefd[9] = ALWAYSDEFD(guest_CS),
1532 .alwaysDefd[10] = ALWAYSDEFD(guest_DS),
1533 .alwaysDefd[11] = ALWAYSDEFD(guest_ES),
1534 .alwaysDefd[12] = ALWAYSDEFD(guest_FS),
1535 .alwaysDefd[13] = ALWAYSDEFD(guest_GS),
1536 .alwaysDefd[14] = ALWAYSDEFD(guest_SS)
sewardjeeac8412004-11-02 00:26:55 +00001537 };
sewardj49651f42004-10-28 22:11:04 +00001538
1539
sewardj36ca5132004-07-24 13:12:23 +00001540/*---------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +00001541/*--- end guest-x86/ghelpers.c ---*/
sewardj36ca5132004-07-24 13:12:23 +00001542/*---------------------------------------------------------------*/