blob: d905c194548020af3bd70d1ef9215bf3a3f7d581 [file] [log] [blame]
njn9c6acb02004-11-30 15:56:47 +00001
2/*---------------------------------------------------------------*/
sewardj752f9062010-05-03 21:38:49 +00003/*--- begin guest_amd64_helpers.c ---*/
njn9c6acb02004-11-30 15:56:47 +00004/*---------------------------------------------------------------*/
5
6/*
sewardj752f9062010-05-03 21:38:49 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
njn9c6acb02004-11-30 15:56:47 +00009
sewardj752f9062010-05-03 21:38:49 +000010 Copyright (C) 2004-2010 OpenWorks LLP
11 info@open-works.net
njn9c6acb02004-11-30 15:56:47 +000012
sewardj752f9062010-05-03 21:38:49 +000013 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
njn9c6acb02004-11-30 15:56:47 +000017
sewardj752f9062010-05-03 21:38:49 +000018 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
sewardj7bd6ffe2005-08-03 16:07:36 +000026 02110-1301, USA.
27
sewardj752f9062010-05-03 21:38:49 +000028 The GNU General Public License is contained in the file COPYING.
njn9c6acb02004-11-30 15:56:47 +000029
30 Neither the names of the U.S. Department of Energy nor the
31 University of California nor the names of its contributors may be
32 used to endorse or promote products derived from this software
33 without prior written permission.
njn9c6acb02004-11-30 15:56:47 +000034*/
35
36#include "libvex_basictypes.h"
37#include "libvex_emwarn.h"
38#include "libvex_guest_amd64.h"
39#include "libvex_ir.h"
40#include "libvex.h"
41
sewardjcef7d3e2009-07-02 12:21:59 +000042#include "main_util.h"
43#include "guest_generic_bb_to_IR.h"
44#include "guest_amd64_defs.h"
45#include "guest_generic_x87.h"
sewardj44d494d2005-01-20 20:26:33 +000046
sewardjf8c37f72005-02-07 18:55:29 +000047
48/* This file contains helper functions for amd64 guest code.
49 Calls to these functions are generated by the back end.
50 These calls are of course in the host machine code and
51 this file will be compiled to host machine code, so that
52 all makes sense.
53
54 Only change the signatures of these helper functions very
55 carefully. If you change the signature here, you'll have to change
56 the parameters passed to it in the IR calls constructed by
57 guest-amd64/toIR.c.
58
59 The convention used is that all functions called from generated
60 code are named amd64g_<something>, and any function whose name lacks
61 that prefix is not called from generated code. Note that some
62 LibVEX_* functions can however be called by VEX's client, but that
63 is not the same as calling them from VEX-generated code.
64*/
65
66
67/* Set to 1 to get detailed profiling info about use of the flag
68 machinery. */
69#define PROFILE_RFLAGS 0
70
71
72/*---------------------------------------------------------------*/
73/*--- %rflags run-time helpers. ---*/
74/*---------------------------------------------------------------*/
75
sewardj1a01e652005-02-23 11:39:21 +000076/* Do 64x64 -> 128 signed/unsigned multiplies, for computing flags
77 after imulq/mulq. */
78
79static void mullS64 ( Long u, Long v, Long* rHi, Long* rLo )
80{
81 ULong u0, v0, w0;
82 Long u1, v1, w1, w2, t;
sewardjdbdc5b32005-03-25 20:31:46 +000083 u0 = u & 0xFFFFFFFFULL;
sewardj1a01e652005-02-23 11:39:21 +000084 u1 = u >> 32;
sewardjdbdc5b32005-03-25 20:31:46 +000085 v0 = v & 0xFFFFFFFFULL;
sewardj1a01e652005-02-23 11:39:21 +000086 v1 = v >> 32;
87 w0 = u0 * v0;
88 t = u1 * v0 + (w0 >> 32);
sewardjdbdc5b32005-03-25 20:31:46 +000089 w1 = t & 0xFFFFFFFFULL;
sewardj1a01e652005-02-23 11:39:21 +000090 w2 = t >> 32;
91 w1 = u0 * v1 + w1;
92 *rHi = u1 * v1 + w2 + (w1 >> 32);
93 *rLo = u * v;
94}
95
96static void mullU64 ( ULong u, ULong v, ULong* rHi, ULong* rLo )
97{
98 ULong u0, v0, w0;
99 ULong u1, v1, w1,w2,t;
sewardjdbdc5b32005-03-25 20:31:46 +0000100 u0 = u & 0xFFFFFFFFULL;
sewardj1a01e652005-02-23 11:39:21 +0000101 u1 = u >> 32;
sewardjdbdc5b32005-03-25 20:31:46 +0000102 v0 = v & 0xFFFFFFFFULL;
sewardj1a01e652005-02-23 11:39:21 +0000103 v1 = v >> 32;
104 w0 = u0 * v0;
105 t = u1 * v0 + (w0 >> 32);
sewardjdbdc5b32005-03-25 20:31:46 +0000106 w1 = t & 0xFFFFFFFFULL;
sewardj1a01e652005-02-23 11:39:21 +0000107 w2 = t >> 32;
108 w1 = u0 * v1 + w1;
109 *rHi = u1 * v1 + w2 + (w1 >> 32);
110 *rLo = u * v;
111}
112
113
sewardjf8c37f72005-02-07 18:55:29 +0000114static const UChar parity_table[256] = {
115 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
116 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
117 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
118 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
119 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
120 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
121 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
122 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
123 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
124 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
125 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
126 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
127 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
128 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
129 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
130 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
131 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
132 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
133 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
134 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
135 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
136 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
137 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
138 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
139 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
140 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
141 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
142 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
143 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
144 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
145 AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0,
146 0, AMD64G_CC_MASK_P, AMD64G_CC_MASK_P, 0, AMD64G_CC_MASK_P, 0, 0, AMD64G_CC_MASK_P,
147};
148
sewardj4a6f3842005-03-26 11:59:23 +0000149/* generalised left-shifter */
sewardj1fa7b802005-03-25 14:39:37 +0000150static inline Long lshift ( Long x, Int n )
sewardj118b23e2005-01-29 02:14:44 +0000151{
sewardjf8c37f72005-02-07 18:55:29 +0000152 if (n >= 0)
153 return x << n;
154 else
155 return x >> (-n);
sewardj118b23e2005-01-29 02:14:44 +0000156}
157
sewardj1fa7b802005-03-25 14:39:37 +0000158/* identity on ULong */
159static inline ULong idULong ( ULong x )
160{
161 return x;
162}
163
sewardj118b23e2005-01-29 02:14:44 +0000164
sewardjf8c37f72005-02-07 18:55:29 +0000165#define PREAMBLE(__data_bits) \
166 /* const */ ULong DATA_MASK \
167 = __data_bits==8 \
168 ? 0xFFULL \
169 : (__data_bits==16 \
170 ? 0xFFFFULL \
171 : (__data_bits==32 \
172 ? 0xFFFFFFFFULL \
173 : 0xFFFFFFFFFFFFFFFFULL)); \
174 /* const */ ULong SIGN_MASK = 1ULL << (__data_bits - 1); \
175 /* const */ ULong CC_DEP1 = cc_dep1_formal; \
176 /* const */ ULong CC_DEP2 = cc_dep2_formal; \
177 /* const */ ULong CC_NDEP = cc_ndep_formal; \
178 /* Four bogus assignments, which hopefully gcc can */ \
179 /* optimise away, and which stop it complaining about */ \
180 /* unused variables. */ \
181 SIGN_MASK = SIGN_MASK; \
182 DATA_MASK = DATA_MASK; \
183 CC_DEP2 = CC_DEP2; \
184 CC_NDEP = CC_NDEP;
185
186
187/*-------------------------------------------------------------*/
188
189#define ACTIONS_ADD(DATA_BITS,DATA_UTYPE) \
190{ \
191 PREAMBLE(DATA_BITS); \
192 { Long cf, pf, af, zf, sf, of; \
193 Long argL, argR, res; \
194 argL = CC_DEP1; \
195 argR = CC_DEP2; \
196 res = argL + argR; \
197 cf = (DATA_UTYPE)res < (DATA_UTYPE)argL; \
198 pf = parity_table[(UChar)res]; \
199 af = (res ^ argL ^ argR) & 0x10; \
200 zf = ((DATA_UTYPE)res == 0) << 6; \
201 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
202 of = lshift((argL ^ argR ^ -1) & (argL ^ res), \
203 12 - DATA_BITS) & AMD64G_CC_MASK_O; \
204 return cf | pf | af | zf | sf | of; \
205 } \
sewardjdf0e0022005-01-25 15:48:43 +0000206}
sewardj44d494d2005-01-20 20:26:33 +0000207
sewardjf8c37f72005-02-07 18:55:29 +0000208/*-------------------------------------------------------------*/
209
210#define ACTIONS_SUB(DATA_BITS,DATA_UTYPE) \
211{ \
212 PREAMBLE(DATA_BITS); \
213 { Long cf, pf, af, zf, sf, of; \
214 Long argL, argR, res; \
215 argL = CC_DEP1; \
216 argR = CC_DEP2; \
217 res = argL - argR; \
218 cf = (DATA_UTYPE)argL < (DATA_UTYPE)argR; \
219 pf = parity_table[(UChar)res]; \
220 af = (res ^ argL ^ argR) & 0x10; \
221 zf = ((DATA_UTYPE)res == 0) << 6; \
222 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
223 of = lshift((argL ^ argR) & (argL ^ res), \
224 12 - DATA_BITS) & AMD64G_CC_MASK_O; \
225 return cf | pf | af | zf | sf | of; \
226 } \
sewardj354e5c62005-01-27 20:12:52 +0000227}
228
sewardjf8c37f72005-02-07 18:55:29 +0000229/*-------------------------------------------------------------*/
230
231#define ACTIONS_ADC(DATA_BITS,DATA_UTYPE) \
232{ \
233 PREAMBLE(DATA_BITS); \
234 { Long cf, pf, af, zf, sf, of; \
235 Long argL, argR, oldC, res; \
236 oldC = CC_NDEP & AMD64G_CC_MASK_C; \
237 argL = CC_DEP1; \
238 argR = CC_DEP2 ^ oldC; \
239 res = (argL + argR) + oldC; \
240 if (oldC) \
241 cf = (DATA_UTYPE)res <= (DATA_UTYPE)argL; \
242 else \
243 cf = (DATA_UTYPE)res < (DATA_UTYPE)argL; \
244 pf = parity_table[(UChar)res]; \
245 af = (res ^ argL ^ argR) & 0x10; \
246 zf = ((DATA_UTYPE)res == 0) << 6; \
247 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
248 of = lshift((argL ^ argR ^ -1) & (argL ^ res), \
249 12 - DATA_BITS) & AMD64G_CC_MASK_O; \
250 return cf | pf | af | zf | sf | of; \
251 } \
252}
253
254/*-------------------------------------------------------------*/
255
256#define ACTIONS_SBB(DATA_BITS,DATA_UTYPE) \
257{ \
258 PREAMBLE(DATA_BITS); \
259 { Long cf, pf, af, zf, sf, of; \
260 Long argL, argR, oldC, res; \
261 oldC = CC_NDEP & AMD64G_CC_MASK_C; \
262 argL = CC_DEP1; \
263 argR = CC_DEP2 ^ oldC; \
264 res = (argL - argR) - oldC; \
265 if (oldC) \
266 cf = (DATA_UTYPE)argL <= (DATA_UTYPE)argR; \
267 else \
268 cf = (DATA_UTYPE)argL < (DATA_UTYPE)argR; \
269 pf = parity_table[(UChar)res]; \
270 af = (res ^ argL ^ argR) & 0x10; \
271 zf = ((DATA_UTYPE)res == 0) << 6; \
272 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
273 of = lshift((argL ^ argR) & (argL ^ res), \
274 12 - DATA_BITS) & AMD64G_CC_MASK_O; \
275 return cf | pf | af | zf | sf | of; \
276 } \
277}
278
279/*-------------------------------------------------------------*/
280
281#define ACTIONS_LOGIC(DATA_BITS,DATA_UTYPE) \
282{ \
283 PREAMBLE(DATA_BITS); \
284 { Long cf, pf, af, zf, sf, of; \
285 cf = 0; \
286 pf = parity_table[(UChar)CC_DEP1]; \
287 af = 0; \
288 zf = ((DATA_UTYPE)CC_DEP1 == 0) << 6; \
289 sf = lshift(CC_DEP1, 8 - DATA_BITS) & 0x80; \
290 of = 0; \
291 return cf | pf | af | zf | sf | of; \
292 } \
293}
294
295/*-------------------------------------------------------------*/
296
297#define ACTIONS_INC(DATA_BITS,DATA_UTYPE) \
298{ \
299 PREAMBLE(DATA_BITS); \
300 { Long cf, pf, af, zf, sf, of; \
301 Long argL, argR, res; \
302 res = CC_DEP1; \
303 argL = res - 1; \
304 argR = 1; \
305 cf = CC_NDEP & AMD64G_CC_MASK_C; \
306 pf = parity_table[(UChar)res]; \
307 af = (res ^ argL ^ argR) & 0x10; \
308 zf = ((DATA_UTYPE)res == 0) << 6; \
309 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
310 of = ((res & DATA_MASK) == SIGN_MASK) << 11; \
311 return cf | pf | af | zf | sf | of; \
312 } \
313}
314
315/*-------------------------------------------------------------*/
316
317#define ACTIONS_DEC(DATA_BITS,DATA_UTYPE) \
318{ \
319 PREAMBLE(DATA_BITS); \
320 { Long cf, pf, af, zf, sf, of; \
321 Long argL, argR, res; \
322 res = CC_DEP1; \
323 argL = res + 1; \
324 argR = 1; \
325 cf = CC_NDEP & AMD64G_CC_MASK_C; \
326 pf = parity_table[(UChar)res]; \
327 af = (res ^ argL ^ argR) & 0x10; \
328 zf = ((DATA_UTYPE)res == 0) << 6; \
329 sf = lshift(res, 8 - DATA_BITS) & 0x80; \
330 of = ((res & DATA_MASK) \
331 == ((ULong)SIGN_MASK - 1)) << 11; \
332 return cf | pf | af | zf | sf | of; \
333 } \
334}
335
336/*-------------------------------------------------------------*/
337
338#define ACTIONS_SHL(DATA_BITS,DATA_UTYPE) \
339{ \
340 PREAMBLE(DATA_BITS); \
341 { Long cf, pf, af, zf, sf, of; \
342 cf = (CC_DEP2 >> (DATA_BITS - 1)) & AMD64G_CC_MASK_C; \
343 pf = parity_table[(UChar)CC_DEP1]; \
344 af = 0; /* undefined */ \
345 zf = ((DATA_UTYPE)CC_DEP1 == 0) << 6; \
346 sf = lshift(CC_DEP1, 8 - DATA_BITS) & 0x80; \
347 /* of is defined if shift count == 1 */ \
348 of = lshift(CC_DEP2 ^ CC_DEP1, 12 - DATA_BITS) \
349 & AMD64G_CC_MASK_O; \
350 return cf | pf | af | zf | sf | of; \
351 } \
352}
353
354/*-------------------------------------------------------------*/
355
356#define ACTIONS_SHR(DATA_BITS,DATA_UTYPE) \
357{ \
358 PREAMBLE(DATA_BITS); \
359 { Long cf, pf, af, zf, sf, of; \
360 cf = CC_DEP2 & 1; \
361 pf = parity_table[(UChar)CC_DEP1]; \
362 af = 0; /* undefined */ \
363 zf = ((DATA_UTYPE)CC_DEP1 == 0) << 6; \
364 sf = lshift(CC_DEP1, 8 - DATA_BITS) & 0x80; \
365 /* of is defined if shift count == 1 */ \
366 of = lshift(CC_DEP2 ^ CC_DEP1, 12 - DATA_BITS) \
367 & AMD64G_CC_MASK_O; \
368 return cf | pf | af | zf | sf | of; \
369 } \
370}
371
372/*-------------------------------------------------------------*/
373
374/* ROL: cf' = lsb(result). of' = msb(result) ^ lsb(result). */
375/* DEP1 = result, NDEP = old flags */
376#define ACTIONS_ROL(DATA_BITS,DATA_UTYPE) \
377{ \
378 PREAMBLE(DATA_BITS); \
379 { Long fl \
380 = (CC_NDEP & ~(AMD64G_CC_MASK_O | AMD64G_CC_MASK_C)) \
sewardj7de0d3c2005-02-13 02:26:41 +0000381 | (AMD64G_CC_MASK_C & CC_DEP1) \
sewardjf8c37f72005-02-07 18:55:29 +0000382 | (AMD64G_CC_MASK_O & (lshift(CC_DEP1, \
383 11-(DATA_BITS-1)) \
384 ^ lshift(CC_DEP1, 11))); \
385 return fl; \
386 } \
387}
388
389/*-------------------------------------------------------------*/
390
391/* ROR: cf' = msb(result). of' = msb(result) ^ msb-1(result). */
392/* DEP1 = result, NDEP = old flags */
393#define ACTIONS_ROR(DATA_BITS,DATA_UTYPE) \
394{ \
395 PREAMBLE(DATA_BITS); \
396 { Long fl \
397 = (CC_NDEP & ~(AMD64G_CC_MASK_O | AMD64G_CC_MASK_C)) \
398 | (AMD64G_CC_MASK_C & (CC_DEP1 >> (DATA_BITS-1))) \
399 | (AMD64G_CC_MASK_O & (lshift(CC_DEP1, \
400 11-(DATA_BITS-1)) \
401 ^ lshift(CC_DEP1, 11-(DATA_BITS-1)+1))); \
402 return fl; \
403 } \
404}
405
406/*-------------------------------------------------------------*/
407
sewardj1fa7b802005-03-25 14:39:37 +0000408#define ACTIONS_UMUL(DATA_BITS, DATA_UTYPE, NARROWtoU, \
409 DATA_U2TYPE, NARROWto2U) \
sewardjf8c37f72005-02-07 18:55:29 +0000410{ \
411 PREAMBLE(DATA_BITS); \
412 { Long cf, pf, af, zf, sf, of; \
413 DATA_UTYPE hi; \
sewardj1fa7b802005-03-25 14:39:37 +0000414 DATA_UTYPE lo \
415 = NARROWtoU( ((DATA_UTYPE)CC_DEP1) \
416 * ((DATA_UTYPE)CC_DEP2) ); \
417 DATA_U2TYPE rr \
418 = NARROWto2U( \
419 ((DATA_U2TYPE)((DATA_UTYPE)CC_DEP1)) \
420 * ((DATA_U2TYPE)((DATA_UTYPE)CC_DEP2)) ); \
421 hi = NARROWtoU(rr >>/*u*/ DATA_BITS); \
sewardjf8c37f72005-02-07 18:55:29 +0000422 cf = (hi != 0); \
423 pf = parity_table[(UChar)lo]; \
424 af = 0; /* undefined */ \
425 zf = (lo == 0) << 6; \
426 sf = lshift(lo, 8 - DATA_BITS) & 0x80; \
427 of = cf << 11; \
428 return cf | pf | af | zf | sf | of; \
429 } \
430}
431
432/*-------------------------------------------------------------*/
433
sewardj1fa7b802005-03-25 14:39:37 +0000434#define ACTIONS_SMUL(DATA_BITS, DATA_STYPE, NARROWtoS, \
435 DATA_S2TYPE, NARROWto2S) \
sewardjf8c37f72005-02-07 18:55:29 +0000436{ \
437 PREAMBLE(DATA_BITS); \
438 { Long cf, pf, af, zf, sf, of; \
439 DATA_STYPE hi; \
sewardj1fa7b802005-03-25 14:39:37 +0000440 DATA_STYPE lo \
441 = NARROWtoS( ((DATA_STYPE)CC_DEP1) \
442 * ((DATA_STYPE)CC_DEP2) ); \
443 DATA_S2TYPE rr \
444 = NARROWto2S( \
445 ((DATA_S2TYPE)((DATA_STYPE)CC_DEP1)) \
446 * ((DATA_S2TYPE)((DATA_STYPE)CC_DEP2)) ); \
447 hi = NARROWtoS(rr >>/*s*/ DATA_BITS); \
sewardjf8c37f72005-02-07 18:55:29 +0000448 cf = (hi != (lo >>/*s*/ (DATA_BITS-1))); \
449 pf = parity_table[(UChar)lo]; \
450 af = 0; /* undefined */ \
451 zf = (lo == 0) << 6; \
452 sf = lshift(lo, 8 - DATA_BITS) & 0x80; \
453 of = cf << 11; \
454 return cf | pf | af | zf | sf | of; \
455 } \
456}
457
sewardj1a01e652005-02-23 11:39:21 +0000458/*-------------------------------------------------------------*/
459
460#define ACTIONS_UMULQ \
461{ \
462 PREAMBLE(64); \
463 { Long cf, pf, af, zf, sf, of; \
464 ULong lo, hi; \
465 mullU64( (ULong)CC_DEP1, (ULong)CC_DEP2, &hi, &lo ); \
466 cf = (hi != 0); \
467 pf = parity_table[(UChar)lo]; \
468 af = 0; /* undefined */ \
469 zf = (lo == 0) << 6; \
470 sf = lshift(lo, 8 - 64) & 0x80; \
471 of = cf << 11; \
472 return cf | pf | af | zf | sf | of; \
473 } \
474}
475
476/*-------------------------------------------------------------*/
477
478#define ACTIONS_SMULQ \
479{ \
480 PREAMBLE(64); \
481 { Long cf, pf, af, zf, sf, of; \
482 Long lo, hi; \
483 mullS64( (Long)CC_DEP1, (Long)CC_DEP2, &hi, &lo ); \
484 cf = (hi != (lo >>/*s*/ (64-1))); \
485 pf = parity_table[(UChar)lo]; \
486 af = 0; /* undefined */ \
487 zf = (lo == 0) << 6; \
488 sf = lshift(lo, 8 - 64) & 0x80; \
489 of = cf << 11; \
490 return cf | pf | af | zf | sf | of; \
491 } \
492}
493
sewardjf8c37f72005-02-07 18:55:29 +0000494
sewardj1fa7b802005-03-25 14:39:37 +0000495#if PROFILE_RFLAGS
sewardjf8c37f72005-02-07 18:55:29 +0000496
497static Bool initted = False;
498
499/* C flag, fast route */
500static UInt tabc_fast[AMD64G_CC_OP_NUMBER];
501/* C flag, slow route */
502static UInt tabc_slow[AMD64G_CC_OP_NUMBER];
503/* table for calculate_cond */
504static UInt tab_cond[AMD64G_CC_OP_NUMBER][16];
505/* total entry counts for calc_all, calc_c, calc_cond. */
506static UInt n_calc_all = 0;
507static UInt n_calc_c = 0;
508static UInt n_calc_cond = 0;
509
510#define SHOW_COUNTS_NOW (0 == (0x3FFFFF & (n_calc_all+n_calc_c+n_calc_cond)))
511
512
513static void showCounts ( void )
514{
515 Int op, co;
516 Char ch;
sewardj1fa7b802005-03-25 14:39:37 +0000517 vex_printf("\nTotal calls: calc_all=%u calc_cond=%u calc_c=%u\n",
sewardjf8c37f72005-02-07 18:55:29 +0000518 n_calc_all, n_calc_cond, n_calc_c);
519
520 vex_printf(" cSLOW cFAST O NO B NB Z NZ BE NBE"
521 " S NS P NP L NL LE NLE\n");
522 vex_printf(" -----------------------------------------------------"
523 "----------------------------------------\n");
524 for (op = 0; op < AMD64G_CC_OP_NUMBER; op++) {
525
526 ch = ' ';
sewardj03540352005-04-26 01:53:48 +0000527 if (op > 0 && (op-1) % 4 == 0)
sewardjf8c37f72005-02-07 18:55:29 +0000528 ch = 'B';
sewardj03540352005-04-26 01:53:48 +0000529 if (op > 0 && (op-1) % 4 == 1)
sewardjf8c37f72005-02-07 18:55:29 +0000530 ch = 'W';
sewardj03540352005-04-26 01:53:48 +0000531 if (op > 0 && (op-1) % 4 == 2)
sewardjf8c37f72005-02-07 18:55:29 +0000532 ch = 'L';
sewardj03540352005-04-26 01:53:48 +0000533 if (op > 0 && (op-1) % 4 == 3)
534 ch = 'Q';
sewardjf8c37f72005-02-07 18:55:29 +0000535
536 vex_printf("%2d%c: ", op, ch);
sewardj1fa7b802005-03-25 14:39:37 +0000537 vex_printf("%6u ", tabc_slow[op]);
538 vex_printf("%6u ", tabc_fast[op]);
sewardjf8c37f72005-02-07 18:55:29 +0000539 for (co = 0; co < 16; co++) {
540 Int n = tab_cond[op][co];
541 if (n >= 1000) {
542 vex_printf(" %3dK", n / 1000);
543 } else
544 if (n >= 0) {
545 vex_printf(" %3d ", n );
546 } else {
547 vex_printf(" ");
548 }
549 }
550 vex_printf("\n");
551 }
552 vex_printf("\n");
553}
554
555static void initCounts ( void )
556{
557 Int op, co;
558 initted = True;
559 for (op = 0; op < AMD64G_CC_OP_NUMBER; op++) {
560 tabc_fast[op] = tabc_slow[op] = 0;
561 for (co = 0; co < 16; co++)
562 tab_cond[op][co] = 0;
563 }
564}
565
sewardj1fa7b802005-03-25 14:39:37 +0000566#endif /* PROFILE_RFLAGS */
sewardjf8c37f72005-02-07 18:55:29 +0000567
568
569/* CALLED FROM GENERATED CODE: CLEAN HELPER */
570/* Calculate all the 6 flags from the supplied thunk parameters.
571 Worker function, not directly called from generated code. */
572static
573ULong amd64g_calculate_rflags_all_WRK ( ULong cc_op,
574 ULong cc_dep1_formal,
575 ULong cc_dep2_formal,
576 ULong cc_ndep_formal )
577{
578 switch (cc_op) {
579 case AMD64G_CC_OP_COPY:
580 return cc_dep1_formal
581 & (AMD64G_CC_MASK_O | AMD64G_CC_MASK_S | AMD64G_CC_MASK_Z
582 | AMD64G_CC_MASK_A | AMD64G_CC_MASK_C | AMD64G_CC_MASK_P);
583
584 case AMD64G_CC_OP_ADDB: ACTIONS_ADD( 8, UChar );
585 case AMD64G_CC_OP_ADDW: ACTIONS_ADD( 16, UShort );
586 case AMD64G_CC_OP_ADDL: ACTIONS_ADD( 32, UInt );
sewardjd0a12df2005-02-10 02:07:43 +0000587 case AMD64G_CC_OP_ADDQ: ACTIONS_ADD( 64, ULong );
sewardjf8c37f72005-02-07 18:55:29 +0000588
589 case AMD64G_CC_OP_ADCB: ACTIONS_ADC( 8, UChar );
590 case AMD64G_CC_OP_ADCW: ACTIONS_ADC( 16, UShort );
591 case AMD64G_CC_OP_ADCL: ACTIONS_ADC( 32, UInt );
sewardj85520e42005-02-19 15:22:38 +0000592 case AMD64G_CC_OP_ADCQ: ACTIONS_ADC( 64, ULong );
sewardjf8c37f72005-02-07 18:55:29 +0000593
594 case AMD64G_CC_OP_SUBB: ACTIONS_SUB( 8, UChar );
595 case AMD64G_CC_OP_SUBW: ACTIONS_SUB( 16, UShort );
596 case AMD64G_CC_OP_SUBL: ACTIONS_SUB( 32, UInt );
597 case AMD64G_CC_OP_SUBQ: ACTIONS_SUB( 64, ULong );
598
599 case AMD64G_CC_OP_SBBB: ACTIONS_SBB( 8, UChar );
600 case AMD64G_CC_OP_SBBW: ACTIONS_SBB( 16, UShort );
601 case AMD64G_CC_OP_SBBL: ACTIONS_SBB( 32, UInt );
sewardj85520e42005-02-19 15:22:38 +0000602 case AMD64G_CC_OP_SBBQ: ACTIONS_SBB( 64, ULong );
sewardjf8c37f72005-02-07 18:55:29 +0000603
604 case AMD64G_CC_OP_LOGICB: ACTIONS_LOGIC( 8, UChar );
605 case AMD64G_CC_OP_LOGICW: ACTIONS_LOGIC( 16, UShort );
606 case AMD64G_CC_OP_LOGICL: ACTIONS_LOGIC( 32, UInt );
607 case AMD64G_CC_OP_LOGICQ: ACTIONS_LOGIC( 64, ULong );
608
609 case AMD64G_CC_OP_INCB: ACTIONS_INC( 8, UChar );
610 case AMD64G_CC_OP_INCW: ACTIONS_INC( 16, UShort );
611 case AMD64G_CC_OP_INCL: ACTIONS_INC( 32, UInt );
sewardj7de0d3c2005-02-13 02:26:41 +0000612 case AMD64G_CC_OP_INCQ: ACTIONS_INC( 64, ULong );
sewardjf8c37f72005-02-07 18:55:29 +0000613
614 case AMD64G_CC_OP_DECB: ACTIONS_DEC( 8, UChar );
615 case AMD64G_CC_OP_DECW: ACTIONS_DEC( 16, UShort );
616 case AMD64G_CC_OP_DECL: ACTIONS_DEC( 32, UInt );
sewardj7de0d3c2005-02-13 02:26:41 +0000617 case AMD64G_CC_OP_DECQ: ACTIONS_DEC( 64, ULong );
sewardjf8c37f72005-02-07 18:55:29 +0000618
619 case AMD64G_CC_OP_SHLB: ACTIONS_SHL( 8, UChar );
620 case AMD64G_CC_OP_SHLW: ACTIONS_SHL( 16, UShort );
621 case AMD64G_CC_OP_SHLL: ACTIONS_SHL( 32, UInt );
sewardj7de0d3c2005-02-13 02:26:41 +0000622 case AMD64G_CC_OP_SHLQ: ACTIONS_SHL( 64, ULong );
sewardjf8c37f72005-02-07 18:55:29 +0000623
624 case AMD64G_CC_OP_SHRB: ACTIONS_SHR( 8, UChar );
625 case AMD64G_CC_OP_SHRW: ACTIONS_SHR( 16, UShort );
626 case AMD64G_CC_OP_SHRL: ACTIONS_SHR( 32, UInt );
sewardja6b93d12005-02-17 09:28:28 +0000627 case AMD64G_CC_OP_SHRQ: ACTIONS_SHR( 64, ULong );
sewardjf8c37f72005-02-07 18:55:29 +0000628
629 case AMD64G_CC_OP_ROLB: ACTIONS_ROL( 8, UChar );
630 case AMD64G_CC_OP_ROLW: ACTIONS_ROL( 16, UShort );
631 case AMD64G_CC_OP_ROLL: ACTIONS_ROL( 32, UInt );
sewardj85520e42005-02-19 15:22:38 +0000632 case AMD64G_CC_OP_ROLQ: ACTIONS_ROL( 64, ULong );
sewardjf8c37f72005-02-07 18:55:29 +0000633
634 case AMD64G_CC_OP_RORB: ACTIONS_ROR( 8, UChar );
635 case AMD64G_CC_OP_RORW: ACTIONS_ROR( 16, UShort );
636 case AMD64G_CC_OP_RORL: ACTIONS_ROR( 32, UInt );
sewardj85520e42005-02-19 15:22:38 +0000637 case AMD64G_CC_OP_RORQ: ACTIONS_ROR( 64, ULong );
sewardjf8c37f72005-02-07 18:55:29 +0000638
sewardj1fa7b802005-03-25 14:39:37 +0000639 case AMD64G_CC_OP_UMULB: ACTIONS_UMUL( 8, UChar, toUChar,
640 UShort, toUShort );
641 case AMD64G_CC_OP_UMULW: ACTIONS_UMUL( 16, UShort, toUShort,
642 UInt, toUInt );
643 case AMD64G_CC_OP_UMULL: ACTIONS_UMUL( 32, UInt, toUInt,
644 ULong, idULong );
sewardjf8c37f72005-02-07 18:55:29 +0000645
sewardj8bdb89a2005-05-05 21:46:50 +0000646 case AMD64G_CC_OP_UMULQ: ACTIONS_UMULQ;
647
sewardj1fa7b802005-03-25 14:39:37 +0000648 case AMD64G_CC_OP_SMULB: ACTIONS_SMUL( 8, Char, toUChar,
649 Short, toUShort );
650 case AMD64G_CC_OP_SMULW: ACTIONS_SMUL( 16, Short, toUShort,
651 Int, toUInt );
652 case AMD64G_CC_OP_SMULL: ACTIONS_SMUL( 32, Int, toUInt,
653 Long, idULong );
654
sewardj1a01e652005-02-23 11:39:21 +0000655 case AMD64G_CC_OP_SMULQ: ACTIONS_SMULQ;
sewardjf8c37f72005-02-07 18:55:29 +0000656
657 default:
658 /* shouldn't really make these calls from generated code */
659 vex_printf("amd64g_calculate_rflags_all_WRK(AMD64)"
sewardj1fa7b802005-03-25 14:39:37 +0000660 "( %llu, 0x%llx, 0x%llx, 0x%llx )\n",
sewardjf8c37f72005-02-07 18:55:29 +0000661 cc_op, cc_dep1_formal, cc_dep2_formal, cc_ndep_formal );
662 vpanic("amd64g_calculate_rflags_all_WRK(AMD64)");
663 }
664}
665
666
667/* CALLED FROM GENERATED CODE: CLEAN HELPER */
668/* Calculate all the 6 flags from the supplied thunk parameters. */
669ULong amd64g_calculate_rflags_all ( ULong cc_op,
670 ULong cc_dep1,
671 ULong cc_dep2,
672 ULong cc_ndep )
673{
sewardj1fa7b802005-03-25 14:39:37 +0000674# if PROFILE_RFLAGS
sewardjf8c37f72005-02-07 18:55:29 +0000675 if (!initted) initCounts();
676 n_calc_all++;
677 if (SHOW_COUNTS_NOW) showCounts();
678# endif
679 return
680 amd64g_calculate_rflags_all_WRK ( cc_op, cc_dep1, cc_dep2, cc_ndep );
681}
682
683
684/* CALLED FROM GENERATED CODE: CLEAN HELPER */
685/* Calculate just the carry flag from the supplied thunk parameters. */
686ULong amd64g_calculate_rflags_c ( ULong cc_op,
687 ULong cc_dep1,
688 ULong cc_dep2,
689 ULong cc_ndep )
690{
sewardj1fa7b802005-03-25 14:39:37 +0000691# if PROFILE_RFLAGS
sewardjf8c37f72005-02-07 18:55:29 +0000692 if (!initted) initCounts();
693 n_calc_c++;
694 tabc_fast[cc_op]++;
695 if (SHOW_COUNTS_NOW) showCounts();
696# endif
697
698 /* Fast-case some common ones. */
699 switch (cc_op) {
sewardj7fc494b2005-05-05 12:05:11 +0000700 case AMD64G_CC_OP_COPY:
701 return (cc_dep1 >> AMD64G_CC_SHIFT_C) & 1;
sewardj03540352005-04-26 01:53:48 +0000702 case AMD64G_CC_OP_LOGICQ:
sewardjf8c37f72005-02-07 18:55:29 +0000703 case AMD64G_CC_OP_LOGICL:
704 case AMD64G_CC_OP_LOGICW:
705 case AMD64G_CC_OP_LOGICB:
706 return 0;
sewardj03540352005-04-26 01:53:48 +0000707 // case AMD64G_CC_OP_SUBL:
708 // return ((UInt)cc_dep1) < ((UInt)cc_dep2)
709 // ? AMD64G_CC_MASK_C : 0;
710 // case AMD64G_CC_OP_SUBW:
711 // return ((UInt)(cc_dep1 & 0xFFFF)) < ((UInt)(cc_dep2 & 0xFFFF))
712 // ? AMD64G_CC_MASK_C : 0;
713 // case AMD64G_CC_OP_SUBB:
714 // return ((UInt)(cc_dep1 & 0xFF)) < ((UInt)(cc_dep2 & 0xFF))
715 // ? AMD64G_CC_MASK_C : 0;
716 // case AMD64G_CC_OP_INCL:
717 // case AMD64G_CC_OP_DECL:
718 // return cc_ndep & AMD64G_CC_MASK_C;
sewardjf8c37f72005-02-07 18:55:29 +0000719 default:
720 break;
721 }
722
sewardj1fa7b802005-03-25 14:39:37 +0000723# if PROFILE_RFLAGS
sewardjf8c37f72005-02-07 18:55:29 +0000724 tabc_fast[cc_op]--;
725 tabc_slow[cc_op]++;
726# endif
727
728 return amd64g_calculate_rflags_all_WRK(cc_op,cc_dep1,cc_dep2,cc_ndep)
729 & AMD64G_CC_MASK_C;
730}
731
732
733/* CALLED FROM GENERATED CODE: CLEAN HELPER */
734/* returns 1 or 0 */
735ULong amd64g_calculate_condition ( ULong/*AMD64Condcode*/ cond,
736 ULong cc_op,
737 ULong cc_dep1,
738 ULong cc_dep2,
739 ULong cc_ndep )
740{
741 ULong rflags = amd64g_calculate_rflags_all_WRK(cc_op, cc_dep1,
742 cc_dep2, cc_ndep);
743 ULong of,sf,zf,cf,pf;
744 ULong inv = cond & 1;
745
sewardj1fa7b802005-03-25 14:39:37 +0000746# if PROFILE_RFLAGS
sewardjf8c37f72005-02-07 18:55:29 +0000747 if (!initted) initCounts();
748 tab_cond[cc_op][cond]++;
749 n_calc_cond++;
750 if (SHOW_COUNTS_NOW) showCounts();
751# endif
752
753 switch (cond) {
754 case AMD64CondNO:
755 case AMD64CondO: /* OF == 1 */
756 of = rflags >> AMD64G_CC_SHIFT_O;
757 return 1 & (inv ^ of);
758
759 case AMD64CondNZ:
760 case AMD64CondZ: /* ZF == 1 */
761 zf = rflags >> AMD64G_CC_SHIFT_Z;
762 return 1 & (inv ^ zf);
763
764 case AMD64CondNB:
765 case AMD64CondB: /* CF == 1 */
766 cf = rflags >> AMD64G_CC_SHIFT_C;
767 return 1 & (inv ^ cf);
768 break;
769
770 case AMD64CondNBE:
771 case AMD64CondBE: /* (CF or ZF) == 1 */
772 cf = rflags >> AMD64G_CC_SHIFT_C;
773 zf = rflags >> AMD64G_CC_SHIFT_Z;
774 return 1 & (inv ^ (cf | zf));
775 break;
776
777 case AMD64CondNS:
778 case AMD64CondS: /* SF == 1 */
779 sf = rflags >> AMD64G_CC_SHIFT_S;
780 return 1 & (inv ^ sf);
781
782 case AMD64CondNP:
783 case AMD64CondP: /* PF == 1 */
784 pf = rflags >> AMD64G_CC_SHIFT_P;
785 return 1 & (inv ^ pf);
786
787 case AMD64CondNL:
788 case AMD64CondL: /* (SF xor OF) == 1 */
789 sf = rflags >> AMD64G_CC_SHIFT_S;
790 of = rflags >> AMD64G_CC_SHIFT_O;
791 return 1 & (inv ^ (sf ^ of));
792 break;
793
794 case AMD64CondNLE:
795 case AMD64CondLE: /* ((SF xor OF) or ZF) == 1 */
796 sf = rflags >> AMD64G_CC_SHIFT_S;
797 of = rflags >> AMD64G_CC_SHIFT_O;
798 zf = rflags >> AMD64G_CC_SHIFT_Z;
799 return 1 & (inv ^ ((sf ^ of) | zf));
800 break;
801
802 default:
803 /* shouldn't really make these calls from generated code */
804 vex_printf("amd64g_calculate_condition"
sewardj1fa7b802005-03-25 14:39:37 +0000805 "( %llu, %llu, 0x%llx, 0x%llx, 0x%llx )\n",
sewardjf8c37f72005-02-07 18:55:29 +0000806 cond, cc_op, cc_dep1, cc_dep2, cc_ndep );
807 vpanic("amd64g_calculate_condition");
808 }
809}
810
811
812/* VISIBLE TO LIBVEX CLIENT */
sewardjf8c37f72005-02-07 18:55:29 +0000813ULong LibVEX_GuestAMD64_get_rflags ( /*IN*/VexGuestAMD64State* vex_state )
814{
815 ULong rflags = amd64g_calculate_rflags_all_WRK(
816 vex_state->guest_CC_OP,
817 vex_state->guest_CC_DEP1,
818 vex_state->guest_CC_DEP2,
819 vex_state->guest_CC_NDEP
820 );
sewardj7de0d3c2005-02-13 02:26:41 +0000821 Long dflag = vex_state->guest_DFLAG;
822 vassert(dflag == 1 || dflag == -1);
823 if (dflag == -1)
sewardjf8c37f72005-02-07 18:55:29 +0000824 rflags |= (1<<10);
sewardj85520e42005-02-19 15:22:38 +0000825 if (vex_state->guest_IDFLAG == 1)
826 rflags |= (1<<21);
sewardj5e120aa2010-09-28 15:59:04 +0000827 if (vex_state->guest_ACFLAG == 1)
828 rflags |= (1<<18);
829
sewardjf8c37f72005-02-07 18:55:29 +0000830 return rflags;
831}
sewardjf8c37f72005-02-07 18:55:29 +0000832
sewardjd660d412008-12-03 21:29:59 +0000833/* VISIBLE TO LIBVEX CLIENT */
834void
835LibVEX_GuestAMD64_put_rflag_c ( ULong new_carry_flag,
836 /*MOD*/VexGuestAMD64State* vex_state )
837{
838 ULong oszacp = amd64g_calculate_rflags_all_WRK(
839 vex_state->guest_CC_OP,
840 vex_state->guest_CC_DEP1,
841 vex_state->guest_CC_DEP2,
842 vex_state->guest_CC_NDEP
843 );
844 if (new_carry_flag & 1) {
845 oszacp |= AMD64G_CC_MASK_C;
846 } else {
847 oszacp &= ~AMD64G_CC_MASK_C;
848 }
849 vex_state->guest_CC_OP = AMD64G_CC_OP_COPY;
850 vex_state->guest_CC_DEP1 = oszacp;
851 vex_state->guest_CC_DEP2 = 0;
852 vex_state->guest_CC_NDEP = 0;
853}
854
sewardjf8c37f72005-02-07 18:55:29 +0000855
856/*---------------------------------------------------------------*/
857/*--- %rflags translation-time function specialisers. ---*/
858/*--- These help iropt specialise calls the above run-time ---*/
859/*--- %rflags functions. ---*/
860/*---------------------------------------------------------------*/
861
sewardj03540352005-04-26 01:53:48 +0000862/* Used by the optimiser to try specialisations. Returns an
863 equivalent expression, or NULL if none. */
864
865static Bool isU64 ( IRExpr* e, ULong n )
866{
sewardj65b17c62005-05-02 15:52:44 +0000867 return toBool( e->tag == Iex_Const
868 && e->Iex.Const.con->tag == Ico_U64
869 && e->Iex.Const.con->Ico.U64 == n );
sewardj03540352005-04-26 01:53:48 +0000870}
sewardj354e5c62005-01-27 20:12:52 +0000871
sewardj58277842005-02-07 03:11:17 +0000872IRExpr* guest_amd64_spechelper ( HChar* function_name,
sewardjbe917912010-08-22 12:38:53 +0000873 IRExpr** args,
874 IRStmt** precedingStmts,
875 Int n_precedingStmts )
sewardj44d494d2005-01-20 20:26:33 +0000876{
sewardj03540352005-04-26 01:53:48 +0000877# define unop(_op,_a1) IRExpr_Unop((_op),(_a1))
878# define binop(_op,_a1,_a2) IRExpr_Binop((_op),(_a1),(_a2))
879# define mkU64(_n) IRExpr_Const(IRConst_U64(_n))
880# define mkU8(_n) IRExpr_Const(IRConst_U8(_n))
881
882 Int i, arity = 0;
883 for (i = 0; args[i]; i++)
884 arity++;
885# if 0
886 vex_printf("spec request:\n");
887 vex_printf(" %s ", function_name);
888 for (i = 0; i < arity; i++) {
889 vex_printf(" ");
890 ppIRExpr(args[i]);
891 }
892 vex_printf("\n");
893# endif
894
895 /* --------- specialising "amd64g_calculate_condition" --------- */
896
897 if (vex_streq(function_name, "amd64g_calculate_condition")) {
898 /* specialise calls to above "calculate condition" function */
899 IRExpr *cond, *cc_op, *cc_dep1, *cc_dep2;
900 vassert(arity == 5);
901 cond = args[0];
902 cc_op = args[1];
903 cc_dep1 = args[2];
904 cc_dep2 = args[3];
905
sewardjdb261e42005-05-11 23:16:43 +0000906 /*---------------- ADDQ ----------------*/
907
908 if (isU64(cc_op, AMD64G_CC_OP_ADDQ) && isU64(cond, AMD64CondZ)) {
909 /* long long add, then Z --> test (dst+src == 0) */
910 return unop(Iop_1Uto64,
911 binop(Iop_CmpEQ64,
912 binop(Iop_Add64, cc_dep1, cc_dep2),
913 mkU64(0)));
914 }
sewardj03540352005-04-26 01:53:48 +0000915
sewardj4b06a0b2005-11-13 19:51:04 +0000916 /*---------------- SUBQ ----------------*/
917
sewardja9e4a802005-12-26 19:33:55 +0000918 if (isU64(cc_op, AMD64G_CC_OP_SUBQ) && isU64(cond, AMD64CondZ)) {
919 /* long long sub/cmp, then Z --> test dst==src */
920 return unop(Iop_1Uto64,
921 binop(Iop_CmpEQ64,cc_dep1,cc_dep2));
922 }
sewardja9e4a802005-12-26 19:33:55 +0000923 if (isU64(cc_op, AMD64G_CC_OP_SUBQ) && isU64(cond, AMD64CondNZ)) {
924 /* long long sub/cmp, then NZ --> test dst!=src */
925 return unop(Iop_1Uto64,
926 binop(Iop_CmpNE64,cc_dep1,cc_dep2));
927 }
928
sewardj4b06a0b2005-11-13 19:51:04 +0000929 if (isU64(cc_op, AMD64G_CC_OP_SUBQ) && isU64(cond, AMD64CondL)) {
930 /* long long sub/cmp, then L (signed less than)
931 --> test dst <s src */
932 return unop(Iop_1Uto64,
933 binop(Iop_CmpLT64S, cc_dep1, cc_dep2));
934 }
935
936 if (isU64(cc_op, AMD64G_CC_OP_SUBQ) && isU64(cond, AMD64CondB)) {
937 /* long long sub/cmp, then B (unsigned less than)
938 --> test dst <u src */
939 return unop(Iop_1Uto64,
940 binop(Iop_CmpLT64U, cc_dep1, cc_dep2));
941 }
sewardja9e4a802005-12-26 19:33:55 +0000942 if (isU64(cc_op, AMD64G_CC_OP_SUBQ) && isU64(cond, AMD64CondNB)) {
943 /* long long sub/cmp, then NB (unsigned greater than or equal)
944 --> test src <=u dst */
945 /* Note, args are opposite way round from the usual */
946 return unop(Iop_1Uto64,
947 binop(Iop_CmpLE64U, cc_dep2, cc_dep1));
948 }
949
950 if (isU64(cc_op, AMD64G_CC_OP_SUBQ) && isU64(cond, AMD64CondBE)) {
951 /* long long sub/cmp, then BE (unsigned less than or equal)
952 --> test dst <=u src */
953 return unop(Iop_1Uto64,
954 binop(Iop_CmpLE64U, cc_dep1, cc_dep2));
955 }
956
sewardj03540352005-04-26 01:53:48 +0000957 /*---------------- SUBL ----------------*/
958
sewardjdb261e42005-05-11 23:16:43 +0000959 if (isU64(cc_op, AMD64G_CC_OP_SUBL) && isU64(cond, AMD64CondZ)) {
960 /* long sub/cmp, then Z --> test dst==src */
961 return unop(Iop_1Uto64,
sewardja9e4a802005-12-26 19:33:55 +0000962 binop(Iop_CmpEQ64,
963 binop(Iop_Shl64,cc_dep1,mkU8(32)),
964 binop(Iop_Shl64,cc_dep2,mkU8(32))));
965 }
sewardja9e4a802005-12-26 19:33:55 +0000966 if (isU64(cc_op, AMD64G_CC_OP_SUBL) && isU64(cond, AMD64CondNZ)) {
967 /* long sub/cmp, then NZ --> test dst!=src */
968 return unop(Iop_1Uto64,
969 binop(Iop_CmpNE64,
970 binop(Iop_Shl64,cc_dep1,mkU8(32)),
971 binop(Iop_Shl64,cc_dep2,mkU8(32))));
sewardjdb261e42005-05-11 23:16:43 +0000972 }
973
sewardj03540352005-04-26 01:53:48 +0000974 if (isU64(cc_op, AMD64G_CC_OP_SUBL) && isU64(cond, AMD64CondL)) {
975 /* long sub/cmp, then L (signed less than)
976 --> test dst <s src */
sewardj6d709a92005-04-27 11:52:40 +0000977 return unop(Iop_1Uto64,
sewardj03540352005-04-26 01:53:48 +0000978 binop(Iop_CmpLT64S,
979 binop(Iop_Shl64,cc_dep1,mkU8(32)),
sewardj6d709a92005-04-27 11:52:40 +0000980 binop(Iop_Shl64,cc_dep2,mkU8(32))));
sewardj03540352005-04-26 01:53:48 +0000981 }
982
983 if (isU64(cc_op, AMD64G_CC_OP_SUBL) && isU64(cond, AMD64CondLE)) {
sewardj3f81c4e2005-07-20 00:30:37 +0000984 /* long sub/cmp, then LE (signed less than or equal)
985 --> test dst <=s src */
sewardj6d709a92005-04-27 11:52:40 +0000986 return unop(Iop_1Uto64,
sewardj03540352005-04-26 01:53:48 +0000987 binop(Iop_CmpLE64S,
988 binop(Iop_Shl64,cc_dep1,mkU8(32)),
sewardj6d709a92005-04-27 11:52:40 +0000989 binop(Iop_Shl64,cc_dep2,mkU8(32))));
sewardj03540352005-04-26 01:53:48 +0000990
991 }
sewardjff6b34a2010-01-15 09:54:55 +0000992 if (isU64(cc_op, AMD64G_CC_OP_SUBL) && isU64(cond, AMD64CondNLE)) {
993 /* long sub/cmp, then NLE (signed greater than)
994 --> test !(dst <=s src)
995 --> test (dst >s src)
996 --> test (src <s dst) */
997 return unop(Iop_1Uto64,
998 binop(Iop_CmpLT64S,
999 binop(Iop_Shl64,cc_dep2,mkU8(32)),
1000 binop(Iop_Shl64,cc_dep1,mkU8(32))));
1001
1002 }
sewardj03540352005-04-26 01:53:48 +00001003
sewardja9e4a802005-12-26 19:33:55 +00001004 if (isU64(cc_op, AMD64G_CC_OP_SUBL) && isU64(cond, AMD64CondBE)) {
1005 /* long sub/cmp, then BE (unsigned less than or equal)
1006 --> test dst <=u src */
1007 return unop(Iop_1Uto64,
1008 binop(Iop_CmpLE64U,
1009 binop(Iop_Shl64,cc_dep1,mkU8(32)),
1010 binop(Iop_Shl64,cc_dep2,mkU8(32))));
1011 }
sewardj32d615b2006-08-25 12:52:19 +00001012 if (isU64(cc_op, AMD64G_CC_OP_SUBL) && isU64(cond, AMD64CondNBE)) {
1013 /* long sub/cmp, then NBE (unsigned greater than)
1014 --> test src <u dst */
1015 /* Note, args are opposite way round from the usual */
1016 return unop(Iop_1Uto64,
1017 binop(Iop_CmpLT64U,
1018 binop(Iop_Shl64,cc_dep2,mkU8(32)),
1019 binop(Iop_Shl64,cc_dep1,mkU8(32))));
1020 }
sewardj03540352005-04-26 01:53:48 +00001021
sewardj3b092352009-11-22 23:38:01 +00001022 if (isU64(cc_op, AMD64G_CC_OP_SUBL) && isU64(cond, AMD64CondS)) {
1023 /* long sub/cmp, then S (negative) --> test (dst-src <s 0) */
1024 return unop(Iop_1Uto64,
1025 binop(Iop_CmpLT64S,
1026 binop(Iop_Sub64,
1027 binop(Iop_Shl64, cc_dep1, mkU8(32)),
1028 binop(Iop_Shl64, cc_dep2, mkU8(32))),
1029 mkU64(0)));
1030 }
1031
sewardj03540352005-04-26 01:53:48 +00001032 /*---------------- SUBW ----------------*/
1033
sewardja82b4762005-05-06 16:30:21 +00001034 if (isU64(cc_op, AMD64G_CC_OP_SUBW) && isU64(cond, AMD64CondZ)) {
1035 /* word sub/cmp, then Z --> test dst==src */
1036 return unop(Iop_1Uto64,
1037 binop(Iop_CmpEQ16,
1038 unop(Iop_64to16,cc_dep1),
1039 unop(Iop_64to16,cc_dep2)));
1040 }
sewardjbeb52912008-05-02 22:15:12 +00001041 if (isU64(cc_op, AMD64G_CC_OP_SUBW) && isU64(cond, AMD64CondNZ)) {
1042 /* word sub/cmp, then NZ --> test dst!=src */
1043 return unop(Iop_1Uto64,
1044 binop(Iop_CmpNE16,
1045 unop(Iop_64to16,cc_dep1),
1046 unop(Iop_64to16,cc_dep2)));
1047 }
sewardj03540352005-04-26 01:53:48 +00001048
sewardj3f81c4e2005-07-20 00:30:37 +00001049 if (isU64(cc_op, AMD64G_CC_OP_SUBW) && isU64(cond, AMD64CondLE)) {
sewardj3be608d2006-05-25 18:48:12 +00001050 /* word sub/cmp, then LE (signed less than or equal)
sewardj3f81c4e2005-07-20 00:30:37 +00001051 --> test dst <=s src */
1052 return unop(Iop_1Uto64,
1053 binop(Iop_CmpLE64S,
1054 binop(Iop_Shl64,cc_dep1,mkU8(48)),
1055 binop(Iop_Shl64,cc_dep2,mkU8(48))));
1056
1057 }
1058
sewardj03540352005-04-26 01:53:48 +00001059 /*---------------- SUBB ----------------*/
1060
1061 if (isU64(cc_op, AMD64G_CC_OP_SUBB) && isU64(cond, AMD64CondZ)) {
1062 /* byte sub/cmp, then Z --> test dst==src */
sewardj6d709a92005-04-27 11:52:40 +00001063 return unop(Iop_1Uto64,
sewardj03540352005-04-26 01:53:48 +00001064 binop(Iop_CmpEQ8,
sewardj6d709a92005-04-27 11:52:40 +00001065 unop(Iop_64to8,cc_dep1),
1066 unop(Iop_64to8,cc_dep2)));
sewardj03540352005-04-26 01:53:48 +00001067 }
sewardj32d615b2006-08-25 12:52:19 +00001068 if (isU64(cc_op, AMD64G_CC_OP_SUBB) && isU64(cond, AMD64CondNZ)) {
1069 /* byte sub/cmp, then NZ --> test dst!=src */
1070 return unop(Iop_1Uto64,
1071 binop(Iop_CmpNE8,
1072 unop(Iop_64to8,cc_dep1),
1073 unop(Iop_64to8,cc_dep2)));
1074 }
1075
sewardj3be608d2006-05-25 18:48:12 +00001076 if (isU64(cc_op, AMD64G_CC_OP_SUBB) && isU64(cond, AMD64CondS)
1077 && isU64(cc_dep2, 0)) {
1078 /* byte sub/cmp of zero, then S --> test (dst-0 <s 0)
1079 --> test dst <s 0
1080 --> (ULong)dst[7]
1081 This is yet another scheme by which gcc figures out if the
1082 top bit of a byte is 1 or 0. See also LOGICB/CondS below. */
1083 /* Note: isU64(cc_dep2, 0) is correct, even though this is
1084 for an 8-bit comparison, since the args to the helper
1085 function are always U64s. */
1086 return binop(Iop_And64,
1087 binop(Iop_Shr64,cc_dep1,mkU8(7)),
1088 mkU64(1));
1089 }
sewardjcd538b42008-03-31 21:57:17 +00001090 if (isU64(cc_op, AMD64G_CC_OP_SUBB) && isU64(cond, AMD64CondNS)
1091 && isU64(cc_dep2, 0)) {
1092 /* byte sub/cmp of zero, then NS --> test !(dst-0 <s 0)
1093 --> test !(dst <s 0)
1094 --> (ULong) !dst[7]
1095 */
1096 return binop(Iop_Xor64,
1097 binop(Iop_And64,
1098 binop(Iop_Shr64,cc_dep1,mkU8(7)),
1099 mkU64(1)),
1100 mkU64(1));
1101 }
sewardj3be608d2006-05-25 18:48:12 +00001102
sewardj4b06a0b2005-11-13 19:51:04 +00001103 /*---------------- LOGICQ ----------------*/
1104
1105 if (isU64(cc_op, AMD64G_CC_OP_LOGICQ) && isU64(cond, AMD64CondZ)) {
1106 /* long long and/or/xor, then Z --> test dst==0 */
1107 return unop(Iop_1Uto64,
1108 binop(Iop_CmpEQ64, cc_dep1, mkU64(0)));
1109 }
1110
sewardj77fd8462005-11-13 20:30:24 +00001111 if (isU64(cc_op, AMD64G_CC_OP_LOGICQ) && isU64(cond, AMD64CondL)) {
1112 /* long long and/or/xor, then L
1113 LOGIC sets SF and ZF according to the
1114 result and makes OF be zero. L computes SF ^ OF, but
1115 OF is zero, so this reduces to SF -- which will be 1 iff
1116 the result is < signed 0. Hence ...
1117 */
1118 return unop(Iop_1Uto64,
1119 binop(Iop_CmpLT64S,
1120 cc_dep1,
1121 mkU64(0)));
1122 }
1123
sewardj03540352005-04-26 01:53:48 +00001124 /*---------------- LOGICL ----------------*/
1125
1126 if (isU64(cc_op, AMD64G_CC_OP_LOGICL) && isU64(cond, AMD64CondZ)) {
1127 /* long and/or/xor, then Z --> test dst==0 */
sewardj6d709a92005-04-27 11:52:40 +00001128 return unop(Iop_1Uto64,
1129 binop(Iop_CmpEQ64,
1130 binop(Iop_Shl64,cc_dep1,mkU8(32)),
1131 mkU64(0)));
sewardj03540352005-04-26 01:53:48 +00001132 }
1133
sewardj005b4ef2005-07-20 01:12:48 +00001134 if (isU64(cc_op, AMD64G_CC_OP_LOGICL) && isU64(cond, AMD64CondNZ)) {
1135 /* long and/or/xor, then NZ --> test dst!=0 */
1136 return unop(Iop_1Uto64,
1137 binop(Iop_CmpNE64,
1138 binop(Iop_Shl64,cc_dep1,mkU8(32)),
1139 mkU64(0)));
1140 }
1141
sewardj03540352005-04-26 01:53:48 +00001142 if (isU64(cc_op, AMD64G_CC_OP_LOGICL) && isU64(cond, AMD64CondLE)) {
1143 /* long and/or/xor, then LE
1144 This is pretty subtle. LOGIC sets SF and ZF according to the
sewardj77fd8462005-11-13 20:30:24 +00001145 result and makes OF be zero. LE computes (SF ^ OF) | ZF, but
1146 OF is zero, so this reduces to SF | ZF -- which will be 1 iff
sewardj03540352005-04-26 01:53:48 +00001147 the result is <=signed 0. Hence ...
1148 */
sewardj6d709a92005-04-27 11:52:40 +00001149 return unop(Iop_1Uto64,
1150 binop(Iop_CmpLE64S,
1151 binop(Iop_Shl64,cc_dep1,mkU8(32)),
1152 mkU64(0)));
sewardj03540352005-04-26 01:53:48 +00001153 }
1154
sewardj4b06a0b2005-11-13 19:51:04 +00001155 /*---------------- LOGICB ----------------*/
1156
1157 if (isU64(cc_op, AMD64G_CC_OP_LOGICB) && isU64(cond, AMD64CondZ)) {
1158 /* byte and/or/xor, then Z --> test dst==0 */
1159 return unop(Iop_1Uto64,
1160 binop(Iop_CmpEQ64, binop(Iop_And64,cc_dep1,mkU64(255)),
1161 mkU64(0)));
1162 }
sewardjff6b34a2010-01-15 09:54:55 +00001163 if (isU64(cc_op, AMD64G_CC_OP_LOGICB) && isU64(cond, AMD64CondNZ)) {
1164 /* byte and/or/xor, then NZ --> test dst!=0 */
1165 return unop(Iop_1Uto64,
1166 binop(Iop_CmpNE64, binop(Iop_And64,cc_dep1,mkU64(255)),
1167 mkU64(0)));
1168 }
sewardj3f81c4e2005-07-20 00:30:37 +00001169
sewardj346d9a12006-05-21 01:02:31 +00001170 if (isU64(cc_op, AMD64G_CC_OP_LOGICB) && isU64(cond, AMD64CondS)) {
1171 /* this is an idiom gcc sometimes uses to find out if the top
1172 bit of a byte register is set: eg testb %al,%al; js ..
1173 Since it just depends on the top bit of the byte, extract
1174 that bit and explicitly get rid of all the rest. This
1175 helps memcheck avoid false positives in the case where any
1176 of the other bits in the byte are undefined. */
1177 /* byte and/or/xor, then S --> (UInt)result[7] */
1178 return binop(Iop_And64,
1179 binop(Iop_Shr64,cc_dep1,mkU8(7)),
1180 mkU64(1));
1181 }
1182
sewardj3f81c4e2005-07-20 00:30:37 +00001183 /*---------------- INCB ----------------*/
1184
1185 if (isU64(cc_op, AMD64G_CC_OP_INCB) && isU64(cond, AMD64CondLE)) {
sewardj4df975f2010-02-28 04:51:02 +00001186 /* 8-bit inc, then LE --> sign bit of the arg */
1187 return binop(Iop_And64,
1188 binop(Iop_Shr64,
1189 binop(Iop_Sub64, cc_dep1, mkU64(1)),
1190 mkU8(7)),
1191 mkU64(1));
sewardj3f81c4e2005-07-20 00:30:37 +00001192 }
1193
sewardj7784bd22006-12-29 01:54:36 +00001194 /*---------------- INCW ----------------*/
1195
1196 if (isU64(cc_op, AMD64G_CC_OP_INCW) && isU64(cond, AMD64CondZ)) {
1197 /* 16-bit inc, then Z --> test dst == 0 */
1198 return unop(Iop_1Uto64,
1199 binop(Iop_CmpEQ64,
1200 binop(Iop_Shl64,cc_dep1,mkU8(48)),
1201 mkU64(0)));
1202 }
1203
sewardj77fd8462005-11-13 20:30:24 +00001204 /*---------------- DECL ----------------*/
1205
1206 if (isU64(cc_op, AMD64G_CC_OP_DECL) && isU64(cond, AMD64CondZ)) {
1207 /* dec L, then Z --> test dst == 0 */
1208 return unop(Iop_1Uto64,
1209 binop(Iop_CmpEQ64,
1210 binop(Iop_Shl64,cc_dep1,mkU8(32)),
1211 mkU64(0)));
1212 }
1213
sewardjb6d02ea2005-08-01 13:35:18 +00001214 /*---------------- DECW ----------------*/
1215
1216 if (isU64(cc_op, AMD64G_CC_OP_DECW) && isU64(cond, AMD64CondNZ)) {
1217 /* 16-bit dec, then NZ --> test dst != 0 */
1218 return unop(Iop_1Uto64,
1219 binop(Iop_CmpNE64,
1220 binop(Iop_Shl64,cc_dep1,mkU8(48)),
1221 mkU64(0)));
1222 }
1223
sewardj7fc494b2005-05-05 12:05:11 +00001224 /*---------------- COPY ----------------*/
1225 /* This can happen, as a result of amd64 FP compares: "comisd ... ;
1226 jbe" for example. */
1227
1228 if (isU64(cc_op, AMD64G_CC_OP_COPY) &&
1229 (isU64(cond, AMD64CondBE) || isU64(cond, AMD64CondNBE))) {
1230 /* COPY, then BE --> extract C and Z from dep1, and test (C
1231 or Z == 1). */
1232 /* COPY, then NBE --> extract C and Z from dep1, and test (C
1233 or Z == 0). */
1234 ULong nnn = isU64(cond, AMD64CondBE) ? 1 : 0;
1235 return
1236 unop(
1237 Iop_1Uto64,
1238 binop(
1239 Iop_CmpEQ64,
1240 binop(
1241 Iop_And64,
1242 binop(
1243 Iop_Or64,
1244 binop(Iop_Shr64, cc_dep1, mkU8(AMD64G_CC_SHIFT_C)),
1245 binop(Iop_Shr64, cc_dep1, mkU8(AMD64G_CC_SHIFT_Z))
1246 ),
1247 mkU64(1)
1248 ),
1249 mkU64(nnn)
1250 )
1251 );
1252 }
1253
sewardj9f05a642005-05-12 02:14:52 +00001254 if (isU64(cc_op, AMD64G_CC_OP_COPY) && isU64(cond, AMD64CondB)) {
1255 /* COPY, then B --> extract C dep1, and test (C == 1). */
1256 return
1257 unop(
1258 Iop_1Uto64,
1259 binop(
1260 Iop_CmpNE64,
1261 binop(
1262 Iop_And64,
1263 binop(Iop_Shr64, cc_dep1, mkU8(AMD64G_CC_SHIFT_C)),
1264 mkU64(1)
1265 ),
1266 mkU64(0)
1267 )
1268 );
1269 }
sewardj03540352005-04-26 01:53:48 +00001270
sewardjb235e5b2006-11-27 04:09:52 +00001271 if (isU64(cc_op, AMD64G_CC_OP_COPY)
1272 && (isU64(cond, AMD64CondZ) || isU64(cond, AMD64CondNZ))) {
1273 /* COPY, then Z --> extract Z from dep1, and test (Z == 1). */
1274 /* COPY, then NZ --> extract Z from dep1, and test (Z == 0). */
1275 UInt nnn = isU64(cond, AMD64CondZ) ? 1 : 0;
1276 return
1277 unop(
1278 Iop_1Uto64,
1279 binop(
1280 Iop_CmpEQ64,
1281 binop(
1282 Iop_And64,
1283 binop(Iop_Shr64, cc_dep1, mkU8(AMD64G_CC_SHIFT_Z)),
1284 mkU64(1)
1285 ),
1286 mkU64(nnn)
1287 )
1288 );
1289 }
1290
1291 if (isU64(cc_op, AMD64G_CC_OP_COPY) && isU64(cond, AMD64CondP)) {
1292 /* COPY, then P --> extract P from dep1, and test (P == 1). */
1293 return
1294 unop(
1295 Iop_1Uto64,
1296 binop(
1297 Iop_CmpNE64,
1298 binop(
1299 Iop_And64,
1300 binop(Iop_Shr64, cc_dep1, mkU8(AMD64G_CC_SHIFT_P)),
1301 mkU64(1)
1302 ),
1303 mkU64(0)
1304 )
1305 );
1306 }
1307
sewardj03540352005-04-26 01:53:48 +00001308 return NULL;
1309 }
1310
1311 /* --------- specialising "amd64g_calculate_rflags_c" --------- */
1312
1313 if (vex_streq(function_name, "amd64g_calculate_rflags_c")) {
1314 /* specialise calls to above "calculate_rflags_c" function */
1315 IRExpr *cc_op, *cc_dep1, *cc_dep2, *cc_ndep;
1316 vassert(arity == 4);
1317 cc_op = args[0];
1318 cc_dep1 = args[1];
1319 cc_dep2 = args[2];
1320 cc_ndep = args[3];
1321
sewardj77fd8462005-11-13 20:30:24 +00001322 if (isU64(cc_op, AMD64G_CC_OP_SUBQ)) {
1323 /* C after sub denotes unsigned less than */
1324 return unop(Iop_1Uto64,
1325 binop(Iop_CmpLT64U,
1326 cc_dep1,
1327 cc_dep2));
1328 }
sewardj03540352005-04-26 01:53:48 +00001329 if (isU64(cc_op, AMD64G_CC_OP_SUBL)) {
1330 /* C after sub denotes unsigned less than */
sewardj6d709a92005-04-27 11:52:40 +00001331 return unop(Iop_1Uto64,
sewardj03540352005-04-26 01:53:48 +00001332 binop(Iop_CmpLT64U,
1333 binop(Iop_Shl64,cc_dep1,mkU8(32)),
sewardj6d709a92005-04-27 11:52:40 +00001334 binop(Iop_Shl64,cc_dep2,mkU8(32))));
sewardj03540352005-04-26 01:53:48 +00001335 }
1336 if (isU64(cc_op, AMD64G_CC_OP_SUBB)) {
1337 /* C after sub denotes unsigned less than */
sewardj6d709a92005-04-27 11:52:40 +00001338 return unop(Iop_1Uto64,
sewardj03540352005-04-26 01:53:48 +00001339 binop(Iop_CmpLT64U,
1340 binop(Iop_And64,cc_dep1,mkU64(0xFF)),
sewardj6d709a92005-04-27 11:52:40 +00001341 binop(Iop_And64,cc_dep2,mkU64(0xFF))));
sewardj03540352005-04-26 01:53:48 +00001342 }
1343 if (isU64(cc_op, AMD64G_CC_OP_LOGICQ)
1344 || isU64(cc_op, AMD64G_CC_OP_LOGICL)
1345 || isU64(cc_op, AMD64G_CC_OP_LOGICW)
1346 || isU64(cc_op, AMD64G_CC_OP_LOGICB)) {
1347 /* cflag after logic is zero */
1348 return mkU64(0);
1349 }
1350 if (isU64(cc_op, AMD64G_CC_OP_DECL) || isU64(cc_op, AMD64G_CC_OP_INCL)
1351 || isU64(cc_op, AMD64G_CC_OP_DECQ) || isU64(cc_op, AMD64G_CC_OP_INCQ)) {
1352 /* If the thunk is dec or inc, the cflag is supplied as CC_NDEP. */
1353 return cc_ndep;
1354 }
sewardj7784bd22006-12-29 01:54:36 +00001355
1356# if 0
1357 if (cc_op->tag == Iex_Const) {
1358 vex_printf("CFLAG "); ppIRExpr(cc_op); vex_printf("\n");
1359 }
1360# endif
sewardj03540352005-04-26 01:53:48 +00001361
1362 return NULL;
1363 }
1364
sewardjf8c37f72005-02-07 18:55:29 +00001365# undef unop
1366# undef binop
sewardj03540352005-04-26 01:53:48 +00001367# undef mkU64
sewardjf8c37f72005-02-07 18:55:29 +00001368# undef mkU8
1369
1370 return NULL;
sewardj44d494d2005-01-20 20:26:33 +00001371}
1372
sewardjf8c37f72005-02-07 18:55:29 +00001373
sewardj8d965312005-02-25 02:48:47 +00001374/*---------------------------------------------------------------*/
1375/*--- Supporting functions for x87 FPU activities. ---*/
1376/*---------------------------------------------------------------*/
1377
sewardj4f9847d2005-07-25 11:58:34 +00001378static inline Bool host_is_little_endian ( void )
1379{
1380 UInt x = 0x76543210;
1381 UChar* p = (UChar*)(&x);
1382 return toBool(*p == 0x10);
1383}
1384
1385/* Inspect a value and its tag, as per the x87 'FXAM' instruction. */
1386/* CALLED FROM GENERATED CODE: CLEAN HELPER */
1387ULong amd64g_calculate_FXAM ( ULong tag, ULong dbl )
1388{
1389 Bool mantissaIsZero;
1390 Int bexp;
1391 UChar sign;
1392 UChar* f64;
1393
1394 vassert(host_is_little_endian());
1395
1396 /* vex_printf("calculate_FXAM ( %d, %llx ) .. ", tag, dbl ); */
1397
1398 f64 = (UChar*)(&dbl);
1399 sign = toUChar( (f64[7] >> 7) & 1 );
1400
1401 /* First off, if the tag indicates the register was empty,
1402 return 1,0,sign,1 */
1403 if (tag == 0) {
1404 /* vex_printf("Empty\n"); */
1405 return AMD64G_FC_MASK_C3 | 0 | (sign << AMD64G_FC_SHIFT_C1)
1406 | AMD64G_FC_MASK_C0;
1407 }
1408
1409 bexp = (f64[7] << 4) | ((f64[6] >> 4) & 0x0F);
1410 bexp &= 0x7FF;
1411
1412 mantissaIsZero
1413 = toBool(
1414 (f64[6] & 0x0F) == 0
1415 && (f64[5] | f64[4] | f64[3] | f64[2] | f64[1] | f64[0]) == 0
1416 );
1417
1418 /* If both exponent and mantissa are zero, the value is zero.
1419 Return 1,0,sign,0. */
1420 if (bexp == 0 && mantissaIsZero) {
1421 /* vex_printf("Zero\n"); */
1422 return AMD64G_FC_MASK_C3 | 0
1423 | (sign << AMD64G_FC_SHIFT_C1) | 0;
1424 }
1425
1426 /* If exponent is zero but mantissa isn't, it's a denormal.
1427 Return 1,1,sign,0. */
1428 if (bexp == 0 && !mantissaIsZero) {
1429 /* vex_printf("Denormal\n"); */
1430 return AMD64G_FC_MASK_C3 | AMD64G_FC_MASK_C2
1431 | (sign << AMD64G_FC_SHIFT_C1) | 0;
1432 }
1433
1434 /* If the exponent is 7FF and the mantissa is zero, this is an infinity.
1435 Return 0,1,sign,1. */
1436 if (bexp == 0x7FF && mantissaIsZero) {
1437 /* vex_printf("Inf\n"); */
1438 return 0 | AMD64G_FC_MASK_C2 | (sign << AMD64G_FC_SHIFT_C1)
1439 | AMD64G_FC_MASK_C0;
1440 }
1441
1442 /* If the exponent is 7FF and the mantissa isn't zero, this is a NaN.
1443 Return 0,0,sign,1. */
1444 if (bexp == 0x7FF && !mantissaIsZero) {
1445 /* vex_printf("NaN\n"); */
1446 return 0 | 0 | (sign << AMD64G_FC_SHIFT_C1) | AMD64G_FC_MASK_C0;
1447 }
1448
1449 /* Uh, ok, we give up. It must be a normal finite number.
1450 Return 0,1,sign,0.
1451 */
1452 /* vex_printf("normal\n"); */
1453 return 0 | AMD64G_FC_MASK_C2 | (sign << AMD64G_FC_SHIFT_C1) | 0;
1454}
1455
1456
sewardj5abcfe62007-01-10 04:59:33 +00001457/* Create an x87 FPU state from the guest state, as close as
1458 we can approximate it. */
1459static
1460void do_get_x87 ( /*IN*/VexGuestAMD64State* vex_state,
1461 /*OUT*/UChar* x87_state )
1462{
1463 Int i, stno, preg;
1464 UInt tagw;
1465 ULong* vexRegs = (ULong*)(&vex_state->guest_FPREG[0]);
1466 UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
1467 Fpu_State* x87 = (Fpu_State*)x87_state;
1468 UInt ftop = vex_state->guest_FTOP;
1469 UInt c3210 = vex_state->guest_FC3210;
1470
1471 for (i = 0; i < 14; i++)
1472 x87->env[i] = 0;
1473
1474 x87->env[1] = x87->env[3] = x87->env[5] = x87->env[13] = 0xFFFF;
1475 x87->env[FP_ENV_STAT]
1476 = toUShort(((ftop & 7) << 11) | (c3210 & 0x4700));
1477 x87->env[FP_ENV_CTRL]
1478 = toUShort(amd64g_create_fpucw( vex_state->guest_FPROUND ));
1479
1480 /* Dump the register stack in ST order. */
1481 tagw = 0;
1482 for (stno = 0; stno < 8; stno++) {
1483 preg = (stno + ftop) & 7;
1484 if (vexTags[preg] == 0) {
1485 /* register is empty */
1486 tagw |= (3 << (2*preg));
1487 convert_f64le_to_f80le( (UChar*)&vexRegs[preg],
1488 &x87->reg[10*stno] );
1489 } else {
1490 /* register is full. */
1491 tagw |= (0 << (2*preg));
1492 convert_f64le_to_f80le( (UChar*)&vexRegs[preg],
1493 &x87->reg[10*stno] );
1494 }
1495 }
1496 x87->env[FP_ENV_TAG] = toUShort(tagw);
1497}
1498
1499
1500/* CALLED FROM GENERATED CODE */
1501/* DIRTY HELPER (reads guest state, writes guest mem) */
1502/* NOTE: only handles 32-bit format (no REX.W on the insn) */
1503void amd64g_dirtyhelper_FXSAVE ( VexGuestAMD64State* gst, HWord addr )
1504{
1505 /* Derived from values obtained from
1506 vendor_id : AuthenticAMD
1507 cpu family : 15
1508 model : 12
1509 model name : AMD Athlon(tm) 64 Processor 3200+
1510 stepping : 0
1511 cpu MHz : 2200.000
1512 cache size : 512 KB
1513 */
1514 /* Somewhat roundabout, but at least it's simple. */
1515 Fpu_State tmp;
1516 UShort* addrS = (UShort*)addr;
1517 UChar* addrC = (UChar*)addr;
1518 U128* xmm = (U128*)(addr + 160);
1519 UInt mxcsr;
1520 UShort fp_tags;
1521 UInt summary_tags;
1522 Int r, stno;
1523 UShort *srcS, *dstS;
1524
1525 do_get_x87( gst, (UChar*)&tmp );
1526 mxcsr = amd64g_create_mxcsr( gst->guest_SSEROUND );
1527
1528 /* Now build the proper fxsave image from the x87 image we just
1529 made. */
1530
1531 addrS[0] = tmp.env[FP_ENV_CTRL]; /* FCW: fpu control word */
1532 addrS[1] = tmp.env[FP_ENV_STAT]; /* FCW: fpu status word */
1533
1534 /* set addrS[2] in an endian-independent way */
1535 summary_tags = 0;
1536 fp_tags = tmp.env[FP_ENV_TAG];
1537 for (r = 0; r < 8; r++) {
1538 if ( ((fp_tags >> (2*r)) & 3) != 3 )
1539 summary_tags |= (1 << r);
1540 }
1541 addrC[4] = toUChar(summary_tags); /* FTW: tag summary byte */
1542 addrC[5] = 0; /* pad */
1543
1544 /* FOP: faulting fpu opcode. From experimentation, the real CPU
1545 does not write this field. (?!) */
1546 addrS[3] = 0; /* BOGUS */
1547
1548 /* RIP (Last x87 instruction pointer). From experimentation, the
1549 real CPU does not write this field. (?!) */
1550 addrS[4] = 0; /* BOGUS */
1551 addrS[5] = 0; /* BOGUS */
1552 addrS[6] = 0; /* BOGUS */
1553 addrS[7] = 0; /* BOGUS */
1554
1555 /* RDP (Last x87 data pointer). From experimentation, the real CPU
1556 does not write this field. (?!) */
1557 addrS[8] = 0; /* BOGUS */
1558 addrS[9] = 0; /* BOGUS */
1559 addrS[10] = 0; /* BOGUS */
1560 addrS[11] = 0; /* BOGUS */
1561
1562 addrS[12] = toUShort(mxcsr); /* MXCSR */
1563 addrS[13] = toUShort(mxcsr >> 16);
1564
1565 addrS[14] = 0xFFFF; /* MXCSR mask (lo16) */
1566 addrS[15] = 0x0000; /* MXCSR mask (hi16) */
1567
1568 /* Copy in the FP registers, in ST order. */
1569 for (stno = 0; stno < 8; stno++) {
1570 srcS = (UShort*)(&tmp.reg[10*stno]);
1571 dstS = (UShort*)(&addrS[16 + 8*stno]);
1572 dstS[0] = srcS[0];
1573 dstS[1] = srcS[1];
1574 dstS[2] = srcS[2];
1575 dstS[3] = srcS[3];
1576 dstS[4] = srcS[4];
1577 dstS[5] = 0;
1578 dstS[6] = 0;
1579 dstS[7] = 0;
1580 }
1581
1582 /* That's the first 160 bytes of the image done. Now only %xmm0
1583 .. %xmm15 remain to be copied. If the host is big-endian, these
1584 need to be byte-swapped. */
1585 vassert(host_is_little_endian());
1586
1587# define COPY_U128(_dst,_src) \
1588 do { _dst[0] = _src[0]; _dst[1] = _src[1]; \
1589 _dst[2] = _src[2]; _dst[3] = _src[3]; } \
1590 while (0)
1591
1592 COPY_U128( xmm[0], gst->guest_XMM0 );
1593 COPY_U128( xmm[1], gst->guest_XMM1 );
1594 COPY_U128( xmm[2], gst->guest_XMM2 );
1595 COPY_U128( xmm[3], gst->guest_XMM3 );
1596 COPY_U128( xmm[4], gst->guest_XMM4 );
1597 COPY_U128( xmm[5], gst->guest_XMM5 );
1598 COPY_U128( xmm[6], gst->guest_XMM6 );
1599 COPY_U128( xmm[7], gst->guest_XMM7 );
1600 COPY_U128( xmm[8], gst->guest_XMM8 );
1601 COPY_U128( xmm[9], gst->guest_XMM9 );
1602 COPY_U128( xmm[10], gst->guest_XMM10 );
1603 COPY_U128( xmm[11], gst->guest_XMM11 );
1604 COPY_U128( xmm[12], gst->guest_XMM12 );
1605 COPY_U128( xmm[13], gst->guest_XMM13 );
1606 COPY_U128( xmm[14], gst->guest_XMM14 );
1607 COPY_U128( xmm[15], gst->guest_XMM15 );
1608
1609# undef COPY_U128
1610}
1611
1612
sewardj0585a032005-11-05 02:55:06 +00001613/* DIRTY HELPER (writes guest state) */
sewardj8d965312005-02-25 02:48:47 +00001614/* Initialise the x87 FPU state as per 'finit'. */
sewardj8d965312005-02-25 02:48:47 +00001615void amd64g_dirtyhelper_FINIT ( VexGuestAMD64State* gst )
1616{
1617 Int i;
1618 gst->guest_FTOP = 0;
1619 for (i = 0; i < 8; i++) {
1620 gst->guest_FPTAG[i] = 0; /* empty */
1621 gst->guest_FPREG[i] = 0; /* IEEE754 64-bit zero */
1622 }
1623 gst->guest_FPROUND = (ULong)Irrm_NEAREST;
1624 gst->guest_FC3210 = 0;
1625}
1626
sewardjd0a12df2005-02-10 02:07:43 +00001627
sewardj924215b2005-03-26 21:50:31 +00001628/* CALLED FROM GENERATED CODE */
1629/* DIRTY HELPER (reads guest memory) */
sewardj8707fef2005-08-23 23:26:37 +00001630ULong amd64g_dirtyhelper_loadF80le ( ULong addrU )
sewardj924215b2005-03-26 21:50:31 +00001631{
1632 ULong f64;
1633 convert_f80le_to_f64le ( (UChar*)ULong_to_Ptr(addrU), (UChar*)&f64 );
1634 return f64;
1635}
1636
1637/* CALLED FROM GENERATED CODE */
1638/* DIRTY HELPER (writes guest memory) */
sewardj8707fef2005-08-23 23:26:37 +00001639void amd64g_dirtyhelper_storeF80le ( ULong addrU, ULong f64 )
sewardj924215b2005-03-26 21:50:31 +00001640{
1641 convert_f64le_to_f80le( (UChar*)&f64, (UChar*)ULong_to_Ptr(addrU) );
1642}
1643
1644
sewardjbcbb9de2005-03-27 02:22:32 +00001645/* CALLED FROM GENERATED CODE */
1646/* CLEAN HELPER */
1647/* mxcsr[15:0] contains a SSE native format MXCSR value.
1648 Extract from it the required SSEROUND value and any resulting
1649 emulation warning, and return (warn << 32) | sseround value.
1650*/
1651ULong amd64g_check_ldmxcsr ( ULong mxcsr )
1652{
1653 /* Decide on a rounding mode. mxcsr[14:13] holds it. */
1654 /* NOTE, encoded exactly as per enum IRRoundingMode. */
1655 ULong rmode = (mxcsr >> 13) & 3;
1656
1657 /* Detect any required emulation warnings. */
1658 VexEmWarn ew = EmWarn_NONE;
1659
1660 if ((mxcsr & 0x1F80) != 0x1F80) {
1661 /* unmasked exceptions! */
1662 ew = EmWarn_X86_sseExns;
1663 }
1664 else
1665 if (mxcsr & (1<<15)) {
1666 /* FZ is set */
1667 ew = EmWarn_X86_fz;
1668 }
1669 else
1670 if (mxcsr & (1<<6)) {
1671 /* DAZ is set */
1672 ew = EmWarn_X86_daz;
1673 }
1674
1675 return (((ULong)ew) << 32) | ((ULong)rmode);
1676}
1677
1678
1679/* CALLED FROM GENERATED CODE */
1680/* CLEAN HELPER */
1681/* Given sseround as an IRRoundingMode value, create a suitable SSE
1682 native format MXCSR value. */
1683ULong amd64g_create_mxcsr ( ULong sseround )
1684{
1685 sseround &= 3;
1686 return 0x1F80 | (sseround << 13);
1687}
1688
1689
sewardj5e205372005-05-09 02:57:08 +00001690/* CLEAN HELPER */
1691/* fpucw[15:0] contains a x87 native format FPU control word.
1692 Extract from it the required FPROUND value and any resulting
1693 emulation warning, and return (warn << 32) | fpround value.
1694*/
1695ULong amd64g_check_fldcw ( ULong fpucw )
1696{
1697 /* Decide on a rounding mode. fpucw[11:10] holds it. */
1698 /* NOTE, encoded exactly as per enum IRRoundingMode. */
1699 ULong rmode = (fpucw >> 10) & 3;
1700
1701 /* Detect any required emulation warnings. */
1702 VexEmWarn ew = EmWarn_NONE;
1703
1704 if ((fpucw & 0x3F) != 0x3F) {
1705 /* unmasked exceptions! */
1706 ew = EmWarn_X86_x87exns;
1707 }
1708 else
1709 if (((fpucw >> 8) & 3) != 3) {
1710 /* unsupported precision */
1711 ew = EmWarn_X86_x87precision;
1712 }
1713
1714 return (((ULong)ew) << 32) | ((ULong)rmode);
1715}
1716
1717
1718/* CLEAN HELPER */
1719/* Given fpround as an IRRoundingMode value, create a suitable x87
1720 native format FPU control word. */
1721ULong amd64g_create_fpucw ( ULong fpround )
1722{
1723 fpround &= 3;
1724 return 0x037F | (fpround << 10);
1725}
1726
sewardjbcbb9de2005-03-27 02:22:32 +00001727
sewardj4017a3b2005-06-13 12:17:27 +00001728/* This is used to implement 'fldenv'.
1729 Reads 28 bytes at x87_state[0 .. 27]. */
1730/* CALLED FROM GENERATED CODE */
1731/* DIRTY HELPER */
1732VexEmWarn amd64g_dirtyhelper_FLDENV ( /*OUT*/VexGuestAMD64State* vex_state,
1733 /*IN*/HWord x87_state)
1734{
1735 Int stno, preg;
1736 UInt tag;
1737 UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
1738 Fpu_State* x87 = (Fpu_State*)x87_state;
1739 UInt ftop = (x87->env[FP_ENV_STAT] >> 11) & 7;
1740 UInt tagw = x87->env[FP_ENV_TAG];
1741 UInt fpucw = x87->env[FP_ENV_CTRL];
1742 ULong c3210 = x87->env[FP_ENV_STAT] & 0x4700;
1743 VexEmWarn ew;
1744 ULong fpround;
1745 ULong pair;
1746
1747 /* Copy tags */
1748 for (stno = 0; stno < 8; stno++) {
1749 preg = (stno + ftop) & 7;
1750 tag = (tagw >> (2*preg)) & 3;
1751 if (tag == 3) {
1752 /* register is empty */
1753 vexTags[preg] = 0;
1754 } else {
1755 /* register is non-empty */
1756 vexTags[preg] = 1;
1757 }
1758 }
1759
1760 /* stack pointer */
1761 vex_state->guest_FTOP = ftop;
1762
1763 /* status word */
1764 vex_state->guest_FC3210 = c3210;
1765
1766 /* handle the control word, setting FPROUND and detecting any
1767 emulation warnings. */
1768 pair = amd64g_check_fldcw ( (ULong)fpucw );
1769 fpround = pair & 0xFFFFFFFFULL;
1770 ew = (VexEmWarn)(pair >> 32);
1771
1772 vex_state->guest_FPROUND = fpround & 3;
1773
1774 /* emulation warnings --> caller */
1775 return ew;
1776}
1777
1778
1779/* CALLED FROM GENERATED CODE */
1780/* DIRTY HELPER */
1781/* Create an x87 FPU env from the guest state, as close as we can
1782 approximate it. Writes 28 bytes at x87_state[0..27]. */
1783void amd64g_dirtyhelper_FSTENV ( /*IN*/VexGuestAMD64State* vex_state,
1784 /*OUT*/HWord x87_state )
1785{
1786 Int i, stno, preg;
1787 UInt tagw;
1788 UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
1789 Fpu_State* x87 = (Fpu_State*)x87_state;
1790 UInt ftop = vex_state->guest_FTOP;
1791 ULong c3210 = vex_state->guest_FC3210;
1792
1793 for (i = 0; i < 14; i++)
1794 x87->env[i] = 0;
1795
1796 x87->env[1] = x87->env[3] = x87->env[5] = x87->env[13] = 0xFFFF;
1797 x87->env[FP_ENV_STAT]
sewardj81d72ea2005-06-14 21:59:16 +00001798 = toUShort(toUInt( ((ftop & 7) << 11) | (c3210 & 0x4700) ));
sewardj4017a3b2005-06-13 12:17:27 +00001799 x87->env[FP_ENV_CTRL]
sewardj81d72ea2005-06-14 21:59:16 +00001800 = toUShort(toUInt( amd64g_create_fpucw( vex_state->guest_FPROUND ) ));
sewardj4017a3b2005-06-13 12:17:27 +00001801
1802 /* Compute the x87 tag word. */
1803 tagw = 0;
1804 for (stno = 0; stno < 8; stno++) {
1805 preg = (stno + ftop) & 7;
1806 if (vexTags[preg] == 0) {
1807 /* register is empty */
1808 tagw |= (3 << (2*preg));
1809 } else {
1810 /* register is full. */
1811 tagw |= (0 << (2*preg));
1812 }
1813 }
1814 x87->env[FP_ENV_TAG] = toUShort(tagw);
1815
1816 /* We don't dump the x87 registers, tho. */
1817}
1818
1819
sewardjd0a12df2005-02-10 02:07:43 +00001820/*---------------------------------------------------------------*/
1821/*--- Misc integer helpers, including rotates and CPUID. ---*/
1822/*---------------------------------------------------------------*/
1823
sewardje9d8a262009-07-01 08:06:34 +00001824/* Claim to be the following CPU, which is probably representative of
1825 the lowliest (earliest) amd64 offerings. It can do neither sse3
1826 nor cx16.
1827
1828 vendor_id : AuthenticAMD
1829 cpu family : 15
1830 model : 5
1831 model name : AMD Opteron (tm) Processor 848
1832 stepping : 10
1833 cpu MHz : 1797.682
1834 cache size : 1024 KB
1835 fpu : yes
1836 fpu_exception : yes
1837 cpuid level : 1
1838 wp : yes
1839 flags : fpu vme de pse tsc msr pae mce cx8 apic sep
1840 mtrr pge mca cmov pat pse36 clflush mmx fxsr
1841 sse sse2 syscall nx mmxext lm 3dnowext 3dnow
1842 bogomips : 3600.62
1843 TLB size : 1088 4K pages
1844 clflush size : 64
1845 cache_alignment : 64
1846 address sizes : 40 bits physical, 48 bits virtual
1847 power management: ts fid vid ttp
1848*/
1849void amd64g_dirtyhelper_CPUID_baseline ( VexGuestAMD64State* st )
1850{
1851# define SET_ABCD(_a,_b,_c,_d) \
1852 do { st->guest_RAX = (ULong)(_a); \
1853 st->guest_RBX = (ULong)(_b); \
1854 st->guest_RCX = (ULong)(_c); \
1855 st->guest_RDX = (ULong)(_d); \
1856 } while (0)
1857
1858 switch (0xFFFFFFFF & st->guest_RAX) {
1859 case 0x00000000:
1860 SET_ABCD(0x00000001, 0x68747541, 0x444d4163, 0x69746e65);
1861 break;
1862 case 0x00000001:
1863 SET_ABCD(0x00000f5a, 0x01000800, 0x00000000, 0x078bfbff);
1864 break;
1865 case 0x80000000:
1866 SET_ABCD(0x80000018, 0x68747541, 0x444d4163, 0x69746e65);
1867 break;
1868 case 0x80000001:
1869 SET_ABCD(0x00000f5a, 0x00000505, 0x00000000, 0xe1d3fbff);
1870 break;
1871 case 0x80000002:
1872 SET_ABCD(0x20444d41, 0x6574704f, 0x206e6f72, 0x296d7428);
1873 break;
1874 case 0x80000003:
1875 SET_ABCD(0x6f725020, 0x73736563, 0x3820726f, 0x00003834);
1876 break;
1877 case 0x80000004:
1878 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
1879 break;
1880 case 0x80000005:
1881 SET_ABCD(0xff08ff08, 0xff20ff20, 0x40020140, 0x40020140);
1882 break;
1883 case 0x80000006:
1884 SET_ABCD(0x00000000, 0x42004200, 0x04008140, 0x00000000);
1885 break;
1886 case 0x80000007:
1887 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x0000000f);
1888 break;
1889 case 0x80000008:
1890 SET_ABCD(0x00003028, 0x00000000, 0x00000000, 0x00000000);
1891 break;
1892 default:
1893 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
1894 break;
1895 }
1896# undef SET_ABCD
1897}
1898
1899
1900/* Claim to be the following CPU (2 x ...), which is sse3 and cx16
1901 capable.
1902
sewardj150c9cd2008-02-09 01:16:02 +00001903 vendor_id : GenuineIntel
1904 cpu family : 6
1905 model : 15
1906 model name : Intel(R) Core(TM)2 CPU 6600 @ 2.40GHz
1907 stepping : 6
1908 cpu MHz : 2394.000
1909 cache size : 4096 KB
1910 physical id : 0
1911 siblings : 2
1912 core id : 0
1913 cpu cores : 2
sewardjd0a12df2005-02-10 02:07:43 +00001914 fpu : yes
1915 fpu_exception : yes
sewardj150c9cd2008-02-09 01:16:02 +00001916 cpuid level : 10
sewardjd0a12df2005-02-10 02:07:43 +00001917 wp : yes
sewardj150c9cd2008-02-09 01:16:02 +00001918 flags : fpu vme de pse tsc msr pae mce cx8 apic sep
1919 mtrr pge mca cmov pat pse36 clflush dts acpi
1920 mmx fxsr sse sse2 ss ht tm syscall nx lm
1921 constant_tsc pni monitor ds_cpl vmx est tm2
1922 cx16 xtpr lahf_lm
1923 bogomips : 4798.78
sewardjd0a12df2005-02-10 02:07:43 +00001924 clflush size : 64
1925 cache_alignment : 64
sewardj150c9cd2008-02-09 01:16:02 +00001926 address sizes : 36 bits physical, 48 bits virtual
1927 power management:
sewardjd0a12df2005-02-10 02:07:43 +00001928*/
sewardje9d8a262009-07-01 08:06:34 +00001929void amd64g_dirtyhelper_CPUID_sse3_and_cx16 ( VexGuestAMD64State* st )
sewardjd0a12df2005-02-10 02:07:43 +00001930{
1931# define SET_ABCD(_a,_b,_c,_d) \
1932 do { st->guest_RAX = (ULong)(_a); \
1933 st->guest_RBX = (ULong)(_b); \
1934 st->guest_RCX = (ULong)(_c); \
1935 st->guest_RDX = (ULong)(_d); \
1936 } while (0)
1937
1938 switch (0xFFFFFFFF & st->guest_RAX) {
sewardj150c9cd2008-02-09 01:16:02 +00001939 case 0x00000000:
1940 SET_ABCD(0x0000000a, 0x756e6547, 0x6c65746e, 0x49656e69);
sewardjd0a12df2005-02-10 02:07:43 +00001941 break;
sewardj150c9cd2008-02-09 01:16:02 +00001942 case 0x00000001:
1943 SET_ABCD(0x000006f6, 0x00020800, 0x0000e3bd, 0xbfebfbff);
sewardjd0a12df2005-02-10 02:07:43 +00001944 break;
sewardj150c9cd2008-02-09 01:16:02 +00001945 case 0x00000002:
1946 SET_ABCD(0x05b0b101, 0x005657f0, 0x00000000, 0x2cb43049);
sewardjd0a12df2005-02-10 02:07:43 +00001947 break;
sewardj150c9cd2008-02-09 01:16:02 +00001948 case 0x00000003:
1949 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
sewardjd0a12df2005-02-10 02:07:43 +00001950 break;
sewardj32bfd3e2008-02-10 13:29:19 +00001951 case 0x00000004: {
1952 switch (0xFFFFFFFF & st->guest_RCX) {
1953 case 0x00000000: SET_ABCD(0x04000121, 0x01c0003f,
1954 0x0000003f, 0x00000001); break;
1955 case 0x00000001: SET_ABCD(0x04000122, 0x01c0003f,
1956 0x0000003f, 0x00000001); break;
1957 case 0x00000002: SET_ABCD(0x04004143, 0x03c0003f,
1958 0x00000fff, 0x00000001); break;
1959 default: SET_ABCD(0x00000000, 0x00000000,
1960 0x00000000, 0x00000000); break;
1961 }
sewardjd0a12df2005-02-10 02:07:43 +00001962 break;
sewardj32bfd3e2008-02-10 13:29:19 +00001963 }
sewardj150c9cd2008-02-09 01:16:02 +00001964 case 0x00000005:
1965 SET_ABCD(0x00000040, 0x00000040, 0x00000003, 0x00000020);
sewardjd0a12df2005-02-10 02:07:43 +00001966 break;
sewardj150c9cd2008-02-09 01:16:02 +00001967 case 0x00000006:
1968 SET_ABCD(0x00000001, 0x00000002, 0x00000001, 0x00000000);
sewardjd0a12df2005-02-10 02:07:43 +00001969 break;
sewardj150c9cd2008-02-09 01:16:02 +00001970 case 0x00000007:
1971 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
sewardjd0a12df2005-02-10 02:07:43 +00001972 break;
sewardj150c9cd2008-02-09 01:16:02 +00001973 case 0x00000008:
1974 SET_ABCD(0x00000400, 0x00000000, 0x00000000, 0x00000000);
sewardjd0a12df2005-02-10 02:07:43 +00001975 break;
sewardj150c9cd2008-02-09 01:16:02 +00001976 case 0x00000009:
1977 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
sewardjd0a12df2005-02-10 02:07:43 +00001978 break;
sewardj150c9cd2008-02-09 01:16:02 +00001979 case 0x0000000a:
sewardj32bfd3e2008-02-10 13:29:19 +00001980 unhandled_eax_value:
sewardj150c9cd2008-02-09 01:16:02 +00001981 SET_ABCD(0x07280202, 0x00000000, 0x00000000, 0x00000000);
1982 break;
1983 case 0x80000000:
1984 SET_ABCD(0x80000008, 0x00000000, 0x00000000, 0x00000000);
1985 break;
1986 case 0x80000001:
1987 SET_ABCD(0x00000000, 0x00000000, 0x00000001, 0x20100800);
1988 break;
1989 case 0x80000002:
1990 SET_ABCD(0x65746e49, 0x2952286c, 0x726f4320, 0x4d542865);
1991 break;
1992 case 0x80000003:
1993 SET_ABCD(0x43203229, 0x20205550, 0x20202020, 0x20202020);
1994 break;
1995 case 0x80000004:
1996 SET_ABCD(0x30303636, 0x20402020, 0x30342e32, 0x007a4847);
1997 break;
1998 case 0x80000005:
1999 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
2000 break;
2001 case 0x80000006:
2002 SET_ABCD(0x00000000, 0x00000000, 0x10008040, 0x00000000);
2003 break;
2004 case 0x80000007:
2005 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
2006 break;
2007 case 0x80000008:
2008 SET_ABCD(0x00003024, 0x00000000, 0x00000000, 0x00000000);
2009 break;
sewardjd0a12df2005-02-10 02:07:43 +00002010 default:
sewardj32bfd3e2008-02-10 13:29:19 +00002011 goto unhandled_eax_value;
sewardjd0a12df2005-02-10 02:07:43 +00002012 }
2013# undef SET_ABCD
2014}
2015
2016
sewardj0b2d3fe2010-08-06 07:59:38 +00002017/* Claim to be the following CPU (4 x ...), which is sse4.2 and cx16
2018 capable.
2019
2020 vendor_id : GenuineIntel
2021 cpu family : 6
2022 model : 37
2023 model name : Intel(R) Core(TM) i5 CPU 670 @ 3.47GHz
2024 stepping : 2
2025 cpu MHz : 3334.000
2026 cache size : 4096 KB
2027 physical id : 0
2028 siblings : 4
2029 core id : 0
2030 cpu cores : 2
2031 apicid : 0
2032 initial apicid : 0
2033 fpu : yes
2034 fpu_exception : yes
2035 cpuid level : 11
2036 wp : yes
2037 flags : fpu vme de pse tsc msr pae mce cx8 apic sep
2038 mtrr pge mca cmov pat pse36 clflush dts acpi
2039 mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp
2040 lm constant_tsc arch_perfmon pebs bts rep_good
2041 xtopology nonstop_tsc aperfmperf pni pclmulqdq
2042 dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16
2043 xtpr pdcm sse4_1 sse4_2 popcnt aes lahf_lm ida
2044 arat tpr_shadow vnmi flexpriority ept vpid
2045 bogomips : 6957.57
2046 clflush size : 64
2047 cache_alignment : 64
2048 address sizes : 36 bits physical, 48 bits virtual
2049 power management:
2050*/
2051void amd64g_dirtyhelper_CPUID_sse42_and_cx16 ( VexGuestAMD64State* st )
2052{
2053# define SET_ABCD(_a,_b,_c,_d) \
2054 do { st->guest_RAX = (ULong)(_a); \
2055 st->guest_RBX = (ULong)(_b); \
2056 st->guest_RCX = (ULong)(_c); \
2057 st->guest_RDX = (ULong)(_d); \
2058 } while (0)
2059
2060 UInt old_eax = (UInt)st->guest_RAX;
2061 UInt old_ecx = (UInt)st->guest_RCX;
2062
2063 switch (old_eax) {
2064 case 0x00000000:
2065 SET_ABCD(0x0000000b, 0x756e6547, 0x6c65746e, 0x49656e69);
2066 break;
2067 case 0x00000001:
2068 SET_ABCD(0x00020652, 0x00100800, 0x0298e3ff, 0xbfebfbff);
2069 break;
2070 case 0x00000002:
2071 SET_ABCD(0x55035a01, 0x00f0b2e3, 0x00000000, 0x09ca212c);
2072 break;
2073 case 0x00000003:
2074 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
2075 break;
2076 case 0x00000004:
2077 switch (old_ecx) {
2078 case 0x00000000: SET_ABCD(0x1c004121, 0x01c0003f,
2079 0x0000003f, 0x00000000); break;
2080 case 0x00000001: SET_ABCD(0x1c004122, 0x00c0003f,
2081 0x0000007f, 0x00000000); break;
2082 case 0x00000002: SET_ABCD(0x1c004143, 0x01c0003f,
2083 0x000001ff, 0x00000000); break;
2084 case 0x00000003: SET_ABCD(0x1c03c163, 0x03c0003f,
2085 0x00000fff, 0x00000002); break;
2086 default: SET_ABCD(0x00000000, 0x00000000,
2087 0x00000000, 0x00000000); break;
2088 }
2089 break;
2090 case 0x00000005:
2091 SET_ABCD(0x00000040, 0x00000040, 0x00000003, 0x00001120);
2092 break;
2093 case 0x00000006:
2094 SET_ABCD(0x00000007, 0x00000002, 0x00000001, 0x00000000);
2095 break;
2096 case 0x00000007:
2097 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
2098 break;
2099 case 0x00000008:
2100 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
2101 break;
2102 case 0x00000009:
2103 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
2104 break;
2105 case 0x0000000a:
2106 SET_ABCD(0x07300403, 0x00000004, 0x00000000, 0x00000603);
2107 break;
2108 case 0x0000000b:
2109 switch (old_ecx) {
2110 case 0x00000000:
2111 SET_ABCD(0x00000001, 0x00000002,
2112 0x00000100, 0x00000000); break;
2113 case 0x00000001:
2114 SET_ABCD(0x00000004, 0x00000004,
2115 0x00000201, 0x00000000); break;
2116 default:
2117 SET_ABCD(0x00000000, 0x00000000,
2118 old_ecx, 0x00000000); break;
2119 }
2120 break;
2121 case 0x0000000c:
2122 SET_ABCD(0x00000001, 0x00000002, 0x00000100, 0x00000000);
2123 break;
2124 case 0x0000000d:
2125 switch (old_ecx) {
2126 case 0x00000000: SET_ABCD(0x00000001, 0x00000002,
2127 0x00000100, 0x00000000); break;
2128 case 0x00000001: SET_ABCD(0x00000004, 0x00000004,
2129 0x00000201, 0x00000000); break;
2130 default: SET_ABCD(0x00000000, 0x00000000,
2131 old_ecx, 0x00000000); break;
2132 }
2133 break;
2134 case 0x80000000:
2135 SET_ABCD(0x80000008, 0x00000000, 0x00000000, 0x00000000);
2136 break;
2137 case 0x80000001:
2138 SET_ABCD(0x00000000, 0x00000000, 0x00000001, 0x28100800);
2139 break;
2140 case 0x80000002:
2141 SET_ABCD(0x65746e49, 0x2952286c, 0x726f4320, 0x4d542865);
2142 break;
2143 case 0x80000003:
2144 SET_ABCD(0x35692029, 0x55504320, 0x20202020, 0x20202020);
2145 break;
2146 case 0x80000004:
2147 SET_ABCD(0x30373620, 0x20402020, 0x37342e33, 0x007a4847);
2148 break;
2149 case 0x80000005:
2150 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000000);
2151 break;
2152 case 0x80000006:
2153 SET_ABCD(0x00000000, 0x00000000, 0x01006040, 0x00000000);
2154 break;
2155 case 0x80000007:
2156 SET_ABCD(0x00000000, 0x00000000, 0x00000000, 0x00000100);
2157 break;
2158 case 0x80000008:
2159 SET_ABCD(0x00003024, 0x00000000, 0x00000000, 0x00000000);
2160 break;
2161 default:
2162 SET_ABCD(0x00000001, 0x00000002, 0x00000100, 0x00000000);
2163 break;
2164 }
2165# undef SET_ABCD
2166}
2167
2168
sewardj112b0992005-07-23 13:19:32 +00002169ULong amd64g_calculate_RCR ( ULong arg,
2170 ULong rot_amt,
2171 ULong rflags_in,
2172 Long szIN )
2173{
2174 Bool wantRflags = toBool(szIN < 0);
2175 ULong sz = wantRflags ? (-szIN) : szIN;
2176 ULong tempCOUNT = rot_amt & (sz == 8 ? 0x3F : 0x1F);
2177 ULong cf=0, of=0, tempcf;
2178
2179 switch (sz) {
2180 case 8:
2181 cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
2182 of = ((arg >> 63) ^ cf) & 1;
2183 while (tempCOUNT > 0) {
2184 tempcf = arg & 1;
2185 arg = (arg >> 1) | (cf << 63);
2186 cf = tempcf;
2187 tempCOUNT--;
2188 }
2189 break;
2190 case 4:
2191 while (tempCOUNT >= 33) tempCOUNT -= 33;
2192 cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
2193 of = ((arg >> 31) ^ cf) & 1;
2194 while (tempCOUNT > 0) {
2195 tempcf = arg & 1;
2196 arg = ((arg >> 1) & 0x7FFFFFFFULL) | (cf << 31);
2197 cf = tempcf;
2198 tempCOUNT--;
2199 }
2200 break;
2201 case 2:
2202 while (tempCOUNT >= 17) tempCOUNT -= 17;
2203 cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
2204 of = ((arg >> 15) ^ cf) & 1;
2205 while (tempCOUNT > 0) {
2206 tempcf = arg & 1;
2207 arg = ((arg >> 1) & 0x7FFFULL) | (cf << 15);
2208 cf = tempcf;
2209 tempCOUNT--;
2210 }
2211 break;
2212 case 1:
2213 while (tempCOUNT >= 9) tempCOUNT -= 9;
2214 cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
2215 of = ((arg >> 7) ^ cf) & 1;
2216 while (tempCOUNT > 0) {
2217 tempcf = arg & 1;
2218 arg = ((arg >> 1) & 0x7FULL) | (cf << 7);
2219 cf = tempcf;
2220 tempCOUNT--;
2221 }
2222 break;
2223 default:
2224 vpanic("calculate_RCR(amd64g): invalid size");
2225 }
2226
2227 cf &= 1;
2228 of &= 1;
2229 rflags_in &= ~(AMD64G_CC_MASK_C | AMD64G_CC_MASK_O);
2230 rflags_in |= (cf << AMD64G_CC_SHIFT_C) | (of << AMD64G_CC_SHIFT_O);
2231
2232 /* caller can ask to have back either the resulting flags or
2233 resulting value, but not both */
2234 return wantRflags ? rflags_in : arg;
2235}
2236
sewardjb5e5c6d2007-01-12 20:29:01 +00002237ULong amd64g_calculate_RCL ( ULong arg,
2238 ULong rot_amt,
2239 ULong rflags_in,
2240 Long szIN )
2241{
2242 Bool wantRflags = toBool(szIN < 0);
2243 ULong sz = wantRflags ? (-szIN) : szIN;
2244 ULong tempCOUNT = rot_amt & (sz == 8 ? 0x3F : 0x1F);
2245 ULong cf=0, of=0, tempcf;
2246
2247 switch (sz) {
2248 case 8:
2249 cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
2250 while (tempCOUNT > 0) {
2251 tempcf = (arg >> 63) & 1;
2252 arg = (arg << 1) | (cf & 1);
2253 cf = tempcf;
2254 tempCOUNT--;
2255 }
2256 of = ((arg >> 63) ^ cf) & 1;
2257 break;
2258 case 4:
2259 while (tempCOUNT >= 33) tempCOUNT -= 33;
2260 cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
2261 while (tempCOUNT > 0) {
2262 tempcf = (arg >> 31) & 1;
2263 arg = 0xFFFFFFFFULL & ((arg << 1) | (cf & 1));
2264 cf = tempcf;
2265 tempCOUNT--;
2266 }
2267 of = ((arg >> 31) ^ cf) & 1;
2268 break;
2269 case 2:
2270 while (tempCOUNT >= 17) tempCOUNT -= 17;
2271 cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
2272 while (tempCOUNT > 0) {
2273 tempcf = (arg >> 15) & 1;
2274 arg = 0xFFFFULL & ((arg << 1) | (cf & 1));
2275 cf = tempcf;
2276 tempCOUNT--;
2277 }
2278 of = ((arg >> 15) ^ cf) & 1;
2279 break;
2280 case 1:
2281 while (tempCOUNT >= 9) tempCOUNT -= 9;
2282 cf = (rflags_in >> AMD64G_CC_SHIFT_C) & 1;
2283 while (tempCOUNT > 0) {
2284 tempcf = (arg >> 7) & 1;
2285 arg = 0xFFULL & ((arg << 1) | (cf & 1));
2286 cf = tempcf;
2287 tempCOUNT--;
2288 }
2289 of = ((arg >> 7) ^ cf) & 1;
2290 break;
2291 default:
2292 vpanic("calculate_RCL(amd64g): invalid size");
2293 }
2294
2295 cf &= 1;
2296 of &= 1;
2297 rflags_in &= ~(AMD64G_CC_MASK_C | AMD64G_CC_MASK_O);
2298 rflags_in |= (cf << AMD64G_CC_SHIFT_C) | (of << AMD64G_CC_SHIFT_O);
2299
2300 return wantRflags ? rflags_in : arg;
2301}
2302
sewardj1a179b52010-09-28 19:56:32 +00002303/* Taken from gf2x-0.9.5, released under GPLv2+ (later versions LGPLv2+)
2304 * svn://scm.gforge.inria.fr/svn/gf2x/trunk/hardware/opteron/gf2x_mul1.h@25
2305 */
2306ULong amd64g_calculate_pclmul(ULong a, ULong b, ULong which)
2307{
2308 ULong hi, lo, tmp, A[16];
2309
2310 A[0] = 0; A[1] = a;
2311 A[2] = A[1] << 1; A[3] = A[2] ^ a;
2312 A[4] = A[2] << 1; A[5] = A[4] ^ a;
2313 A[6] = A[3] << 1; A[7] = A[6] ^ a;
2314 A[8] = A[4] << 1; A[9] = A[8] ^ a;
2315 A[10] = A[5] << 1; A[11] = A[10] ^ a;
2316 A[12] = A[6] << 1; A[13] = A[12] ^ a;
2317 A[14] = A[7] << 1; A[15] = A[14] ^ a;
2318
2319 lo = (A[b >> 60] << 4) ^ A[(b >> 56) & 15];
2320 hi = lo >> 56;
2321 lo = (lo << 8) ^ (A[(b >> 52) & 15] << 4) ^ A[(b >> 48) & 15];
2322 hi = (hi << 8) | (lo >> 56);
2323 lo = (lo << 8) ^ (A[(b >> 44) & 15] << 4) ^ A[(b >> 40) & 15];
2324 hi = (hi << 8) | (lo >> 56);
2325 lo = (lo << 8) ^ (A[(b >> 36) & 15] << 4) ^ A[(b >> 32) & 15];
2326 hi = (hi << 8) | (lo >> 56);
2327 lo = (lo << 8) ^ (A[(b >> 28) & 15] << 4) ^ A[(b >> 24) & 15];
2328 hi = (hi << 8) | (lo >> 56);
2329 lo = (lo << 8) ^ (A[(b >> 20) & 15] << 4) ^ A[(b >> 16) & 15];
2330 hi = (hi << 8) | (lo >> 56);
2331 lo = (lo << 8) ^ (A[(b >> 12) & 15] << 4) ^ A[(b >> 8) & 15];
2332 hi = (hi << 8) | (lo >> 56);
2333 lo = (lo << 8) ^ (A[(b >> 4) & 15] << 4) ^ A[b & 15];
2334
2335 ULong m0 = -1;
2336 m0 /= 255;
2337 tmp = -((a >> 63) & 1); tmp &= ((b & (m0 * 0xfe)) >> 1); hi = hi ^ tmp;
2338 tmp = -((a >> 62) & 1); tmp &= ((b & (m0 * 0xfc)) >> 2); hi = hi ^ tmp;
2339 tmp = -((a >> 61) & 1); tmp &= ((b & (m0 * 0xf8)) >> 3); hi = hi ^ tmp;
2340 tmp = -((a >> 60) & 1); tmp &= ((b & (m0 * 0xf0)) >> 4); hi = hi ^ tmp;
2341 tmp = -((a >> 59) & 1); tmp &= ((b & (m0 * 0xe0)) >> 5); hi = hi ^ tmp;
2342 tmp = -((a >> 58) & 1); tmp &= ((b & (m0 * 0xc0)) >> 6); hi = hi ^ tmp;
2343 tmp = -((a >> 57) & 1); tmp &= ((b & (m0 * 0x80)) >> 7); hi = hi ^ tmp;
2344
2345 return which ? hi : lo;
2346}
2347
sewardj112b0992005-07-23 13:19:32 +00002348
sewardjbc6af532005-08-23 23:16:51 +00002349/* CALLED FROM GENERATED CODE */
2350/* DIRTY HELPER (non-referentially-transparent) */
2351/* Horrible hack. On non-amd64 platforms, return 1. */
2352ULong amd64g_dirtyhelper_RDTSC ( void )
2353{
2354# if defined(__x86_64__)
2355 UInt eax, edx;
2356 __asm__ __volatile__("rdtsc" : "=a" (eax), "=d" (edx));
2357 return (((ULong)edx) << 32) | ((ULong)eax);
2358# else
2359 return 1ULL;
2360# endif
2361}
2362
2363
sewardjbb4396c2007-11-20 17:29:08 +00002364/* CALLED FROM GENERATED CODE */
2365/* DIRTY HELPER (non-referentially-transparent) */
2366/* Horrible hack. On non-amd64 platforms, return 0. */
2367ULong amd64g_dirtyhelper_IN ( ULong portno, ULong sz/*1,2 or 4*/ )
2368{
2369# if defined(__x86_64__)
2370 ULong r = 0;
2371 portno &= 0xFFFF;
2372 switch (sz) {
2373 case 4:
2374 __asm__ __volatile__("movq $0,%%rax; inl %w1,%%eax; movq %%rax,%0"
2375 : "=a" (r) : "Nd" (portno));
2376 break;
2377 case 2:
2378 __asm__ __volatile__("movq $0,%%rax; inw %w1,%w0"
2379 : "=a" (r) : "Nd" (portno));
2380 break;
2381 case 1:
2382 __asm__ __volatile__("movq $0,%%rax; inb %w1,%b0"
2383 : "=a" (r) : "Nd" (portno));
2384 break;
2385 default:
2386 break; /* note: no 64-bit version of insn exists */
2387 }
2388 return r;
2389# else
2390 return 0;
2391# endif
2392}
2393
2394
2395/* CALLED FROM GENERATED CODE */
2396/* DIRTY HELPER (non-referentially-transparent) */
2397/* Horrible hack. On non-amd64 platforms, do nothing. */
2398void amd64g_dirtyhelper_OUT ( ULong portno, ULong data, ULong sz/*1,2 or 4*/ )
2399{
2400# if defined(__x86_64__)
2401 portno &= 0xFFFF;
2402 switch (sz) {
2403 case 4:
2404 __asm__ __volatile__("movq %0,%%rax; outl %%eax, %w1"
2405 : : "a" (data), "Nd" (portno));
2406 break;
2407 case 2:
2408 __asm__ __volatile__("outw %w0, %w1"
2409 : : "a" (data), "Nd" (portno));
2410 break;
2411 case 1:
2412 __asm__ __volatile__("outb %b0, %w1"
2413 : : "a" (data), "Nd" (portno));
2414 break;
2415 default:
2416 break; /* note: no 64-bit version of insn exists */
2417 }
2418# else
2419 /* do nothing */
2420# endif
2421}
2422
sewardjb9dc2432010-06-07 16:22:22 +00002423/* CALLED FROM GENERATED CODE */
2424/* DIRTY HELPER (non-referentially-transparent) */
2425/* Horrible hack. On non-amd64 platforms, do nothing. */
2426/* op = 0: call the native SGDT instruction.
2427 op = 1: call the native SIDT instruction.
2428*/
2429void amd64g_dirtyhelper_SxDT ( void *address, ULong op ) {
2430# if defined(__x86_64__)
2431 switch (op) {
2432 case 0:
2433 __asm__ __volatile__("sgdt (%0)" : : "r" (address) : "memory");
2434 break;
2435 case 1:
2436 __asm__ __volatile__("sidt (%0)" : : "r" (address) : "memory");
2437 break;
2438 default:
2439 vpanic("amd64g_dirtyhelper_SxDT");
2440 }
2441# else
2442 /* do nothing */
2443 UChar* p = (UChar*)address;
2444 p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = 0;
2445 p[6] = p[7] = p[8] = p[9] = 0;
2446# endif
2447}
sewardjbb4396c2007-11-20 17:29:08 +00002448
sewardj8711f662005-05-09 17:52:56 +00002449/*---------------------------------------------------------------*/
2450/*--- Helpers for MMX/SSE/SSE2. ---*/
2451/*---------------------------------------------------------------*/
2452
sewardja7ba8c42005-05-10 20:08:34 +00002453static inline UChar abdU8 ( UChar xx, UChar yy ) {
2454 return toUChar(xx>yy ? xx-yy : yy-xx);
2455}
2456
sewardj8711f662005-05-09 17:52:56 +00002457static inline ULong mk32x2 ( UInt w1, UInt w0 ) {
2458 return (((ULong)w1) << 32) | ((ULong)w0);
2459}
2460
2461static inline UShort sel16x4_3 ( ULong w64 ) {
2462 UInt hi32 = toUInt(w64 >> 32);
2463 return toUShort(hi32 >> 16);
2464}
2465static inline UShort sel16x4_2 ( ULong w64 ) {
2466 UInt hi32 = toUInt(w64 >> 32);
2467 return toUShort(hi32);
2468}
2469static inline UShort sel16x4_1 ( ULong w64 ) {
2470 UInt lo32 = toUInt(w64);
2471 return toUShort(lo32 >> 16);
2472}
2473static inline UShort sel16x4_0 ( ULong w64 ) {
2474 UInt lo32 = toUInt(w64);
2475 return toUShort(lo32);
2476}
2477
sewardja7ba8c42005-05-10 20:08:34 +00002478static inline UChar sel8x8_7 ( ULong w64 ) {
2479 UInt hi32 = toUInt(w64 >> 32);
2480 return toUChar(hi32 >> 24);
2481}
2482static inline UChar sel8x8_6 ( ULong w64 ) {
2483 UInt hi32 = toUInt(w64 >> 32);
2484 return toUChar(hi32 >> 16);
2485}
2486static inline UChar sel8x8_5 ( ULong w64 ) {
2487 UInt hi32 = toUInt(w64 >> 32);
2488 return toUChar(hi32 >> 8);
2489}
2490static inline UChar sel8x8_4 ( ULong w64 ) {
2491 UInt hi32 = toUInt(w64 >> 32);
2492 return toUChar(hi32 >> 0);
2493}
2494static inline UChar sel8x8_3 ( ULong w64 ) {
2495 UInt lo32 = toUInt(w64);
2496 return toUChar(lo32 >> 24);
2497}
2498static inline UChar sel8x8_2 ( ULong w64 ) {
2499 UInt lo32 = toUInt(w64);
2500 return toUChar(lo32 >> 16);
2501}
2502static inline UChar sel8x8_1 ( ULong w64 ) {
2503 UInt lo32 = toUInt(w64);
2504 return toUChar(lo32 >> 8);
2505}
2506static inline UChar sel8x8_0 ( ULong w64 ) {
2507 UInt lo32 = toUInt(w64);
2508 return toUChar(lo32 >> 0);
2509}
2510
sewardj8711f662005-05-09 17:52:56 +00002511/* CALLED FROM GENERATED CODE: CLEAN HELPER */
2512ULong amd64g_calculate_mmx_pmaddwd ( ULong xx, ULong yy )
2513{
2514 return
2515 mk32x2(
2516 (((Int)(Short)sel16x4_3(xx)) * ((Int)(Short)sel16x4_3(yy)))
2517 + (((Int)(Short)sel16x4_2(xx)) * ((Int)(Short)sel16x4_2(yy))),
2518 (((Int)(Short)sel16x4_1(xx)) * ((Int)(Short)sel16x4_1(yy)))
2519 + (((Int)(Short)sel16x4_0(xx)) * ((Int)(Short)sel16x4_0(yy)))
2520 );
2521}
2522
sewardja7ba8c42005-05-10 20:08:34 +00002523/* CALLED FROM GENERATED CODE: CLEAN HELPER */
2524ULong amd64g_calculate_mmx_pmovmskb ( ULong xx )
2525{
2526 ULong r = 0;
2527 if (xx & (1ULL << (64-1))) r |= (1<<7);
2528 if (xx & (1ULL << (56-1))) r |= (1<<6);
2529 if (xx & (1ULL << (48-1))) r |= (1<<5);
2530 if (xx & (1ULL << (40-1))) r |= (1<<4);
2531 if (xx & (1ULL << (32-1))) r |= (1<<3);
2532 if (xx & (1ULL << (24-1))) r |= (1<<2);
2533 if (xx & (1ULL << (16-1))) r |= (1<<1);
2534 if (xx & (1ULL << ( 8-1))) r |= (1<<0);
2535 return r;
2536}
2537
2538/* CALLED FROM GENERATED CODE: CLEAN HELPER */
2539ULong amd64g_calculate_mmx_psadbw ( ULong xx, ULong yy )
2540{
2541 UInt t = 0;
2542 t += (UInt)abdU8( sel8x8_7(xx), sel8x8_7(yy) );
2543 t += (UInt)abdU8( sel8x8_6(xx), sel8x8_6(yy) );
2544 t += (UInt)abdU8( sel8x8_5(xx), sel8x8_5(yy) );
2545 t += (UInt)abdU8( sel8x8_4(xx), sel8x8_4(yy) );
2546 t += (UInt)abdU8( sel8x8_3(xx), sel8x8_3(yy) );
2547 t += (UInt)abdU8( sel8x8_2(xx), sel8x8_2(yy) );
2548 t += (UInt)abdU8( sel8x8_1(xx), sel8x8_1(yy) );
2549 t += (UInt)abdU8( sel8x8_0(xx), sel8x8_0(yy) );
2550 t &= 0xFFFF;
2551 return (ULong)t;
2552}
2553
sewardjadffcef2005-05-11 00:03:06 +00002554/* CALLED FROM GENERATED CODE: CLEAN HELPER */
2555ULong amd64g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo )
2556{
2557 ULong rHi8 = amd64g_calculate_mmx_pmovmskb ( w64hi );
2558 ULong rLo8 = amd64g_calculate_mmx_pmovmskb ( w64lo );
2559 return ((rHi8 & 0xFF) << 8) | (rLo8 & 0xFF);
2560}
2561
sewardjd0a12df2005-02-10 02:07:43 +00002562
sewardjf8c37f72005-02-07 18:55:29 +00002563/*---------------------------------------------------------------*/
sewardj0b2d3fe2010-08-06 07:59:38 +00002564/*--- Helpers for SSE4.2 PCMP{E,I}STR{I,M} ---*/
2565/*---------------------------------------------------------------*/
2566
sewardjacfbd7d2010-08-17 22:52:08 +00002567static UInt zmask_from_V128 ( V128* arg )
2568{
2569 UInt i, res = 0;
2570 for (i = 0; i < 16; i++) {
2571 res |= ((arg->w8[i] == 0) ? 1 : 0) << i;
2572 }
2573 return res;
2574}
2575
2576/* Helps with PCMP{I,E}STR{I,M}.
2577
2578 CALLED FROM GENERATED CODE: DIRTY HELPER(s). (But not really,
sewardj0b2d3fe2010-08-06 07:59:38 +00002579 actually it could be a clean helper, but for the fact that we can't
sewardjacfbd7d2010-08-17 22:52:08 +00002580 pass by value 2 x V128 to a clean helper, nor have one returned.)
2581 Reads guest state, writes to guest state for the xSTRM cases, no
2582 accesses of memory, is a pure function.
2583
2584 opc_and_imm contains (4th byte of opcode << 8) | the-imm8-byte so
2585 the callee knows which I/E and I/M variant it is dealing with and
2586 what the specific operation is. 4th byte of opcode is in the range
2587 0x60 to 0x63:
2588 istri 66 0F 3A 63
2589 istrm 66 0F 3A 62
2590 estri 66 0F 3A 61
2591 estrm 66 0F 3A 60
2592
2593 gstOffL and gstOffR are the guest state offsets for the two XMM
2594 register inputs. We never have to deal with the memory case since
2595 that is handled by pre-loading the relevant value into the fake
2596 XMM16 register.
2597
2598 For ESTRx variants, edxIN and eaxIN hold the values of those two
2599 registers.
2600
2601 In all cases, the bottom 16 bits of the result contain the new
2602 OSZACP %rflags values. For xSTRI variants, bits[31:16] of the
2603 result hold the new %ecx value. For xSTRM variants, the helper
2604 writes the result directly to the guest XMM0.
2605
2606 Declarable side effects: in all cases, reads guest state at
2607 [gstOffL, +16) and [gstOffR, +16). For xSTRM variants, also writes
2608 guest_XMM0.
2609
2610 Is expected to be called with opc_and_imm combinations which have
2611 actually been validated, and will assert if otherwise. The front
2612 end should ensure we're only called with verified values.
sewardj0b2d3fe2010-08-06 07:59:38 +00002613*/
sewardjacfbd7d2010-08-17 22:52:08 +00002614ULong amd64g_dirtyhelper_PCMPxSTRx (
2615 VexGuestAMD64State* gst,
2616 HWord opc4_and_imm,
2617 HWord gstOffL, HWord gstOffR,
2618 HWord edxIN, HWord eaxIN
2619 )
sewardj0b2d3fe2010-08-06 07:59:38 +00002620{
sewardjacfbd7d2010-08-17 22:52:08 +00002621 HWord opc4 = (opc4_and_imm >> 8) & 0xFF;
2622 HWord imm8 = opc4_and_imm & 0xFF;
2623 HWord isISTRx = opc4 & 2;
2624 HWord isxSTRM = (opc4 & 1) ^ 1;
2625 vassert((opc4 & 0xFC) == 0x60); /* 0x60 .. 0x63 */
2626 vassert((imm8 & 1) == 0); /* we support byte-size cases only */
sewardj0b2d3fe2010-08-06 07:59:38 +00002627
sewardjacfbd7d2010-08-17 22:52:08 +00002628 // where the args are
2629 V128* argL = (V128*)( ((UChar*)gst) + gstOffL );
2630 V128* argR = (V128*)( ((UChar*)gst) + gstOffR );
sewardj0b2d3fe2010-08-06 07:59:38 +00002631
sewardjacfbd7d2010-08-17 22:52:08 +00002632 /* Create the arg validity masks, either from the vectors
2633 themselves or from the supplied edx/eax values. */
2634 // FIXME: this is only right for the 8-bit data cases.
2635 // At least that is asserted above.
2636 UInt zmaskL, zmaskR;
2637 if (isISTRx) {
2638 zmaskL = zmask_from_V128(argL);
2639 zmaskR = zmask_from_V128(argR);
2640 } else {
2641 Int tmp;
2642 tmp = edxIN & 0xFFFFFFFF;
2643 if (tmp < -16) tmp = -16;
2644 if (tmp > 16) tmp = 16;
2645 if (tmp < 0) tmp = -tmp;
2646 vassert(tmp >= 0 && tmp <= 16);
2647 zmaskL = (1 << tmp) & 0xFFFF;
2648 tmp = eaxIN & 0xFFFFFFFF;
2649 if (tmp < -16) tmp = -16;
2650 if (tmp > 16) tmp = 16;
2651 if (tmp < 0) tmp = -tmp;
2652 vassert(tmp >= 0 && tmp <= 16);
2653 zmaskR = (1 << tmp) & 0xFFFF;
2654 }
sewardj0b2d3fe2010-08-06 07:59:38 +00002655
sewardjacfbd7d2010-08-17 22:52:08 +00002656 // temp spot for the resulting flags and vector.
2657 V128 resV;
2658 UInt resOSZACP;
2659
2660 // do the meyaath
2661 Bool ok = compute_PCMPxSTRx (
2662 &resV, &resOSZACP, argL, argR,
2663 zmaskL, zmaskR, imm8, (Bool)isxSTRM
2664 );
2665
2666 // front end shouldn't pass us any imm8 variants we can't
2667 // handle. Hence:
2668 vassert(ok);
2669
2670 // So, finally we need to get the results back to the caller.
2671 // In all cases, the new OSZACP value is the lowest 16 of
2672 // the return value.
2673 if (isxSTRM) {
2674 /* gst->guest_XMM0 = resV; */ // gcc don't like that
2675 gst->guest_XMM0[0] = resV.w32[0];
2676 gst->guest_XMM0[1] = resV.w32[1];
2677 gst->guest_XMM0[2] = resV.w32[2];
2678 gst->guest_XMM0[3] = resV.w32[3];
2679 return resOSZACP & 0x8D5;
2680 } else {
2681 UInt newECX = resV.w32[0] & 0xFFFF;
2682 return (newECX << 16) | (resOSZACP & 0x8D5);
2683 }
sewardj0b2d3fe2010-08-06 07:59:38 +00002684}
2685
2686
2687/*---------------------------------------------------------------*/
sewardjf8c37f72005-02-07 18:55:29 +00002688/*--- Helpers for dealing with, and describing, ---*/
2689/*--- guest state as a whole. ---*/
2690/*---------------------------------------------------------------*/
2691
2692/* Initialise the entire amd64 guest state. */
2693/* VISIBLE TO LIBVEX CLIENT */
2694void LibVEX_GuestAMD64_initialise ( /*OUT*/VexGuestAMD64State* vex_state )
2695{
sewardjf8c37f72005-02-07 18:55:29 +00002696 vex_state->guest_RAX = 0;
2697 vex_state->guest_RCX = 0;
2698 vex_state->guest_RDX = 0;
2699 vex_state->guest_RBX = 0;
2700 vex_state->guest_RSP = 0;
2701 vex_state->guest_RBP = 0;
2702 vex_state->guest_RSI = 0;
2703 vex_state->guest_RDI = 0;
2704 vex_state->guest_R8 = 0;
2705 vex_state->guest_R9 = 0;
2706 vex_state->guest_R10 = 0;
2707 vex_state->guest_R11 = 0;
2708 vex_state->guest_R12 = 0;
2709 vex_state->guest_R13 = 0;
2710 vex_state->guest_R14 = 0;
2711 vex_state->guest_R15 = 0;
2712
2713 vex_state->guest_CC_OP = AMD64G_CC_OP_COPY;
2714 vex_state->guest_CC_DEP1 = 0;
2715 vex_state->guest_CC_DEP2 = 0;
2716 vex_state->guest_CC_NDEP = 0;
2717
sewardjd0a12df2005-02-10 02:07:43 +00002718 vex_state->guest_DFLAG = 1; /* forwards */
sewardj85520e42005-02-19 15:22:38 +00002719 vex_state->guest_IDFLAG = 0;
sewardjf8c37f72005-02-07 18:55:29 +00002720
sewardjcb6091d2005-02-21 08:23:39 +00002721 /* HACK: represent the offset associated with %fs==0. This
2722 assumes that %fs is only ever zero. */
sewardja6b93d12005-02-17 09:28:28 +00002723 vex_state->guest_FS_ZERO = 0;
2724
sewardjf8c37f72005-02-07 18:55:29 +00002725 vex_state->guest_RIP = 0;
2726
sewardj8d965312005-02-25 02:48:47 +00002727 /* Initialise the simulated FPU */
2728 amd64g_dirtyhelper_FINIT( vex_state );
2729
sewardjcb6091d2005-02-21 08:23:39 +00002730 /* Initialise the SSE state. */
2731# define SSEZERO(_xmm) _xmm[0]=_xmm[1]=_xmm[2]=_xmm[3] = 0;
2732
2733 vex_state->guest_SSEROUND = (ULong)Irrm_NEAREST;
2734 SSEZERO(vex_state->guest_XMM0);
2735 SSEZERO(vex_state->guest_XMM1);
2736 SSEZERO(vex_state->guest_XMM2);
2737 SSEZERO(vex_state->guest_XMM3);
2738 SSEZERO(vex_state->guest_XMM4);
2739 SSEZERO(vex_state->guest_XMM5);
2740 SSEZERO(vex_state->guest_XMM6);
2741 SSEZERO(vex_state->guest_XMM7);
2742 SSEZERO(vex_state->guest_XMM8);
2743 SSEZERO(vex_state->guest_XMM9);
2744 SSEZERO(vex_state->guest_XMM10);
2745 SSEZERO(vex_state->guest_XMM11);
2746 SSEZERO(vex_state->guest_XMM12);
2747 SSEZERO(vex_state->guest_XMM13);
2748 SSEZERO(vex_state->guest_XMM14);
2749 SSEZERO(vex_state->guest_XMM15);
sewardj0b2d3fe2010-08-06 07:59:38 +00002750 SSEZERO(vex_state->guest_XMM16);
sewardjcb6091d2005-02-21 08:23:39 +00002751
2752# undef SSEZERO
sewardjf8c37f72005-02-07 18:55:29 +00002753
2754 vex_state->guest_EMWARN = EmWarn_NONE;
sewardj1f126c52005-03-16 13:57:58 +00002755
2756 /* These should not ever be either read or written, but we
2757 initialise them anyway. */
2758 vex_state->guest_TISTART = 0;
2759 vex_state->guest_TILEN = 0;
sewardjce02aa72006-01-12 12:27:58 +00002760
sewardjd660d412008-12-03 21:29:59 +00002761 vex_state->guest_NRADDR = 0;
2762 vex_state->guest_SC_CLASS = 0;
2763 vex_state->guest_GS_0x60 = 0;
2764
sewardje86310f2009-03-19 22:21:40 +00002765 vex_state->guest_IP_AT_SYSCALL = 0;
sewardj90472eb2009-03-19 23:59:01 +00002766 /* vex_state->padding = 0; */
sewardjf8c37f72005-02-07 18:55:29 +00002767}
2768
2769
sewardj2f959cc2005-01-26 01:19:35 +00002770/* Figure out if any part of the guest state contained in minoff
2771 .. maxoff requires precise memory exceptions. If in doubt return
2772 True (but this is generates significantly slower code).
2773
sewardj4cca75c2005-03-16 11:52:25 +00002774 By default we enforce precise exns for guest %RSP, %RBP and %RIP
2775 only. These are the minimum needed to extract correct stack
2776 backtraces from amd64 code.
sewardj2f959cc2005-01-26 01:19:35 +00002777*/
sewardj44d494d2005-01-20 20:26:33 +00002778Bool guest_amd64_state_requires_precise_mem_exns ( Int minoff,
2779 Int maxoff)
2780{
sewardj4cca75c2005-03-16 11:52:25 +00002781 Int rbp_min = offsetof(VexGuestAMD64State, guest_RBP);
2782 Int rbp_max = rbp_min + 8 - 1;
sewardj2f959cc2005-01-26 01:19:35 +00002783 Int rsp_min = offsetof(VexGuestAMD64State, guest_RSP);
2784 Int rsp_max = rsp_min + 8 - 1;
2785 Int rip_min = offsetof(VexGuestAMD64State, guest_RIP);
2786 Int rip_max = rip_min + 8 - 1;
2787
sewardj4cca75c2005-03-16 11:52:25 +00002788 if (maxoff < rbp_min || minoff > rbp_max) {
2789 /* no overlap with rbp */
2790 } else {
2791 return True;
2792 }
2793
sewardj2f959cc2005-01-26 01:19:35 +00002794 if (maxoff < rsp_min || minoff > rsp_max) {
2795 /* no overlap with rsp */
2796 } else {
2797 return True;
2798 }
2799
2800 if (maxoff < rip_min || minoff > rip_max) {
2801 /* no overlap with eip */
2802 } else {
2803 return True;
2804 }
2805
2806 return False;
sewardj44d494d2005-01-20 20:26:33 +00002807}
sewardj2f959cc2005-01-26 01:19:35 +00002808
2809
sewardjc85e91c2005-02-07 14:59:28 +00002810#define ALWAYSDEFD(field) \
2811 { offsetof(VexGuestAMD64State, field), \
2812 (sizeof ((VexGuestAMD64State*)0)->field) }
sewardj44d494d2005-01-20 20:26:33 +00002813
2814VexGuestLayout
sewardjc85e91c2005-02-07 14:59:28 +00002815 amd64guest_layout
sewardj44d494d2005-01-20 20:26:33 +00002816 = {
2817 /* Total size of the guest state, in bytes. */
sewardjc85e91c2005-02-07 14:59:28 +00002818 .total_sizeB = sizeof(VexGuestAMD64State),
sewardj44d494d2005-01-20 20:26:33 +00002819
2820 /* Describe the stack pointer. */
sewardjc85e91c2005-02-07 14:59:28 +00002821 .offset_SP = offsetof(VexGuestAMD64State,guest_RSP),
2822 .sizeof_SP = 8,
sewardj44d494d2005-01-20 20:26:33 +00002823
sewardja2033302008-08-19 11:15:10 +00002824 /* Describe the frame pointer. */
2825 .offset_FP = offsetof(VexGuestAMD64State,guest_RBP),
2826 .sizeof_FP = 8,
2827
sewardj44d494d2005-01-20 20:26:33 +00002828 /* Describe the instruction pointer. */
sewardjc85e91c2005-02-07 14:59:28 +00002829 .offset_IP = offsetof(VexGuestAMD64State,guest_RIP),
2830 .sizeof_IP = 8,
sewardj44d494d2005-01-20 20:26:33 +00002831
2832 /* Describe any sections to be regarded by Memcheck as
2833 'always-defined'. */
sewardje86310f2009-03-19 22:21:40 +00002834 .n_alwaysDefd = 16,
sewardj44d494d2005-01-20 20:26:33 +00002835
2836 /* flags thunk: OP and NDEP are always defd, whereas DEP1
2837 and DEP2 have to be tracked. See detailed comment in
2838 gdefs.h on meaning of thunk fields. */
2839 .alwaysDefd
2840 = { /* 0 */ ALWAYSDEFD(guest_CC_OP),
2841 /* 1 */ ALWAYSDEFD(guest_CC_NDEP),
sewardj85520e42005-02-19 15:22:38 +00002842 /* 2 */ ALWAYSDEFD(guest_DFLAG),
2843 /* 3 */ ALWAYSDEFD(guest_IDFLAG),
2844 /* 4 */ ALWAYSDEFD(guest_RIP),
2845 /* 5 */ ALWAYSDEFD(guest_FS_ZERO),
sewardj8d965312005-02-25 02:48:47 +00002846 /* 6 */ ALWAYSDEFD(guest_FTOP),
2847 /* 7 */ ALWAYSDEFD(guest_FPTAG),
2848 /* 8 */ ALWAYSDEFD(guest_FPROUND),
2849 /* 9 */ ALWAYSDEFD(guest_FC3210),
sewardj85520e42005-02-19 15:22:38 +00002850 // /* */ ALWAYSDEFD(guest_CS),
2851 // /* */ ALWAYSDEFD(guest_DS),
2852 // /* */ ALWAYSDEFD(guest_ES),
2853 // /* */ ALWAYSDEFD(guest_FS),
2854 // /* */ ALWAYSDEFD(guest_GS),
2855 // /* */ ALWAYSDEFD(guest_SS),
2856 // /* */ ALWAYSDEFD(guest_LDT),
2857 // /* */ ALWAYSDEFD(guest_GDT),
sewardjbcbb9de2005-03-27 02:22:32 +00002858 /* 10 */ ALWAYSDEFD(guest_EMWARN),
sewardj16a403b2005-07-07 12:26:36 +00002859 /* 11 */ ALWAYSDEFD(guest_SSEROUND),
2860 /* 12 */ ALWAYSDEFD(guest_TISTART),
sewardje86310f2009-03-19 22:21:40 +00002861 /* 13 */ ALWAYSDEFD(guest_TILEN),
2862 /* 14 */ ALWAYSDEFD(guest_SC_CLASS),
2863 /* 15 */ ALWAYSDEFD(guest_IP_AT_SYSCALL)
sewardj44d494d2005-01-20 20:26:33 +00002864 }
2865 };
njn9c6acb02004-11-30 15:56:47 +00002866
2867
njn9c6acb02004-11-30 15:56:47 +00002868/*---------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +00002869/*--- end guest_amd64_helpers.c ---*/
njn9c6acb02004-11-30 15:56:47 +00002870/*---------------------------------------------------------------*/