VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IEMAllThrdPython.py@ 104116

Last change on this file since 104116 was 104099, checked in by vboxsync, 11 months ago

VMM/IEM: Emit native code for shl Ev,CL. bugref:10376

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 186.9 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllThrdPython.py 104099 2024-03-28 01:42:59Z vboxsync $
4# pylint: disable=invalid-name
5
6"""
7Annotates and generates threaded functions from IEMAllInst*.cpp.h.
8"""
9
10from __future__ import print_function;
11
12__copyright__ = \
13"""
14Copyright (C) 2023 Oracle and/or its affiliates.
15
16This file is part of VirtualBox base platform packages, as
17available from https://www.virtualbox.org.
18
19This program is free software; you can redistribute it and/or
20modify it under the terms of the GNU General Public License
21as published by the Free Software Foundation, in version 3 of the
22License.
23
24This program is distributed in the hope that it will be useful, but
25WITHOUT ANY WARRANTY; without even the implied warranty of
26MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27General Public License for more details.
28
29You should have received a copy of the GNU General Public License
30along with this program; if not, see <https://www.gnu.org/licenses>.
31
32SPDX-License-Identifier: GPL-3.0-only
33"""
34__version__ = "$Revision: 104099 $"
35
36# Standard python imports.
37import copy;
38import datetime;
39import os;
40import re;
41import sys;
42import argparse;
43from typing import Dict, List;
44
45import IEMAllInstPython as iai;
46import IEMAllN8vePython as ian;
47
48
49# Python 3 hacks:
50if sys.version_info[0] >= 3:
51 long = int; # pylint: disable=redefined-builtin,invalid-name
52
53## Number of generic parameters for the thread functions.
54g_kcThreadedParams = 3;
55
56g_kdTypeInfo = {
57 # type name: (cBits, fSigned, C-type )
58 'int8_t': ( 8, True, 'int8_t', ),
59 'int16_t': ( 16, True, 'int16_t', ),
60 'int32_t': ( 32, True, 'int32_t', ),
61 'int64_t': ( 64, True, 'int64_t', ),
62 'uint4_t': ( 4, False, 'uint8_t', ),
63 'uint8_t': ( 8, False, 'uint8_t', ),
64 'uint16_t': ( 16, False, 'uint16_t', ),
65 'uint32_t': ( 32, False, 'uint32_t', ),
66 'uint64_t': ( 64, False, 'uint64_t', ),
67 'uintptr_t': ( 64, False, 'uintptr_t',), # ASSUMES 64-bit host pointer size.
68 'bool': ( 1, False, 'bool', ),
69 'IEMMODE': ( 2, False, 'IEMMODE', ),
70};
71
72# Only for getTypeBitCount/variables.
73g_kdTypeInfo2 = {
74 'RTFLOAT32U': ( 32, False, 'RTFLOAT32U', ),
75 'RTFLOAT64U': ( 64, False, 'RTFLOAT64U', ),
76 'RTUINT64U': ( 64, False, 'RTUINT64U', ),
77 'RTGCPTR': ( 64, False, 'RTGCPTR', ),
78 'RTPBCD80U': ( 80, False, 'RTPBCD80U', ),
79 'RTFLOAT80U': ( 80, False, 'RTFLOAT80U', ),
80 'IEMFPURESULT': (80+16, False, 'IEMFPURESULT', ),
81 'IEMFPURESULTTWO': (80+16+80,False, 'IEMFPURESULTTWO', ),
82 'RTUINT128U': ( 128, False, 'RTUINT128U', ),
83 'X86XMMREG': ( 128, False, 'X86XMMREG', ),
84 'IEMSSERESULT': ( 128+32, False, 'IEMSSERESULT', ),
85 'IEMMEDIAF2XMMSRC': ( 256, False, 'IEMMEDIAF2XMMSRC',),
86 'RTUINT256U': ( 256, False, 'RTUINT256U', ),
87 'IEMPCMPISTRXSRC': ( 256, False, 'IEMPCMPISTRXSRC', ),
88 'IEMPCMPESTRXSRC': ( 384, False, 'IEMPCMPESTRXSRC', ),
89}; #| g_kdTypeInfo; - requires 3.9
90g_kdTypeInfo2.update(g_kdTypeInfo);
91
92def getTypeBitCount(sType):
93 """
94 Translate a type to size in bits
95 """
96 if sType in g_kdTypeInfo2:
97 return g_kdTypeInfo2[sType][0];
98 if '*' in sType or sType[0] == 'P':
99 return 64;
100 #raise Exception('Unknown type: %s' % (sType,));
101 print('error: Unknown type: %s' % (sType,));
102 return 64;
103
104g_kdIemFieldToType = {
105 # Illegal ones:
106 'offInstrNextByte': ( None, ),
107 'cbInstrBuf': ( None, ),
108 'pbInstrBuf': ( None, ),
109 'uInstrBufPc': ( None, ),
110 'cbInstrBufTotal': ( None, ),
111 'offCurInstrStart': ( None, ),
112 'cbOpcode': ( None, ),
113 'offOpcode': ( None, ),
114 'offModRm': ( None, ),
115 # Okay ones.
116 'fPrefixes': ( 'uint32_t', ),
117 'uRexReg': ( 'uint8_t', ),
118 'uRexB': ( 'uint8_t', ),
119 'uRexIndex': ( 'uint8_t', ),
120 'iEffSeg': ( 'uint8_t', ),
121 'enmEffOpSize': ( 'IEMMODE', ),
122 'enmDefAddrMode': ( 'IEMMODE', ),
123 'enmEffAddrMode': ( 'IEMMODE', ),
124 'enmDefOpSize': ( 'IEMMODE', ),
125 'idxPrefix': ( 'uint8_t', ),
126 'uVex3rdReg': ( 'uint8_t', ),
127 'uVexLength': ( 'uint8_t', ),
128 'fEvexStuff': ( 'uint8_t', ),
129 'uFpuOpcode': ( 'uint16_t', ),
130};
131
132## @name McStmtCond.oIfBranchAnnotation/McStmtCond.oElseBranchAnnotation values
133## @{
134g_ksFinishAnnotation_Advance = 'Advance';
135g_ksFinishAnnotation_RelJmp = 'RelJmp';
136g_ksFinishAnnotation_SetJmp = 'SetJmp';
137g_ksFinishAnnotation_DeferToCImpl = 'DeferToCImpl';
138## @}
139
140
141class ThreadedParamRef(object):
142 """
143 A parameter reference for a threaded function.
144 """
145
146 def __init__(self, sOrgRef, sType, oStmt, iParam = None, offParam = 0, sStdRef = None):
147 ## The name / reference in the original code.
148 self.sOrgRef = sOrgRef;
149 ## Normalized name to deal with spaces in macro invocations and such.
150 self.sStdRef = sStdRef if sStdRef else ''.join(sOrgRef.split());
151 ## Indicates that sOrgRef may not match the parameter.
152 self.fCustomRef = sStdRef is not None;
153 ## The type (typically derived).
154 self.sType = sType;
155 ## The statement making the reference.
156 self.oStmt = oStmt;
157 ## The parameter containing the references. None if implicit.
158 self.iParam = iParam;
159 ## The offset in the parameter of the reference.
160 self.offParam = offParam;
161
162 ## The variable name in the threaded function.
163 self.sNewName = 'x';
164 ## The this is packed into.
165 self.iNewParam = 99;
166 ## The bit offset in iNewParam.
167 self.offNewParam = 1024
168
169
170class ThreadedFunctionVariation(object):
171 """ Threaded function variation. """
172
173 ## @name Variations.
174 ## These variations will match translation block selection/distinctions as well.
175 ## @{
176 # pylint: disable=line-too-long
177 ksVariation_Default = ''; ##< No variations - only used by IEM_MC_DEFER_TO_CIMPL_X_RET.
178 ksVariation_16 = '_16'; ##< 16-bit mode code (386+).
179 ksVariation_16f = '_16f'; ##< 16-bit mode code (386+), check+clear eflags.
180 ksVariation_16_Jmp = '_16_Jmp'; ##< 16-bit mode code (386+), conditional jump taken.
181 ksVariation_16f_Jmp = '_16f_Jmp'; ##< 16-bit mode code (386+), check+clear eflags, conditional jump taken.
182 ksVariation_16_NoJmp = '_16_NoJmp'; ##< 16-bit mode code (386+), conditional jump not taken.
183 ksVariation_16f_NoJmp = '_16f_NoJmp'; ##< 16-bit mode code (386+), check+clear eflags, conditional jump not taken.
184 ksVariation_16_Addr32 = '_16_Addr32'; ##< 16-bit mode code (386+), address size prefixed to 32-bit addressing.
185 ksVariation_16f_Addr32 = '_16f_Addr32'; ##< 16-bit mode code (386+), address size prefixed to 32-bit addressing, eflags.
186 ksVariation_16_Pre386 = '_16_Pre386'; ##< 16-bit mode code, pre-386 CPU target.
187 ksVariation_16f_Pre386 = '_16f_Pre386'; ##< 16-bit mode code, pre-386 CPU target, check+clear eflags.
188 ksVariation_16_Pre386_Jmp = '_16_Pre386_Jmp'; ##< 16-bit mode code, pre-386 CPU target, conditional jump taken.
189 ksVariation_16f_Pre386_Jmp = '_16f_Pre386_Jmp'; ##< 16-bit mode code, pre-386 CPU target, check+clear eflags, conditional jump taken.
190 ksVariation_16_Pre386_NoJmp = '_16_Pre386_NoJmp'; ##< 16-bit mode code, pre-386 CPU target, conditional jump not taken.
191 ksVariation_16f_Pre386_NoJmp = '_16f_Pre386_NoJmp'; ##< 16-bit mode code, pre-386 CPU target, check+clear eflags, conditional jump not taken.
192 ksVariation_32 = '_32'; ##< 32-bit mode code (386+).
193 ksVariation_32f = '_32f'; ##< 32-bit mode code (386+), check+clear eflags.
194 ksVariation_32_Jmp = '_32_Jmp'; ##< 32-bit mode code (386+), conditional jump taken.
195 ksVariation_32f_Jmp = '_32f_Jmp'; ##< 32-bit mode code (386+), check+clear eflags, conditional jump taken.
196 ksVariation_32_NoJmp = '_32_NoJmp'; ##< 32-bit mode code (386+), conditional jump not taken.
197 ksVariation_32f_NoJmp = '_32f_NoJmp'; ##< 32-bit mode code (386+), check+clear eflags, conditional jump not taken.
198 ksVariation_32_Flat = '_32_Flat'; ##< 32-bit mode code (386+) with CS, DS, E,S and SS flat and 4GB wide.
199 ksVariation_32f_Flat = '_32f_Flat'; ##< 32-bit mode code (386+) with CS, DS, E,S and SS flat and 4GB wide, eflags.
200 ksVariation_32_Addr16 = '_32_Addr16'; ##< 32-bit mode code (386+), address size prefixed to 16-bit addressing.
201 ksVariation_32f_Addr16 = '_32f_Addr16'; ##< 32-bit mode code (386+), address size prefixed to 16-bit addressing, eflags.
202 ksVariation_64 = '_64'; ##< 64-bit mode code.
203 ksVariation_64f = '_64f'; ##< 64-bit mode code, check+clear eflags.
204 ksVariation_64_Jmp = '_64_Jmp'; ##< 64-bit mode code, conditional jump taken.
205 ksVariation_64f_Jmp = '_64f_Jmp'; ##< 64-bit mode code, check+clear eflags, conditional jump taken.
206 ksVariation_64_NoJmp = '_64_NoJmp'; ##< 64-bit mode code, conditional jump not taken.
207 ksVariation_64f_NoJmp = '_64f_NoJmp'; ##< 64-bit mode code, check+clear eflags, conditional jump not taken.
208 ksVariation_64_FsGs = '_64_FsGs'; ##< 64-bit mode code, with memory accesses via FS or GS.
209 ksVariation_64f_FsGs = '_64f_FsGs'; ##< 64-bit mode code, with memory accesses via FS or GS, check+clear eflags.
210 ksVariation_64_Addr32 = '_64_Addr32'; ##< 64-bit mode code, address size prefixed to 32-bit addressing.
211 ksVariation_64f_Addr32 = '_64f_Addr32'; ##< 64-bit mode code, address size prefixed to 32-bit addressing, c+c eflags.
212 # pylint: enable=line-too-long
213 kasVariations = (
214 ksVariation_Default,
215 ksVariation_16,
216 ksVariation_16f,
217 ksVariation_16_Jmp,
218 ksVariation_16f_Jmp,
219 ksVariation_16_NoJmp,
220 ksVariation_16f_NoJmp,
221 ksVariation_16_Addr32,
222 ksVariation_16f_Addr32,
223 ksVariation_16_Pre386,
224 ksVariation_16f_Pre386,
225 ksVariation_16_Pre386_Jmp,
226 ksVariation_16f_Pre386_Jmp,
227 ksVariation_16_Pre386_NoJmp,
228 ksVariation_16f_Pre386_NoJmp,
229 ksVariation_32,
230 ksVariation_32f,
231 ksVariation_32_Jmp,
232 ksVariation_32f_Jmp,
233 ksVariation_32_NoJmp,
234 ksVariation_32f_NoJmp,
235 ksVariation_32_Flat,
236 ksVariation_32f_Flat,
237 ksVariation_32_Addr16,
238 ksVariation_32f_Addr16,
239 ksVariation_64,
240 ksVariation_64f,
241 ksVariation_64_Jmp,
242 ksVariation_64f_Jmp,
243 ksVariation_64_NoJmp,
244 ksVariation_64f_NoJmp,
245 ksVariation_64_FsGs,
246 ksVariation_64f_FsGs,
247 ksVariation_64_Addr32,
248 ksVariation_64f_Addr32,
249 );
250 kasVariationsWithoutAddress = (
251 ksVariation_16,
252 ksVariation_16f,
253 ksVariation_16_Pre386,
254 ksVariation_16f_Pre386,
255 ksVariation_32,
256 ksVariation_32f,
257 ksVariation_64,
258 ksVariation_64f,
259 );
260 kasVariationsWithoutAddressNot286 = (
261 ksVariation_16,
262 ksVariation_16f,
263 ksVariation_32,
264 ksVariation_32f,
265 ksVariation_64,
266 ksVariation_64f,
267 );
268 kasVariationsWithoutAddressNot286Not64 = (
269 ksVariation_16,
270 ksVariation_16f,
271 ksVariation_32,
272 ksVariation_32f,
273 );
274 kasVariationsWithoutAddressNot64 = (
275 ksVariation_16,
276 ksVariation_16f,
277 ksVariation_16_Pre386,
278 ksVariation_16f_Pre386,
279 ksVariation_32,
280 ksVariation_32f,
281 );
282 kasVariationsWithoutAddressOnly64 = (
283 ksVariation_64,
284 ksVariation_64f,
285 );
286 kasVariationsWithAddress = (
287 ksVariation_16,
288 ksVariation_16f,
289 ksVariation_16_Addr32,
290 ksVariation_16f_Addr32,
291 ksVariation_16_Pre386,
292 ksVariation_16f_Pre386,
293 ksVariation_32,
294 ksVariation_32f,
295 ksVariation_32_Flat,
296 ksVariation_32f_Flat,
297 ksVariation_32_Addr16,
298 ksVariation_32f_Addr16,
299 ksVariation_64,
300 ksVariation_64f,
301 ksVariation_64_FsGs,
302 ksVariation_64f_FsGs,
303 ksVariation_64_Addr32,
304 ksVariation_64f_Addr32,
305 );
306 kasVariationsWithAddressNot286 = (
307 ksVariation_16,
308 ksVariation_16f,
309 ksVariation_16_Addr32,
310 ksVariation_16f_Addr32,
311 ksVariation_32,
312 ksVariation_32f,
313 ksVariation_32_Flat,
314 ksVariation_32f_Flat,
315 ksVariation_32_Addr16,
316 ksVariation_32f_Addr16,
317 ksVariation_64,
318 ksVariation_64f,
319 ksVariation_64_FsGs,
320 ksVariation_64f_FsGs,
321 ksVariation_64_Addr32,
322 ksVariation_64f_Addr32,
323 );
324 kasVariationsWithAddressNot286Not64 = (
325 ksVariation_16,
326 ksVariation_16f,
327 ksVariation_16_Addr32,
328 ksVariation_16f_Addr32,
329 ksVariation_32,
330 ksVariation_32f,
331 ksVariation_32_Flat,
332 ksVariation_32f_Flat,
333 ksVariation_32_Addr16,
334 ksVariation_32f_Addr16,
335 );
336 kasVariationsWithAddressNot64 = (
337 ksVariation_16,
338 ksVariation_16f,
339 ksVariation_16_Addr32,
340 ksVariation_16f_Addr32,
341 ksVariation_16_Pre386,
342 ksVariation_16f_Pre386,
343 ksVariation_32,
344 ksVariation_32f,
345 ksVariation_32_Flat,
346 ksVariation_32f_Flat,
347 ksVariation_32_Addr16,
348 ksVariation_32f_Addr16,
349 );
350 kasVariationsWithAddressOnly64 = (
351 ksVariation_64,
352 ksVariation_64f,
353 ksVariation_64_FsGs,
354 ksVariation_64f_FsGs,
355 ksVariation_64_Addr32,
356 ksVariation_64f_Addr32,
357 );
358 kasVariationsOnlyPre386 = (
359 ksVariation_16_Pre386,
360 ksVariation_16f_Pre386,
361 );
362 kasVariationsEmitOrder = (
363 ksVariation_Default,
364 ksVariation_64,
365 ksVariation_64f,
366 ksVariation_64_Jmp,
367 ksVariation_64f_Jmp,
368 ksVariation_64_NoJmp,
369 ksVariation_64f_NoJmp,
370 ksVariation_64_FsGs,
371 ksVariation_64f_FsGs,
372 ksVariation_32_Flat,
373 ksVariation_32f_Flat,
374 ksVariation_32,
375 ksVariation_32f,
376 ksVariation_32_Jmp,
377 ksVariation_32f_Jmp,
378 ksVariation_32_NoJmp,
379 ksVariation_32f_NoJmp,
380 ksVariation_16,
381 ksVariation_16f,
382 ksVariation_16_Jmp,
383 ksVariation_16f_Jmp,
384 ksVariation_16_NoJmp,
385 ksVariation_16f_NoJmp,
386 ksVariation_16_Addr32,
387 ksVariation_16f_Addr32,
388 ksVariation_16_Pre386,
389 ksVariation_16f_Pre386,
390 ksVariation_16_Pre386_Jmp,
391 ksVariation_16f_Pre386_Jmp,
392 ksVariation_16_Pre386_NoJmp,
393 ksVariation_16f_Pre386_NoJmp,
394 ksVariation_32_Addr16,
395 ksVariation_32f_Addr16,
396 ksVariation_64_Addr32,
397 ksVariation_64f_Addr32,
398 );
399 kdVariationNames = {
400 ksVariation_Default: 'defer-to-cimpl',
401 ksVariation_16: '16-bit',
402 ksVariation_16f: '16-bit w/ eflag checking and clearing',
403 ksVariation_16_Jmp: '16-bit w/ conditional jump taken',
404 ksVariation_16f_Jmp: '16-bit w/ eflag checking and clearing and conditional jump taken',
405 ksVariation_16_NoJmp: '16-bit w/ conditional jump not taken',
406 ksVariation_16f_NoJmp: '16-bit w/ eflag checking and clearing and conditional jump not taken',
407 ksVariation_16_Addr32: '16-bit w/ address prefix (Addr32)',
408 ksVariation_16f_Addr32: '16-bit w/ address prefix (Addr32) and eflag checking and clearing',
409 ksVariation_16_Pre386: '16-bit on pre-386 CPU',
410 ksVariation_16f_Pre386: '16-bit on pre-386 CPU w/ eflag checking and clearing',
411 ksVariation_16_Pre386_Jmp: '16-bit on pre-386 CPU w/ conditional jump taken',
412 ksVariation_16f_Pre386_Jmp: '16-bit on pre-386 CPU w/ eflag checking and clearing and conditional jump taken',
413 ksVariation_16_Pre386_NoJmp: '16-bit on pre-386 CPU w/ conditional jump taken',
414 ksVariation_16f_Pre386_NoJmp: '16-bit on pre-386 CPU w/ eflag checking and clearing and conditional jump taken',
415 ksVariation_32: '32-bit',
416 ksVariation_32f: '32-bit w/ eflag checking and clearing',
417 ksVariation_32_Jmp: '32-bit w/ conditional jump taken',
418 ksVariation_32f_Jmp: '32-bit w/ eflag checking and clearing and conditional jump taken',
419 ksVariation_32_NoJmp: '32-bit w/ conditional jump not taken',
420 ksVariation_32f_NoJmp: '32-bit w/ eflag checking and clearing and conditional jump not taken',
421 ksVariation_32_Flat: '32-bit flat and wide open CS, SS, DS and ES',
422 ksVariation_32f_Flat: '32-bit flat and wide open CS, SS, DS and ES w/ eflag checking and clearing',
423 ksVariation_32_Addr16: '32-bit w/ address prefix (Addr16)',
424 ksVariation_32f_Addr16: '32-bit w/ address prefix (Addr16) and eflag checking and clearing',
425 ksVariation_64: '64-bit',
426 ksVariation_64f: '64-bit w/ eflag checking and clearing',
427 ksVariation_64_Jmp: '64-bit w/ conditional jump taken',
428 ksVariation_64f_Jmp: '64-bit w/ eflag checking and clearing and conditional jump taken',
429 ksVariation_64_NoJmp: '64-bit w/ conditional jump not taken',
430 ksVariation_64f_NoJmp: '64-bit w/ eflag checking and clearing and conditional jump not taken',
431 ksVariation_64_FsGs: '64-bit with memory accessed via FS or GS',
432 ksVariation_64f_FsGs: '64-bit with memory accessed via FS or GS and eflag checking and clearing',
433 ksVariation_64_Addr32: '64-bit w/ address prefix (Addr32)',
434 ksVariation_64f_Addr32: '64-bit w/ address prefix (Addr32) and eflag checking and clearing',
435 };
436 kdVariationsWithEflagsCheckingAndClearing = {
437 ksVariation_16f: True,
438 ksVariation_16f_Jmp: True,
439 ksVariation_16f_NoJmp: True,
440 ksVariation_16f_Addr32: True,
441 ksVariation_16f_Pre386: True,
442 ksVariation_16f_Pre386_Jmp: True,
443 ksVariation_16f_Pre386_NoJmp: True,
444 ksVariation_32f: True,
445 ksVariation_32f_Jmp: True,
446 ksVariation_32f_NoJmp: True,
447 ksVariation_32f_Flat: True,
448 ksVariation_32f_Addr16: True,
449 ksVariation_64f: True,
450 ksVariation_64f_Jmp: True,
451 ksVariation_64f_NoJmp: True,
452 ksVariation_64f_FsGs: True,
453 ksVariation_64f_Addr32: True,
454 };
455 kdVariationsOnly64NoFlags = {
456 ksVariation_64: True,
457 ksVariation_64_Jmp: True,
458 ksVariation_64_NoJmp: True,
459 ksVariation_64_FsGs: True,
460 ksVariation_64_Addr32: True,
461 };
462 kdVariationsOnly64WithFlags = {
463 ksVariation_64f: True,
464 ksVariation_64f_Jmp: True,
465 ksVariation_64f_NoJmp: True,
466 ksVariation_64f_FsGs: True,
467 ksVariation_64f_Addr32: True,
468 };
469 kdVariationsOnlyPre386NoFlags = {
470 ksVariation_16_Pre386: True,
471 ksVariation_16_Pre386_Jmp: True,
472 ksVariation_16_Pre386_NoJmp: True,
473 };
474 kdVariationsOnlyPre386WithFlags = {
475 ksVariation_16f_Pre386: True,
476 ksVariation_16f_Pre386_Jmp: True,
477 ksVariation_16f_Pre386_NoJmp: True,
478 };
479 kdVariationsWithFlatAddress = {
480 ksVariation_32_Flat: True,
481 ksVariation_32f_Flat: True,
482 ksVariation_64: True,
483 ksVariation_64f: True,
484 ksVariation_64_Addr32: True,
485 ksVariation_64f_Addr32: True,
486 };
487 kdVariationsWithFlatStackAddress = {
488 ksVariation_32_Flat: True,
489 ksVariation_32f_Flat: True,
490 ksVariation_64: True,
491 ksVariation_64f: True,
492 ksVariation_64_FsGs: True,
493 ksVariation_64f_FsGs: True,
494 ksVariation_64_Addr32: True,
495 ksVariation_64f_Addr32: True,
496 };
497 kdVariationsWithFlat64StackAddress = {
498 ksVariation_64: True,
499 ksVariation_64f: True,
500 ksVariation_64_FsGs: True,
501 ksVariation_64f_FsGs: True,
502 ksVariation_64_Addr32: True,
503 ksVariation_64f_Addr32: True,
504 };
505 kdVariationsWithFlatAddr16 = {
506 ksVariation_16: True,
507 ksVariation_16f: True,
508 ksVariation_16_Pre386: True,
509 ksVariation_16f_Pre386: True,
510 ksVariation_32_Addr16: True,
511 ksVariation_32f_Addr16: True,
512 };
513 kdVariationsWithFlatAddr32No64 = {
514 ksVariation_16_Addr32: True,
515 ksVariation_16f_Addr32: True,
516 ksVariation_32: True,
517 ksVariation_32f: True,
518 ksVariation_32_Flat: True,
519 ksVariation_32f_Flat: True,
520 };
521 kdVariationsWithAddressOnly64 = {
522 ksVariation_64: True,
523 ksVariation_64f: True,
524 ksVariation_64_FsGs: True,
525 ksVariation_64f_FsGs: True,
526 ksVariation_64_Addr32: True,
527 ksVariation_64f_Addr32: True,
528 };
529 kdVariationsWithConditional = {
530 ksVariation_16_Jmp: True,
531 ksVariation_16_NoJmp: True,
532 ksVariation_16_Pre386_Jmp: True,
533 ksVariation_16_Pre386_NoJmp: True,
534 ksVariation_32_Jmp: True,
535 ksVariation_32_NoJmp: True,
536 ksVariation_64_Jmp: True,
537 ksVariation_64_NoJmp: True,
538 ksVariation_16f_Jmp: True,
539 ksVariation_16f_NoJmp: True,
540 ksVariation_16f_Pre386_Jmp: True,
541 ksVariation_16f_Pre386_NoJmp: True,
542 ksVariation_32f_Jmp: True,
543 ksVariation_32f_NoJmp: True,
544 ksVariation_64f_Jmp: True,
545 ksVariation_64f_NoJmp: True,
546 };
547 kdVariationsWithConditionalNoJmp = {
548 ksVariation_16_NoJmp: True,
549 ksVariation_16_Pre386_NoJmp: True,
550 ksVariation_32_NoJmp: True,
551 ksVariation_64_NoJmp: True,
552 ksVariation_16f_NoJmp: True,
553 ksVariation_16f_Pre386_NoJmp: True,
554 ksVariation_32f_NoJmp: True,
555 ksVariation_64f_NoJmp: True,
556 };
557 kdVariationsOnlyPre386 = {
558 ksVariation_16_Pre386: True,
559 ksVariation_16f_Pre386: True,
560 ksVariation_16_Pre386_Jmp: True,
561 ksVariation_16f_Pre386_Jmp: True,
562 ksVariation_16_Pre386_NoJmp: True,
563 ksVariation_16f_Pre386_NoJmp: True,
564 };
565 ## @}
566
567 ## IEM_CIMPL_F_XXX flags that we know.
568 ## The value indicates whether it terminates the TB or not. The goal is to
569 ## improve the recompiler so all but END_TB will be False.
570 ##
571 ## @note iemThreadedRecompilerMcDeferToCImpl0 duplicates info found here.
572 kdCImplFlags = {
573 'IEM_CIMPL_F_MODE': False,
574 'IEM_CIMPL_F_BRANCH_DIRECT': False,
575 'IEM_CIMPL_F_BRANCH_INDIRECT': False,
576 'IEM_CIMPL_F_BRANCH_RELATIVE': False,
577 'IEM_CIMPL_F_BRANCH_FAR': True,
578 'IEM_CIMPL_F_BRANCH_CONDITIONAL': False,
579 # IEM_CIMPL_F_BRANCH_ANY should only be used for testing, so not included here.
580 'IEM_CIMPL_F_BRANCH_STACK': False,
581 'IEM_CIMPL_F_BRANCH_STACK_FAR': False,
582 'IEM_CIMPL_F_RFLAGS': False,
583 'IEM_CIMPL_F_INHIBIT_SHADOW': False,
584 'IEM_CIMPL_F_CHECK_IRQ_AFTER': False,
585 'IEM_CIMPL_F_CHECK_IRQ_BEFORE': False,
586 'IEM_CIMPL_F_CHECK_IRQ_BEFORE_AND_AFTER': False, # (ignore)
587 'IEM_CIMPL_F_STATUS_FLAGS': False,
588 'IEM_CIMPL_F_VMEXIT': False,
589 'IEM_CIMPL_F_FPU': False,
590 'IEM_CIMPL_F_REP': False,
591 'IEM_CIMPL_F_IO': False,
592 'IEM_CIMPL_F_END_TB': True,
593 'IEM_CIMPL_F_XCPT': True,
594 'IEM_CIMPL_F_CALLS_CIMPL': False,
595 'IEM_CIMPL_F_CALLS_AIMPL': False,
596 'IEM_CIMPL_F_CALLS_AIMPL_WITH_FXSTATE': False,
597 'IEM_CIMPL_F_CALLS_AIMPL_WITH_XSTATE': False,
598 };
599
600 def __init__(self, oThreadedFunction, sVariation = ksVariation_Default):
601 self.oParent = oThreadedFunction # type: ThreadedFunction
602 ##< ksVariation_Xxxx.
603 self.sVariation = sVariation
604
605 ## Threaded function parameter references.
606 self.aoParamRefs = [] # type: List[ThreadedParamRef]
607 ## Unique parameter references.
608 self.dParamRefs = {} # type: Dict[str, List[ThreadedParamRef]]
609 ## Minimum number of parameters to the threaded function.
610 self.cMinParams = 0;
611
612 ## List/tree of statements for the threaded function.
613 self.aoStmtsForThreadedFunction = [] # type: List[McStmt]
614
615 ## Function enum number, for verification. Set by generateThreadedFunctionsHeader.
616 self.iEnumValue = -1;
617
618 ## Native recompilation details for this variation.
619 self.oNativeRecomp = None;
620
621 def getIndexName(self):
622 sName = self.oParent.oMcBlock.sFunction;
623 if sName.startswith('iemOp_'):
624 sName = sName[len('iemOp_'):];
625 return 'kIemThreadedFunc_%s%s%s' % ( sName, self.oParent.sSubName, self.sVariation, );
626
627 def getThreadedFunctionName(self):
628 sName = self.oParent.oMcBlock.sFunction;
629 if sName.startswith('iemOp_'):
630 sName = sName[len('iemOp_'):];
631 return 'iemThreadedFunc_%s%s%s' % ( sName, self.oParent.sSubName, self.sVariation, );
632
633 def getNativeFunctionName(self):
634 return 'iemNativeRecompFunc_' + self.getThreadedFunctionName()[len('iemThreadedFunc_'):];
635
636 def getLivenessFunctionName(self):
637 return 'iemNativeLivenessFunc_' + self.getThreadedFunctionName()[len('iemThreadedFunc_'):];
638
639 def getShortName(self):
640 sName = self.oParent.oMcBlock.sFunction;
641 if sName.startswith('iemOp_'):
642 sName = sName[len('iemOp_'):];
643 return '%s%s%s' % ( sName, self.oParent.sSubName, self.sVariation, );
644
645 def getThreadedFunctionStatisticsName(self):
646 sName = self.oParent.oMcBlock.sFunction;
647 if sName.startswith('iemOp_'):
648 sName = sName[len('iemOp_'):];
649
650 sVarNm = self.sVariation;
651 if sVarNm:
652 if sVarNm.startswith('_'):
653 sVarNm = sVarNm[1:];
654 if sVarNm.endswith('_Jmp'):
655 sVarNm = sVarNm[:-4];
656 sName += '_Jmp';
657 elif sVarNm.endswith('_NoJmp'):
658 sVarNm = sVarNm[:-6];
659 sName += '_NoJmp';
660 else:
661 sVarNm = 'DeferToCImpl';
662
663 return '%s/%s%s' % ( sVarNm, sName, self.oParent.sSubName );
664
665 def isWithFlagsCheckingAndClearingVariation(self):
666 """
667 Checks if this is a variation that checks and clears EFLAGS.
668 """
669 return self.sVariation in ThreadedFunctionVariation.kdVariationsWithEflagsCheckingAndClearing;
670
671 #
672 # Analysis and code morphing.
673 #
674
675 def raiseProblem(self, sMessage):
676 """ Raises a problem. """
677 self.oParent.raiseProblem(sMessage);
678
679 def warning(self, sMessage):
680 """ Emits a warning. """
681 self.oParent.warning(sMessage);
682
683 def analyzeReferenceToType(self, sRef):
684 """
685 Translates a variable or structure reference to a type.
686 Returns type name.
687 Raises exception if unable to figure it out.
688 """
689 ch0 = sRef[0];
690 if ch0 == 'u':
691 if sRef.startswith('u32'):
692 return 'uint32_t';
693 if sRef.startswith('u8') or sRef == 'uReg':
694 return 'uint8_t';
695 if sRef.startswith('u64'):
696 return 'uint64_t';
697 if sRef.startswith('u16'):
698 return 'uint16_t';
699 elif ch0 == 'b':
700 return 'uint8_t';
701 elif ch0 == 'f':
702 return 'bool';
703 elif ch0 == 'i':
704 if sRef.startswith('i8'):
705 return 'int8_t';
706 if sRef.startswith('i16'):
707 return 'int16_t';
708 if sRef.startswith('i32'):
709 return 'int32_t';
710 if sRef.startswith('i64'):
711 return 'int64_t';
712 if sRef in ('iReg', 'iFixedReg', 'iGReg', 'iSegReg', 'iSrcReg', 'iDstReg', 'iCrReg'):
713 return 'uint8_t';
714 elif ch0 == 'p':
715 if sRef.find('-') < 0:
716 return 'uintptr_t';
717 if sRef.startswith('pVCpu->iem.s.'):
718 sField = sRef[len('pVCpu->iem.s.') : ];
719 if sField in g_kdIemFieldToType:
720 if g_kdIemFieldToType[sField][0]:
721 return g_kdIemFieldToType[sField][0];
722 elif ch0 == 'G' and sRef.startswith('GCPtr'):
723 return 'uint64_t';
724 elif ch0 == 'e':
725 if sRef == 'enmEffOpSize':
726 return 'IEMMODE';
727 elif ch0 == 'o':
728 if sRef.startswith('off32'):
729 return 'uint32_t';
730 elif sRef == 'cbFrame': # enter
731 return 'uint16_t';
732 elif sRef == 'cShift': ## @todo risky
733 return 'uint8_t';
734
735 self.raiseProblem('Unknown reference: %s' % (sRef,));
736 return None; # Shut up pylint 2.16.2.
737
738 def analyzeCallToType(self, sFnRef):
739 """
740 Determins the type of an indirect function call.
741 """
742 assert sFnRef[0] == 'p';
743
744 #
745 # Simple?
746 #
747 if sFnRef.find('-') < 0:
748 oDecoderFunction = self.oParent.oMcBlock.oFunction;
749
750 # Try the argument list of the function defintion macro invocation first.
751 iArg = 2;
752 while iArg < len(oDecoderFunction.asDefArgs):
753 if sFnRef == oDecoderFunction.asDefArgs[iArg]:
754 return oDecoderFunction.asDefArgs[iArg - 1];
755 iArg += 1;
756
757 # Then check out line that includes the word and looks like a variable declaration.
758 oRe = re.compile(' +(P[A-Z0-9_]+|const +IEMOP[A-Z0-9_]+ *[*]) +(const |) *' + sFnRef + ' *(;|=)');
759 for sLine in oDecoderFunction.asLines:
760 oMatch = oRe.match(sLine);
761 if oMatch:
762 if not oMatch.group(1).startswith('const'):
763 return oMatch.group(1);
764 return 'PC' + oMatch.group(1)[len('const ') : -1].strip();
765
766 #
767 # Deal with the pImpl->pfnXxx:
768 #
769 elif sFnRef.startswith('pImpl->pfn'):
770 sMember = sFnRef[len('pImpl->') : ];
771 sBaseType = self.analyzeCallToType('pImpl');
772 offBits = sMember.rfind('U') + 1;
773 if sBaseType == 'PCIEMOPBINSIZES': return 'PFNIEMAIMPLBINU' + sMember[offBits:];
774 if sBaseType == 'PCIEMOPUNARYSIZES': return 'PFNIEMAIMPLUNARYU' + sMember[offBits:];
775 if sBaseType == 'PCIEMOPSHIFTSIZES': return 'PFNIEMAIMPLSHIFTU' + sMember[offBits:];
776 if sBaseType == 'PCIEMOPSHIFTDBLSIZES': return 'PFNIEMAIMPLSHIFTDBLU' + sMember[offBits:];
777 if sBaseType == 'PCIEMOPMULDIVSIZES': return 'PFNIEMAIMPLMULDIVU' + sMember[offBits:];
778 if sBaseType == 'PCIEMOPMEDIAF3': return 'PFNIEMAIMPLMEDIAF3U' + sMember[offBits:];
779 if sBaseType == 'PCIEMOPMEDIAOPTF2': return 'PFNIEMAIMPLMEDIAOPTF2U' + sMember[offBits:];
780 if sBaseType == 'PCIEMOPMEDIAOPTF2IMM8': return 'PFNIEMAIMPLMEDIAOPTF2U' + sMember[offBits:] + 'IMM8';
781 if sBaseType == 'PCIEMOPMEDIAOPTF3': return 'PFNIEMAIMPLMEDIAOPTF3U' + sMember[offBits:];
782 if sBaseType == 'PCIEMOPMEDIAOPTF3IMM8': return 'PFNIEMAIMPLMEDIAOPTF3U' + sMember[offBits:] + 'IMM8';
783 if sBaseType == 'PCIEMOPBLENDOP': return 'PFNIEMAIMPLAVXBLENDU' + sMember[offBits:];
784
785 self.raiseProblem('Unknown call reference: %s::%s (%s)' % (sBaseType, sMember, sFnRef,));
786
787 self.raiseProblem('Unknown call reference: %s' % (sFnRef,));
788 return None; # Shut up pylint 2.16.2.
789
790 def analyze8BitGRegStmt(self, oStmt):
791 """
792 Gets the 8-bit general purpose register access details of the given statement.
793 ASSUMES the statement is one accessing an 8-bit GREG.
794 """
795 idxReg = 0;
796 if ( oStmt.sName.find('_FETCH_') > 0
797 or oStmt.sName.find('_REF_') > 0
798 or oStmt.sName.find('_TO_LOCAL') > 0):
799 idxReg = 1;
800
801 sRegRef = oStmt.asParams[idxReg];
802 if sRegRef.startswith('IEM_GET_MODRM_RM') or sRegRef.startswith('IEM_GET_MODRM_REG'):
803 asBits = [sBit.strip() for sBit in sRegRef.replace('(', ',').replace(')', '').split(',')];
804 if len(asBits) != 3 or asBits[1] != 'pVCpu' or (asBits[0] != 'IEM_GET_MODRM_RM' and asBits[0] != 'IEM_GET_MODRM_REG'):
805 self.raiseProblem('Unexpected reference: %s (asBits=%s)' % (sRegRef, asBits));
806 sOrgExpr = asBits[0] + '_EX8(pVCpu, ' + asBits[2] + ')';
807 else:
808 sOrgExpr = '((%s) < 4 || (pVCpu->iem.s.fPrefixes & (IEM_OP_PRF_REX | IEM_OP_PRF_VEX)) ? (%s) : (%s) + 12)' \
809 % (sRegRef, sRegRef, sRegRef,);
810
811 if sRegRef.find('IEM_GET_MODRM_RM') >= 0: sStdRef = 'bRmRm8Ex';
812 elif sRegRef.find('IEM_GET_MODRM_REG') >= 0: sStdRef = 'bRmReg8Ex';
813 elif sRegRef == 'X86_GREG_xAX': sStdRef = 'bGregXAx8Ex';
814 elif sRegRef == 'X86_GREG_xCX': sStdRef = 'bGregXCx8Ex';
815 elif sRegRef == 'X86_GREG_xSP': sStdRef = 'bGregXSp8Ex';
816 elif sRegRef == 'iFixedReg': sStdRef = 'bFixedReg8Ex';
817 else:
818 self.warning('analyze8BitGRegStmt: sRegRef=%s -> bOther8Ex; %s %s; sOrgExpr=%s'
819 % (sRegRef, oStmt.sName, oStmt.asParams, sOrgExpr,));
820 sStdRef = 'bOther8Ex';
821
822 #print('analyze8BitGRegStmt: %s %s; sRegRef=%s\n -> idxReg=%s sOrgExpr=%s sStdRef=%s'
823 # % (oStmt.sName, oStmt.asParams, sRegRef, idxReg, sOrgExpr, sStdRef));
824 return (idxReg, sOrgExpr, sStdRef);
825
826
827 ## Maps memory related MCs to info for FLAT conversion.
828 ## This is used in 64-bit and flat 32-bit variants to skip the unnecessary
829 ## segmentation checking for every memory access. Only applied to access
830 ## via ES, DS and SS. FS, GS and CS gets the full segmentation threatment,
831 ## the latter (CS) is just to keep things simple (we could safely fetch via
832 ## it, but only in 64-bit mode could we safely write via it, IIRC).
833 kdMemMcToFlatInfo = {
834 'IEM_MC_FETCH_MEM_U8': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8' ),
835 'IEM_MC_FETCH_MEM16_U8': ( 1, 'IEM_MC_FETCH_MEM16_FLAT_U8' ),
836 'IEM_MC_FETCH_MEM32_U8': ( 1, 'IEM_MC_FETCH_MEM32_FLAT_U8' ),
837 'IEM_MC_FETCH_MEM_U16': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16' ),
838 'IEM_MC_FETCH_MEM_U16_DISP': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16_DISP' ),
839 'IEM_MC_FETCH_MEM_I16': ( 1, 'IEM_MC_FETCH_MEM_FLAT_I16' ),
840 'IEM_MC_FETCH_MEM_U32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U32' ),
841 'IEM_MC_FETCH_MEM_U32_DISP': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U32_DISP' ),
842 'IEM_MC_FETCH_MEM_I32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_I32' ),
843 'IEM_MC_FETCH_MEM_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U64' ),
844 'IEM_MC_FETCH_MEM_U64_DISP': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U64_DISP' ),
845 'IEM_MC_FETCH_MEM_U64_ALIGN_U128': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U64_ALIGN_U128' ),
846 'IEM_MC_FETCH_MEM_I64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_I64' ),
847 'IEM_MC_FETCH_MEM_R32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_R32' ),
848 'IEM_MC_FETCH_MEM_R64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_R64' ),
849 'IEM_MC_FETCH_MEM_R80': ( 1, 'IEM_MC_FETCH_MEM_FLAT_R80' ),
850 'IEM_MC_FETCH_MEM_D80': ( 1, 'IEM_MC_FETCH_MEM_FLAT_D80' ),
851 'IEM_MC_FETCH_MEM_U128': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U128' ),
852 'IEM_MC_FETCH_MEM_U128_NO_AC': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U128_NO_AC' ),
853 'IEM_MC_FETCH_MEM_U128_ALIGN_SSE': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U128_ALIGN_SSE' ),
854 'IEM_MC_FETCH_MEM_XMM': ( 1, 'IEM_MC_FETCH_MEM_FLAT_XMM' ),
855 'IEM_MC_FETCH_MEM_XMM_NO_AC': ( 1, 'IEM_MC_FETCH_MEM_FLAT_XMM_NO_AC' ),
856 'IEM_MC_FETCH_MEM_XMM_ALIGN_SSE': ( 1, 'IEM_MC_FETCH_MEM_FLAT_XMM_ALIGN_SSE' ),
857 'IEM_MC_FETCH_MEM_XMM_U32': ( 2, 'IEM_MC_FETCH_MEM_FLAT_XMM_U32' ),
858 'IEM_MC_FETCH_MEM_XMM_U64': ( 2, 'IEM_MC_FETCH_MEM_FLAT_XMM_U64' ),
859 'IEM_MC_FETCH_MEM_U256': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U256' ),
860 'IEM_MC_FETCH_MEM_U256_NO_AC': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U256_NO_AC' ),
861 'IEM_MC_FETCH_MEM_U256_ALIGN_AVX': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U256_ALIGN_AVX' ),
862 'IEM_MC_FETCH_MEM_YMM': ( 1, 'IEM_MC_FETCH_MEM_FLAT_YMM' ),
863 'IEM_MC_FETCH_MEM_YMM_NO_AC': ( 1, 'IEM_MC_FETCH_MEM_FLAT_YMM_NO_AC' ),
864 'IEM_MC_FETCH_MEM_YMM_ALIGN_AVX': ( 1, 'IEM_MC_FETCH_MEM_FLAT_YMM_ALIGN_AVX' ),
865 'IEM_MC_FETCH_MEM_U8_ZX_U16': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U16' ),
866 'IEM_MC_FETCH_MEM_U8_ZX_U32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U32' ),
867 'IEM_MC_FETCH_MEM_U8_ZX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U64' ),
868 'IEM_MC_FETCH_MEM_U16_ZX_U32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16_ZX_U32' ),
869 'IEM_MC_FETCH_MEM_U16_ZX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16_ZX_U64' ),
870 'IEM_MC_FETCH_MEM_U32_ZX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U32_ZX_U64' ),
871 'IEM_MC_FETCH_MEM_U8_SX_U16': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U16' ),
872 'IEM_MC_FETCH_MEM_U8_SX_U32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U32' ),
873 'IEM_MC_FETCH_MEM_U8_SX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U64' ),
874 'IEM_MC_FETCH_MEM_U16_SX_U32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16_SX_U32' ),
875 'IEM_MC_FETCH_MEM_U16_SX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16_SX_U64' ),
876 'IEM_MC_FETCH_MEM_U32_SX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U32_SX_U64' ),
877 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128': ( 2, 'IEM_MC_FETCH_MEM_FLAT_U128_AND_XREG_U128' ),
878 'IEM_MC_FETCH_MEM_XMM_ALIGN_SSE_AND_XREG_XMM': ( 2, 'IEM_MC_FETCH_MEM_FLAT_XMM_ALIGN_SSE_AND_XREG_XMM' ),
879 'IEM_MC_FETCH_MEM_XMM_U32_AND_XREG_XMM': ( 3, 'IEM_MC_FETCH_MEM_FLAT_XMM_U32_AND_XREG_XMM' ),
880 'IEM_MC_FETCH_MEM_XMM_U64_AND_XREG_XMM': ( 3, 'IEM_MC_FETCH_MEM_FLAT_XMM_U64_AND_XREG_XMM' ),
881 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128_AND_RAX_RDX_U64':
882 ( 2, 'IEM_MC_FETCH_MEM_FLAT_U128_AND_XREG_U128_AND_RAX_RDX_U64' ),
883 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128_AND_EAX_EDX_U32_SX_U64':
884 ( 2, 'IEM_MC_FETCH_MEM_FLAT_U128_AND_XREG_U128_AND_EAX_EDX_U32_SX_U64' ),
885 'IEM_MC_STORE_MEM_U8': ( 0, 'IEM_MC_STORE_MEM_FLAT_U8' ),
886 'IEM_MC_STORE_MEM_U16': ( 0, 'IEM_MC_STORE_MEM_FLAT_U16' ),
887 'IEM_MC_STORE_MEM_U32': ( 0, 'IEM_MC_STORE_MEM_FLAT_U32' ),
888 'IEM_MC_STORE_MEM_U64': ( 0, 'IEM_MC_STORE_MEM_FLAT_U64' ),
889 'IEM_MC_STORE_MEM_U8_CONST': ( 0, 'IEM_MC_STORE_MEM_FLAT_U8_CONST' ),
890 'IEM_MC_STORE_MEM_U16_CONST': ( 0, 'IEM_MC_STORE_MEM_FLAT_U16_CONST' ),
891 'IEM_MC_STORE_MEM_U32_CONST': ( 0, 'IEM_MC_STORE_MEM_FLAT_U32_CONST' ),
892 'IEM_MC_STORE_MEM_U64_CONST': ( 0, 'IEM_MC_STORE_MEM_FLAT_U64_CONST' ),
893 'IEM_MC_STORE_MEM_U128': ( 0, 'IEM_MC_STORE_MEM_FLAT_U128' ),
894 'IEM_MC_STORE_MEM_U128_NO_AC': ( 0, 'IEM_MC_STORE_MEM_FLAT_U128_NO_AC' ),
895 'IEM_MC_STORE_MEM_U128_ALIGN_SSE': ( 0, 'IEM_MC_STORE_MEM_FLAT_U128_ALIGN_SSE' ),
896 'IEM_MC_STORE_MEM_U256': ( 0, 'IEM_MC_STORE_MEM_FLAT_U256' ),
897 'IEM_MC_STORE_MEM_U256_NO_AC': ( 0, 'IEM_MC_STORE_MEM_FLAT_U256_NO_AC' ),
898 'IEM_MC_STORE_MEM_U256_ALIGN_AVX': ( 0, 'IEM_MC_STORE_MEM_FLAT_U256_ALIGN_AVX' ),
899 'IEM_MC_MEM_MAP_D80_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_D80_WO' ),
900 'IEM_MC_MEM_MAP_I16_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_I16_WO' ),
901 'IEM_MC_MEM_MAP_I32_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_I32_WO' ),
902 'IEM_MC_MEM_MAP_I64_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_I64_WO' ),
903 'IEM_MC_MEM_MAP_R32_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_R32_WO' ),
904 'IEM_MC_MEM_MAP_R64_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_R64_WO' ),
905 'IEM_MC_MEM_MAP_R80_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_R80_WO' ),
906 'IEM_MC_MEM_MAP_U8_ATOMIC': ( 2, 'IEM_MC_MEM_FLAT_MAP_U8_ATOMIC' ),
907 'IEM_MC_MEM_MAP_U8_RW': ( 2, 'IEM_MC_MEM_FLAT_MAP_U8_RW' ),
908 'IEM_MC_MEM_MAP_U8_RO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U8_RO' ),
909 'IEM_MC_MEM_MAP_U8_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U8_WO' ),
910 'IEM_MC_MEM_MAP_U16_ATOMIC': ( 2, 'IEM_MC_MEM_FLAT_MAP_U16_ATOMIC' ),
911 'IEM_MC_MEM_MAP_U16_RW': ( 2, 'IEM_MC_MEM_FLAT_MAP_U16_RW' ),
912 'IEM_MC_MEM_MAP_U16_RO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U16_RO' ),
913 'IEM_MC_MEM_MAP_U16_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U16_WO' ),
914 'IEM_MC_MEM_MAP_U32_ATOMIC': ( 2, 'IEM_MC_MEM_FLAT_MAP_U32_ATOMIC' ),
915 'IEM_MC_MEM_MAP_U32_RW': ( 2, 'IEM_MC_MEM_FLAT_MAP_U32_RW' ),
916 'IEM_MC_MEM_MAP_U32_RO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U32_RO' ),
917 'IEM_MC_MEM_MAP_U32_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U32_WO' ),
918 'IEM_MC_MEM_MAP_U64_ATOMIC': ( 2, 'IEM_MC_MEM_FLAT_MAP_U64_ATOMIC' ),
919 'IEM_MC_MEM_MAP_U64_RW': ( 2, 'IEM_MC_MEM_FLAT_MAP_U64_RW' ),
920 'IEM_MC_MEM_MAP_U64_RO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U64_RO' ),
921 'IEM_MC_MEM_MAP_U64_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U64_WO' ),
922 'IEM_MC_MEM_MAP_U128_ATOMIC': ( 2, 'IEM_MC_MEM_FLAT_MAP_U128_ATOMIC' ),
923 'IEM_MC_MEM_MAP_U128_RW': ( 2, 'IEM_MC_MEM_FLAT_MAP_U128_RW' ),
924 'IEM_MC_MEM_MAP_U128_RO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U128_RO' ),
925 'IEM_MC_MEM_MAP_U128_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U128_WO' ),
926 'IEM_MC_MEM_MAP_EX': ( 3, 'IEM_MC_MEM_FLAT_MAP_EX' ),
927 };
928
929 kdMemMcToFlatInfoStack = {
930 'IEM_MC_PUSH_U16': ( 'IEM_MC_FLAT32_PUSH_U16', 'IEM_MC_FLAT64_PUSH_U16', ),
931 'IEM_MC_PUSH_U32': ( 'IEM_MC_FLAT32_PUSH_U32', 'IEM_MC_PUSH_U32', ),
932 'IEM_MC_PUSH_U64': ( 'IEM_MC_PUSH_U64', 'IEM_MC_FLAT64_PUSH_U64', ),
933 'IEM_MC_PUSH_U32_SREG': ( 'IEM_MC_FLAT32_PUSH_U32_SREG', 'IEM_MC_PUSH_U32_SREG' ),
934 'IEM_MC_POP_GREG_U16': ( 'IEM_MC_FLAT32_POP_GREG_U16', 'IEM_MC_FLAT64_POP_GREG_U16', ),
935 'IEM_MC_POP_GREG_U32': ( 'IEM_MC_FLAT32_POP_GREG_U32', 'IEM_MC_POP_GREG_U32', ),
936 'IEM_MC_POP_GREG_U64': ( 'IEM_MC_POP_GREG_U64', 'IEM_MC_FLAT64_POP_GREG_U64', ),
937 };
938
939 kdThreadedCalcRmEffAddrMcByVariation = {
940 ksVariation_16: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
941 ksVariation_16f: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
942 ksVariation_16_Pre386: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
943 ksVariation_16f_Pre386: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
944 ksVariation_32_Addr16: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
945 ksVariation_32f_Addr16: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
946 ksVariation_16_Addr32: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
947 ksVariation_16f_Addr32: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
948 ksVariation_32: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
949 ksVariation_32f: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
950 ksVariation_32_Flat: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
951 ksVariation_32f_Flat: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
952 ksVariation_64: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64',
953 ksVariation_64f: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64',
954 ksVariation_64_FsGs: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64_FSGS',
955 ksVariation_64f_FsGs: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64_FSGS',
956 ksVariation_64_Addr32: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64_ADDR32', ## @todo How did this work again...
957 ksVariation_64f_Addr32: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64_ADDR32',
958 };
959
960 def analyzeMorphStmtForThreaded(self, aoStmts, dState, iParamRef = 0, iLevel = 0):
961 """
962 Transforms (copy) the statements into those for the threaded function.
963
964 Returns list/tree of statements (aoStmts is not modified) and the new
965 iParamRef value.
966 """
967 #
968 # We'll be traversing aoParamRefs in parallel to the statements, so we
969 # must match the traversal in analyzeFindThreadedParamRefs exactly.
970 #
971 #print('McBlock at %s:%s' % (os.path.split(self.oMcBlock.sSrcFile)[1], self.oMcBlock.iBeginLine,));
972 aoThreadedStmts = [];
973 for oStmt in aoStmts:
974 # Skip C++ statements that is purely related to decoding.
975 if not oStmt.isCppStmt() or not oStmt.fDecode:
976 # Copy the statement. Make a deep copy to make sure we've got our own
977 # copies of all instance variables, even if a bit overkill at the moment.
978 oNewStmt = copy.deepcopy(oStmt);
979 aoThreadedStmts.append(oNewStmt);
980 #print('oNewStmt %s %s' % (oNewStmt.sName, len(oNewStmt.asParams),));
981
982 # If the statement has parameter references, process the relevant parameters.
983 # We grab the references relevant to this statement and apply them in reserve order.
984 if iParamRef < len(self.aoParamRefs) and self.aoParamRefs[iParamRef].oStmt == oStmt:
985 iParamRefFirst = iParamRef;
986 while True:
987 iParamRef += 1;
988 if iParamRef >= len(self.aoParamRefs) or self.aoParamRefs[iParamRef].oStmt != oStmt:
989 break;
990
991 #print('iParamRefFirst=%s iParamRef=%s' % (iParamRefFirst, iParamRef));
992 for iCurRef in range(iParamRef - 1, iParamRefFirst - 1, -1):
993 oCurRef = self.aoParamRefs[iCurRef];
994 if oCurRef.iParam is not None:
995 assert oCurRef.oStmt == oStmt;
996 #print('iCurRef=%s iParam=%s sOrgRef=%s' % (iCurRef, oCurRef.iParam, oCurRef.sOrgRef));
997 sSrcParam = oNewStmt.asParams[oCurRef.iParam];
998 assert ( sSrcParam[oCurRef.offParam : oCurRef.offParam + len(oCurRef.sOrgRef)] == oCurRef.sOrgRef
999 or oCurRef.fCustomRef), \
1000 'offParam=%s sOrgRef=%s iParam=%s oStmt.sName=%s sSrcParam=%s<eos>' \
1001 % (oCurRef.offParam, oCurRef.sOrgRef, oCurRef.iParam, oStmt.sName, sSrcParam);
1002 oNewStmt.asParams[oCurRef.iParam] = sSrcParam[0 : oCurRef.offParam] \
1003 + oCurRef.sNewName \
1004 + sSrcParam[oCurRef.offParam + len(oCurRef.sOrgRef) : ];
1005
1006 # Morph IEM_MC_CALC_RM_EFF_ADDR into IEM_MC_CALC_RM_EFF_ADDR_THREADED ...
1007 if oNewStmt.sName == 'IEM_MC_CALC_RM_EFF_ADDR':
1008 oNewStmt.sName = self.kdThreadedCalcRmEffAddrMcByVariation[self.sVariation];
1009 assert len(oNewStmt.asParams) == 3;
1010
1011 if self.sVariation in self.kdVariationsWithFlatAddr16:
1012 oNewStmt.asParams = [
1013 oNewStmt.asParams[0], oNewStmt.asParams[1], self.dParamRefs['u16Disp'][0].sNewName,
1014 ];
1015 else:
1016 sSibAndMore = self.dParamRefs['bSib'][0].sNewName; # Merge bSib and 2nd part of cbImmAndRspOffset.
1017 if oStmt.asParams[2] not in ('0', '1', '2', '4'):
1018 sSibAndMore = '(%s) | ((%s) & 0x0f00)' % (self.dParamRefs['bSib'][0].sNewName, oStmt.asParams[2]);
1019
1020 if self.sVariation in self.kdVariationsWithFlatAddr32No64:
1021 oNewStmt.asParams = [
1022 oNewStmt.asParams[0], oNewStmt.asParams[1], sSibAndMore, self.dParamRefs['u32Disp'][0].sNewName,
1023 ];
1024 else:
1025 oNewStmt.asParams = [
1026 oNewStmt.asParams[0], self.dParamRefs['bRmEx'][0].sNewName, sSibAndMore,
1027 self.dParamRefs['u32Disp'][0].sNewName, self.dParamRefs['cbInstr'][0].sNewName,
1028 ];
1029 # ... and IEM_MC_ADVANCE_RIP_AND_FINISH into *_THREADED_PCxx[_WITH_FLAGS] ...
1030 elif ( oNewStmt.sName
1031 in ('IEM_MC_ADVANCE_RIP_AND_FINISH',
1032 'IEM_MC_REL_JMP_S8_AND_FINISH', 'IEM_MC_REL_JMP_S16_AND_FINISH', 'IEM_MC_REL_JMP_S32_AND_FINISH',
1033 'IEM_MC_SET_RIP_U16_AND_FINISH', 'IEM_MC_SET_RIP_U32_AND_FINISH', 'IEM_MC_SET_RIP_U64_AND_FINISH', )):
1034 if oNewStmt.sName not in ('IEM_MC_SET_RIP_U16_AND_FINISH', 'IEM_MC_SET_RIP_U32_AND_FINISH',
1035 'IEM_MC_SET_RIP_U64_AND_FINISH', ):
1036 oNewStmt.asParams.append(self.dParamRefs['cbInstr'][0].sNewName);
1037 if ( oNewStmt.sName in ('IEM_MC_REL_JMP_S8_AND_FINISH', )
1038 and self.sVariation not in self.kdVariationsOnlyPre386):
1039 oNewStmt.asParams.append(self.dParamRefs['pVCpu->iem.s.enmEffOpSize'][0].sNewName);
1040 oNewStmt.sName += '_THREADED';
1041 if self.sVariation in self.kdVariationsOnly64NoFlags:
1042 oNewStmt.sName += '_PC64';
1043 elif self.sVariation in self.kdVariationsOnly64WithFlags:
1044 oNewStmt.sName += '_PC64_WITH_FLAGS';
1045 elif self.sVariation in self.kdVariationsOnlyPre386NoFlags:
1046 oNewStmt.sName += '_PC16';
1047 elif self.sVariation in self.kdVariationsOnlyPre386WithFlags:
1048 oNewStmt.sName += '_PC16_WITH_FLAGS';
1049 elif self.sVariation not in self.kdVariationsWithEflagsCheckingAndClearing:
1050 assert self.sVariation != self.ksVariation_Default;
1051 oNewStmt.sName += '_PC32';
1052 else:
1053 oNewStmt.sName += '_PC32_WITH_FLAGS';
1054
1055 # This is making the wrong branch of conditionals break out of the TB.
1056 if (oStmt.sName in ('IEM_MC_ADVANCE_RIP_AND_FINISH', 'IEM_MC_REL_JMP_S8_AND_FINISH',
1057 'IEM_MC_REL_JMP_S16_AND_FINISH', 'IEM_MC_REL_JMP_S32_AND_FINISH')):
1058 sExitTbStatus = 'VINF_SUCCESS';
1059 if self.sVariation in self.kdVariationsWithConditional:
1060 if self.sVariation in self.kdVariationsWithConditionalNoJmp:
1061 if oStmt.sName != 'IEM_MC_ADVANCE_RIP_AND_FINISH':
1062 sExitTbStatus = 'VINF_IEM_REEXEC_BREAK';
1063 elif oStmt.sName == 'IEM_MC_ADVANCE_RIP_AND_FINISH':
1064 sExitTbStatus = 'VINF_IEM_REEXEC_BREAK';
1065 oNewStmt.asParams.append(sExitTbStatus);
1066
1067 # Insert an MC so we can assert the correctioness of modified flags annotations on IEM_MC_REF_EFLAGS.
1068 if 'IEM_MC_ASSERT_EFLAGS' in dState:
1069 aoThreadedStmts.insert(len(aoThreadedStmts) - 1,
1070 iai.McStmtAssertEFlags(self.oParent.oMcBlock.oInstruction));
1071 del dState['IEM_MC_ASSERT_EFLAGS'];
1072
1073 # ... and IEM_MC_*_GREG_U8 into *_THREADED w/ reworked index taking REX into account
1074 elif oNewStmt.sName.startswith('IEM_MC_') and oNewStmt.sName.find('_GREG_U8') > 0:
1075 (idxReg, _, sStdRef) = self.analyze8BitGRegStmt(oStmt); # Don't use oNewStmt as it has been modified!
1076 oNewStmt.asParams[idxReg] = self.dParamRefs[sStdRef][0].sNewName;
1077 oNewStmt.sName += '_THREADED';
1078
1079 # ... and IEM_MC_CALL_CIMPL_[0-5] and IEM_MC_DEFER_TO_CIMPL_[0-5]_RET into *_THREADED ...
1080 elif oNewStmt.sName.startswith('IEM_MC_CALL_CIMPL_') or oNewStmt.sName.startswith('IEM_MC_DEFER_TO_CIMPL_'):
1081 oNewStmt.sName += '_THREADED';
1082 oNewStmt.idxFn += 1;
1083 oNewStmt.idxParams += 1;
1084 oNewStmt.asParams.insert(0, self.dParamRefs['cbInstr'][0].sNewName);
1085
1086 # ... and in FLAT modes we must morph memory access into FLAT accesses ...
1087 elif ( self.sVariation in self.kdVariationsWithFlatAddress
1088 and ( oNewStmt.sName.startswith('IEM_MC_FETCH_MEM')
1089 or (oNewStmt.sName.startswith('IEM_MC_STORE_MEM_') and oNewStmt.sName.find('_BY_REF') < 0)
1090 or oNewStmt.sName.startswith('IEM_MC_MEM_MAP') )):
1091 idxEffSeg = self.kdMemMcToFlatInfo[oNewStmt.sName][0];
1092 if idxEffSeg != -1:
1093 if ( oNewStmt.asParams[idxEffSeg].find('iEffSeg') < 0
1094 and oNewStmt.asParams[idxEffSeg] not in ('X86_SREG_ES', ) ):
1095 self.raiseProblem('Expected iEffSeg as param #%d to %s: %s'
1096 % (idxEffSeg + 1, oNewStmt.sName, oNewStmt.asParams[idxEffSeg],));
1097 oNewStmt.asParams.pop(idxEffSeg);
1098 oNewStmt.sName = self.kdMemMcToFlatInfo[oNewStmt.sName][1];
1099
1100 # ... PUSH and POP also needs flat variants, but these differ a little.
1101 elif ( self.sVariation in self.kdVariationsWithFlatStackAddress
1102 and ( (oNewStmt.sName.startswith('IEM_MC_PUSH') and oNewStmt.sName.find('_FPU') < 0)
1103 or oNewStmt.sName.startswith('IEM_MC_POP'))):
1104 oNewStmt.sName = self.kdMemMcToFlatInfoStack[oNewStmt.sName][int(self.sVariation in
1105 self.kdVariationsWithFlat64StackAddress)];
1106
1107 # Add EFLAGS usage annotations to relevant MCs.
1108 elif oNewStmt.sName in ('IEM_MC_COMMIT_EFLAGS', 'IEM_MC_COMMIT_EFLAGS_OPT', 'IEM_MC_REF_EFLAGS',
1109 'IEM_MC_FETCH_EFLAGS'):
1110 oInstruction = self.oParent.oMcBlock.oInstruction;
1111 oNewStmt.sName += '_EX';
1112 oNewStmt.asParams.append(oInstruction.getTestedFlagsCStyle()); # Shall crash and burn if oInstruction is
1113 oNewStmt.asParams.append(oInstruction.getModifiedFlagsCStyle()); # None. Fix the IEM decoder code.
1114
1115 # For IEM_MC_REF_EFLAGS we to emit an MC before the ..._FINISH
1116 if oNewStmt.sName == 'IEM_MC_REF_EFLAGS_EX':
1117 dState['IEM_MC_ASSERT_EFLAGS'] = iLevel;
1118
1119 # Process branches of conditionals recursively.
1120 if isinstance(oStmt, iai.McStmtCond):
1121 (oNewStmt.aoIfBranch, iParamRef) = self.analyzeMorphStmtForThreaded(oStmt.aoIfBranch, dState,
1122 iParamRef, iLevel + 1);
1123 if oStmt.aoElseBranch:
1124 (oNewStmt.aoElseBranch, iParamRef) = self.analyzeMorphStmtForThreaded(oStmt.aoElseBranch,
1125 dState, iParamRef, iLevel + 1);
1126
1127 # Insert an MC so we can assert the correctioness of modified flags annotations
1128 # on IEM_MC_REF_EFLAGS if it goes out of scope.
1129 if dState.get('IEM_MC_ASSERT_EFLAGS', -1) == iLevel:
1130 aoThreadedStmts.append(iai.McStmtAssertEFlags(self.oParent.oMcBlock.oInstruction));
1131 del dState['IEM_MC_ASSERT_EFLAGS'];
1132
1133 return (aoThreadedStmts, iParamRef);
1134
1135
1136 def analyzeConsolidateThreadedParamRefs(self):
1137 """
1138 Consolidate threaded function parameter references into a dictionary
1139 with lists of the references to each variable/field.
1140 """
1141 # Gather unique parameters.
1142 self.dParamRefs = {};
1143 for oRef in self.aoParamRefs:
1144 if oRef.sStdRef not in self.dParamRefs:
1145 self.dParamRefs[oRef.sStdRef] = [oRef,];
1146 else:
1147 self.dParamRefs[oRef.sStdRef].append(oRef);
1148
1149 # Generate names for them for use in the threaded function.
1150 dParamNames = {};
1151 for sName, aoRefs in self.dParamRefs.items():
1152 # Morph the reference expression into a name.
1153 if sName.startswith('IEM_GET_MODRM_REG'): sName = 'bModRmRegP';
1154 elif sName.startswith('IEM_GET_MODRM_RM'): sName = 'bModRmRmP';
1155 elif sName.startswith('IEM_GET_MODRM_REG_8'): sName = 'bModRmReg8P';
1156 elif sName.startswith('IEM_GET_MODRM_RM_8'): sName = 'bModRmRm8P';
1157 elif sName.startswith('IEM_GET_EFFECTIVE_VVVV'): sName = 'bEffVvvvP';
1158 elif sName.startswith('IEM_GET_IMM8_REG'): sName = 'bImm8Reg';
1159 elif sName.find('.') >= 0 or sName.find('->') >= 0:
1160 sName = sName[max(sName.rfind('.'), sName.rfind('>')) + 1 : ] + 'P';
1161 else:
1162 sName += 'P';
1163
1164 # Ensure it's unique.
1165 if sName in dParamNames:
1166 for i in range(10):
1167 if sName + str(i) not in dParamNames:
1168 sName += str(i);
1169 break;
1170 dParamNames[sName] = True;
1171
1172 # Update all the references.
1173 for oRef in aoRefs:
1174 oRef.sNewName = sName;
1175
1176 # Organize them by size too for the purpose of optimize them.
1177 dBySize = {} # type: Dict[str, str]
1178 for sStdRef, aoRefs in self.dParamRefs.items():
1179 if aoRefs[0].sType[0] != 'P':
1180 cBits = g_kdTypeInfo[aoRefs[0].sType][0];
1181 assert(cBits <= 64);
1182 else:
1183 cBits = 64;
1184
1185 if cBits not in dBySize:
1186 dBySize[cBits] = [sStdRef,]
1187 else:
1188 dBySize[cBits].append(sStdRef);
1189
1190 # Pack the parameters as best as we can, starting with the largest ones
1191 # and ASSUMING a 64-bit parameter size.
1192 self.cMinParams = 0;
1193 offNewParam = 0;
1194 for cBits in sorted(dBySize.keys(), reverse = True):
1195 for sStdRef in dBySize[cBits]:
1196 if offNewParam == 0 or offNewParam + cBits > 64:
1197 self.cMinParams += 1;
1198 offNewParam = cBits;
1199 else:
1200 offNewParam += cBits;
1201 assert(offNewParam <= 64);
1202
1203 for oRef in self.dParamRefs[sStdRef]:
1204 oRef.iNewParam = self.cMinParams - 1;
1205 oRef.offNewParam = offNewParam - cBits;
1206
1207 # Currently there are a few that requires 4 parameters, list these so we can figure out why:
1208 if self.cMinParams >= 4:
1209 print('debug: cMinParams=%s cRawParams=%s - %s:%d'
1210 % (self.cMinParams, len(self.dParamRefs), self.oParent.oMcBlock.sSrcFile, self.oParent.oMcBlock.iBeginLine,));
1211
1212 return True;
1213
1214 ksHexDigits = '0123456789abcdefABCDEF';
1215
1216 def analyzeFindThreadedParamRefs(self, aoStmts): # pylint: disable=too-many-statements
1217 """
1218 Scans the statements for things that have to passed on to the threaded
1219 function (populates self.aoParamRefs).
1220 """
1221 for oStmt in aoStmts:
1222 # Some statements we can skip alltogether.
1223 if isinstance(oStmt, iai.McCppPreProc):
1224 continue;
1225 if oStmt.isCppStmt() and oStmt.fDecode:
1226 continue;
1227 if oStmt.sName in ('IEM_MC_BEGIN',):
1228 continue;
1229
1230 if isinstance(oStmt, iai.McStmtVar):
1231 if oStmt.sValue is None:
1232 continue;
1233 aiSkipParams = { 0: True, 1: True, 3: True };
1234 else:
1235 aiSkipParams = {};
1236
1237 # Several statements have implicit parameters and some have different parameters.
1238 if oStmt.sName in ('IEM_MC_ADVANCE_RIP_AND_FINISH', 'IEM_MC_REL_JMP_S8_AND_FINISH', 'IEM_MC_REL_JMP_S16_AND_FINISH',
1239 'IEM_MC_REL_JMP_S32_AND_FINISH', 'IEM_MC_CALL_CIMPL_0', 'IEM_MC_CALL_CIMPL_1',
1240 'IEM_MC_CALL_CIMPL_2', 'IEM_MC_CALL_CIMPL_3', 'IEM_MC_CALL_CIMPL_4', 'IEM_MC_CALL_CIMPL_5',
1241 'IEM_MC_DEFER_TO_CIMPL_0_RET', 'IEM_MC_DEFER_TO_CIMPL_1_RET', 'IEM_MC_DEFER_TO_CIMPL_2_RET',
1242 'IEM_MC_DEFER_TO_CIMPL_3_RET', 'IEM_MC_DEFER_TO_CIMPL_4_RET', 'IEM_MC_DEFER_TO_CIMPL_5_RET', ):
1243 self.aoParamRefs.append(ThreadedParamRef('IEM_GET_INSTR_LEN(pVCpu)', 'uint4_t', oStmt, sStdRef = 'cbInstr'));
1244
1245 if ( oStmt.sName in ('IEM_MC_REL_JMP_S8_AND_FINISH',)
1246 and self.sVariation not in self.kdVariationsOnlyPre386):
1247 self.aoParamRefs.append(ThreadedParamRef('pVCpu->iem.s.enmEffOpSize', 'IEMMODE', oStmt));
1248
1249 if oStmt.sName == 'IEM_MC_CALC_RM_EFF_ADDR':
1250 # This is being pretty presumptive about bRm always being the RM byte...
1251 assert len(oStmt.asParams) == 3;
1252 assert oStmt.asParams[1] == 'bRm';
1253
1254 if self.sVariation in self.kdVariationsWithFlatAddr16:
1255 self.aoParamRefs.append(ThreadedParamRef('bRm', 'uint8_t', oStmt));
1256 self.aoParamRefs.append(ThreadedParamRef('(uint16_t)uEffAddrInfo' ,
1257 'uint16_t', oStmt, sStdRef = 'u16Disp'));
1258 elif self.sVariation in self.kdVariationsWithFlatAddr32No64:
1259 self.aoParamRefs.append(ThreadedParamRef('bRm', 'uint8_t', oStmt));
1260 self.aoParamRefs.append(ThreadedParamRef('(uint8_t)(uEffAddrInfo >> 32)',
1261 'uint8_t', oStmt, sStdRef = 'bSib'));
1262 self.aoParamRefs.append(ThreadedParamRef('(uint32_t)uEffAddrInfo',
1263 'uint32_t', oStmt, sStdRef = 'u32Disp'));
1264 else:
1265 assert self.sVariation in self.kdVariationsWithAddressOnly64;
1266 self.aoParamRefs.append(ThreadedParamRef('IEM_GET_MODRM_EX(pVCpu, bRm)',
1267 'uint8_t', oStmt, sStdRef = 'bRmEx'));
1268 self.aoParamRefs.append(ThreadedParamRef('(uint8_t)(uEffAddrInfo >> 32)',
1269 'uint8_t', oStmt, sStdRef = 'bSib'));
1270 self.aoParamRefs.append(ThreadedParamRef('(uint32_t)uEffAddrInfo',
1271 'uint32_t', oStmt, sStdRef = 'u32Disp'));
1272 self.aoParamRefs.append(ThreadedParamRef('IEM_GET_INSTR_LEN(pVCpu)',
1273 'uint4_t', oStmt, sStdRef = 'cbInstr'));
1274 aiSkipParams[1] = True; # Skip the bRm parameter as it is being replaced by bRmEx.
1275
1276 # 8-bit register accesses needs to have their index argument reworked to take REX into account.
1277 if oStmt.sName.startswith('IEM_MC_') and oStmt.sName.find('_GREG_U8') > 0:
1278 (idxReg, sOrgRef, sStdRef) = self.analyze8BitGRegStmt(oStmt);
1279 self.aoParamRefs.append(ThreadedParamRef(sOrgRef, 'uint8_t', oStmt, idxReg, sStdRef = sStdRef));
1280 aiSkipParams[idxReg] = True; # Skip the parameter below.
1281
1282 # If in flat mode variation, ignore the effective segment parameter to memory MCs.
1283 if ( self.sVariation in self.kdVariationsWithFlatAddress
1284 and oStmt.sName in self.kdMemMcToFlatInfo
1285 and self.kdMemMcToFlatInfo[oStmt.sName][0] != -1):
1286 aiSkipParams[self.kdMemMcToFlatInfo[oStmt.sName][0]] = True;
1287
1288 # Inspect the target of calls to see if we need to pass down a
1289 # function pointer or function table pointer for it to work.
1290 if isinstance(oStmt, iai.McStmtCall):
1291 if oStmt.sFn[0] == 'p':
1292 self.aoParamRefs.append(ThreadedParamRef(oStmt.sFn, self.analyzeCallToType(oStmt.sFn), oStmt, oStmt.idxFn));
1293 elif ( oStmt.sFn[0] != 'i'
1294 and not oStmt.sFn.startswith('RT_CONCAT3')
1295 and not oStmt.sFn.startswith('IEMTARGETCPU_EFL_BEHAVIOR_SELECT')
1296 and not oStmt.sFn.startswith('IEM_SELECT_HOST_OR_FALLBACK') ):
1297 self.raiseProblem('Bogus function name in %s: %s' % (oStmt.sName, oStmt.sFn,));
1298 aiSkipParams[oStmt.idxFn] = True;
1299
1300 # Skip the hint parameter (first) for IEM_MC_CALL_CIMPL_X.
1301 if oStmt.sName.startswith('IEM_MC_CALL_CIMPL_'):
1302 assert oStmt.idxFn == 2;
1303 aiSkipParams[0] = True;
1304
1305 # Skip the function parameter (first) for IEM_MC_NATIVE_EMIT_X.
1306 if oStmt.sName.startswith('IEM_MC_NATIVE_EMIT_'):
1307 aiSkipParams[0] = True;
1308
1309
1310 # Check all the parameters for bogus references.
1311 for iParam, sParam in enumerate(oStmt.asParams):
1312 if iParam not in aiSkipParams and sParam not in self.oParent.dVariables:
1313 # The parameter may contain a C expression, so we have to try
1314 # extract the relevant bits, i.e. variables and fields while
1315 # ignoring operators and parentheses.
1316 offParam = 0;
1317 while offParam < len(sParam):
1318 # Is it the start of an C identifier? If so, find the end, but don't stop on field separators (->, .).
1319 ch = sParam[offParam];
1320 if ch.isalpha() or ch == '_':
1321 offStart = offParam;
1322 offParam += 1;
1323 while offParam < len(sParam):
1324 ch = sParam[offParam];
1325 if not ch.isalnum() and ch != '_' and ch != '.':
1326 if ch != '-' or sParam[offParam + 1] != '>':
1327 # Special hack for the 'CTX_SUFF(pVM)' bit in pVCpu->CTX_SUFF(pVM)->xxxx:
1328 if ( ch == '('
1329 and sParam[offStart : offParam + len('(pVM)->')] == 'pVCpu->CTX_SUFF(pVM)->'):
1330 offParam += len('(pVM)->') - 1;
1331 else:
1332 break;
1333 offParam += 1;
1334 offParam += 1;
1335 sRef = sParam[offStart : offParam];
1336
1337 # For register references, we pass the full register indexes instead as macros
1338 # like IEM_GET_MODRM_REG implicitly references pVCpu->iem.s.uRexReg and the
1339 # threaded function will be more efficient if we just pass the register index
1340 # as a 4-bit param.
1341 if ( sRef.startswith('IEM_GET_MODRM')
1342 or sRef.startswith('IEM_GET_EFFECTIVE_VVVV')
1343 or sRef.startswith('IEM_GET_IMM8_REG') ):
1344 offParam = iai.McBlock.skipSpacesAt(sParam, offParam, len(sParam));
1345 if sParam[offParam] != '(':
1346 self.raiseProblem('Expected "(" following %s in "%s"' % (sRef, oStmt.renderCode(),));
1347 (asMacroParams, offCloseParam) = iai.McBlock.extractParams(sParam, offParam);
1348 if asMacroParams is None:
1349 self.raiseProblem('Unable to find ")" for %s in "%s"' % (sRef, oStmt.renderCode(),));
1350 offParam = offCloseParam + 1;
1351 self.aoParamRefs.append(ThreadedParamRef(sParam[offStart : offParam], 'uint8_t',
1352 oStmt, iParam, offStart));
1353
1354 # We can skip known variables.
1355 elif sRef in self.oParent.dVariables:
1356 pass;
1357
1358 # Skip certain macro invocations.
1359 elif sRef in ('IEM_GET_HOST_CPU_FEATURES',
1360 'IEM_GET_GUEST_CPU_FEATURES',
1361 'IEM_IS_GUEST_CPU_AMD',
1362 'IEM_IS_16BIT_CODE',
1363 'IEM_IS_32BIT_CODE',
1364 'IEM_IS_64BIT_CODE',
1365 ):
1366 offParam = iai.McBlock.skipSpacesAt(sParam, offParam, len(sParam));
1367 if sParam[offParam] != '(':
1368 self.raiseProblem('Expected "(" following %s in "%s"' % (sRef, oStmt.renderCode(),));
1369 (asMacroParams, offCloseParam) = iai.McBlock.extractParams(sParam, offParam);
1370 if asMacroParams is None:
1371 self.raiseProblem('Unable to find ")" for %s in "%s"' % (sRef, oStmt.renderCode(),));
1372 offParam = offCloseParam + 1;
1373
1374 # Skip any dereference following it, unless it's a predicate like IEM_IS_GUEST_CPU_AMD.
1375 if sRef not in ('IEM_IS_GUEST_CPU_AMD',
1376 'IEM_IS_16BIT_CODE',
1377 'IEM_IS_32BIT_CODE',
1378 'IEM_IS_64BIT_CODE',
1379 ):
1380 offParam = iai.McBlock.skipSpacesAt(sParam, offParam, len(sParam));
1381 if offParam + 2 <= len(sParam) and sParam[offParam : offParam + 2] == '->':
1382 offParam = iai.McBlock.skipSpacesAt(sParam, offParam + 2, len(sParam));
1383 while offParam < len(sParam) and (sParam[offParam].isalnum() or sParam[offParam] in '_.'):
1384 offParam += 1;
1385
1386 # Skip constants, globals, types (casts), sizeof and macros.
1387 elif ( sRef.startswith('IEM_OP_PRF_')
1388 or sRef.startswith('IEM_ACCESS_')
1389 or sRef.startswith('IEMINT_')
1390 or sRef.startswith('X86_GREG_')
1391 or sRef.startswith('X86_SREG_')
1392 or sRef.startswith('X86_EFL_')
1393 or sRef.startswith('X86_FSW_')
1394 or sRef.startswith('X86_FCW_')
1395 or sRef.startswith('X86_XCPT_')
1396 or sRef.startswith('IEMMODE_')
1397 or sRef.startswith('IEM_F_')
1398 or sRef.startswith('IEM_CIMPL_F_')
1399 or sRef.startswith('g_')
1400 or sRef.startswith('iemAImpl_')
1401 or sRef.startswith('kIemNativeGstReg_')
1402 or sRef.startswith('RT_ARCH_VAL_')
1403 or sRef in ( 'int8_t', 'int16_t', 'int32_t', 'int64_t',
1404 'INT8_C', 'INT16_C', 'INT32_C', 'INT64_C',
1405 'uint8_t', 'uint16_t', 'uint32_t', 'uint64_t',
1406 'UINT8_C', 'UINT16_C', 'UINT32_C', 'UINT64_C',
1407 'UINT8_MAX', 'UINT16_MAX', 'UINT32_MAX', 'UINT64_MAX',
1408 'INT8_MAX', 'INT16_MAX', 'INT32_MAX', 'INT64_MAX',
1409 'INT8_MIN', 'INT16_MIN', 'INT32_MIN', 'INT64_MIN',
1410 'sizeof', 'NOREF', 'RT_NOREF', 'IEMMODE_64BIT',
1411 'RT_BIT_32', 'RT_BIT_64', 'true', 'false',
1412 'NIL_RTGCPTR',) ):
1413 pass;
1414
1415 # Skip certain macro invocations.
1416 # Any variable (non-field) and decoder fields in IEMCPU will need to be parameterized.
1417 elif ( ( '.' not in sRef
1418 and '-' not in sRef
1419 and sRef not in ('pVCpu', ) )
1420 or iai.McBlock.koReIemDecoderVars.search(sRef) is not None):
1421 self.aoParamRefs.append(ThreadedParamRef(sRef, self.analyzeReferenceToType(sRef),
1422 oStmt, iParam, offStart));
1423 # Number.
1424 elif ch.isdigit():
1425 if ( ch == '0'
1426 and offParam + 2 <= len(sParam)
1427 and sParam[offParam + 1] in 'xX'
1428 and sParam[offParam + 2] in self.ksHexDigits ):
1429 offParam += 2;
1430 while offParam < len(sParam) and sParam[offParam] in self.ksHexDigits:
1431 offParam += 1;
1432 else:
1433 while offParam < len(sParam) and sParam[offParam].isdigit():
1434 offParam += 1;
1435 # Comment?
1436 elif ( ch == '/'
1437 and offParam + 4 <= len(sParam)
1438 and sParam[offParam + 1] == '*'):
1439 offParam += 2;
1440 offNext = sParam.find('*/', offParam);
1441 if offNext < offParam:
1442 self.raiseProblem('Unable to find "*/" in "%s" ("%s")' % (sRef, oStmt.renderCode(),));
1443 offParam = offNext + 2;
1444 # Whatever else.
1445 else:
1446 offParam += 1;
1447
1448 # Traverse the branches of conditionals.
1449 if isinstance(oStmt, iai.McStmtCond):
1450 self.analyzeFindThreadedParamRefs(oStmt.aoIfBranch);
1451 self.analyzeFindThreadedParamRefs(oStmt.aoElseBranch);
1452 return True;
1453
1454 def analyzeVariation(self, aoStmts):
1455 """
1456 2nd part of the analysis, done on each variation.
1457
1458 The variations may differ in parameter requirements and will end up with
1459 slightly different MC sequences. Thus this is done on each individually.
1460
1461 Returns dummy True - raises exception on trouble.
1462 """
1463 # Now scan the code for variables and field references that needs to
1464 # be passed to the threaded function because they are related to the
1465 # instruction decoding.
1466 self.analyzeFindThreadedParamRefs(aoStmts);
1467 self.analyzeConsolidateThreadedParamRefs();
1468
1469 # Morph the statement stream for the block into what we'll be using in the threaded function.
1470 (self.aoStmtsForThreadedFunction, iParamRef) = self.analyzeMorphStmtForThreaded(aoStmts, {});
1471 if iParamRef != len(self.aoParamRefs):
1472 raise Exception('iParamRef=%s, expected %s!' % (iParamRef, len(self.aoParamRefs),));
1473
1474 return True;
1475
1476 def emitThreadedCallStmts(self, cchIndent, sCallVarNm = None):
1477 """
1478 Produces generic C++ statments that emits a call to the thread function
1479 variation and any subsequent checks that may be necessary after that.
1480
1481 The sCallVarNm is the name of the variable with the threaded function
1482 to call. This is for the case where all the variations have the same
1483 parameters and only the threaded function number differs.
1484 """
1485 aoStmts = [
1486 iai.McCppCall('IEM_MC2_BEGIN_EMIT_CALLS',
1487 ['1' if 'IEM_CIMPL_F_CHECK_IRQ_BEFORE' in self.oParent.dsCImplFlags else '0'],
1488 cchIndent = cchIndent), # Scope and a hook for various stuff.
1489 ];
1490
1491 # The call to the threaded function.
1492 asCallArgs = [ self.getIndexName() if not sCallVarNm else sCallVarNm, ];
1493 for iParam in range(self.cMinParams):
1494 asFrags = [];
1495 for aoRefs in self.dParamRefs.values():
1496 oRef = aoRefs[0];
1497 if oRef.iNewParam == iParam:
1498 sCast = '(uint64_t)'
1499 if oRef.sType in ('int8_t', 'int16_t', 'int32_t'): # Make sure these doesn't get sign-extended.
1500 sCast = '(uint64_t)(u' + oRef.sType + ')';
1501 if oRef.offNewParam == 0:
1502 asFrags.append(sCast + '(' + oRef.sOrgRef + ')');
1503 else:
1504 asFrags.append('(%s(%s) << %s)' % (sCast, oRef.sOrgRef, oRef.offNewParam));
1505 assert asFrags;
1506 asCallArgs.append(' | '.join(asFrags));
1507
1508 aoStmts.append(iai.McCppCall('IEM_MC2_EMIT_CALL_%s' % (len(asCallArgs) - 1,), asCallArgs, cchIndent = cchIndent));
1509
1510 # 2023-11-28: This has to be done AFTER the CIMPL call, so we have to
1511 # emit this mode check from the compilation loop. On the
1512 # plus side, this means we eliminate unnecessary call at
1513 # end of the TB. :-)
1514 ## For CIMPL stuff, we need to consult the associated IEM_CIMPL_F_XXX
1515 ## mask and maybe emit additional checks.
1516 #if ( 'IEM_CIMPL_F_MODE' in self.oParent.dsCImplFlags
1517 # or 'IEM_CIMPL_F_XCPT' in self.oParent.dsCImplFlags
1518 # or 'IEM_CIMPL_F_VMEXIT' in self.oParent.dsCImplFlags):
1519 # aoStmts.append(iai.McCppCall('IEM_MC2_EMIT_CALL_1', ( 'kIemThreadedFunc_BltIn_CheckMode', 'pVCpu->iem.s.fExec', ),
1520 # cchIndent = cchIndent));
1521
1522 sCImplFlags = ' | '.join(self.oParent.dsCImplFlags.keys());
1523 if not sCImplFlags:
1524 sCImplFlags = '0'
1525 aoStmts.append(iai.McCppCall('IEM_MC2_END_EMIT_CALLS', ( sCImplFlags, ), cchIndent = cchIndent)); # For closing the scope.
1526
1527 # Emit fEndTb = true or fTbBranched = true if any of the CIMPL flags
1528 # indicates we should do so.
1529 # Note! iemThreadedRecompilerMcDeferToCImpl0 duplicates work done here.
1530 asEndTbFlags = [];
1531 asTbBranchedFlags = [];
1532 for sFlag in self.oParent.dsCImplFlags:
1533 if self.kdCImplFlags[sFlag] is True:
1534 asEndTbFlags.append(sFlag);
1535 elif sFlag.startswith('IEM_CIMPL_F_BRANCH_'):
1536 asTbBranchedFlags.append(sFlag);
1537 if ( asTbBranchedFlags
1538 and ( 'IEM_CIMPL_F_BRANCH_CONDITIONAL' not in asTbBranchedFlags
1539 or self.sVariation not in self.kdVariationsWithConditionalNoJmp)):
1540 aoStmts.append(iai.McCppGeneric('iemThreadedSetBranched(pVCpu, %s);'
1541 % ((' | '.join(asTbBranchedFlags)).replace('IEM_CIMPL_F_BRANCH', 'IEMBRANCHED_F'),),
1542 cchIndent = cchIndent)); # Inline fn saves ~2 seconds for gcc 13/dbg (1m13s vs 1m15s).
1543 if asEndTbFlags:
1544 aoStmts.append(iai.McCppGeneric('pVCpu->iem.s.fEndTb = true; /* %s */' % (','.join(asEndTbFlags),),
1545 cchIndent = cchIndent));
1546
1547 if 'IEM_CIMPL_F_CHECK_IRQ_AFTER' in self.oParent.dsCImplFlags:
1548 aoStmts.append(iai.McCppGeneric('pVCpu->iem.s.cInstrTillIrqCheck = 0;', cchIndent = cchIndent));
1549
1550 return aoStmts;
1551
1552
1553class ThreadedFunction(object):
1554 """
1555 A threaded function.
1556 """
1557
1558 def __init__(self, oMcBlock: iai.McBlock) -> None:
1559 self.oMcBlock = oMcBlock # type: iai.McBlock
1560 # The remaining fields are only useful after analyze() has been called:
1561 ## Variations for this block. There is at least one.
1562 self.aoVariations = [] # type: List[ThreadedFunctionVariation]
1563 ## Variation dictionary containing the same as aoVariations.
1564 self.dVariations = {} # type: Dict[str, ThreadedFunctionVariation]
1565 ## Dictionary of local variables (IEM_MC_LOCAL[_CONST]) and call arguments (IEM_MC_ARG*).
1566 self.dVariables = {} # type: Dict[str, iai.McStmtVar]
1567 ## Dictionary with any IEM_CIMPL_F_XXX flags explicitly advertised in the code block
1568 ## and those determined by analyzeCodeOperation().
1569 self.dsCImplFlags = {} # type: Dict[str, bool]
1570 ## The unique sub-name for this threaded function.
1571 self.sSubName = '';
1572 #if oMcBlock.iInFunction > 0 or (oMcBlock.oInstruction and len(oMcBlock.oInstruction.aoMcBlocks) > 1):
1573 # self.sSubName = '_%s' % (oMcBlock.iInFunction);
1574
1575 @staticmethod
1576 def dummyInstance():
1577 """ Gets a dummy instance. """
1578 return ThreadedFunction(iai.McBlock('null', 999999999, 999999999,
1579 iai.DecoderFunction('null', 999999999, 'nil', ('','')), 999999999));
1580
1581 def hasWithFlagsCheckingAndClearingVariation(self):
1582 """
1583 Check if there is one or more with flags checking and clearing
1584 variations for this threaded function.
1585 """
1586 for sVarWithFlags in ThreadedFunctionVariation.kdVariationsWithEflagsCheckingAndClearing:
1587 if sVarWithFlags in self.dVariations:
1588 return True;
1589 return False;
1590
1591 #
1592 # Analysis and code morphing.
1593 #
1594
1595 def raiseProblem(self, sMessage):
1596 """ Raises a problem. """
1597 raise Exception('%s:%s: error: %s' % (self.oMcBlock.sSrcFile, self.oMcBlock.iBeginLine, sMessage, ));
1598
1599 def error(self, sMessage, oGenerator):
1600 """ Emits an error via the generator object, causing it to fail. """
1601 oGenerator.rawError('%s:%s: error: %s' % (self.oMcBlock.sSrcFile, self.oMcBlock.iBeginLine, sMessage, ));
1602
1603 def warning(self, sMessage):
1604 """ Emits a warning. """
1605 print('%s:%s: warning: %s' % (self.oMcBlock.sSrcFile, self.oMcBlock.iBeginLine, sMessage, ));
1606
1607 ## Used by analyzeAndAnnotateName for memory MC blocks.
1608 kdAnnotateNameMemStmts = {
1609 'IEM_MC_FETCH_MEM16_U8': '__mem8',
1610 'IEM_MC_FETCH_MEM32_U8': '__mem8',
1611 'IEM_MC_FETCH_MEM_D80': '__mem80',
1612 'IEM_MC_FETCH_MEM_I16': '__mem16',
1613 'IEM_MC_FETCH_MEM_I32': '__mem32',
1614 'IEM_MC_FETCH_MEM_I64': '__mem64',
1615 'IEM_MC_FETCH_MEM_R32': '__mem32',
1616 'IEM_MC_FETCH_MEM_R64': '__mem64',
1617 'IEM_MC_FETCH_MEM_R80': '__mem80',
1618 'IEM_MC_FETCH_MEM_U128': '__mem128',
1619 'IEM_MC_FETCH_MEM_U128_ALIGN_SSE': '__mem128',
1620 'IEM_MC_FETCH_MEM_U128_NO_AC': '__mem128',
1621 'IEM_MC_FETCH_MEM_U16': '__mem16',
1622 'IEM_MC_FETCH_MEM_U16_DISP': '__mem16',
1623 'IEM_MC_FETCH_MEM_U16_SX_U32': '__mem16sx32',
1624 'IEM_MC_FETCH_MEM_U16_SX_U64': '__mem16sx64',
1625 'IEM_MC_FETCH_MEM_U16_ZX_U32': '__mem16zx32',
1626 'IEM_MC_FETCH_MEM_U16_ZX_U64': '__mem16zx64',
1627 'IEM_MC_FETCH_MEM_U256': '__mem256',
1628 'IEM_MC_FETCH_MEM_U256_ALIGN_AVX': '__mem256',
1629 'IEM_MC_FETCH_MEM_U256_NO_AC': '__mem256',
1630 'IEM_MC_FETCH_MEM_U32': '__mem32',
1631 'IEM_MC_FETCH_MEM_U32_DISP': '__mem32',
1632 'IEM_MC_FETCH_MEM_U32_SX_U64': '__mem32sx64',
1633 'IEM_MC_FETCH_MEM_U32_ZX_U64': '__mem32zx64',
1634 'IEM_MC_FETCH_MEM_U64': '__mem64',
1635 'IEM_MC_FETCH_MEM_U64_ALIGN_U128': '__mem64',
1636 'IEM_MC_FETCH_MEM_U64_DISP': '__mem64',
1637 'IEM_MC_FETCH_MEM_U8': '__mem8',
1638 'IEM_MC_FETCH_MEM_U8_DISP': '__mem8',
1639 'IEM_MC_FETCH_MEM_U8_SX_U16': '__mem8sx16',
1640 'IEM_MC_FETCH_MEM_U8_SX_U32': '__mem8sx32',
1641 'IEM_MC_FETCH_MEM_U8_SX_U64': '__mem8sx64',
1642 'IEM_MC_FETCH_MEM_U8_ZX_U16': '__mem8zx16',
1643 'IEM_MC_FETCH_MEM_U8_ZX_U32': '__mem8zx32',
1644 'IEM_MC_FETCH_MEM_U8_ZX_U64': '__mem8zx64',
1645 'IEM_MC_FETCH_MEM_XMM': '__mem128',
1646 'IEM_MC_FETCH_MEM_XMM_ALIGN_SSE': '__mem128',
1647 'IEM_MC_FETCH_MEM_XMM_NO_AC': '__mem128',
1648 'IEM_MC_FETCH_MEM_XMM_U32': '__mem32',
1649 'IEM_MC_FETCH_MEM_XMM_U64': '__mem64',
1650 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128': '__mem128',
1651 'IEM_MC_FETCH_MEM_XMM_ALIGN_SSE_AND_XREG_XMM': '__mem128',
1652 'IEM_MC_FETCH_MEM_XMM_U32_AND_XREG_XMM': '__mem32',
1653 'IEM_MC_FETCH_MEM_XMM_U64_AND_XREG_XMM': '__mem64',
1654 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128_AND_RAX_RDX_U64': '__mem128',
1655 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128_AND_EAX_EDX_U32_SX_U64': '__mem128',
1656
1657 'IEM_MC_STORE_MEM_I16_CONST_BY_REF': '__mem16',
1658 'IEM_MC_STORE_MEM_I32_CONST_BY_REF': '__mem32',
1659 'IEM_MC_STORE_MEM_I64_CONST_BY_REF': '__mem64',
1660 'IEM_MC_STORE_MEM_I8_CONST_BY_REF': '__mem8',
1661 'IEM_MC_STORE_MEM_INDEF_D80_BY_REF': '__mem80',
1662 'IEM_MC_STORE_MEM_NEG_QNAN_R32_BY_REF': '__mem32',
1663 'IEM_MC_STORE_MEM_NEG_QNAN_R64_BY_REF': '__mem64',
1664 'IEM_MC_STORE_MEM_NEG_QNAN_R80_BY_REF': '__mem80',
1665 'IEM_MC_STORE_MEM_U128': '__mem128',
1666 'IEM_MC_STORE_MEM_U128_ALIGN_SSE': '__mem128',
1667 'IEM_MC_STORE_MEM_U128_NO_AC': '__mem128',
1668 'IEM_MC_STORE_MEM_U16': '__mem16',
1669 'IEM_MC_STORE_MEM_U16_CONST': '__mem16c',
1670 'IEM_MC_STORE_MEM_U256': '__mem256',
1671 'IEM_MC_STORE_MEM_U256_ALIGN_AVX': '__mem256',
1672 'IEM_MC_STORE_MEM_U256_NO_AC': '__mem256',
1673 'IEM_MC_STORE_MEM_U32': '__mem32',
1674 'IEM_MC_STORE_MEM_U32_CONST': '__mem32c',
1675 'IEM_MC_STORE_MEM_U64': '__mem64',
1676 'IEM_MC_STORE_MEM_U64_CONST': '__mem64c',
1677 'IEM_MC_STORE_MEM_U8': '__mem8',
1678 'IEM_MC_STORE_MEM_U8_CONST': '__mem8c',
1679
1680 'IEM_MC_MEM_MAP_D80_WO': '__mem80',
1681 'IEM_MC_MEM_MAP_I16_WO': '__mem16',
1682 'IEM_MC_MEM_MAP_I32_WO': '__mem32',
1683 'IEM_MC_MEM_MAP_I64_WO': '__mem64',
1684 'IEM_MC_MEM_MAP_R32_WO': '__mem32',
1685 'IEM_MC_MEM_MAP_R64_WO': '__mem64',
1686 'IEM_MC_MEM_MAP_R80_WO': '__mem80',
1687 'IEM_MC_MEM_MAP_U128_ATOMIC': '__mem128a',
1688 'IEM_MC_MEM_MAP_U128_RO': '__mem128',
1689 'IEM_MC_MEM_MAP_U128_RW': '__mem128',
1690 'IEM_MC_MEM_MAP_U128_WO': '__mem128',
1691 'IEM_MC_MEM_MAP_U16_ATOMIC': '__mem16a',
1692 'IEM_MC_MEM_MAP_U16_RO': '__mem16',
1693 'IEM_MC_MEM_MAP_U16_RW': '__mem16',
1694 'IEM_MC_MEM_MAP_U16_WO': '__mem16',
1695 'IEM_MC_MEM_MAP_U32_ATOMIC': '__mem32a',
1696 'IEM_MC_MEM_MAP_U32_RO': '__mem32',
1697 'IEM_MC_MEM_MAP_U32_RW': '__mem32',
1698 'IEM_MC_MEM_MAP_U32_WO': '__mem32',
1699 'IEM_MC_MEM_MAP_U64_ATOMIC': '__mem64a',
1700 'IEM_MC_MEM_MAP_U64_RO': '__mem64',
1701 'IEM_MC_MEM_MAP_U64_RW': '__mem64',
1702 'IEM_MC_MEM_MAP_U64_WO': '__mem64',
1703 'IEM_MC_MEM_MAP_U8_ATOMIC': '__mem8a',
1704 'IEM_MC_MEM_MAP_U8_RO': '__mem8',
1705 'IEM_MC_MEM_MAP_U8_RW': '__mem8',
1706 'IEM_MC_MEM_MAP_U8_WO': '__mem8',
1707 };
1708 ## Used by analyzeAndAnnotateName for non-memory MC blocks.
1709 kdAnnotateNameRegStmts = {
1710 'IEM_MC_FETCH_GREG_U8': '__greg8',
1711 'IEM_MC_FETCH_GREG_U8_ZX_U16': '__greg8zx16',
1712 'IEM_MC_FETCH_GREG_U8_ZX_U32': '__greg8zx32',
1713 'IEM_MC_FETCH_GREG_U8_ZX_U64': '__greg8zx64',
1714 'IEM_MC_FETCH_GREG_U8_SX_U16': '__greg8sx16',
1715 'IEM_MC_FETCH_GREG_U8_SX_U32': '__greg8sx32',
1716 'IEM_MC_FETCH_GREG_U8_SX_U64': '__greg8sx64',
1717 'IEM_MC_FETCH_GREG_U16': '__greg16',
1718 'IEM_MC_FETCH_GREG_U16_ZX_U32': '__greg16zx32',
1719 'IEM_MC_FETCH_GREG_U16_ZX_U64': '__greg16zx64',
1720 'IEM_MC_FETCH_GREG_U16_SX_U32': '__greg16sx32',
1721 'IEM_MC_FETCH_GREG_U16_SX_U64': '__greg16sx64',
1722 'IEM_MC_FETCH_GREG_U32': '__greg32',
1723 'IEM_MC_FETCH_GREG_U32_ZX_U64': '__greg32zx64',
1724 'IEM_MC_FETCH_GREG_U32_SX_U64': '__greg32sx64',
1725 'IEM_MC_FETCH_GREG_U64': '__greg64',
1726 'IEM_MC_FETCH_GREG_U64_ZX_U64': '__greg64zx64',
1727 'IEM_MC_FETCH_GREG_PAIR_U32': '__greg32',
1728 'IEM_MC_FETCH_GREG_PAIR_U64': '__greg64',
1729
1730 'IEM_MC_STORE_GREG_U8': '__greg8',
1731 'IEM_MC_STORE_GREG_U16': '__greg16',
1732 'IEM_MC_STORE_GREG_U32': '__greg32',
1733 'IEM_MC_STORE_GREG_U64': '__greg64',
1734 'IEM_MC_STORE_GREG_I64': '__greg64',
1735 'IEM_MC_STORE_GREG_U8_CONST': '__greg8c',
1736 'IEM_MC_STORE_GREG_U16_CONST': '__greg16c',
1737 'IEM_MC_STORE_GREG_U32_CONST': '__greg32c',
1738 'IEM_MC_STORE_GREG_U64_CONST': '__greg64c',
1739 'IEM_MC_STORE_GREG_PAIR_U32': '__greg32',
1740 'IEM_MC_STORE_GREG_PAIR_U64': '__greg64',
1741
1742 'IEM_MC_FETCH_SREG_U16': '__sreg16',
1743 'IEM_MC_FETCH_SREG_ZX_U32': '__sreg32',
1744 'IEM_MC_FETCH_SREG_ZX_U64': '__sreg64',
1745 'IEM_MC_FETCH_SREG_BASE_U64': '__sbase64',
1746 'IEM_MC_FETCH_SREG_BASE_U32': '__sbase32',
1747 'IEM_MC_STORE_SREG_BASE_U64': '__sbase64',
1748 'IEM_MC_STORE_SREG_BASE_U32': '__sbase32',
1749
1750 'IEM_MC_REF_GREG_U8': '__greg8',
1751 'IEM_MC_REF_GREG_U16': '__greg16',
1752 'IEM_MC_REF_GREG_U32': '__greg32',
1753 'IEM_MC_REF_GREG_U64': '__greg64',
1754 'IEM_MC_REF_GREG_U8_CONST': '__greg8',
1755 'IEM_MC_REF_GREG_U16_CONST': '__greg16',
1756 'IEM_MC_REF_GREG_U32_CONST': '__greg32',
1757 'IEM_MC_REF_GREG_U64_CONST': '__greg64',
1758 'IEM_MC_REF_GREG_I32': '__greg32',
1759 'IEM_MC_REF_GREG_I64': '__greg64',
1760 'IEM_MC_REF_GREG_I32_CONST': '__greg32',
1761 'IEM_MC_REF_GREG_I64_CONST': '__greg64',
1762
1763 'IEM_MC_STORE_FPUREG_R80_SRC_REF': '__fpu',
1764 'IEM_MC_REF_FPUREG': '__fpu',
1765
1766 'IEM_MC_FETCH_MREG_U64': '__mreg64',
1767 'IEM_MC_FETCH_MREG_U32': '__mreg32',
1768 'IEM_MC_FETCH_MREG_U16': '__mreg16',
1769 'IEM_MC_FETCH_MREG_U8': '__mreg8',
1770 'IEM_MC_STORE_MREG_U64': '__mreg64',
1771 'IEM_MC_STORE_MREG_U32': '__mreg32',
1772 'IEM_MC_STORE_MREG_U16': '__mreg16',
1773 'IEM_MC_STORE_MREG_U8': '__mreg8',
1774 'IEM_MC_STORE_MREG_U32_ZX_U64': '__mreg32zx64',
1775 'IEM_MC_REF_MREG_U64': '__mreg64',
1776 'IEM_MC_REF_MREG_U64_CONST': '__mreg64',
1777 'IEM_MC_REF_MREG_U32_CONST': '__mreg32',
1778
1779 'IEM_MC_CLEAR_XREG_U32_MASK': '__xreg32x4',
1780 'IEM_MC_FETCH_XREG_U128': '__xreg128',
1781 'IEM_MC_FETCH_XREG_XMM': '__xreg128',
1782 'IEM_MC_FETCH_XREG_U64': '__xreg64',
1783 'IEM_MC_FETCH_XREG_U32': '__xreg32',
1784 'IEM_MC_FETCH_XREG_U16': '__xreg16',
1785 'IEM_MC_FETCH_XREG_U8': '__xreg8',
1786 'IEM_MC_FETCH_XREG_PAIR_U128': '__xreg128p',
1787 'IEM_MC_FETCH_XREG_PAIR_XMM': '__xreg128p',
1788 'IEM_MC_FETCH_XREG_PAIR_U128_AND_RAX_RDX_U64': '__xreg128p',
1789 'IEM_MC_FETCH_XREG_PAIR_U128_AND_EAX_EDX_U32_SX_U64': '__xreg128p',
1790
1791 'IEM_MC_STORE_XREG_U32_U128': '__xreg32',
1792 'IEM_MC_STORE_XREG_U128': '__xreg128',
1793 'IEM_MC_STORE_XREG_XMM': '__xreg128',
1794 'IEM_MC_STORE_XREG_XMM_U32': '__xreg32',
1795 'IEM_MC_STORE_XREG_XMM_U64': '__xreg64',
1796 'IEM_MC_STORE_XREG_U64': '__xreg64',
1797 'IEM_MC_STORE_XREG_U64_ZX_U128': '__xreg64zx128',
1798 'IEM_MC_STORE_XREG_U32': '__xreg32',
1799 'IEM_MC_STORE_XREG_U16': '__xreg16',
1800 'IEM_MC_STORE_XREG_U8': '__xreg8',
1801 'IEM_MC_STORE_XREG_U32_ZX_U128': '__xreg32zx128',
1802 'IEM_MC_STORE_XREG_R32': '__xreg32',
1803 'IEM_MC_STORE_XREG_R64': '__xreg64',
1804 'IEM_MC_BROADCAST_XREG_U8_ZX_VLMAX': '__xreg8zx',
1805 'IEM_MC_BROADCAST_XREG_U16_ZX_VLMAX': '__xreg16zx',
1806 'IEM_MC_BROADCAST_XREG_U32_ZX_VLMAX': '__xreg32zx',
1807 'IEM_MC_BROADCAST_XREG_U64_ZX_VLMAX': '__xreg64zx',
1808 'IEM_MC_BROADCAST_XREG_U128_ZX_VLMAX': '__xreg128zx',
1809 'IEM_MC_REF_XREG_U128': '__xreg128',
1810 'IEM_MC_REF_XREG_U128_CONST': '__xreg128',
1811 'IEM_MC_REF_XREG_U32_CONST': '__xreg32',
1812 'IEM_MC_REF_XREG_U64_CONST': '__xreg64',
1813 'IEM_MC_REF_XREG_R32_CONST': '__xreg32',
1814 'IEM_MC_REF_XREG_R64_CONST': '__xreg64',
1815 'IEM_MC_REF_XREG_XMM_CONST': '__xreg128',
1816 'IEM_MC_COPY_XREG_U128': '__xreg128',
1817
1818 'IEM_MC_FETCH_YREG_U256': '__yreg256',
1819 'IEM_MC_FETCH_YREG_U128': '__yreg128',
1820 'IEM_MC_FETCH_YREG_U64': '__yreg64',
1821 'IEM_MC_FETCH_YREG_U32': '__yreg32',
1822 'IEM_MC_STORE_YREG_U128': '__yreg128',
1823 'IEM_MC_STORE_YREG_U32_ZX_VLMAX': '__yreg32zx',
1824 'IEM_MC_STORE_YREG_U64_ZX_VLMAX': '__yreg64zx',
1825 'IEM_MC_STORE_YREG_U128_ZX_VLMAX': '__yreg128zx',
1826 'IEM_MC_STORE_YREG_U256_ZX_VLMAX': '__yreg256zx',
1827 'IEM_MC_BROADCAST_YREG_U8_ZX_VLMAX': '__yreg8',
1828 'IEM_MC_BROADCAST_YREG_U16_ZX_VLMAX': '__yreg16',
1829 'IEM_MC_BROADCAST_YREG_U32_ZX_VLMAX': '__yreg32',
1830 'IEM_MC_BROADCAST_YREG_U64_ZX_VLMAX': '__yreg64',
1831 'IEM_MC_BROADCAST_YREG_U128_ZX_VLMAX': '__yreg128',
1832 'IEM_MC_REF_YREG_U128': '__yreg128',
1833 'IEM_MC_REF_YREG_U128_CONST': '__yreg128',
1834 'IEM_MC_REF_YREG_U64_CONST': '__yreg64',
1835 'IEM_MC_COPY_YREG_U256_ZX_VLMAX': '__yreg256zx',
1836 'IEM_MC_COPY_YREG_U128_ZX_VLMAX': '__yreg128zx',
1837 'IEM_MC_COPY_YREG_U64_ZX_VLMAX': '__yreg64zx',
1838 'IEM_MC_MERGE_YREG_U32_U96_ZX_VLMAX': '__yreg3296',
1839 'IEM_MC_MERGE_YREG_U64_U64_ZX_VLMAX': '__yreg6464',
1840 'IEM_MC_MERGE_YREG_U64HI_U64HI_ZX_VLMAX': '__yreg64hi64hi',
1841 'IEM_MC_MERGE_YREG_U64LO_U64LO_ZX_VLMAX': '__yreg64lo64lo',
1842 'IEM_MC_MERGE_YREG_U64LO_U64LOCAL_ZX_VLMAX':'__yreg64',
1843 'IEM_MC_MERGE_YREG_U64LOCAL_U64HI_ZX_VLMAX':'__yreg64',
1844 };
1845 kdAnnotateNameCallStmts = {
1846 'IEM_MC_CALL_CIMPL_0': '__cimpl',
1847 'IEM_MC_CALL_CIMPL_1': '__cimpl',
1848 'IEM_MC_CALL_CIMPL_2': '__cimpl',
1849 'IEM_MC_CALL_CIMPL_3': '__cimpl',
1850 'IEM_MC_CALL_CIMPL_4': '__cimpl',
1851 'IEM_MC_CALL_CIMPL_5': '__cimpl',
1852 'IEM_MC_CALL_CIMPL_6': '__cimpl',
1853 'IEM_MC_CALL_CIMPL_7': '__cimpl',
1854 'IEM_MC_DEFER_TO_CIMPL_0_RET': '__cimpl_defer',
1855 'IEM_MC_DEFER_TO_CIMPL_1_RET': '__cimpl_defer',
1856 'IEM_MC_DEFER_TO_CIMPL_2_RET': '__cimpl_defer',
1857 'IEM_MC_DEFER_TO_CIMPL_3_RET': '__cimpl_defer',
1858 'IEM_MC_DEFER_TO_CIMPL_4_RET': '__cimpl_defer',
1859 'IEM_MC_DEFER_TO_CIMPL_5_RET': '__cimpl_defer',
1860 'IEM_MC_DEFER_TO_CIMPL_6_RET': '__cimpl_defer',
1861 'IEM_MC_DEFER_TO_CIMPL_7_RET': '__cimpl_defer',
1862 'IEM_MC_CALL_VOID_AIMPL_0': '__aimpl',
1863 'IEM_MC_CALL_VOID_AIMPL_1': '__aimpl',
1864 'IEM_MC_CALL_VOID_AIMPL_2': '__aimpl',
1865 'IEM_MC_CALL_VOID_AIMPL_3': '__aimpl',
1866 'IEM_MC_CALL_VOID_AIMPL_4': '__aimpl',
1867 'IEM_MC_CALL_VOID_AIMPL_5': '__aimpl',
1868 'IEM_MC_CALL_AIMPL_0': '__aimpl_ret',
1869 'IEM_MC_CALL_AIMPL_1': '__aimpl_ret',
1870 'IEM_MC_CALL_AIMPL_2': '__aimpl_ret',
1871 'IEM_MC_CALL_AIMPL_3': '__aimpl_ret',
1872 'IEM_MC_CALL_AIMPL_4': '__aimpl_ret',
1873 'IEM_MC_CALL_AIMPL_5': '__aimpl_ret',
1874 'IEM_MC_CALL_AIMPL_6': '__aimpl_ret',
1875 'IEM_MC_CALL_VOID_AIMPL_6': '__aimpl_fpu',
1876 'IEM_MC_CALL_FPU_AIMPL_0': '__aimpl_fpu',
1877 'IEM_MC_CALL_FPU_AIMPL_1': '__aimpl_fpu',
1878 'IEM_MC_CALL_FPU_AIMPL_2': '__aimpl_fpu',
1879 'IEM_MC_CALL_FPU_AIMPL_3': '__aimpl_fpu',
1880 'IEM_MC_CALL_FPU_AIMPL_4': '__aimpl_fpu',
1881 'IEM_MC_CALL_FPU_AIMPL_5': '__aimpl_fpu',
1882 'IEM_MC_CALL_MMX_AIMPL_0': '__aimpl_mmx',
1883 'IEM_MC_CALL_MMX_AIMPL_1': '__aimpl_mmx',
1884 'IEM_MC_CALL_MMX_AIMPL_2': '__aimpl_mmx',
1885 'IEM_MC_CALL_MMX_AIMPL_3': '__aimpl_mmx',
1886 'IEM_MC_CALL_MMX_AIMPL_4': '__aimpl_mmx',
1887 'IEM_MC_CALL_MMX_AIMPL_5': '__aimpl_mmx',
1888 'IEM_MC_CALL_SSE_AIMPL_0': '__aimpl_sse',
1889 'IEM_MC_CALL_SSE_AIMPL_1': '__aimpl_sse',
1890 'IEM_MC_CALL_SSE_AIMPL_2': '__aimpl_sse',
1891 'IEM_MC_CALL_SSE_AIMPL_3': '__aimpl_sse',
1892 'IEM_MC_CALL_SSE_AIMPL_4': '__aimpl_sse',
1893 'IEM_MC_CALL_SSE_AIMPL_5': '__aimpl_sse',
1894 'IEM_MC_CALL_AVX_AIMPL_0': '__aimpl_avx',
1895 'IEM_MC_CALL_AVX_AIMPL_1': '__aimpl_avx',
1896 'IEM_MC_CALL_AVX_AIMPL_2': '__aimpl_avx',
1897 'IEM_MC_CALL_AVX_AIMPL_3': '__aimpl_avx',
1898 'IEM_MC_CALL_AVX_AIMPL_4': '__aimpl_avx',
1899 'IEM_MC_CALL_AVX_AIMPL_5': '__aimpl_avx',
1900 };
1901 def analyzeAndAnnotateName(self, aoStmts: List[iai.McStmt]):
1902 """
1903 Scans the statements and variation lists for clues about the threaded function,
1904 and sets self.sSubName if successfull.
1905 """
1906 # Operand base naming:
1907 dHits = {};
1908 cHits = iai.McStmt.countStmtsByName(aoStmts, self.kdAnnotateNameMemStmts, dHits);
1909 if cHits > 0:
1910 sStmtNm = sorted(dHits.keys())[-1]; # priority: STORE, MEM_MAP, FETCH.
1911 sName = self.kdAnnotateNameMemStmts[sStmtNm];
1912 else:
1913 cHits = iai.McStmt.countStmtsByName(aoStmts, self.kdAnnotateNameRegStmts, dHits);
1914 if cHits > 0:
1915 sStmtNm = sorted(dHits.keys())[-1]; # priority: STORE, MEM_MAP, FETCH.
1916 sName = self.kdAnnotateNameRegStmts[sStmtNm];
1917 else:
1918 # No op details, try name it by call type...
1919 cHits = iai.McStmt.countStmtsByName(aoStmts, self.kdAnnotateNameCallStmts, dHits);
1920 if cHits > 0:
1921 sStmtNm = sorted(dHits.keys())[-1]; # Not really necessary to sort, but simple this way.
1922 self.sSubName = self.kdAnnotateNameCallStmts[sStmtNm];
1923 return;
1924
1925 # Add call info if any:
1926 dHits = {};
1927 cHits = iai.McStmt.countStmtsByName(aoStmts, self.kdAnnotateNameCallStmts, dHits);
1928 if cHits > 0:
1929 sStmtNm = sorted(dHits.keys())[-1]; # Not really necessary to sort, but simple this way.
1930 sName += self.kdAnnotateNameCallStmts[sStmtNm][1:];
1931
1932 self.sSubName = sName;
1933 return;
1934
1935 def analyzeFindVariablesAndCallArgs(self, aoStmts: List[iai.McStmt]) -> bool:
1936 """ Scans the statements for MC variables and call arguments. """
1937 for oStmt in aoStmts:
1938 if isinstance(oStmt, iai.McStmtVar):
1939 if oStmt.sVarName in self.dVariables:
1940 raise Exception('Variable %s is defined more than once!' % (oStmt.sVarName,));
1941 self.dVariables[oStmt.sVarName] = oStmt.sVarName;
1942
1943 # There shouldn't be any variables or arguments declared inside if/
1944 # else blocks, but scan them too to be on the safe side.
1945 if isinstance(oStmt, iai.McStmtCond):
1946 #cBefore = len(self.dVariables);
1947 self.analyzeFindVariablesAndCallArgs(oStmt.aoIfBranch);
1948 self.analyzeFindVariablesAndCallArgs(oStmt.aoElseBranch);
1949 #if len(self.dVariables) != cBefore:
1950 # raise Exception('Variables/arguments defined in conditional branches!');
1951 return True;
1952
1953 def analyzeCodeOperation(self, aoStmts: List[iai.McStmt], dEflStmts, fSeenConditional = False) -> bool:
1954 """
1955 Analyzes the code looking clues as to additional side-effects.
1956
1957 Currently this is simply looking for branching and adding the relevant
1958 branch flags to dsCImplFlags. ASSUMES the caller pre-populates the
1959 dictionary with a copy of self.oMcBlock.dsCImplFlags.
1960
1961 This also sets McStmtCond.oIfBranchAnnotation & McStmtCond.oElseBranchAnnotation.
1962
1963 Returns annotation on return style.
1964 """
1965 sAnnotation = None;
1966 for oStmt in aoStmts:
1967 # Set IEM_IMPL_C_F_BRANCH if we see any branching MCs.
1968 if oStmt.sName.startswith('IEM_MC_SET_RIP'):
1969 assert not fSeenConditional;
1970 self.dsCImplFlags['IEM_CIMPL_F_BRANCH_INDIRECT'] = True;
1971 elif oStmt.sName.startswith('IEM_MC_REL_JMP'):
1972 self.dsCImplFlags['IEM_CIMPL_F_BRANCH_RELATIVE'] = True;
1973 if fSeenConditional:
1974 self.dsCImplFlags['IEM_CIMPL_F_BRANCH_CONDITIONAL'] = True;
1975
1976 # Check for CIMPL and AIMPL calls.
1977 if oStmt.sName.startswith('IEM_MC_CALL_'):
1978 if oStmt.sName.startswith('IEM_MC_CALL_CIMPL_'):
1979 self.dsCImplFlags['IEM_CIMPL_F_CALLS_CIMPL'] = True;
1980 elif ( oStmt.sName.startswith('IEM_MC_CALL_VOID_AIMPL_')
1981 or oStmt.sName.startswith('IEM_MC_CALL_AIMPL_')):
1982 self.dsCImplFlags['IEM_CIMPL_F_CALLS_AIMPL'] = True;
1983 elif ( oStmt.sName.startswith('IEM_MC_CALL_SSE_AIMPL_')
1984 or oStmt.sName.startswith('IEM_MC_CALL_MMX_AIMPL_')
1985 or oStmt.sName.startswith('IEM_MC_CALL_FPU_AIMPL_')):
1986 self.dsCImplFlags['IEM_CIMPL_F_CALLS_AIMPL_WITH_FXSTATE'] = True;
1987 elif oStmt.sName.startswith('IEM_MC_CALL_AVX_AIMPL_'):
1988 self.dsCImplFlags['IEM_CIMPL_F_CALLS_AIMPL_WITH_XSTATE'] = True;
1989 else:
1990 raise Exception('Unknown IEM_MC_CALL_* statement: %s' % (oStmt.sName,));
1991
1992 # Check for return statements.
1993 if oStmt.sName in ('IEM_MC_ADVANCE_RIP_AND_FINISH',):
1994 assert sAnnotation is None;
1995 sAnnotation = g_ksFinishAnnotation_Advance;
1996 elif oStmt.sName in ('IEM_MC_REL_JMP_S8_AND_FINISH', 'IEM_MC_REL_JMP_S16_AND_FINISH',
1997 'IEM_MC_REL_JMP_S32_AND_FINISH',):
1998 assert sAnnotation is None;
1999 sAnnotation = g_ksFinishAnnotation_RelJmp;
2000 elif oStmt.sName in ('IEM_MC_SET_RIP_U16_AND_FINISH', 'IEM_MC_SET_RIP_U32_AND_FINISH',
2001 'IEM_MC_SET_RIP_U64_AND_FINISH',):
2002 assert sAnnotation is None;
2003 sAnnotation = g_ksFinishAnnotation_SetJmp;
2004 elif oStmt.sName.startswith('IEM_MC_DEFER_TO_CIMPL_'):
2005 assert sAnnotation is None;
2006 sAnnotation = g_ksFinishAnnotation_DeferToCImpl;
2007
2008 # Collect MCs working on EFLAGS. Caller will check this.
2009 if oStmt.sName in ('IEM_MC_FETCH_EFLAGS', 'IEM_MC_FETCH_EFLAGS_U8', 'IEM_MC_COMMIT_EFLAGS',
2010 'IEM_MC_COMMIT_EFLAGS_OPT', 'IEM_MC_REF_EFLAGS', 'IEM_MC_ARG_LOCAL_EFLAGS', ):
2011 dEflStmts[oStmt.sName] = oStmt;
2012 elif isinstance(oStmt, iai.McStmtCall):
2013 if oStmt.sName in ('IEM_MC_CALL_CIMPL_0', 'IEM_MC_CALL_CIMPL_1', 'IEM_MC_CALL_CIMPL_2',
2014 'IEM_MC_CALL_CIMPL_3', 'IEM_MC_CALL_CIMPL_4', 'IEM_MC_CALL_CIMPL_5',):
2015 if ( oStmt.asParams[0].find('IEM_CIMPL_F_RFLAGS') >= 0
2016 or oStmt.asParams[0].find('IEM_CIMPL_F_STATUS_FLAGS') >= 0):
2017 dEflStmts[oStmt.sName] = oStmt;
2018
2019 # Process branches of conditionals recursively.
2020 if isinstance(oStmt, iai.McStmtCond):
2021 oStmt.oIfBranchAnnotation = self.analyzeCodeOperation(oStmt.aoIfBranch, dEflStmts, True);
2022 if oStmt.aoElseBranch:
2023 oStmt.oElseBranchAnnotation = self.analyzeCodeOperation(oStmt.aoElseBranch, dEflStmts, True);
2024
2025 return sAnnotation;
2026
2027 def analyzeThreadedFunction(self, oGenerator):
2028 """
2029 Analyzes the code, identifying the number of parameters it requires and such.
2030
2031 Returns dummy True - raises exception on trouble.
2032 """
2033
2034 #
2035 # Decode the block into a list/tree of McStmt objects.
2036 #
2037 aoStmts = self.oMcBlock.decode();
2038
2039 #
2040 # Check the block for errors before we proceed (will decode it).
2041 #
2042 asErrors = self.oMcBlock.check();
2043 if asErrors:
2044 raise Exception('\n'.join(['%s:%s: error: %s' % (self.oMcBlock.sSrcFile, self.oMcBlock.iBeginLine, sError, )
2045 for sError in asErrors]));
2046
2047 #
2048 # Scan the statements for local variables and call arguments (self.dVariables).
2049 #
2050 self.analyzeFindVariablesAndCallArgs(aoStmts);
2051
2052 #
2053 # Scan the code for IEM_CIMPL_F_ and other clues.
2054 #
2055 self.dsCImplFlags = self.oMcBlock.dsCImplFlags.copy();
2056 dEflStmts = {};
2057 self.analyzeCodeOperation(aoStmts, dEflStmts);
2058 if ( ('IEM_CIMPL_F_CALLS_CIMPL' in self.dsCImplFlags)
2059 + ('IEM_CIMPL_F_CALLS_AIMPL' in self.dsCImplFlags)
2060 + ('IEM_CIMPL_F_CALLS_AIMPL_WITH_FXSTATE' in self.dsCImplFlags)
2061 + ('IEM_CIMPL_F_CALLS_AIMPL_WITH_XSTATE' in self.dsCImplFlags) > 1):
2062 self.error('Mixing CIMPL/AIMPL/AIMPL_WITH_FXSTATE/AIMPL_WITH_XSTATE calls', oGenerator);
2063
2064 #
2065 # Analyse EFLAGS related MCs and @opflmodify and friends.
2066 #
2067 if dEflStmts:
2068 oInstruction = self.oMcBlock.oInstruction; # iai.Instruction
2069 if ( oInstruction is None
2070 or (oInstruction.asFlTest is None and oInstruction.asFlModify is None)):
2071 sMcNames = '+'.join(dEflStmts.keys());
2072 if len(dEflStmts) != 1 or not sMcNames.startswith('IEM_MC_CALL_CIMPL_'): # Hack for far calls
2073 self.error('Uses %s but has no @opflmodify, @opfltest or @opflclass with details!' % (sMcNames,), oGenerator);
2074 elif 'IEM_MC_COMMIT_EFLAGS' in dEflStmts or 'IEM_MC_COMMIT_EFLAGS_OPT' in dEflStmts:
2075 if not oInstruction.asFlModify:
2076 if oInstruction.sMnemonic not in [ 'not', ]:
2077 self.error('Uses IEM_MC_COMMIT_EFLAGS[_OPT] but has no flags in @opflmodify!', oGenerator);
2078 elif ( 'IEM_MC_CALL_CIMPL_0' in dEflStmts
2079 or 'IEM_MC_CALL_CIMPL_1' in dEflStmts
2080 or 'IEM_MC_CALL_CIMPL_2' in dEflStmts
2081 or 'IEM_MC_CALL_CIMPL_3' in dEflStmts
2082 or 'IEM_MC_CALL_CIMPL_4' in dEflStmts
2083 or 'IEM_MC_CALL_CIMPL_5' in dEflStmts ):
2084 if not oInstruction.asFlModify:
2085 self.error('Uses IEM_MC_CALL_CIMPL_x or IEM_MC_DEFER_TO_CIMPL_5_RET with IEM_CIMPL_F_STATUS_FLAGS '
2086 'or IEM_CIMPL_F_RFLAGS but has no flags in @opflmodify!', oGenerator);
2087 elif 'IEM_MC_REF_EFLAGS' not in dEflStmts:
2088 if not oInstruction.asFlTest:
2089 if oInstruction.sMnemonic not in [ 'not', ]:
2090 self.error('Expected @opfltest!', oGenerator);
2091 if oInstruction and oInstruction.asFlSet:
2092 for sFlag in oInstruction.asFlSet:
2093 if sFlag not in oInstruction.asFlModify:
2094 self.error('"%s" in @opflset but missing from @opflmodify (%s)!'
2095 % (sFlag, ', '.join(oInstruction.asFlModify)), oGenerator);
2096 if oInstruction and oInstruction.asFlClear:
2097 for sFlag in oInstruction.asFlClear:
2098 if sFlag not in oInstruction.asFlModify:
2099 self.error('"%s" in @opflclear but missing from @opflmodify (%s)!'
2100 % (sFlag, ', '.join(oInstruction.asFlModify)), oGenerator);
2101
2102 #
2103 # Create variations as needed.
2104 #
2105 if iai.McStmt.findStmtByNames(aoStmts,
2106 { 'IEM_MC_DEFER_TO_CIMPL_0_RET': True,
2107 'IEM_MC_DEFER_TO_CIMPL_1_RET': True,
2108 'IEM_MC_DEFER_TO_CIMPL_2_RET': True,
2109 'IEM_MC_DEFER_TO_CIMPL_3_RET': True, }):
2110 asVariations = (ThreadedFunctionVariation.ksVariation_Default,);
2111
2112 elif iai.McStmt.findStmtByNames(aoStmts, { 'IEM_MC_CALC_RM_EFF_ADDR' : True,
2113 'IEM_MC_FETCH_MEM_U8' : True, # mov_AL_Ob ++
2114 'IEM_MC_FETCH_MEM_U16' : True, # mov_rAX_Ov ++
2115 'IEM_MC_FETCH_MEM_U32' : True,
2116 'IEM_MC_FETCH_MEM_U64' : True,
2117 'IEM_MC_STORE_MEM_U8' : True, # mov_Ob_AL ++
2118 'IEM_MC_STORE_MEM_U16' : True, # mov_Ov_rAX ++
2119 'IEM_MC_STORE_MEM_U32' : True,
2120 'IEM_MC_STORE_MEM_U64' : True, }):
2121 if 'IEM_MC_F_64BIT' in self.oMcBlock.dsMcFlags:
2122 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressOnly64;
2123 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags and 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
2124 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressNot286Not64;
2125 elif 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
2126 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressNot286;
2127 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags:
2128 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressNot64;
2129 elif 'IEM_MC_F_ONLY_8086' in self.oMcBlock.dsMcFlags:
2130 asVariations = ThreadedFunctionVariation.kasVariationsOnlyPre386;
2131 else:
2132 asVariations = ThreadedFunctionVariation.kasVariationsWithAddress;
2133 else:
2134 if 'IEM_MC_F_64BIT' in self.oMcBlock.dsMcFlags:
2135 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressOnly64;
2136 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags and 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
2137 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressNot286Not64;
2138 elif 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
2139 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressNot286;
2140 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags:
2141 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressNot64;
2142 elif 'IEM_MC_F_ONLY_8086' in self.oMcBlock.dsMcFlags:
2143 asVariations = ThreadedFunctionVariation.kasVariationsOnlyPre386;
2144 else:
2145 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddress;
2146
2147 if ( 'IEM_CIMPL_F_BRANCH_CONDITIONAL' in self.dsCImplFlags
2148 and 'IEM_CIMPL_F_BRANCH_RELATIVE' in self.dsCImplFlags): # (latter to avoid iemOp_into)
2149 assert set(asVariations).issubset(ThreadedFunctionVariation.kasVariationsWithoutAddress), \
2150 '%s: vars=%s McFlags=%s' % (self.oMcBlock.oFunction.sName, asVariations, self.oMcBlock.dsMcFlags);
2151 asVariationsBase = asVariations;
2152 asVariations = [];
2153 for sVariation in asVariationsBase:
2154 asVariations.extend([sVariation + '_Jmp', sVariation + '_NoJmp']);
2155 assert set(asVariations).issubset(ThreadedFunctionVariation.kdVariationsWithConditional);
2156
2157 if not iai.McStmt.findStmtByNames(aoStmts,
2158 { 'IEM_MC_ADVANCE_RIP_AND_FINISH': True,
2159 'IEM_MC_REL_JMP_S8_AND_FINISH': True,
2160 'IEM_MC_REL_JMP_S16_AND_FINISH': True,
2161 'IEM_MC_REL_JMP_S32_AND_FINISH': True,
2162 'IEM_MC_SET_RIP_U16_AND_FINISH': True,
2163 'IEM_MC_SET_RIP_U32_AND_FINISH': True,
2164 'IEM_MC_SET_RIP_U64_AND_FINISH': True,
2165 }):
2166 asVariations = [sVariation for sVariation in asVariations
2167 if sVariation not in ThreadedFunctionVariation.kdVariationsWithEflagsCheckingAndClearing];
2168
2169 self.aoVariations = [ThreadedFunctionVariation(self, sVar) for sVar in asVariations];
2170
2171 # Dictionary variant of the list.
2172 self.dVariations = { oVar.sVariation: oVar for oVar in self.aoVariations };
2173
2174 #
2175 # Try annotate the threaded function name.
2176 #
2177 self.analyzeAndAnnotateName(aoStmts);
2178
2179 #
2180 # Continue the analysis on each variation.
2181 #
2182 for oVariation in self.aoVariations:
2183 oVariation.analyzeVariation(aoStmts);
2184
2185 return True;
2186
2187 ## Used by emitThreadedCallStmts.
2188 kdVariationsWithNeedForPrefixCheck = {
2189 ThreadedFunctionVariation.ksVariation_64_Addr32: True,
2190 ThreadedFunctionVariation.ksVariation_64f_Addr32: True,
2191 ThreadedFunctionVariation.ksVariation_64_FsGs: True,
2192 ThreadedFunctionVariation.ksVariation_64f_FsGs: True,
2193 ThreadedFunctionVariation.ksVariation_32_Addr16: True,
2194 ThreadedFunctionVariation.ksVariation_32f_Addr16: True,
2195 ThreadedFunctionVariation.ksVariation_32_Flat: True,
2196 ThreadedFunctionVariation.ksVariation_32f_Flat: True,
2197 ThreadedFunctionVariation.ksVariation_16_Addr32: True,
2198 ThreadedFunctionVariation.ksVariation_16f_Addr32: True,
2199 };
2200
2201 def emitThreadedCallStmts(self, sBranch = None): # pylint: disable=too-many-statements
2202 """
2203 Worker for morphInputCode that returns a list of statements that emits
2204 the call to the threaded functions for the block.
2205
2206 The sBranch parameter is used with conditional branches where we'll emit
2207 different threaded calls depending on whether we're in the jump-taken or
2208 no-jump code path.
2209 """
2210 # Special case for only default variation:
2211 if len(self.aoVariations) == 1 and self.aoVariations[0].sVariation == ThreadedFunctionVariation.ksVariation_Default:
2212 assert not sBranch;
2213 return self.aoVariations[0].emitThreadedCallStmts(0);
2214
2215 #
2216 # Case statement sub-class.
2217 #
2218 dByVari = self.dVariations;
2219 #fDbg = self.oMcBlock.sFunction == 'iemOpCommonPushSReg';
2220 class Case:
2221 def __init__(self, sCond, sVarNm = None):
2222 self.sCond = sCond;
2223 self.sVarNm = sVarNm;
2224 self.oVar = dByVari[sVarNm] if sVarNm else None;
2225 self.aoBody = self.oVar.emitThreadedCallStmts(8) if sVarNm else None;
2226
2227 def toCode(self):
2228 aoStmts = [ iai.McCppGeneric('case %s:' % (self.sCond), cchIndent = 4), ];
2229 if self.aoBody:
2230 aoStmts.extend(self.aoBody);
2231 aoStmts.append(iai.McCppGeneric('break;', cchIndent = 8));
2232 return aoStmts;
2233
2234 def toFunctionAssignment(self):
2235 aoStmts = [ iai.McCppGeneric('case %s:' % (self.sCond), cchIndent = 4), ];
2236 if self.aoBody:
2237 aoStmts.extend([
2238 iai.McCppGeneric('enmFunction = %s;' % (self.oVar.getIndexName(),), cchIndent = 8),
2239 iai.McCppGeneric('break;', cchIndent = 8),
2240 ]);
2241 return aoStmts;
2242
2243 def isSame(self, oThat):
2244 if not self.aoBody: # fall thru always matches.
2245 return True;
2246 if len(self.aoBody) != len(oThat.aoBody):
2247 #if fDbg: print('dbg: body len diff: %s vs %s' % (len(self.aoBody), len(oThat.aoBody),));
2248 return False;
2249 for iStmt, oStmt in enumerate(self.aoBody):
2250 oThatStmt = oThat.aoBody[iStmt] # type: iai.McStmt
2251 assert isinstance(oStmt, iai.McCppGeneric);
2252 assert not isinstance(oStmt, iai.McStmtCond);
2253 if isinstance(oStmt, iai.McStmtCond):
2254 return False;
2255 if oStmt.sName != oThatStmt.sName:
2256 #if fDbg: print('dbg: stmt #%s name: %s vs %s' % (iStmt, oStmt.sName, oThatStmt.sName,));
2257 return False;
2258 if len(oStmt.asParams) != len(oThatStmt.asParams):
2259 #if fDbg: print('dbg: stmt #%s param count: %s vs %s'
2260 # % (iStmt, len(oStmt.asParams), len(oThatStmt.asParams),));
2261 return False;
2262 for iParam, sParam in enumerate(oStmt.asParams):
2263 if ( sParam != oThatStmt.asParams[iParam]
2264 and ( iParam != 1
2265 or not isinstance(oStmt, iai.McCppCall)
2266 or not oStmt.asParams[0].startswith('IEM_MC2_EMIT_CALL_')
2267 or sParam != self.oVar.getIndexName()
2268 or oThatStmt.asParams[iParam] != oThat.oVar.getIndexName() )):
2269 #if fDbg: print('dbg: stmt #%s, param #%s: %s vs %s'
2270 # % (iStmt, iParam, sParam, oThatStmt.asParams[iParam],));
2271 return False;
2272 return True;
2273
2274 #
2275 # Determine what we're switch on.
2276 # This ASSUMES that (IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | IEM_F_MODE_CPUMODE_MASK) == 7!
2277 #
2278 fSimple = True;
2279 sSwitchValue = '(pVCpu->iem.s.fExec & (IEM_F_MODE_CPUMODE_MASK | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK))';
2280 if dByVari.keys() & self.kdVariationsWithNeedForPrefixCheck.keys():
2281 sSwitchValue += ' | (pVCpu->iem.s.enmEffAddrMode == (pVCpu->iem.s.fExec & IEM_F_MODE_CPUMODE_MASK) ? 0 : 8)';
2282 # Accesses via FS and GS and CS goes thru non-FLAT functions. (CS
2283 # is not writable in 32-bit mode (at least), thus the penalty mode
2284 # for any accesses via it (simpler this way).)
2285 sSwitchValue += ' | (pVCpu->iem.s.iEffSeg < X86_SREG_FS && pVCpu->iem.s.iEffSeg != X86_SREG_CS ? 0 : 16)';
2286 fSimple = False; # threaded functions.
2287 if dByVari.keys() & ThreadedFunctionVariation.kdVariationsWithEflagsCheckingAndClearing:
2288 sSwitchValue += ' | ((pVCpu->iem.s.fTbPrevInstr & (IEM_CIMPL_F_RFLAGS | IEM_CIMPL_F_INHIBIT_SHADOW)) || ' \
2289 + '(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_MASK) ? 32 : 0)';
2290
2291 #
2292 # Generate the case statements.
2293 #
2294 # pylintx: disable=x
2295 aoCases = [];
2296 if ThreadedFunctionVariation.ksVariation_64_Addr32 in dByVari:
2297 assert not fSimple and not sBranch;
2298 aoCases.extend([
2299 Case('IEMMODE_64BIT', ThrdFnVar.ksVariation_64),
2300 Case('IEMMODE_64BIT | 16', ThrdFnVar.ksVariation_64_FsGs),
2301 Case('IEMMODE_64BIT | 8 | 16', None), # fall thru
2302 Case('IEMMODE_64BIT | 8', ThrdFnVar.ksVariation_64_Addr32),
2303 ]);
2304 if ThreadedFunctionVariation.ksVariation_64f_Addr32 in dByVari:
2305 aoCases.extend([
2306 Case('IEMMODE_64BIT | 32', ThrdFnVar.ksVariation_64f),
2307 Case('IEMMODE_64BIT | 32 | 16', ThrdFnVar.ksVariation_64f_FsGs),
2308 Case('IEMMODE_64BIT | 32 | 8 | 16', None), # fall thru
2309 Case('IEMMODE_64BIT | 32 | 8', ThrdFnVar.ksVariation_64f_Addr32),
2310 ]);
2311 elif ThrdFnVar.ksVariation_64 in dByVari:
2312 assert fSimple and not sBranch;
2313 aoCases.append(Case('IEMMODE_64BIT', ThrdFnVar.ksVariation_64));
2314 if ThreadedFunctionVariation.ksVariation_64f in dByVari:
2315 aoCases.append(Case('IEMMODE_64BIT | 32', ThrdFnVar.ksVariation_64f));
2316 elif ThrdFnVar.ksVariation_64_Jmp in dByVari:
2317 assert fSimple and sBranch;
2318 aoCases.append(Case('IEMMODE_64BIT',
2319 ThrdFnVar.ksVariation_64_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_64_NoJmp));
2320 if ThreadedFunctionVariation.ksVariation_64f_Jmp in dByVari:
2321 aoCases.append(Case('IEMMODE_64BIT | 32',
2322 ThrdFnVar.ksVariation_64f_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_64f_NoJmp));
2323
2324 if ThrdFnVar.ksVariation_32_Addr16 in dByVari:
2325 assert not fSimple and not sBranch;
2326 aoCases.extend([
2327 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK', ThrdFnVar.ksVariation_32_Flat),
2328 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 16', None), # fall thru
2329 Case('IEMMODE_32BIT | 16', None), # fall thru
2330 Case('IEMMODE_32BIT', ThrdFnVar.ksVariation_32),
2331 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 8', None), # fall thru
2332 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 8 | 16',None), # fall thru
2333 Case('IEMMODE_32BIT | 8 | 16',None), # fall thru
2334 Case('IEMMODE_32BIT | 8', ThrdFnVar.ksVariation_32_Addr16),
2335 ]);
2336 if ThrdFnVar.ksVariation_32f_Addr16 in dByVari:
2337 aoCases.extend([
2338 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32', ThrdFnVar.ksVariation_32f_Flat),
2339 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32 | 16', None), # fall thru
2340 Case('IEMMODE_32BIT | 32 | 16', None), # fall thru
2341 Case('IEMMODE_32BIT | 32', ThrdFnVar.ksVariation_32f),
2342 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32 | 8', None), # fall thru
2343 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32 | 8 | 16',None), # fall thru
2344 Case('IEMMODE_32BIT | 32 | 8 | 16',None), # fall thru
2345 Case('IEMMODE_32BIT | 32 | 8', ThrdFnVar.ksVariation_32f_Addr16),
2346 ]);
2347 elif ThrdFnVar.ksVariation_32 in dByVari:
2348 assert fSimple and not sBranch;
2349 aoCases.extend([
2350 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK', None), # fall thru
2351 Case('IEMMODE_32BIT', ThrdFnVar.ksVariation_32),
2352 ]);
2353 if ThrdFnVar.ksVariation_32f in dByVari:
2354 aoCases.extend([
2355 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32', None), # fall thru
2356 Case('IEMMODE_32BIT | 32', ThrdFnVar.ksVariation_32f),
2357 ]);
2358 elif ThrdFnVar.ksVariation_32_Jmp in dByVari:
2359 assert fSimple and sBranch;
2360 aoCases.extend([
2361 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK', None), # fall thru
2362 Case('IEMMODE_32BIT',
2363 ThrdFnVar.ksVariation_32_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_32_NoJmp),
2364 ]);
2365 if ThrdFnVar.ksVariation_32f_Jmp in dByVari:
2366 aoCases.extend([
2367 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32', None), # fall thru
2368 Case('IEMMODE_32BIT | 32',
2369 ThrdFnVar.ksVariation_32f_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_32f_NoJmp),
2370 ]);
2371
2372 if ThrdFnVar.ksVariation_16_Addr32 in dByVari:
2373 assert not fSimple and not sBranch;
2374 aoCases.extend([
2375 Case('IEMMODE_16BIT | 16', None), # fall thru
2376 Case('IEMMODE_16BIT', ThrdFnVar.ksVariation_16),
2377 Case('IEMMODE_16BIT | 8 | 16', None), # fall thru
2378 Case('IEMMODE_16BIT | 8', ThrdFnVar.ksVariation_16_Addr32),
2379 ]);
2380 if ThrdFnVar.ksVariation_16f_Addr32 in dByVari:
2381 aoCases.extend([
2382 Case('IEMMODE_16BIT | 32 | 16', None), # fall thru
2383 Case('IEMMODE_16BIT | 32', ThrdFnVar.ksVariation_16f),
2384 Case('IEMMODE_16BIT | 32 | 8 | 16', None), # fall thru
2385 Case('IEMMODE_16BIT | 32 | 8', ThrdFnVar.ksVariation_16f_Addr32),
2386 ]);
2387 elif ThrdFnVar.ksVariation_16 in dByVari:
2388 assert fSimple and not sBranch;
2389 aoCases.append(Case('IEMMODE_16BIT', ThrdFnVar.ksVariation_16));
2390 if ThrdFnVar.ksVariation_16f in dByVari:
2391 aoCases.append(Case('IEMMODE_16BIT | 32', ThrdFnVar.ksVariation_16f));
2392 elif ThrdFnVar.ksVariation_16_Jmp in dByVari:
2393 assert fSimple and sBranch;
2394 aoCases.append(Case('IEMMODE_16BIT',
2395 ThrdFnVar.ksVariation_16_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_16_NoJmp));
2396 if ThrdFnVar.ksVariation_16f_Jmp in dByVari:
2397 aoCases.append(Case('IEMMODE_16BIT | 32',
2398 ThrdFnVar.ksVariation_16f_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_16f_NoJmp));
2399
2400
2401 if ThrdFnVar.ksVariation_16_Pre386 in dByVari:
2402 if not fSimple:
2403 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 16', None)); # fall thru
2404 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK', ThrdFnVar.ksVariation_16_Pre386));
2405 if ThrdFnVar.ksVariation_16f_Pre386 in dByVari: # should be nested under previous if, but line too long.
2406 if not fSimple:
2407 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32 | 16', None)); # fall thru
2408 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32', ThrdFnVar.ksVariation_16f_Pre386));
2409
2410 if ThrdFnVar.ksVariation_16_Pre386_Jmp in dByVari:
2411 assert fSimple and sBranch;
2412 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK',
2413 ThrdFnVar.ksVariation_16_Pre386_Jmp if sBranch == 'Jmp'
2414 else ThrdFnVar.ksVariation_16_Pre386_NoJmp));
2415 if ThrdFnVar.ksVariation_16f_Pre386_Jmp in dByVari:
2416 assert fSimple and sBranch;
2417 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32',
2418 ThrdFnVar.ksVariation_16f_Pre386_Jmp if sBranch == 'Jmp'
2419 else ThrdFnVar.ksVariation_16f_Pre386_NoJmp));
2420
2421 #
2422 # If the case bodies are all the same, except for the function called,
2423 # we can reduce the code size and hopefully compile time.
2424 #
2425 iFirstCaseWithBody = 0;
2426 while not aoCases[iFirstCaseWithBody].aoBody:
2427 iFirstCaseWithBody += 1
2428 fAllSameCases = True
2429 for iCase in range(iFirstCaseWithBody + 1, len(aoCases)):
2430 fAllSameCases = fAllSameCases and aoCases[iCase].isSame(aoCases[iFirstCaseWithBody]);
2431 #if fDbg: print('fAllSameCases=%s %s' % (fAllSameCases, self.oMcBlock.sFunction,));
2432 if fAllSameCases:
2433 aoStmts = [
2434 iai.McCppGeneric('IEMTHREADEDFUNCS enmFunction;'),
2435 iai.McCppGeneric('switch (%s)' % (sSwitchValue,)),
2436 iai.McCppGeneric('{'),
2437 ];
2438 for oCase in aoCases:
2439 aoStmts.extend(oCase.toFunctionAssignment());
2440 aoStmts.extend([
2441 iai.McCppGeneric('IEM_NOT_REACHED_DEFAULT_CASE_RET();', cchIndent = 4),
2442 iai.McCppGeneric('}'),
2443 ]);
2444 aoStmts.extend(dByVari[aoCases[iFirstCaseWithBody].sVarNm].emitThreadedCallStmts(0, 'enmFunction'));
2445
2446 else:
2447 #
2448 # Generate the generic switch statement.
2449 #
2450 aoStmts = [
2451 iai.McCppGeneric('switch (%s)' % (sSwitchValue,)),
2452 iai.McCppGeneric('{'),
2453 ];
2454 for oCase in aoCases:
2455 aoStmts.extend(oCase.toCode());
2456 aoStmts.extend([
2457 iai.McCppGeneric('IEM_NOT_REACHED_DEFAULT_CASE_RET();', cchIndent = 4),
2458 iai.McCppGeneric('}'),
2459 ]);
2460
2461 return aoStmts;
2462
2463 def morphInputCode(self, aoStmts, fIsConditional = False, fCallEmitted = False, cDepth = 0, sBranchAnnotation = None):
2464 """
2465 Adjusts (& copies) the statements for the input/decoder so it will emit
2466 calls to the right threaded functions for each block.
2467
2468 Returns list/tree of statements (aoStmts is not modified) and updated
2469 fCallEmitted status.
2470 """
2471 #print('McBlock at %s:%s' % (os.path.split(self.oMcBlock.sSrcFile)[1], self.oMcBlock.iBeginLine,));
2472 aoDecoderStmts = [];
2473
2474 for iStmt, oStmt in enumerate(aoStmts):
2475 # Copy the statement. Make a deep copy to make sure we've got our own
2476 # copies of all instance variables, even if a bit overkill at the moment.
2477 oNewStmt = copy.deepcopy(oStmt);
2478 aoDecoderStmts.append(oNewStmt);
2479 #print('oNewStmt %s %s' % (oNewStmt.sName, len(oNewStmt.asParams),));
2480 if oNewStmt.sName == 'IEM_MC_BEGIN' and self.dsCImplFlags:
2481 oNewStmt.asParams[1] = ' | '.join(sorted(self.dsCImplFlags.keys()));
2482
2483 # If we haven't emitted the threaded function call yet, look for
2484 # statements which it would naturally follow or preceed.
2485 if not fCallEmitted:
2486 if not oStmt.isCppStmt():
2487 if ( oStmt.sName.startswith('IEM_MC_MAYBE_RAISE_') \
2488 or (oStmt.sName.endswith('_AND_FINISH') and oStmt.sName.startswith('IEM_MC_'))
2489 or oStmt.sName.startswith('IEM_MC_CALL_CIMPL_')
2490 or oStmt.sName.startswith('IEM_MC_DEFER_TO_CIMPL_')
2491 or oStmt.sName in ('IEM_MC_RAISE_DIVIDE_ERROR',)):
2492 aoDecoderStmts.pop();
2493 if not fIsConditional:
2494 aoDecoderStmts.extend(self.emitThreadedCallStmts());
2495 elif oStmt.sName == 'IEM_MC_ADVANCE_RIP_AND_FINISH':
2496 aoDecoderStmts.extend(self.emitThreadedCallStmts('NoJmp'));
2497 else:
2498 assert oStmt.sName in { 'IEM_MC_REL_JMP_S8_AND_FINISH': True,
2499 'IEM_MC_REL_JMP_S16_AND_FINISH': True,
2500 'IEM_MC_REL_JMP_S32_AND_FINISH': True, };
2501 aoDecoderStmts.extend(self.emitThreadedCallStmts('Jmp'));
2502 aoDecoderStmts.append(oNewStmt);
2503 fCallEmitted = True;
2504
2505 elif iai.g_dMcStmtParsers[oStmt.sName][2]:
2506 # This is for Jmp/NoJmp with loopne and friends which modifies state other than RIP.
2507 if not sBranchAnnotation:
2508 self.raiseProblem('Modifying state before emitting calls! %s' % (oStmt.sName,));
2509 assert fIsConditional;
2510 aoDecoderStmts.pop();
2511 if sBranchAnnotation == g_ksFinishAnnotation_Advance:
2512 assert iai.McStmt.findStmtByNames(aoStmts[iStmt:], {'IEM_MC_ADVANCE_RIP_AND_FINISH':1,})
2513 aoDecoderStmts.extend(self.emitThreadedCallStmts('NoJmp'));
2514 elif sBranchAnnotation == g_ksFinishAnnotation_RelJmp:
2515 assert iai.McStmt.findStmtByNames(aoStmts[iStmt:],
2516 { 'IEM_MC_REL_JMP_S8_AND_FINISH': 1,
2517 'IEM_MC_REL_JMP_S16_AND_FINISH': 1,
2518 'IEM_MC_REL_JMP_S32_AND_FINISH': 1, });
2519 aoDecoderStmts.extend(self.emitThreadedCallStmts('Jmp'));
2520 else:
2521 self.raiseProblem('Modifying state before emitting calls! %s' % (oStmt.sName,));
2522 aoDecoderStmts.append(oNewStmt);
2523 fCallEmitted = True;
2524
2525 elif ( not fIsConditional
2526 and oStmt.fDecode
2527 and ( oStmt.asParams[0].find('IEMOP_HLP_DONE_') >= 0
2528 or oStmt.asParams[0].find('IEMOP_HLP_DECODED_') >= 0)):
2529 aoDecoderStmts.extend(self.emitThreadedCallStmts());
2530 fCallEmitted = True;
2531
2532 # Process branches of conditionals recursively.
2533 if isinstance(oStmt, iai.McStmtCond):
2534 (oNewStmt.aoIfBranch, fCallEmitted1) = self.morphInputCode(oStmt.aoIfBranch, fIsConditional,
2535 fCallEmitted, cDepth + 1, oStmt.oIfBranchAnnotation);
2536 if oStmt.aoElseBranch:
2537 (oNewStmt.aoElseBranch, fCallEmitted2) = self.morphInputCode(oStmt.aoElseBranch, fIsConditional,
2538 fCallEmitted, cDepth + 1,
2539 oStmt.oElseBranchAnnotation);
2540 else:
2541 fCallEmitted2 = False;
2542 fCallEmitted = fCallEmitted or (fCallEmitted1 and fCallEmitted2);
2543
2544 if not fCallEmitted and cDepth == 0:
2545 self.raiseProblem('Unable to insert call to threaded function.');
2546
2547 return (aoDecoderStmts, fCallEmitted);
2548
2549
2550 def generateInputCode(self):
2551 """
2552 Modifies the input code.
2553 """
2554 cchIndent = (self.oMcBlock.cchIndent + 3) // 4 * 4;
2555
2556 if len(self.oMcBlock.aoStmts) == 1:
2557 # IEM_MC_DEFER_TO_CIMPL_X_RET - need to wrap in {} to make it safe to insert into random code.
2558 sCode = ' ' * cchIndent + 'pVCpu->iem.s.fTbCurInstr = ';
2559 if self.dsCImplFlags:
2560 sCode += ' | '.join(sorted(self.dsCImplFlags.keys())) + ';\n';
2561 else:
2562 sCode += '0;\n';
2563 sCode += iai.McStmt.renderCodeForList(self.morphInputCode(self.oMcBlock.aoStmts)[0],
2564 cchIndent = cchIndent).replace('\n', ' /* gen */\n', 1);
2565 sIndent = ' ' * (min(cchIndent, 2) - 2);
2566 sCode = sIndent + '{\n' + sCode + sIndent + '}\n';
2567 return sCode;
2568
2569 # IEM_MC_BEGIN/END block
2570 assert len(self.oMcBlock.asLines) > 2, "asLines=%s" % (self.oMcBlock.asLines,);
2571 fIsConditional = ( 'IEM_CIMPL_F_BRANCH_CONDITIONAL' in self.dsCImplFlags
2572 and 'IEM_CIMPL_F_BRANCH_RELATIVE' in self.dsCImplFlags); # (latter to avoid iemOp_into)
2573 return iai.McStmt.renderCodeForList(self.morphInputCode(self.oMcBlock.aoStmts, fIsConditional)[0],
2574 cchIndent = cchIndent).replace('\n', ' /* gen */\n', 1);
2575
2576# Short alias for ThreadedFunctionVariation.
2577ThrdFnVar = ThreadedFunctionVariation;
2578
2579
2580class IEMThreadedGenerator(object):
2581 """
2582 The threaded code generator & annotator.
2583 """
2584
2585 def __init__(self):
2586 self.aoThreadedFuncs = [] # type: List[ThreadedFunction]
2587 self.oOptions = None # type: argparse.Namespace
2588 self.aoParsers = [] # type: List[IEMAllInstPython.SimpleParser]
2589 self.aidxFirstFunctions = [] # type: List[int] ##< Runs parallel to aoParser giving the index of the first function.
2590 self.cErrors = 0;
2591
2592 #
2593 # Error reporting.
2594 #
2595
2596 def rawError(self, sCompleteMessage):
2597 """ Output a raw error and increment the error counter. """
2598 print(sCompleteMessage, file = sys.stderr);
2599 self.cErrors += 1;
2600 return False;
2601
2602 #
2603 # Processing.
2604 #
2605
2606 def processInputFiles(self, sHostArch, fNativeRecompilerEnabled):
2607 """
2608 Process the input files.
2609 """
2610
2611 # Parse the files.
2612 self.aoParsers = iai.parseFiles(self.oOptions.asInFiles, sHostArch);
2613
2614 # Create threaded functions for the MC blocks.
2615 self.aoThreadedFuncs = [ThreadedFunction(oMcBlock) for oMcBlock in iai.g_aoMcBlocks];
2616
2617 # Analyze the threaded functions.
2618 dRawParamCounts = {};
2619 dMinParamCounts = {};
2620 for oThreadedFunction in self.aoThreadedFuncs:
2621 oThreadedFunction.analyzeThreadedFunction(self);
2622 for oVariation in oThreadedFunction.aoVariations:
2623 dRawParamCounts[len(oVariation.dParamRefs)] = dRawParamCounts.get(len(oVariation.dParamRefs), 0) + 1;
2624 dMinParamCounts[oVariation.cMinParams] = dMinParamCounts.get(oVariation.cMinParams, 0) + 1;
2625 print('debug: param count distribution, raw and optimized:', file = sys.stderr);
2626 for cCount in sorted({cBits: True for cBits in list(dRawParamCounts.keys()) + list(dMinParamCounts.keys())}.keys()):
2627 print('debug: %s params: %4s raw, %4s min'
2628 % (cCount, dRawParamCounts.get(cCount, 0), dMinParamCounts.get(cCount, 0)),
2629 file = sys.stderr);
2630
2631 # Do another pass over the threaded functions to settle the name suffix.
2632 iThreadedFn = 0;
2633 while iThreadedFn < len(self.aoThreadedFuncs):
2634 oFunction = self.aoThreadedFuncs[iThreadedFn].oMcBlock.oFunction;
2635 assert oFunction;
2636 iThreadedFnNext = iThreadedFn + 1;
2637 dSubNames = { self.aoThreadedFuncs[iThreadedFn].sSubName: 1 };
2638 while ( iThreadedFnNext < len(self.aoThreadedFuncs)
2639 and self.aoThreadedFuncs[iThreadedFnNext].oMcBlock.oFunction == oFunction):
2640 dSubNames[self.aoThreadedFuncs[iThreadedFnNext].sSubName] = 1;
2641 iThreadedFnNext += 1;
2642 if iThreadedFnNext - iThreadedFn > len(dSubNames):
2643 iSubName = 0;
2644 while iThreadedFn + iSubName < iThreadedFnNext:
2645 self.aoThreadedFuncs[iThreadedFn + iSubName].sSubName += '_%s' % (iSubName,);
2646 iSubName += 1;
2647 iThreadedFn = iThreadedFnNext;
2648
2649 # Populate aidxFirstFunctions. This is ASSUMING that
2650 # g_aoMcBlocks/self.aoThreadedFuncs are in self.aoParsers order.
2651 iThreadedFunction = 0;
2652 oThreadedFunction = self.getThreadedFunctionByIndex(0);
2653 self.aidxFirstFunctions = [];
2654 for oParser in self.aoParsers:
2655 self.aidxFirstFunctions.append(iThreadedFunction);
2656
2657 while oThreadedFunction.oMcBlock.sSrcFile == oParser.sSrcFile:
2658 iThreadedFunction += 1;
2659 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
2660
2661 # Analyze the threaded functions and their variations for native recompilation.
2662 if fNativeRecompilerEnabled:
2663 ian.analyzeThreadedFunctionsForNativeRecomp(self.aoThreadedFuncs, sHostArch);
2664
2665 # Gather arguments + variable statistics for the MC blocks.
2666 cMaxArgs = 0;
2667 cMaxVars = 0;
2668 cMaxVarsAndArgs = 0;
2669 cbMaxArgs = 0;
2670 cbMaxVars = 0;
2671 cbMaxVarsAndArgs = 0;
2672 for oThreadedFunction in self.aoThreadedFuncs:
2673 if oThreadedFunction.oMcBlock.aoLocals or oThreadedFunction.oMcBlock.aoArgs:
2674 # Counts.
2675 cMaxVars = max(cMaxVars, len(oThreadedFunction.oMcBlock.aoLocals));
2676 cMaxArgs = max(cMaxArgs, len(oThreadedFunction.oMcBlock.aoArgs));
2677 cMaxVarsAndArgs = max(cMaxVarsAndArgs,
2678 len(oThreadedFunction.oMcBlock.aoLocals) + len(oThreadedFunction.oMcBlock.aoArgs));
2679 if cMaxVarsAndArgs > 9:
2680 raise Exception('%s potentially uses too many variables / args: %u, max 10 - %u vars and %u args'
2681 % (oThreadedFunction.oMcBlock.oFunction.sName, cMaxVarsAndArgs,
2682 len(oThreadedFunction.oMcBlock.aoLocals), len(oThreadedFunction.oMcBlock.aoArgs),));
2683 # Calc stack allocation size:
2684 cbArgs = 0;
2685 for oArg in oThreadedFunction.oMcBlock.aoArgs:
2686 cbArgs += (getTypeBitCount(oArg.sType) + 63) // 64 * 8;
2687 cbVars = 0;
2688 for oVar in oThreadedFunction.oMcBlock.aoLocals:
2689 cbVars += (getTypeBitCount(oVar.sType) + 63) // 64 * 8;
2690 cbMaxVars = max(cbMaxVars, cbVars);
2691 cbMaxArgs = max(cbMaxArgs, cbArgs);
2692 cbMaxVarsAndArgs = max(cbMaxVarsAndArgs, cbVars + cbArgs);
2693 if cbMaxVarsAndArgs >= 0xc0:
2694 raise Exception('%s potentially uses too much stack: cbMaxVars=%#x cbMaxArgs=%#x'
2695 % (oThreadedFunction.oMcBlock.oFunction.sName, cbMaxVars, cbMaxArgs,));
2696
2697 print('debug: max vars+args: %u bytes / %u; max vars: %u bytes / %u; max args: %u bytes / %u'
2698 % (cbMaxVarsAndArgs, cMaxVarsAndArgs, cbMaxVars, cMaxVars, cbMaxArgs, cMaxArgs,), file = sys.stderr);
2699
2700 if self.cErrors > 0:
2701 print('fatal error: %u error%s during processing. Details above.'
2702 % (self.cErrors, 's' if self.cErrors > 1 else '',), file = sys.stderr);
2703 return False;
2704 return True;
2705
2706 #
2707 # Output
2708 #
2709
2710 def generateLicenseHeader(self):
2711 """
2712 Returns the lines for a license header.
2713 """
2714 return [
2715 '/*',
2716 ' * Autogenerated by $Id: IEMAllThrdPython.py 104099 2024-03-28 01:42:59Z vboxsync $ ',
2717 ' * Do not edit!',
2718 ' */',
2719 '',
2720 '/*',
2721 ' * Copyright (C) 2023-' + str(datetime.date.today().year) + ' Oracle and/or its affiliates.',
2722 ' *',
2723 ' * This file is part of VirtualBox base platform packages, as',
2724 ' * available from https://www.virtualbox.org.',
2725 ' *',
2726 ' * This program is free software; you can redistribute it and/or',
2727 ' * modify it under the terms of the GNU General Public License',
2728 ' * as published by the Free Software Foundation, in version 3 of the',
2729 ' * License.',
2730 ' *',
2731 ' * This program is distributed in the hope that it will be useful, but',
2732 ' * WITHOUT ANY WARRANTY; without even the implied warranty of',
2733 ' * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU',
2734 ' * General Public License for more details.',
2735 ' *',
2736 ' * You should have received a copy of the GNU General Public License',
2737 ' * along with this program; if not, see <https://www.gnu.org/licenses>.',
2738 ' *',
2739 ' * The contents of this file may alternatively be used under the terms',
2740 ' * of the Common Development and Distribution License Version 1.0',
2741 ' * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included',
2742 ' * in the VirtualBox distribution, in which case the provisions of the',
2743 ' * CDDL are applicable instead of those of the GPL.',
2744 ' *',
2745 ' * You may elect to license modified versions of this file under the',
2746 ' * terms and conditions of either the GPL or the CDDL or both.',
2747 ' *',
2748 ' * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0',
2749 ' */',
2750 '',
2751 '',
2752 '',
2753 ];
2754
2755 ## List of built-in threaded functions with user argument counts and
2756 ## whether it has a native recompiler implementation.
2757 katBltIns = (
2758 ( 'Nop', 0, True ),
2759 ( 'LogCpuState', 0, True ),
2760
2761 ( 'DeferToCImpl0', 2, True ),
2762 ( 'CheckIrq', 0, True ),
2763 ( 'CheckMode', 1, True ),
2764 ( 'CheckHwInstrBps', 0, False ),
2765 ( 'CheckCsLim', 1, True ),
2766
2767 ( 'CheckCsLimAndOpcodes', 3, True ),
2768 ( 'CheckOpcodes', 3, True ),
2769 ( 'CheckOpcodesConsiderCsLim', 3, True ),
2770
2771 ( 'CheckCsLimAndPcAndOpcodes', 3, True ),
2772 ( 'CheckPcAndOpcodes', 3, True ),
2773 ( 'CheckPcAndOpcodesConsiderCsLim', 3, True ),
2774
2775 ( 'CheckCsLimAndOpcodesAcrossPageLoadingTlb', 3, True ),
2776 ( 'CheckOpcodesAcrossPageLoadingTlb', 3, True ),
2777 ( 'CheckOpcodesAcrossPageLoadingTlbConsiderCsLim', 2, True ),
2778
2779 ( 'CheckCsLimAndOpcodesLoadingTlb', 3, True ),
2780 ( 'CheckOpcodesLoadingTlb', 3, True ),
2781 ( 'CheckOpcodesLoadingTlbConsiderCsLim', 3, True ),
2782
2783 ( 'CheckCsLimAndOpcodesOnNextPageLoadingTlb', 2, True ),
2784 ( 'CheckOpcodesOnNextPageLoadingTlb', 2, True ),
2785 ( 'CheckOpcodesOnNextPageLoadingTlbConsiderCsLim', 2, True ),
2786
2787 ( 'CheckCsLimAndOpcodesOnNewPageLoadingTlb', 2, True ),
2788 ( 'CheckOpcodesOnNewPageLoadingTlb', 2, True ),
2789 ( 'CheckOpcodesOnNewPageLoadingTlbConsiderCsLim', 2, True ),
2790 );
2791
2792 def generateThreadedFunctionsHeader(self, oOut, _):
2793 """
2794 Generates the threaded functions header file.
2795 Returns success indicator.
2796 """
2797
2798 asLines = self.generateLicenseHeader();
2799
2800 # Generate the threaded function table indexes.
2801 asLines += [
2802 'typedef enum IEMTHREADEDFUNCS',
2803 '{',
2804 ' kIemThreadedFunc_Invalid = 0,',
2805 '',
2806 ' /*',
2807 ' * Predefined',
2808 ' */',
2809 ];
2810 asLines += [' kIemThreadedFunc_BltIn_%s,' % (sFuncNm,) for sFuncNm, _, _ in self.katBltIns];
2811
2812 iThreadedFunction = 1 + len(self.katBltIns);
2813 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
2814 asLines += [
2815 '',
2816 ' /*',
2817 ' * Variation: ' + ThreadedFunctionVariation.kdVariationNames[sVariation] + '',
2818 ' */',
2819 ];
2820 for oThreadedFunction in self.aoThreadedFuncs:
2821 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
2822 if oVariation:
2823 iThreadedFunction += 1;
2824 oVariation.iEnumValue = iThreadedFunction;
2825 asLines.append(' ' + oVariation.getIndexName() + ',');
2826 asLines += [
2827 ' kIemThreadedFunc_End',
2828 '} IEMTHREADEDFUNCS;',
2829 '',
2830 ];
2831
2832 # Prototype the function table.
2833 asLines += [
2834 'extern const PFNIEMTHREADEDFUNC g_apfnIemThreadedFunctions[kIemThreadedFunc_End];',
2835 'extern uint8_t const g_acIemThreadedFunctionUsedArgs[kIemThreadedFunc_End];',
2836 '#if defined(IN_RING3) || defined(LOG_ENABLED)',
2837 'extern const char * const g_apszIemThreadedFunctions[kIemThreadedFunc_End];',
2838 '#endif',
2839 '#if defined(IN_RING3)',
2840 'extern const char * const g_apszIemThreadedFunctionStats[kIemThreadedFunc_End];',
2841 '#endif',
2842 ];
2843
2844 oOut.write('\n'.join(asLines));
2845 return True;
2846
2847 ksBitsToIntMask = {
2848 1: "UINT64_C(0x1)",
2849 2: "UINT64_C(0x3)",
2850 4: "UINT64_C(0xf)",
2851 8: "UINT64_C(0xff)",
2852 16: "UINT64_C(0xffff)",
2853 32: "UINT64_C(0xffffffff)",
2854 };
2855
2856 def generateFunctionParameterUnpacking(self, oVariation, oOut, asParams, uNoRefLevel = 0):
2857 """
2858 Outputs code for unpacking parameters.
2859 This is shared by the threaded and native code generators.
2860 """
2861 aasVars = [];
2862 for aoRefs in oVariation.dParamRefs.values():
2863 oRef = aoRefs[0];
2864 if oRef.sType[0] != 'P':
2865 cBits = g_kdTypeInfo[oRef.sType][0];
2866 sType = g_kdTypeInfo[oRef.sType][2];
2867 else:
2868 cBits = 64;
2869 sType = oRef.sType;
2870
2871 sTypeDecl = sType + ' const';
2872
2873 if cBits == 64:
2874 assert oRef.offNewParam == 0;
2875 if sType == 'uint64_t':
2876 sUnpack = '%s;' % (asParams[oRef.iNewParam],);
2877 else:
2878 sUnpack = '(%s)%s;' % (sType, asParams[oRef.iNewParam],);
2879 elif oRef.offNewParam == 0:
2880 sUnpack = '(%s)(%s & %s);' % (sType, asParams[oRef.iNewParam], self.ksBitsToIntMask[cBits]);
2881 else:
2882 sUnpack = '(%s)((%s >> %s) & %s);' \
2883 % (sType, asParams[oRef.iNewParam], oRef.offNewParam, self.ksBitsToIntMask[cBits]);
2884
2885 sComment = '/* %s - %s ref%s */' % (oRef.sOrgRef, len(aoRefs), 's' if len(aoRefs) != 1 else '',);
2886
2887 aasVars.append([ '%s:%02u' % (oRef.iNewParam, oRef.offNewParam),
2888 sTypeDecl, oRef.sNewName, sUnpack, sComment ]);
2889 acchVars = [0, 0, 0, 0, 0];
2890 for asVar in aasVars:
2891 for iCol, sStr in enumerate(asVar):
2892 acchVars[iCol] = max(acchVars[iCol], len(sStr));
2893 sFmt = ' %%-%ss %%-%ss = %%-%ss %%s\n' % (acchVars[1], acchVars[2], acchVars[3]);
2894 for asVar in sorted(aasVars):
2895 oOut.write(sFmt % (asVar[1], asVar[2], asVar[3], asVar[4],));
2896
2897 if uNoRefLevel > 0 and aasVars:
2898 if uNoRefLevel > 1:
2899 # level 2: Everything. This is used by liveness.
2900 oOut.write(' ');
2901 for asVar in sorted(aasVars):
2902 oOut.write(' RT_NOREF_PV(%s);' % (asVar[2],));
2903 oOut.write('\n');
2904 else:
2905 # level 1: Only pfnXxxx variables. This is used by native.
2906 for asVar in sorted(aasVars):
2907 if asVar[2].startswith('pfn'):
2908 oOut.write(' RT_NOREF_PV(%s);\n' % (asVar[2],));
2909 return True;
2910
2911 kasThreadedParamNames = ('uParam0', 'uParam1', 'uParam2');
2912 def generateThreadedFunctionsSource(self, oOut, _):
2913 """
2914 Generates the threaded functions source file.
2915 Returns success indicator.
2916 """
2917
2918 asLines = self.generateLicenseHeader();
2919 oOut.write('\n'.join(asLines));
2920
2921 #
2922 # Emit the function definitions.
2923 #
2924 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
2925 sVarName = ThreadedFunctionVariation.kdVariationNames[sVariation];
2926 oOut.write( '\n'
2927 + '\n'
2928 + '\n'
2929 + '\n'
2930 + '/*' + '*' * 128 + '\n'
2931 + '* Variation: ' + sVarName + ' ' * (129 - len(sVarName) - 15) + '*\n'
2932 + '*' * 128 + '*/\n');
2933
2934 for oThreadedFunction in self.aoThreadedFuncs:
2935 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
2936 if oVariation:
2937 oMcBlock = oThreadedFunction.oMcBlock;
2938
2939 # Function header
2940 oOut.write( '\n'
2941 + '\n'
2942 + '/**\n'
2943 + ' * #%u: %s at line %s offset %s in %s%s\n'
2944 % (oVariation.iEnumValue, oMcBlock.sFunction, oMcBlock.iBeginLine, oMcBlock.offBeginLine,
2945 os.path.split(oMcBlock.sSrcFile)[1],
2946 ' (macro expansion)' if oMcBlock.iBeginLine == oMcBlock.iEndLine else '')
2947 + ' */\n'
2948 + 'static IEM_DECL_IEMTHREADEDFUNC_DEF(' + oVariation.getThreadedFunctionName() + ')\n'
2949 + '{\n');
2950
2951 # Unpack parameters.
2952 self.generateFunctionParameterUnpacking(oVariation, oOut, self.kasThreadedParamNames);
2953
2954 # RT_NOREF for unused parameters.
2955 if oVariation.cMinParams < g_kcThreadedParams:
2956 oOut.write(' RT_NOREF(' + ', '.join(self.kasThreadedParamNames[oVariation.cMinParams:]) + ');\n');
2957
2958 # Now for the actual statements.
2959 oOut.write(iai.McStmt.renderCodeForList(oVariation.aoStmtsForThreadedFunction, cchIndent = 4));
2960
2961 oOut.write('}\n');
2962
2963
2964 #
2965 # Generate the output tables in parallel.
2966 #
2967 asFuncTable = [
2968 '/**',
2969 ' * Function pointer table.',
2970 ' */',
2971 'PFNIEMTHREADEDFUNC const g_apfnIemThreadedFunctions[kIemThreadedFunc_End] =',
2972 '{',
2973 ' /*Invalid*/ NULL,',
2974 ];
2975 asArgCntTab = [
2976 '/**',
2977 ' * Argument count table.',
2978 ' */',
2979 'uint8_t const g_acIemThreadedFunctionUsedArgs[kIemThreadedFunc_End] =',
2980 '{',
2981 ' 0, /*Invalid*/',
2982 ];
2983 asNameTable = [
2984 '/**',
2985 ' * Function name table.',
2986 ' */',
2987 'const char * const g_apszIemThreadedFunctions[kIemThreadedFunc_End] =',
2988 '{',
2989 ' "Invalid",',
2990 ];
2991 asStatTable = [
2992 '/**',
2993 ' * Function statistics name table.',
2994 ' */',
2995 'const char * const g_apszIemThreadedFunctionStats[kIemThreadedFunc_End] =',
2996 '{',
2997 ' NULL,',
2998 ];
2999 aasTables = (asFuncTable, asArgCntTab, asNameTable, asStatTable,);
3000
3001 for asTable in aasTables:
3002 asTable.extend((
3003 '',
3004 ' /*',
3005 ' * Predefined.',
3006 ' */',
3007 ));
3008 for sFuncNm, cArgs, _ in self.katBltIns:
3009 asFuncTable.append(' iemThreadedFunc_BltIn_%s,' % (sFuncNm,));
3010 asArgCntTab.append(' %d, /*BltIn_%s*/' % (cArgs, sFuncNm,));
3011 asNameTable.append(' "BltIn_%s",' % (sFuncNm,));
3012 asStatTable.append(' "BltIn/%s",' % (sFuncNm,));
3013
3014 iThreadedFunction = 1 + len(self.katBltIns);
3015 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
3016 for asTable in aasTables:
3017 asTable.extend((
3018 '',
3019 ' /*',
3020 ' * Variation: ' + ThreadedFunctionVariation.kdVariationNames[sVariation],
3021 ' */',
3022 ));
3023 for oThreadedFunction in self.aoThreadedFuncs:
3024 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
3025 if oVariation:
3026 iThreadedFunction += 1;
3027 assert oVariation.iEnumValue == iThreadedFunction;
3028 sName = oVariation.getThreadedFunctionName();
3029 asFuncTable.append(' /*%4u*/ %s,' % (iThreadedFunction, sName,));
3030 asNameTable.append(' /*%4u*/ "%s",' % (iThreadedFunction, sName,));
3031 asArgCntTab.append(' /*%4u*/ %d, /*%s*/' % (iThreadedFunction, oVariation.cMinParams, sName,));
3032 asStatTable.append(' "%s",' % (oVariation.getThreadedFunctionStatisticsName(),));
3033
3034 for asTable in aasTables:
3035 asTable.append('};');
3036
3037 #
3038 # Output the tables.
3039 #
3040 oOut.write( '\n'
3041 + '\n');
3042 oOut.write('\n'.join(asFuncTable));
3043 oOut.write( '\n'
3044 + '\n'
3045 + '\n');
3046 oOut.write('\n'.join(asArgCntTab));
3047 oOut.write( '\n'
3048 + '\n'
3049 + '#if defined(IN_RING3) || defined(LOG_ENABLED)\n');
3050 oOut.write('\n'.join(asNameTable));
3051 oOut.write( '\n'
3052 + '#endif /* IN_RING3 || LOG_ENABLED */\n'
3053 + '\n'
3054 + '\n'
3055 + '#if defined(IN_RING3)\n');
3056 oOut.write('\n'.join(asStatTable));
3057 oOut.write( '\n'
3058 + '#endif /* IN_RING3 */\n');
3059
3060 return True;
3061
3062 def generateNativeFunctionsHeader(self, oOut, _):
3063 """
3064 Generates the native recompiler functions header file.
3065 Returns success indicator.
3066 """
3067 if not self.oOptions.fNativeRecompilerEnabled:
3068 return True;
3069
3070 asLines = self.generateLicenseHeader();
3071
3072 # Prototype the function table.
3073 asLines += [
3074 'extern const PFNIEMNATIVERECOMPFUNC g_apfnIemNativeRecompileFunctions[kIemThreadedFunc_End];',
3075 'extern const PFNIEMNATIVELIVENESSFUNC g_apfnIemNativeLivenessFunctions[kIemThreadedFunc_End];',
3076 '',
3077 ];
3078
3079 # Emit indicators as to which of the builtin functions have a native
3080 # recompiler function and which not. (We only really need this for
3081 # kIemThreadedFunc_BltIn_CheckMode, but do all just for simplicity.)
3082 for atBltIn in self.katBltIns:
3083 if atBltIn[1]:
3084 asLines.append('#define IEMNATIVE_WITH_BLTIN_' + atBltIn[0].upper())
3085 else:
3086 asLines.append('#define IEMNATIVE_WITHOUT_BLTIN_' + atBltIn[0].upper())
3087
3088 # Emit prototypes for the builtin functions we use in tables.
3089 asLines += [
3090 '',
3091 '/* Prototypes for built-in functions used in the above tables. */',
3092 ];
3093 for sFuncNm, _, fHaveRecompFunc in self.katBltIns:
3094 if fHaveRecompFunc:
3095 asLines += [
3096 'IEM_DECL_IEMNATIVERECOMPFUNC_PROTO( iemNativeRecompFunc_BltIn_%s);' % (sFuncNm,),
3097 'IEM_DECL_IEMNATIVELIVENESSFUNC_PROTO(iemNativeLivenessFunc_BltIn_%s);' % (sFuncNm,),
3098 ];
3099
3100 # Emit prototypes for table function.
3101 asLines += [
3102 '',
3103 '#ifdef IEMNATIVE_INCL_TABLE_FUNCTION_PROTOTYPES'
3104 ]
3105 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
3106 sVarName = ThreadedFunctionVariation.kdVariationNames[sVariation];
3107 asLines += [
3108 '',
3109 '/* Variation: ' + sVarName + ' */',
3110 ];
3111 for oThreadedFunction in self.aoThreadedFuncs:
3112 oVariation = oThreadedFunction.dVariations.get(sVariation, None) # type: ThreadedFunctionVariation
3113 if oVariation and oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
3114 asLines.append('IEM_DECL_IEMNATIVERECOMPFUNC_PROTO(' + oVariation.getNativeFunctionName() + ');');
3115 asLines += [
3116 '',
3117 '#endif /* IEMNATIVE_INCL_TABLE_FUNCTION_PROTOTYPES */',
3118 ]
3119
3120 oOut.write('\n'.join(asLines));
3121 return True;
3122
3123 def generateNativeFunctionsSource(self, oOut, idxPart):
3124 """
3125 Generates the native recompiler functions source file.
3126 Returns success indicator.
3127 """
3128 cParts = 4;
3129 assert(idxPart in range(cParts));
3130 if not self.oOptions.fNativeRecompilerEnabled:
3131 return True;
3132
3133 #
3134 # The file header.
3135 #
3136 oOut.write('\n'.join(self.generateLicenseHeader()));
3137
3138 #
3139 # Emit the functions.
3140 #
3141 # The files are split up by threaded variation as that's the simplest way to
3142 # do it, even if the distribution isn't entirely even (ksVariation_Default
3143 # only has the defer to cimpl bits and the pre-386 variants will naturally
3144 # have fewer instructions).
3145 #
3146 cVariationsPerFile = len(ThreadedFunctionVariation.kasVariationsEmitOrder) // cParts;
3147 idxFirstVar = idxPart * cVariationsPerFile;
3148 idxEndVar = idxFirstVar + cVariationsPerFile;
3149 if idxPart + 1 >= cParts:
3150 idxEndVar = len(ThreadedFunctionVariation.kasVariationsEmitOrder);
3151 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder[idxFirstVar:idxEndVar]:
3152 sVarName = ThreadedFunctionVariation.kdVariationNames[sVariation];
3153 oOut.write( '\n'
3154 + '\n'
3155 + '\n'
3156 + '\n'
3157 + '/*' + '*' * 128 + '\n'
3158 + '* Variation: ' + sVarName + ' ' * (129 - len(sVarName) - 15) + '*\n'
3159 + '*' * 128 + '*/\n');
3160
3161 for oThreadedFunction in self.aoThreadedFuncs:
3162 oVariation = oThreadedFunction.dVariations.get(sVariation, None) # type: ThreadedFunctionVariation
3163 if oVariation and oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
3164 oMcBlock = oThreadedFunction.oMcBlock;
3165
3166 # Function header
3167 oOut.write( '\n'
3168 + '\n'
3169 + '/**\n'
3170 + ' * #%u: %s at line %s offset %s in %s%s\n'
3171 % (oVariation.iEnumValue, oMcBlock.sFunction, oMcBlock.iBeginLine, oMcBlock.offBeginLine,
3172 os.path.split(oMcBlock.sSrcFile)[1],
3173 ' (macro expansion)' if oMcBlock.iBeginLine == oMcBlock.iEndLine else '')
3174 + ' */\n'
3175 + 'IEM_DECL_IEMNATIVERECOMPFUNC_DEF(' + oVariation.getNativeFunctionName() + ')\n'
3176 + '{\n');
3177
3178 # Unpack parameters.
3179 self.generateFunctionParameterUnpacking(oVariation, oOut,
3180 ('pCallEntry->auParams[0]',
3181 'pCallEntry->auParams[1]',
3182 'pCallEntry->auParams[2]',),
3183 uNoRefLevel = 1);
3184
3185 # Now for the actual statements.
3186 oOut.write(oVariation.oNativeRecomp.renderCode(cchIndent = 4));
3187
3188 oOut.write('}\n');
3189
3190 #
3191 # Output the function table if this is the first file.
3192 #
3193 if idxPart == 0:
3194 oOut.write( '\n'
3195 + '\n'
3196 + '/*\n'
3197 + ' * Function table running parallel to g_apfnIemThreadedFunctions and friends.\n'
3198 + ' */\n'
3199 + 'const PFNIEMNATIVERECOMPFUNC g_apfnIemNativeRecompileFunctions[kIemThreadedFunc_End] =\n'
3200 + '{\n'
3201 + ' /*Invalid*/ NULL,'
3202 + '\n'
3203 + ' /*\n'
3204 + ' * Predefined.\n'
3205 + ' */\n'
3206 );
3207 for sFuncNm, _, fHaveRecompFunc in self.katBltIns:
3208 if fHaveRecompFunc:
3209 oOut.write(' iemNativeRecompFunc_BltIn_%s,\n' % (sFuncNm,))
3210 else:
3211 oOut.write(' NULL, /*BltIn_%s*/\n' % (sFuncNm,))
3212
3213 iThreadedFunction = 1 + len(self.katBltIns);
3214 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
3215 oOut.write( ' /*\n'
3216 + ' * Variation: ' + ThreadedFunctionVariation.kdVariationNames[sVariation] + '\n'
3217 + ' */\n');
3218 for oThreadedFunction in self.aoThreadedFuncs:
3219 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
3220 if oVariation:
3221 iThreadedFunction += 1;
3222 assert oVariation.iEnumValue == iThreadedFunction;
3223 sName = oVariation.getNativeFunctionName();
3224 if oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
3225 oOut.write(' /*%4u*/ %s,\n' % (iThreadedFunction, sName,));
3226 else:
3227 oOut.write(' /*%4u*/ NULL /*%s*/,\n' % (iThreadedFunction, sName,));
3228
3229 oOut.write( '};\n');
3230
3231 oOut.write('\n');
3232 return True;
3233
3234 def generateNativeLivenessSource(self, oOut, _):
3235 """
3236 Generates the native recompiler liveness analysis functions source file.
3237 Returns success indicator.
3238 """
3239 if not self.oOptions.fNativeRecompilerEnabled:
3240 return True;
3241
3242 #
3243 # The file header.
3244 #
3245 oOut.write('\n'.join(self.generateLicenseHeader()));
3246
3247 #
3248 # Emit the functions.
3249 #
3250 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
3251 sVarName = ThreadedFunctionVariation.kdVariationNames[sVariation];
3252 oOut.write( '\n'
3253 + '\n'
3254 + '\n'
3255 + '\n'
3256 + '/*' + '*' * 128 + '\n'
3257 + '* Variation: ' + sVarName + ' ' * (129 - len(sVarName) - 15) + '*\n'
3258 + '*' * 128 + '*/\n');
3259
3260 for oThreadedFunction in self.aoThreadedFuncs:
3261 oVariation = oThreadedFunction.dVariations.get(sVariation, None) # type: ThreadedFunctionVariation
3262 if oVariation and oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
3263 oMcBlock = oThreadedFunction.oMcBlock;
3264
3265 # Function header
3266 oOut.write( '\n'
3267 + '\n'
3268 + '/**\n'
3269 + ' * #%u: %s at line %s offset %s in %s%s\n'
3270 % (oVariation.iEnumValue, oMcBlock.sFunction, oMcBlock.iBeginLine, oMcBlock.offBeginLine,
3271 os.path.split(oMcBlock.sSrcFile)[1],
3272 ' (macro expansion)' if oMcBlock.iBeginLine == oMcBlock.iEndLine else '')
3273 + ' */\n'
3274 + 'static IEM_DECL_IEMNATIVELIVENESSFUNC_DEF(' + oVariation.getLivenessFunctionName() + ')\n'
3275 + '{\n');
3276
3277 # Unpack parameters.
3278 self.generateFunctionParameterUnpacking(oVariation, oOut,
3279 ('pCallEntry->auParams[0]',
3280 'pCallEntry->auParams[1]',
3281 'pCallEntry->auParams[2]',),
3282 uNoRefLevel = 2);
3283
3284 # Now for the actual statements.
3285 oOut.write(oVariation.oNativeRecomp.renderCode(cchIndent = 4));
3286
3287 oOut.write('}\n');
3288
3289 #
3290 # Output the function table.
3291 #
3292 oOut.write( '\n'
3293 + '\n'
3294 + '/*\n'
3295 + ' * Liveness analysis function table running parallel to g_apfnIemThreadedFunctions and friends.\n'
3296 + ' */\n'
3297 + 'const PFNIEMNATIVELIVENESSFUNC g_apfnIemNativeLivenessFunctions[kIemThreadedFunc_End] =\n'
3298 + '{\n'
3299 + ' /*Invalid*/ NULL,'
3300 + '\n'
3301 + ' /*\n'
3302 + ' * Predefined.\n'
3303 + ' */\n'
3304 );
3305 for sFuncNm, _, fHaveRecompFunc in self.katBltIns:
3306 if fHaveRecompFunc:
3307 oOut.write(' iemNativeLivenessFunc_BltIn_%s,\n' % (sFuncNm,))
3308 else:
3309 oOut.write(' NULL, /*BltIn_%s*/\n' % (sFuncNm,))
3310
3311 iThreadedFunction = 1 + len(self.katBltIns);
3312 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
3313 oOut.write( ' /*\n'
3314 + ' * Variation: ' + ThreadedFunctionVariation.kdVariationNames[sVariation] + '\n'
3315 + ' */\n');
3316 for oThreadedFunction in self.aoThreadedFuncs:
3317 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
3318 if oVariation:
3319 iThreadedFunction += 1;
3320 assert oVariation.iEnumValue == iThreadedFunction;
3321 sName = oVariation.getLivenessFunctionName();
3322 if oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
3323 oOut.write(' /*%4u*/ %s,\n' % (iThreadedFunction, sName,));
3324 else:
3325 oOut.write(' /*%4u*/ NULL /*%s*/,\n' % (iThreadedFunction, sName,));
3326
3327 oOut.write( '};\n'
3328 + '\n');
3329 return True;
3330
3331
3332 def getThreadedFunctionByIndex(self, idx):
3333 """
3334 Returns a ThreadedFunction object for the given index. If the index is
3335 out of bounds, a dummy is returned.
3336 """
3337 if idx < len(self.aoThreadedFuncs):
3338 return self.aoThreadedFuncs[idx];
3339 return ThreadedFunction.dummyInstance();
3340
3341 def generateModifiedInput(self, oOut, idxFile):
3342 """
3343 Generates the combined modified input source/header file.
3344 Returns success indicator.
3345 """
3346 #
3347 # File header and assert assumptions.
3348 #
3349 oOut.write('\n'.join(self.generateLicenseHeader()));
3350 oOut.write('AssertCompile((IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | IEM_F_MODE_CPUMODE_MASK) == 7);\n');
3351
3352 #
3353 # Iterate all parsers (input files) and output the ones related to the
3354 # file set given by idxFile.
3355 #
3356 for idxParser, oParser in enumerate(self.aoParsers): # type: int, IEMAllInstPython.SimpleParser
3357 # Is this included in the file set?
3358 sSrcBaseFile = os.path.basename(oParser.sSrcFile).lower();
3359 fInclude = -1;
3360 for aoInfo in iai.g_aaoAllInstrFilesAndDefaultMapAndSet:
3361 if sSrcBaseFile == aoInfo[0].lower():
3362 fInclude = aoInfo[2] in (-1, idxFile);
3363 break;
3364 if fInclude is not True:
3365 assert fInclude is False;
3366 continue;
3367
3368 # Output it.
3369 oOut.write("\n\n/* ****** BEGIN %s ******* */\n" % (oParser.sSrcFile,));
3370
3371 iThreadedFunction = self.aidxFirstFunctions[idxParser];
3372 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
3373 iLine = 0;
3374 while iLine < len(oParser.asLines):
3375 sLine = oParser.asLines[iLine];
3376 iLine += 1; # iBeginLine and iEndLine are 1-based.
3377
3378 # Can we pass it thru?
3379 if ( iLine not in [oThreadedFunction.oMcBlock.iBeginLine, oThreadedFunction.oMcBlock.iEndLine]
3380 or oThreadedFunction.oMcBlock.sSrcFile != oParser.sSrcFile):
3381 oOut.write(sLine);
3382 #
3383 # Single MC block. Just extract it and insert the replacement.
3384 #
3385 elif oThreadedFunction.oMcBlock.iBeginLine != oThreadedFunction.oMcBlock.iEndLine:
3386 assert ( (sLine.count('IEM_MC_') - sLine.count('IEM_MC_F_') == 1)
3387 or oThreadedFunction.oMcBlock.iMacroExp == iai.McBlock.kiMacroExp_Partial), 'sLine="%s"' % (sLine,);
3388 oOut.write(sLine[:oThreadedFunction.oMcBlock.offBeginLine]);
3389 sModified = oThreadedFunction.generateInputCode().strip();
3390 oOut.write(sModified);
3391
3392 iLine = oThreadedFunction.oMcBlock.iEndLine;
3393 sLine = oParser.asLines[iLine - 1];
3394 assert ( sLine.count('IEM_MC_') - sLine.count('IEM_MC_F_') == 1
3395 or len(oThreadedFunction.oMcBlock.aoStmts) == 1
3396 or oThreadedFunction.oMcBlock.iMacroExp == iai.McBlock.kiMacroExp_Partial);
3397 oOut.write(sLine[oThreadedFunction.oMcBlock.offAfterEnd : ]);
3398
3399 # Advance
3400 iThreadedFunction += 1;
3401 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
3402 #
3403 # Macro expansion line that have sublines and may contain multiple MC blocks.
3404 #
3405 else:
3406 offLine = 0;
3407 while iLine == oThreadedFunction.oMcBlock.iBeginLine:
3408 oOut.write(sLine[offLine : oThreadedFunction.oMcBlock.offBeginLine]);
3409
3410 sModified = oThreadedFunction.generateInputCode().strip();
3411 assert ( sModified.startswith('IEM_MC_BEGIN')
3412 or (sModified.find('IEM_MC_DEFER_TO_CIMPL_') > 0 and sModified.strip().startswith('{\n'))
3413 or sModified.startswith('pVCpu->iem.s.fEndTb = true')
3414 or sModified.startswith('pVCpu->iem.s.fTbCurInstr = ')
3415 ), 'sModified="%s"' % (sModified,);
3416 oOut.write(sModified);
3417
3418 offLine = oThreadedFunction.oMcBlock.offAfterEnd;
3419
3420 # Advance
3421 iThreadedFunction += 1;
3422 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
3423
3424 # Last line segment.
3425 if offLine < len(sLine):
3426 oOut.write(sLine[offLine : ]);
3427
3428 oOut.write("/* ****** END %s ******* */\n" % (oParser.sSrcFile,));
3429
3430 return True;
3431
3432
3433 #
3434 # Main
3435 #
3436
3437 def main(self, asArgs):
3438 """
3439 C-like main function.
3440 Returns exit code.
3441 """
3442
3443 #
3444 # Parse arguments
3445 #
3446 sScriptDir = os.path.dirname(__file__);
3447 oParser = argparse.ArgumentParser(add_help = False);
3448 oParser.add_argument('asInFiles',
3449 metavar = 'input.cpp.h',
3450 nargs = '*',
3451 default = [os.path.join(sScriptDir, aoInfo[0])
3452 for aoInfo in iai.g_aaoAllInstrFilesAndDefaultMapAndSet],
3453 help = "Selection of VMMAll/IEMAllInst*.cpp.h files to use as input.");
3454 oParser.add_argument('--host-arch',
3455 metavar = 'arch',
3456 dest = 'sHostArch',
3457 action = 'store',
3458 default = None,
3459 help = 'The host architecture.');
3460
3461 oParser.add_argument('--out-thrd-funcs-hdr',
3462 metavar = 'file-thrd-funcs.h',
3463 dest = 'sOutFileThrdFuncsHdr',
3464 action = 'store',
3465 default = '-',
3466 help = 'The output header file for the threaded functions.');
3467 oParser.add_argument('--out-thrd-funcs-cpp',
3468 metavar = 'file-thrd-funcs.cpp',
3469 dest = 'sOutFileThrdFuncsCpp',
3470 action = 'store',
3471 default = '-',
3472 help = 'The output C++ file for the threaded functions.');
3473 oParser.add_argument('--out-n8ve-funcs-hdr',
3474 metavar = 'file-n8tv-funcs.h',
3475 dest = 'sOutFileN8veFuncsHdr',
3476 action = 'store',
3477 default = '-',
3478 help = 'The output header file for the native recompiler functions.');
3479 oParser.add_argument('--out-n8ve-funcs-cpp1',
3480 metavar = 'file-n8tv-funcs1.cpp',
3481 dest = 'sOutFileN8veFuncsCpp1',
3482 action = 'store',
3483 default = '-',
3484 help = 'The output C++ file for the native recompiler functions part 1.');
3485 oParser.add_argument('--out-n8ve-funcs-cpp2',
3486 metavar = 'file-n8ve-funcs2.cpp',
3487 dest = 'sOutFileN8veFuncsCpp2',
3488 action = 'store',
3489 default = '-',
3490 help = 'The output C++ file for the native recompiler functions part 2.');
3491 oParser.add_argument('--out-n8ve-funcs-cpp3',
3492 metavar = 'file-n8ve-funcs3.cpp',
3493 dest = 'sOutFileN8veFuncsCpp3',
3494 action = 'store',
3495 default = '-',
3496 help = 'The output C++ file for the native recompiler functions part 3.');
3497 oParser.add_argument('--out-n8ve-funcs-cpp4',
3498 metavar = 'file-n8ve-funcs4.cpp',
3499 dest = 'sOutFileN8veFuncsCpp4',
3500 action = 'store',
3501 default = '-',
3502 help = 'The output C++ file for the native recompiler functions part 4.');
3503 oParser.add_argument('--out-n8ve-liveness-cpp',
3504 metavar = 'file-n8ve-liveness.cpp',
3505 dest = 'sOutFileN8veLivenessCpp',
3506 action = 'store',
3507 default = '-',
3508 help = 'The output C++ file for the native recompiler liveness analysis functions.');
3509 oParser.add_argument('--native',
3510 dest = 'fNativeRecompilerEnabled',
3511 action = 'store_true',
3512 default = False,
3513 help = 'Enables generating the files related to native recompilation.');
3514 oParser.add_argument('--out-mod-input1',
3515 metavar = 'file-instr.cpp.h',
3516 dest = 'sOutFileModInput1',
3517 action = 'store',
3518 default = '-',
3519 help = 'The output C++/header file for modified input instruction files part 1.');
3520 oParser.add_argument('--out-mod-input2',
3521 metavar = 'file-instr.cpp.h',
3522 dest = 'sOutFileModInput2',
3523 action = 'store',
3524 default = '-',
3525 help = 'The output C++/header file for modified input instruction files part 2.');
3526 oParser.add_argument('--out-mod-input3',
3527 metavar = 'file-instr.cpp.h',
3528 dest = 'sOutFileModInput3',
3529 action = 'store',
3530 default = '-',
3531 help = 'The output C++/header file for modified input instruction files part 3.');
3532 oParser.add_argument('--out-mod-input4',
3533 metavar = 'file-instr.cpp.h',
3534 dest = 'sOutFileModInput4',
3535 action = 'store',
3536 default = '-',
3537 help = 'The output C++/header file for modified input instruction files part 4.');
3538 oParser.add_argument('--help', '-h', '-?',
3539 action = 'help',
3540 help = 'Display help and exit.');
3541 oParser.add_argument('--version', '-V',
3542 action = 'version',
3543 version = 'r%s (IEMAllThreadedPython.py), r%s (IEMAllInstPython.py)'
3544 % (__version__.split()[1], iai.__version__.split()[1],),
3545 help = 'Displays the version/revision of the script and exit.');
3546 self.oOptions = oParser.parse_args(asArgs[1:]);
3547 print("oOptions=%s" % (self.oOptions,), file = sys.stderr);
3548
3549 if self.oOptions.sHostArch not in ('amd64', 'arm64'):
3550 print('error! Unsupported (or missing) host architecture: %s' % (self.oOptions.sHostArch,), file = sys.stderr);
3551 return 1;
3552
3553 #
3554 # Process the instructions specified in the IEM sources.
3555 #
3556 if self.processInputFiles(self.oOptions.sHostArch, self.oOptions.fNativeRecompilerEnabled):
3557 #
3558 # Generate the output files.
3559 #
3560 aaoOutputFiles = (
3561 ( self.oOptions.sOutFileThrdFuncsHdr, self.generateThreadedFunctionsHeader, 0, ),
3562 ( self.oOptions.sOutFileThrdFuncsCpp, self.generateThreadedFunctionsSource, 0, ),
3563 ( self.oOptions.sOutFileN8veFuncsHdr, self.generateNativeFunctionsHeader, 0, ),
3564 ( self.oOptions.sOutFileN8veFuncsCpp1, self.generateNativeFunctionsSource, 0, ),
3565 ( self.oOptions.sOutFileN8veFuncsCpp2, self.generateNativeFunctionsSource, 1, ),
3566 ( self.oOptions.sOutFileN8veFuncsCpp3, self.generateNativeFunctionsSource, 2, ),
3567 ( self.oOptions.sOutFileN8veFuncsCpp4, self.generateNativeFunctionsSource, 3, ),
3568 ( self.oOptions.sOutFileN8veLivenessCpp, self.generateNativeLivenessSource, 0, ),
3569 ( self.oOptions.sOutFileModInput1, self.generateModifiedInput, 1, ),
3570 ( self.oOptions.sOutFileModInput2, self.generateModifiedInput, 2, ),
3571 ( self.oOptions.sOutFileModInput3, self.generateModifiedInput, 3, ),
3572 ( self.oOptions.sOutFileModInput4, self.generateModifiedInput, 4, ),
3573 );
3574 fRc = True;
3575 for sOutFile, fnGenMethod, iPartNo in aaoOutputFiles:
3576 if sOutFile == '-':
3577 fRc = fnGenMethod(sys.stdout, iPartNo) and fRc;
3578 else:
3579 try:
3580 oOut = open(sOutFile, 'w'); # pylint: disable=consider-using-with,unspecified-encoding
3581 except Exception as oXcpt:
3582 print('error! Failed open "%s" for writing: %s' % (sOutFile, oXcpt,), file = sys.stderr);
3583 return 1;
3584 fRc = fnGenMethod(oOut, iPartNo) and fRc;
3585 oOut.close();
3586 if fRc:
3587 return 0;
3588
3589 return 1;
3590
3591
3592if __name__ == '__main__':
3593 sys.exit(IEMThreadedGenerator().main(sys.argv));
3594
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette