VirtualBox

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

最後變更 在這個檔案從101484是 101484,由 vboxsync 提交於 17 月 前

VMM/IEM: Basic register allocator sketches that incorporates simple skipping of guest register value loads. Sketched out varable and argument managmenet. Start telling GDB our jitted code to help with backtraces. ++ bugref:10371

  • 屬性 svn:eol-style 設為 LF
  • 屬性 svn:executable 設為 *
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 124.4 KB
 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllThrdPython.py 101484 2023-10-18 01:32:17Z 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.alldomusa.eu.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: 101484 $"
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;
90
91def getTypeBitCount(sType):
92 """
93 Translate a type to size in bits
94 """
95 if sType in g_kdTypeInfo2:
96 return g_kdTypeInfo2[sType][0];
97 if '*' in sType or sType[0] == 'P':
98 return 64;
99 #raise Exception('Unknown type: %s' % (sType,));
100 print('error: Unknown type: %s' % (sType,));
101 return 64;
102
103g_kdIemFieldToType = {
104 # Illegal ones:
105 'offInstrNextByte': ( None, ),
106 'cbInstrBuf': ( None, ),
107 'pbInstrBuf': ( None, ),
108 'uInstrBufPc': ( None, ),
109 'cbInstrBufTotal': ( None, ),
110 'offCurInstrStart': ( None, ),
111 'cbOpcode': ( None, ),
112 'offOpcode': ( None, ),
113 'offModRm': ( None, ),
114 # Okay ones.
115 'fPrefixes': ( 'uint32_t', ),
116 'uRexReg': ( 'uint8_t', ),
117 'uRexB': ( 'uint8_t', ),
118 'uRexIndex': ( 'uint8_t', ),
119 'iEffSeg': ( 'uint8_t', ),
120 'enmEffOpSize': ( 'IEMMODE', ),
121 'enmDefAddrMode': ( 'IEMMODE', ),
122 'enmEffAddrMode': ( 'IEMMODE', ),
123 'enmDefOpSize': ( 'IEMMODE', ),
124 'idxPrefix': ( 'uint8_t', ),
125 'uVex3rdReg': ( 'uint8_t', ),
126 'uVexLength': ( 'uint8_t', ),
127 'fEvexStuff': ( 'uint8_t', ),
128 'uFpuOpcode': ( 'uint16_t', ),
129};
130
131class ThreadedParamRef(object):
132 """
133 A parameter reference for a threaded function.
134 """
135
136 def __init__(self, sOrgRef, sType, oStmt, iParam = None, offParam = 0, sStdRef = None):
137 ## The name / reference in the original code.
138 self.sOrgRef = sOrgRef;
139 ## Normalized name to deal with spaces in macro invocations and such.
140 self.sStdRef = sStdRef if sStdRef else ''.join(sOrgRef.split());
141 ## Indicates that sOrgRef may not match the parameter.
142 self.fCustomRef = sStdRef is not None;
143 ## The type (typically derived).
144 self.sType = sType;
145 ## The statement making the reference.
146 self.oStmt = oStmt;
147 ## The parameter containing the references. None if implicit.
148 self.iParam = iParam;
149 ## The offset in the parameter of the reference.
150 self.offParam = offParam;
151
152 ## The variable name in the threaded function.
153 self.sNewName = 'x';
154 ## The this is packed into.
155 self.iNewParam = 99;
156 ## The bit offset in iNewParam.
157 self.offNewParam = 1024
158
159
160class ThreadedFunctionVariation(object):
161 """ Threaded function variation. """
162
163 ## @name Variations.
164 ## These variations will match translation block selection/distinctions as well.
165 ## @{
166 ksVariation_Default = ''; ##< No variations - only used by IEM_MC_DEFER_TO_CIMPL_X_RET.
167 ksVariation_16 = '_16'; ##< 16-bit mode code (386+).
168 ksVariation_16f = '_16f'; ##< 16-bit mode code (386+), check+clear eflags.
169 ksVariation_16_Addr32 = '_16_Addr32'; ##< 16-bit mode code (386+), address size prefixed to 32-bit addressing.
170 ksVariation_16f_Addr32 = '_16f_Addr32'; ##< 16-bit mode code (386+), address size prefixed to 32-bit addressing, eflags.
171 ksVariation_16_Pre386 = '_16_Pre386'; ##< 16-bit mode code, pre-386 CPU target.
172 ksVariation_16f_Pre386 = '_16f_Pre386'; ##< 16-bit mode code, pre-386 CPU target, check+clear eflags.
173 ksVariation_32 = '_32'; ##< 32-bit mode code (386+).
174 ksVariation_32f = '_32f'; ##< 32-bit mode code (386+), check+clear eflags.
175 ksVariation_32_Flat = '_32_Flat'; ##< 32-bit mode code (386+) with CS, DS, E,S and SS flat and 4GB wide.
176 ksVariation_32f_Flat = '_32f_Flat'; ##< 32-bit mode code (386+) with CS, DS, E,S and SS flat and 4GB wide, eflags.
177 ksVariation_32_Addr16 = '_32_Addr16'; ##< 32-bit mode code (386+), address size prefixed to 16-bit addressing.
178 ksVariation_32f_Addr16 = '_32f_Addr16'; ##< 32-bit mode code (386+), address size prefixed to 16-bit addressing, eflags.
179 ksVariation_64 = '_64'; ##< 64-bit mode code.
180 ksVariation_64f = '_64f'; ##< 64-bit mode code, check+clear eflags.
181 ksVariation_64_FsGs = '_64_FsGs'; ##< 64-bit mode code, with memory accesses via FS or GS.
182 ksVariation_64f_FsGs = '_64f_FsGs'; ##< 64-bit mode code, with memory accesses via FS or GS, check+clear eflags.
183 ksVariation_64_Addr32 = '_64_Addr32'; ##< 64-bit mode code, address size prefixed to 32-bit addressing.
184 ksVariation_64f_Addr32 = '_64f_Addr32'; ##< 64-bit mode code, address size prefixed to 32-bit addressing, c+c eflags.
185 kasVariations = (
186 ksVariation_Default,
187 ksVariation_16,
188 ksVariation_16f,
189 ksVariation_16_Addr32,
190 ksVariation_16f_Addr32,
191 ksVariation_16_Pre386,
192 ksVariation_16f_Pre386,
193 ksVariation_32,
194 ksVariation_32f,
195 ksVariation_32_Flat,
196 ksVariation_32f_Flat,
197 ksVariation_32_Addr16,
198 ksVariation_32f_Addr16,
199 ksVariation_64,
200 ksVariation_64f,
201 ksVariation_64_FsGs,
202 ksVariation_64f_FsGs,
203 ksVariation_64_Addr32,
204 ksVariation_64f_Addr32,
205 );
206 kasVariationsWithoutAddress = (
207 ksVariation_16,
208 ksVariation_16f,
209 ksVariation_16_Pre386,
210 ksVariation_16f_Pre386,
211 ksVariation_32,
212 ksVariation_32f,
213 ksVariation_64,
214 ksVariation_64f,
215 );
216 kasVariationsWithoutAddressNot286 = (
217 ksVariation_16,
218 ksVariation_16f,
219 ksVariation_32,
220 ksVariation_32f,
221 ksVariation_64,
222 ksVariation_64f,
223 );
224 kasVariationsWithoutAddressNot286Not64 = (
225 ksVariation_16,
226 ksVariation_16f,
227 ksVariation_32,
228 ksVariation_32f,
229 );
230 kasVariationsWithoutAddressNot64 = (
231 ksVariation_16,
232 ksVariation_16f,
233 ksVariation_16_Pre386,
234 ksVariation_16f_Pre386,
235 ksVariation_32,
236 ksVariation_32f,
237 );
238 kasVariationsWithoutAddressOnly64 = (
239 ksVariation_64,
240 ksVariation_64f,
241 );
242 kasVariationsWithAddress = (
243 ksVariation_16,
244 ksVariation_16f,
245 ksVariation_16_Addr32,
246 ksVariation_16f_Addr32,
247 ksVariation_16_Pre386,
248 ksVariation_16f_Pre386,
249 ksVariation_32,
250 ksVariation_32f,
251 ksVariation_32_Flat,
252 ksVariation_32f_Flat,
253 ksVariation_32_Addr16,
254 ksVariation_32f_Addr16,
255 ksVariation_64,
256 ksVariation_64f,
257 ksVariation_64_FsGs,
258 ksVariation_64f_FsGs,
259 ksVariation_64_Addr32,
260 ksVariation_64f_Addr32,
261 );
262 kasVariationsWithAddressNot286 = (
263 ksVariation_16,
264 ksVariation_16f,
265 ksVariation_16_Addr32,
266 ksVariation_16f_Addr32,
267 ksVariation_32,
268 ksVariation_32f,
269 ksVariation_32_Flat,
270 ksVariation_32f_Flat,
271 ksVariation_32_Addr16,
272 ksVariation_32f_Addr16,
273 ksVariation_64,
274 ksVariation_64f,
275 ksVariation_64_FsGs,
276 ksVariation_64f_FsGs,
277 ksVariation_64_Addr32,
278 ksVariation_64f_Addr32,
279 );
280 kasVariationsWithAddressNot286Not64 = (
281 ksVariation_16,
282 ksVariation_16f,
283 ksVariation_16_Addr32,
284 ksVariation_16f_Addr32,
285 ksVariation_32,
286 ksVariation_32f,
287 ksVariation_32_Flat,
288 ksVariation_32f_Flat,
289 ksVariation_32_Addr16,
290 ksVariation_32f_Addr16,
291 );
292 kasVariationsWithAddressNot64 = (
293 ksVariation_16,
294 ksVariation_16f,
295 ksVariation_16_Addr32,
296 ksVariation_16f_Addr32,
297 ksVariation_16_Pre386,
298 ksVariation_16f_Pre386,
299 ksVariation_32,
300 ksVariation_32f,
301 ksVariation_32_Flat,
302 ksVariation_32f_Flat,
303 ksVariation_32_Addr16,
304 ksVariation_32f_Addr16,
305 );
306 kasVariationsWithAddressOnly64 = (
307 ksVariation_64,
308 ksVariation_64f,
309 ksVariation_64_FsGs,
310 ksVariation_64f_FsGs,
311 ksVariation_64_Addr32,
312 ksVariation_64f_Addr32,
313 );
314 kasVariationsOnlyPre386 = (
315 ksVariation_16_Pre386,
316 ksVariation_16f_Pre386,
317 );
318 kasVariationsEmitOrder = (
319 ksVariation_Default,
320 ksVariation_64,
321 ksVariation_64f,
322 ksVariation_64_FsGs,
323 ksVariation_64f_FsGs,
324 ksVariation_32_Flat,
325 ksVariation_32f_Flat,
326 ksVariation_32,
327 ksVariation_32f,
328 ksVariation_16,
329 ksVariation_16f,
330 ksVariation_16_Addr32,
331 ksVariation_16f_Addr32,
332 ksVariation_16_Pre386,
333 ksVariation_16f_Pre386,
334 ksVariation_32_Addr16,
335 ksVariation_32f_Addr16,
336 ksVariation_64_Addr32,
337 ksVariation_64f_Addr32,
338 );
339 kdVariationNames = {
340 ksVariation_Default: 'defer-to-cimpl',
341 ksVariation_16: '16-bit',
342 ksVariation_16f: '16-bit w/ eflag checking and clearing',
343 ksVariation_16_Addr32: '16-bit w/ address prefix (Addr32)',
344 ksVariation_16f_Addr32: '16-bit w/ address prefix (Addr32) and eflag checking and clearing',
345 ksVariation_16_Pre386: '16-bit on pre-386 CPU',
346 ksVariation_16f_Pre386: '16-bit on pre-386 CPU w/ eflag checking and clearing',
347 ksVariation_32: '32-bit',
348 ksVariation_32f: '32-bit w/ eflag checking and clearing',
349 ksVariation_32_Flat: '32-bit flat and wide open CS, SS, DS and ES',
350 ksVariation_32f_Flat: '32-bit flat and wide open CS, SS, DS and ES w/ eflag checking and clearing',
351 ksVariation_32_Addr16: '32-bit w/ address prefix (Addr16)',
352 ksVariation_32f_Addr16: '32-bit w/ address prefix (Addr16) and eflag checking and clearing',
353 ksVariation_64: '64-bit',
354 ksVariation_64f: '64-bit w/ eflag checking and clearing',
355 ksVariation_64_FsGs: '64-bit with memory accessed via FS or GS',
356 ksVariation_64f_FsGs: '64-bit with memory accessed via FS or GS and eflag checking and clearing',
357 ksVariation_64_Addr32: '64-bit w/ address prefix (Addr32)',
358 ksVariation_64f_Addr32: '64-bit w/ address prefix (Addr32) and eflag checking and clearing',
359 };
360 kdVariationsWithEflagsCheckingAndClearing = {
361 ksVariation_16f: True,
362 ksVariation_16f_Addr32: True,
363 ksVariation_16f_Pre386: True,
364 ksVariation_32f: True,
365 ksVariation_32f_Flat: True,
366 ksVariation_32f_Addr16: True,
367 ksVariation_64f: True,
368 ksVariation_64f_FsGs: True,
369 ksVariation_64f_Addr32: True,
370 };
371 kdVariationsWithFlatAddress = {
372 ksVariation_32_Flat: True,
373 ksVariation_32f_Flat: True,
374 ksVariation_64: True,
375 ksVariation_64f: True,
376 };
377 kdVariationsWithFlatAddr16 = {
378 ksVariation_16: True,
379 ksVariation_16f: True,
380 ksVariation_16_Pre386: True,
381 ksVariation_16f_Pre386: True,
382 ksVariation_32_Addr16: True,
383 ksVariation_32f_Addr16: True,
384 };
385 kdVariationsWithFlatAddr32No64 = {
386 ksVariation_16_Addr32: True,
387 ksVariation_16f_Addr32: True,
388 ksVariation_32: True,
389 ksVariation_32f: True,
390 ksVariation_32_Flat: True,
391 ksVariation_32f_Flat: True,
392 };
393 ## @}
394
395 ## IEM_CIMPL_F_XXX flags that we know.
396 ## The value indicates whether it terminates the TB or not. The goal is to
397 ## improve the recompiler so all but END_TB will be False.
398 ##
399 ## @note iemThreadedRecompilerMcDeferToCImpl0 duplicates info found here.
400 kdCImplFlags = {
401 'IEM_CIMPL_F_MODE': False,
402 'IEM_CIMPL_F_BRANCH_DIRECT': False,
403 'IEM_CIMPL_F_BRANCH_INDIRECT': False,
404 'IEM_CIMPL_F_BRANCH_RELATIVE': False,
405 'IEM_CIMPL_F_BRANCH_FAR': True,
406 'IEM_CIMPL_F_BRANCH_CONDITIONAL': False,
407 # IEM_CIMPL_F_BRANCH_ANY should only be used for testing, so not included here.
408 'IEM_CIMPL_F_RFLAGS': False,
409 'IEM_CIMPL_F_INHIBIT_SHADOW': False,
410 'IEM_CIMPL_F_CHECK_IRQ_AFTER': False,
411 'IEM_CIMPL_F_CHECK_IRQ_BEFORE': False,
412 'IEM_CIMPL_F_CHECK_IRQ_BEFORE_AND_AFTER': False, # (ignore)
413 'IEM_CIMPL_F_STATUS_FLAGS': False,
414 'IEM_CIMPL_F_VMEXIT': False,
415 'IEM_CIMPL_F_FPU': False,
416 'IEM_CIMPL_F_REP': False,
417 'IEM_CIMPL_F_IO': False,
418 'IEM_CIMPL_F_END_TB': True,
419 'IEM_CIMPL_F_XCPT': True,
420 };
421
422 def __init__(self, oThreadedFunction, sVariation = ksVariation_Default):
423 self.oParent = oThreadedFunction # type: ThreadedFunction
424 ##< ksVariation_Xxxx.
425 self.sVariation = sVariation
426
427 ## Threaded function parameter references.
428 self.aoParamRefs = [] # type: List[ThreadedParamRef]
429 ## Unique parameter references.
430 self.dParamRefs = {} # type: Dict[str, List[ThreadedParamRef]]
431 ## Minimum number of parameters to the threaded function.
432 self.cMinParams = 0;
433
434 ## List/tree of statements for the threaded function.
435 self.aoStmtsForThreadedFunction = [] # type: List[McStmt]
436
437 ## Function enum number, for verification. Set by generateThreadedFunctionsHeader.
438 self.iEnumValue = -1;
439
440 ## Native recompilation details for this variation.
441 self.oNativeRecomp = None;
442
443 def getIndexName(self):
444 sName = self.oParent.oMcBlock.sFunction;
445 if sName.startswith('iemOp_'):
446 sName = sName[len('iemOp_'):];
447 if self.oParent.oMcBlock.iInFunction == 0:
448 return 'kIemThreadedFunc_%s%s' % ( sName, self.sVariation, );
449 return 'kIemThreadedFunc_%s_%s%s' % ( sName, self.oParent.oMcBlock.iInFunction, self.sVariation, );
450
451 def getThreadedFunctionName(self):
452 sName = self.oParent.oMcBlock.sFunction;
453 if sName.startswith('iemOp_'):
454 sName = sName[len('iemOp_'):];
455 if self.oParent.oMcBlock.iInFunction == 0:
456 return 'iemThreadedFunc_%s%s' % ( sName, self.sVariation, );
457 return 'iemThreadedFunc_%s_%s%s' % ( sName, self.oParent.oMcBlock.iInFunction, self.sVariation, );
458
459 def getNativeFunctionName(self):
460 return 'iemNativeRecompFunc_' + self.getThreadedFunctionName()[len('iemThreadedFunc_'):];
461
462 #
463 # Analysis and code morphing.
464 #
465
466 def raiseProblem(self, sMessage):
467 """ Raises a problem. """
468 self.oParent.raiseProblem(sMessage);
469
470 def warning(self, sMessage):
471 """ Emits a warning. """
472 self.oParent.warning(sMessage);
473
474 def analyzeReferenceToType(self, sRef):
475 """
476 Translates a variable or structure reference to a type.
477 Returns type name.
478 Raises exception if unable to figure it out.
479 """
480 ch0 = sRef[0];
481 if ch0 == 'u':
482 if sRef.startswith('u32'):
483 return 'uint32_t';
484 if sRef.startswith('u8') or sRef == 'uReg':
485 return 'uint8_t';
486 if sRef.startswith('u64'):
487 return 'uint64_t';
488 if sRef.startswith('u16'):
489 return 'uint16_t';
490 elif ch0 == 'b':
491 return 'uint8_t';
492 elif ch0 == 'f':
493 return 'bool';
494 elif ch0 == 'i':
495 if sRef.startswith('i8'):
496 return 'int8_t';
497 if sRef.startswith('i16'):
498 return 'int16_t';
499 if sRef.startswith('i32'):
500 return 'int32_t';
501 if sRef.startswith('i64'):
502 return 'int64_t';
503 if sRef in ('iReg', 'iFixedReg', 'iGReg', 'iSegReg', 'iSrcReg', 'iDstReg', 'iCrReg'):
504 return 'uint8_t';
505 elif ch0 == 'p':
506 if sRef.find('-') < 0:
507 return 'uintptr_t';
508 if sRef.startswith('pVCpu->iem.s.'):
509 sField = sRef[len('pVCpu->iem.s.') : ];
510 if sField in g_kdIemFieldToType:
511 if g_kdIemFieldToType[sField][0]:
512 return g_kdIemFieldToType[sField][0];
513 elif ch0 == 'G' and sRef.startswith('GCPtr'):
514 return 'uint64_t';
515 elif ch0 == 'e':
516 if sRef == 'enmEffOpSize':
517 return 'IEMMODE';
518 elif ch0 == 'o':
519 if sRef.startswith('off32'):
520 return 'uint32_t';
521 elif sRef == 'cbFrame': # enter
522 return 'uint16_t';
523 elif sRef == 'cShift': ## @todo risky
524 return 'uint8_t';
525
526 self.raiseProblem('Unknown reference: %s' % (sRef,));
527 return None; # Shut up pylint 2.16.2.
528
529 def analyzeCallToType(self, sFnRef):
530 """
531 Determins the type of an indirect function call.
532 """
533 assert sFnRef[0] == 'p';
534
535 #
536 # Simple?
537 #
538 if sFnRef.find('-') < 0:
539 oDecoderFunction = self.oParent.oMcBlock.oFunction;
540
541 # Try the argument list of the function defintion macro invocation first.
542 iArg = 2;
543 while iArg < len(oDecoderFunction.asDefArgs):
544 if sFnRef == oDecoderFunction.asDefArgs[iArg]:
545 return oDecoderFunction.asDefArgs[iArg - 1];
546 iArg += 1;
547
548 # Then check out line that includes the word and looks like a variable declaration.
549 oRe = re.compile(' +(P[A-Z0-9_]+|const +IEMOP[A-Z0-9_]+ *[*]) +(const |) *' + sFnRef + ' *(;|=)');
550 for sLine in oDecoderFunction.asLines:
551 oMatch = oRe.match(sLine);
552 if oMatch:
553 if not oMatch.group(1).startswith('const'):
554 return oMatch.group(1);
555 return 'PC' + oMatch.group(1)[len('const ') : -1].strip();
556
557 #
558 # Deal with the pImpl->pfnXxx:
559 #
560 elif sFnRef.startswith('pImpl->pfn'):
561 sMember = sFnRef[len('pImpl->') : ];
562 sBaseType = self.analyzeCallToType('pImpl');
563 offBits = sMember.rfind('U') + 1;
564 if sBaseType == 'PCIEMOPBINSIZES': return 'PFNIEMAIMPLBINU' + sMember[offBits:];
565 if sBaseType == 'PCIEMOPUNARYSIZES': return 'PFNIEMAIMPLUNARYU' + sMember[offBits:];
566 if sBaseType == 'PCIEMOPSHIFTSIZES': return 'PFNIEMAIMPLSHIFTU' + sMember[offBits:];
567 if sBaseType == 'PCIEMOPSHIFTDBLSIZES': return 'PFNIEMAIMPLSHIFTDBLU' + sMember[offBits:];
568 if sBaseType == 'PCIEMOPMULDIVSIZES': return 'PFNIEMAIMPLMULDIVU' + sMember[offBits:];
569 if sBaseType == 'PCIEMOPMEDIAF3': return 'PFNIEMAIMPLMEDIAF3U' + sMember[offBits:];
570 if sBaseType == 'PCIEMOPMEDIAOPTF3': return 'PFNIEMAIMPLMEDIAOPTF3U' + sMember[offBits:];
571 if sBaseType == 'PCIEMOPMEDIAOPTF2': return 'PFNIEMAIMPLMEDIAOPTF2U' + sMember[offBits:];
572 if sBaseType == 'PCIEMOPMEDIAOPTF3IMM8': return 'PFNIEMAIMPLMEDIAOPTF3U' + sMember[offBits:] + 'IMM8';
573 if sBaseType == 'PCIEMOPBLENDOP': return 'PFNIEMAIMPLAVXBLENDU' + sMember[offBits:];
574
575 self.raiseProblem('Unknown call reference: %s::%s (%s)' % (sBaseType, sMember, sFnRef,));
576
577 self.raiseProblem('Unknown call reference: %s' % (sFnRef,));
578 return None; # Shut up pylint 2.16.2.
579
580 def analyze8BitGRegStmt(self, oStmt):
581 """
582 Gets the 8-bit general purpose register access details of the given statement.
583 ASSUMES the statement is one accessing an 8-bit GREG.
584 """
585 idxReg = 0;
586 if ( oStmt.sName.find('_FETCH_') > 0
587 or oStmt.sName.find('_REF_') > 0
588 or oStmt.sName.find('_TO_LOCAL') > 0):
589 idxReg = 1;
590
591 sRegRef = oStmt.asParams[idxReg];
592 if sRegRef.startswith('IEM_GET_MODRM_RM') or sRegRef.startswith('IEM_GET_MODRM_REG'):
593 asBits = [sBit.strip() for sBit in sRegRef.replace('(', ',').replace(')', '').split(',')];
594 if len(asBits) != 3 or asBits[1] != 'pVCpu' or (asBits[0] != 'IEM_GET_MODRM_RM' and asBits[0] != 'IEM_GET_MODRM_REG'):
595 self.raiseProblem('Unexpected reference: %s (asBits=%s)' % (sRegRef, asBits));
596 sOrgExpr = asBits[0] + '_EX8(pVCpu, ' + asBits[2] + ')';
597 else:
598 sOrgExpr = '((%s) < 4 || (pVCpu->iem.s.fPrefixes & IEM_OP_PRF_REX) ? (%s) : (%s) + 12)' % (sRegRef, sRegRef, sRegRef);
599
600 if sRegRef.find('IEM_GET_MODRM_RM') >= 0: sStdRef = 'bRmRm8Ex';
601 elif sRegRef.find('IEM_GET_MODRM_REG') >= 0: sStdRef = 'bRmReg8Ex';
602 elif sRegRef == 'X86_GREG_xAX': sStdRef = 'bGregXAx8Ex';
603 elif sRegRef == 'X86_GREG_xCX': sStdRef = 'bGregXCx8Ex';
604 elif sRegRef == 'X86_GREG_xSP': sStdRef = 'bGregXSp8Ex';
605 elif sRegRef == 'iFixedReg': sStdRef = 'bFixedReg8Ex';
606 else:
607 self.warning('analyze8BitGRegStmt: sRegRef=%s -> bOther8Ex; %s %s; sOrgExpr=%s'
608 % (sRegRef, oStmt.sName, oStmt.asParams, sOrgExpr,));
609 sStdRef = 'bOther8Ex';
610
611 #print('analyze8BitGRegStmt: %s %s; sRegRef=%s\n -> idxReg=%s sOrgExpr=%s sStdRef=%s'
612 # % (oStmt.sName, oStmt.asParams, sRegRef, idxReg, sOrgExpr, sStdRef));
613 return (idxReg, sOrgExpr, sStdRef);
614
615
616 ## Maps memory related MCs to info for FLAT conversion.
617 ## This is used in 64-bit and flat 32-bit variants to skip the unnecessary
618 ## segmentation checking for every memory access. Only applied to access
619 ## via ES, DS and SS. FS, GS and CS gets the full segmentation threatment,
620 ## the latter (CS) is just to keep things simple (we could safely fetch via
621 ## it, but only in 64-bit mode could we safely write via it, IIRC).
622 kdMemMcToFlatInfo = {
623 'IEM_MC_FETCH_MEM_U8': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8' ),
624 'IEM_MC_FETCH_MEM16_U8': ( 1, 'IEM_MC_FETCH_MEM16_FLAT_U8' ),
625 'IEM_MC_FETCH_MEM32_U8': ( 1, 'IEM_MC_FETCH_MEM32_FLAT_U8' ),
626 'IEM_MC_FETCH_MEM_U16': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16' ),
627 'IEM_MC_FETCH_MEM_U16_DISP': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16_DISP' ),
628 'IEM_MC_FETCH_MEM_I16': ( 1, 'IEM_MC_FETCH_MEM_FLAT_I16' ),
629 'IEM_MC_FETCH_MEM_U32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U32' ),
630 'IEM_MC_FETCH_MEM_U32_DISP': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U32_DISP' ),
631 'IEM_MC_FETCH_MEM_I32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_I32' ),
632 'IEM_MC_FETCH_MEM_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U64' ),
633 'IEM_MC_FETCH_MEM_U64_DISP': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U64_DISP' ),
634 'IEM_MC_FETCH_MEM_U64_ALIGN_U128': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U64_ALIGN_U128' ),
635 'IEM_MC_FETCH_MEM_I64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_I64' ),
636 'IEM_MC_FETCH_MEM_R32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_R32' ),
637 'IEM_MC_FETCH_MEM_R64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_R64' ),
638 'IEM_MC_FETCH_MEM_R80': ( 1, 'IEM_MC_FETCH_MEM_FLAT_R80' ),
639 'IEM_MC_FETCH_MEM_D80': ( 1, 'IEM_MC_FETCH_MEM_FLAT_D80' ),
640 'IEM_MC_FETCH_MEM_U128': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U128' ),
641 'IEM_MC_FETCH_MEM_U128_NO_AC': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U128_NO_AC' ),
642 'IEM_MC_FETCH_MEM_U128_ALIGN_SSE': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U128_ALIGN_SSE' ),
643 'IEM_MC_FETCH_MEM_XMM': ( 1, 'IEM_MC_FETCH_MEM_FLAT_XMM' ),
644 'IEM_MC_FETCH_MEM_XMM_NO_AC': ( 1, 'IEM_MC_FETCH_MEM_FLAT_XMM_NO_AC' ),
645 'IEM_MC_FETCH_MEM_XMM_ALIGN_SSE': ( 1, 'IEM_MC_FETCH_MEM_FLAT_XMM_ALIGN_SSE' ),
646 'IEM_MC_FETCH_MEM_XMM_U32': ( 2, 'IEM_MC_FETCH_MEM_FLAT_XMM_U32' ),
647 'IEM_MC_FETCH_MEM_XMM_U64': ( 2, 'IEM_MC_FETCH_MEM_FLAT_XMM_U64' ),
648 'IEM_MC_FETCH_MEM_U256': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U256' ),
649 'IEM_MC_FETCH_MEM_U256_NO_AC': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U256_NO_AC' ),
650 'IEM_MC_FETCH_MEM_U256_ALIGN_AVX': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U256_ALIGN_AVX' ),
651 'IEM_MC_FETCH_MEM_YMM': ( 1, 'IEM_MC_FETCH_MEM_FLAT_YMM' ),
652 'IEM_MC_FETCH_MEM_YMM_NO_AC': ( 1, 'IEM_MC_FETCH_MEM_FLAT_YMM_NO_AC' ),
653 'IEM_MC_FETCH_MEM_YMM_ALIGN_AVX': ( 1, 'IEM_MC_FETCH_MEM_FLAT_YMM_ALIGN_AVX' ),
654 'IEM_MC_FETCH_MEM_U8_ZX_U16': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U16' ),
655 'IEM_MC_FETCH_MEM_U8_ZX_U32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U32' ),
656 'IEM_MC_FETCH_MEM_U8_ZX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U64' ),
657 'IEM_MC_FETCH_MEM_U16_ZX_U32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16_ZX_U32' ),
658 'IEM_MC_FETCH_MEM_U16_ZX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16_ZX_U64' ),
659 'IEM_MC_FETCH_MEM_U32_ZX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U32_ZX_U64' ),
660 'IEM_MC_FETCH_MEM_U8_SX_U16': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U16' ),
661 'IEM_MC_FETCH_MEM_U8_SX_U32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U32' ),
662 'IEM_MC_FETCH_MEM_U8_SX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U64' ),
663 'IEM_MC_FETCH_MEM_U16_SX_U32': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16_SX_U32' ),
664 'IEM_MC_FETCH_MEM_U16_SX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U16_SX_U64' ),
665 'IEM_MC_FETCH_MEM_U32_SX_U64': ( 1, 'IEM_MC_FETCH_MEM_FLAT_U32_SX_U64' ),
666 'IEM_MC_STORE_MEM_U8': ( 0, 'IEM_MC_STORE_MEM_FLAT_U8' ),
667 'IEM_MC_STORE_MEM_U16': ( 0, 'IEM_MC_STORE_MEM_FLAT_U16' ),
668 'IEM_MC_STORE_MEM_U32': ( 0, 'IEM_MC_STORE_MEM_FLAT_U32' ),
669 'IEM_MC_STORE_MEM_U64': ( 0, 'IEM_MC_STORE_MEM_FLAT_U64' ),
670 'IEM_MC_STORE_MEM_U8_CONST': ( 0, 'IEM_MC_STORE_MEM_FLAT_U8_CONST' ),
671 'IEM_MC_STORE_MEM_U16_CONST': ( 0, 'IEM_MC_STORE_MEM_FLAT_U16_CONST' ),
672 'IEM_MC_STORE_MEM_U32_CONST': ( 0, 'IEM_MC_STORE_MEM_FLAT_U32_CONST' ),
673 'IEM_MC_STORE_MEM_U64_CONST': ( 0, 'IEM_MC_STORE_MEM_FLAT_U64_CONST' ),
674 'IEM_MC_STORE_MEM_U128': ( 0, 'IEM_MC_STORE_MEM_FLAT_U128' ),
675 'IEM_MC_STORE_MEM_U128_ALIGN_SSE': ( 0, 'IEM_MC_STORE_MEM_FLAT_U128_ALIGN_SSE' ),
676 'IEM_MC_STORE_MEM_U256': ( 0, 'IEM_MC_STORE_MEM_FLAT_U256' ),
677 'IEM_MC_STORE_MEM_U256_ALIGN_AVX': ( 0, 'IEM_MC_STORE_MEM_FLAT_U256_ALIGN_AVX' ),
678 'IEM_MC_MEM_MAP': ( 2, 'IEM_MC_MEM_FLAT_MAP' ),
679 'IEM_MC_MEM_MAP_U8_RW': ( 2, 'IEM_MC_MEM_FLAT_MAP_U8_RW' ),
680 'IEM_MC_MEM_MAP_U8_RO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U8_RO' ),
681 'IEM_MC_MEM_MAP_U8_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U8_WO' ),
682 'IEM_MC_MEM_MAP_U16_RW': ( 2, 'IEM_MC_MEM_FLAT_MAP_U16_RW' ),
683 'IEM_MC_MEM_MAP_U16_RO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U16_RO' ),
684 'IEM_MC_MEM_MAP_U16_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U16_WO' ),
685 'IEM_MC_MEM_MAP_U32_RW': ( 2, 'IEM_MC_MEM_FLAT_MAP_U32_RW' ),
686 'IEM_MC_MEM_MAP_U32_RO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U32_RO' ),
687 'IEM_MC_MEM_MAP_U32_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U32_WO' ),
688 'IEM_MC_MEM_MAP_U64_RW': ( 2, 'IEM_MC_MEM_FLAT_MAP_U64_RW' ),
689 'IEM_MC_MEM_MAP_U64_RO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U64_RO' ),
690 'IEM_MC_MEM_MAP_U64_WO': ( 2, 'IEM_MC_MEM_FLAT_MAP_U64_WO' ),
691 'IEM_MC_MEM_MAP_EX': ( 3, 'IEM_MC_MEM_FLAT_MAP_EX' ),
692 };
693
694 kdMemMcToFlatInfoStack = {
695 'IEM_MC_PUSH_U16': ( 'IEM_MC_FLAT32_PUSH_U16', 'IEM_MC_FLAT64_PUSH_U16', ),
696 'IEM_MC_PUSH_U32': ( 'IEM_MC_FLAT32_PUSH_U32', 'IEM_MC_PUSH_U32', ),
697 'IEM_MC_PUSH_U64': ( 'IEM_MC_PUSH_U64', 'IEM_MC_FLAT64_PUSH_U64', ),
698 'IEM_MC_PUSH_U32_SREG': ( 'IEM_MC_FLAT32_PUSH_U32_SREG', 'IEM_MC_PUSH_U32_SREG' ),
699 'IEM_MC_POP_U16': ( 'IEM_MC_FLAT32_POP_U16', 'IEM_MC_FLAT64_POP_U16', ),
700 'IEM_MC_POP_U32': ( 'IEM_MC_FLAT32_POP_U32', 'IEM_MC_POP_U32', ),
701 'IEM_MC_POP_U64': ( 'IEM_MC_POP_U64', 'IEM_MC_FLAT64_POP_U64', ),
702 };
703
704 kdThreadedCalcRmEffAddrMcByVariation = {
705 ksVariation_16: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
706 ksVariation_16f: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
707 ksVariation_16_Pre386: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
708 ksVariation_16f_Pre386: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
709 ksVariation_32_Addr16: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
710 ksVariation_32f_Addr16: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16',
711 ksVariation_16_Addr32: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
712 ksVariation_16f_Addr32: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
713 ksVariation_32: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
714 ksVariation_32f: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
715 ksVariation_32_Flat: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
716 ksVariation_32f_Flat: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32',
717 ksVariation_64: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64',
718 ksVariation_64f: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64',
719 ksVariation_64_FsGs: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64_FSGS',
720 ksVariation_64f_FsGs: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64_FSGS',
721 ksVariation_64_Addr32: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64_ADDR32', ## @todo How did this work again...
722 ksVariation_64f_Addr32: 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64_ADDR32',
723 };
724
725 def analyzeMorphStmtForThreaded(self, aoStmts, iParamRef = 0):
726 """
727 Transforms (copy) the statements into those for the threaded function.
728
729 Returns list/tree of statements (aoStmts is not modified) and the new
730 iParamRef value.
731 """
732 #
733 # We'll be traversing aoParamRefs in parallel to the statements, so we
734 # must match the traversal in analyzeFindThreadedParamRefs exactly.
735 #
736 #print('McBlock at %s:%s' % (os.path.split(self.oMcBlock.sSrcFile)[1], self.oMcBlock.iBeginLine,));
737 aoThreadedStmts = [];
738 for oStmt in aoStmts:
739 # Skip C++ statements that is purely related to decoding.
740 if not oStmt.isCppStmt() or not oStmt.fDecode:
741 # Copy the statement. Make a deep copy to make sure we've got our own
742 # copies of all instance variables, even if a bit overkill at the moment.
743 oNewStmt = copy.deepcopy(oStmt);
744 aoThreadedStmts.append(oNewStmt);
745 #print('oNewStmt %s %s' % (oNewStmt.sName, len(oNewStmt.asParams),));
746
747 # If the statement has parameter references, process the relevant parameters.
748 # We grab the references relevant to this statement and apply them in reserve order.
749 if iParamRef < len(self.aoParamRefs) and self.aoParamRefs[iParamRef].oStmt == oStmt:
750 iParamRefFirst = iParamRef;
751 while True:
752 iParamRef += 1;
753 if iParamRef >= len(self.aoParamRefs) or self.aoParamRefs[iParamRef].oStmt != oStmt:
754 break;
755
756 #print('iParamRefFirst=%s iParamRef=%s' % (iParamRefFirst, iParamRef));
757 for iCurRef in range(iParamRef - 1, iParamRefFirst - 1, -1):
758 oCurRef = self.aoParamRefs[iCurRef];
759 if oCurRef.iParam is not None:
760 assert oCurRef.oStmt == oStmt;
761 #print('iCurRef=%s iParam=%s sOrgRef=%s' % (iCurRef, oCurRef.iParam, oCurRef.sOrgRef));
762 sSrcParam = oNewStmt.asParams[oCurRef.iParam];
763 assert ( sSrcParam[oCurRef.offParam : oCurRef.offParam + len(oCurRef.sOrgRef)] == oCurRef.sOrgRef
764 or oCurRef.fCustomRef), \
765 'offParam=%s sOrgRef=%s iParam=%s oStmt.sName=%s sSrcParam=%s<eos>' \
766 % (oCurRef.offParam, oCurRef.sOrgRef, oCurRef.iParam, oStmt.sName, sSrcParam);
767 oNewStmt.asParams[oCurRef.iParam] = sSrcParam[0 : oCurRef.offParam] \
768 + oCurRef.sNewName \
769 + sSrcParam[oCurRef.offParam + len(oCurRef.sOrgRef) : ];
770
771 # Morph IEM_MC_CALC_RM_EFF_ADDR into IEM_MC_CALC_RM_EFF_ADDR_THREADED ...
772 if oNewStmt.sName == 'IEM_MC_CALC_RM_EFF_ADDR':
773 oNewStmt.sName = self.kdThreadedCalcRmEffAddrMcByVariation[self.sVariation];
774 assert len(oNewStmt.asParams) == 3;
775
776 if self.sVariation in self.kdVariationsWithFlatAddr16:
777 oNewStmt.asParams = [
778 oNewStmt.asParams[0], oNewStmt.asParams[1], self.dParamRefs['u16Disp'][0].sNewName,
779 ];
780 else:
781 sSibAndMore = self.dParamRefs['bSib'][0].sNewName; # Merge bSib and 2nd part of cbImmAndRspOffset.
782 if oStmt.asParams[2] not in ('0', '1', '2', '4'):
783 sSibAndMore = '(%s) | ((%s) & 0x0f00)' % (self.dParamRefs['bSib'][0].sNewName, oStmt.asParams[2]);
784
785 if self.sVariation in self.kdVariationsWithFlatAddr32No64:
786 oNewStmt.asParams = [
787 oNewStmt.asParams[0], oNewStmt.asParams[1], sSibAndMore, self.dParamRefs['u32Disp'][0].sNewName,
788 ];
789 else:
790 oNewStmt.asParams = [
791 oNewStmt.asParams[0], self.dParamRefs['bRmEx'][0].sNewName, sSibAndMore,
792 self.dParamRefs['u32Disp'][0].sNewName, self.dParamRefs['cbInstr'][0].sNewName,
793 ];
794 # ... and IEM_MC_ADVANCE_RIP_AND_FINISH into *_THREADED_PCxx[_WITH_FLAGS] ...
795 elif oNewStmt.sName in ('IEM_MC_ADVANCE_RIP_AND_FINISH', 'IEM_MC_REL_JMP_S8_AND_FINISH',
796 'IEM_MC_REL_JMP_S16_AND_FINISH', 'IEM_MC_REL_JMP_S32_AND_FINISH'):
797 oNewStmt.asParams.append(self.dParamRefs['cbInstr'][0].sNewName);
798 if ( oNewStmt.sName in ('IEM_MC_REL_JMP_S8_AND_FINISH', )
799 and self.sVariation not in (self.ksVariation_16_Pre386, self.ksVariation_16f_Pre386,)):
800 oNewStmt.asParams.append(self.dParamRefs['pVCpu->iem.s.enmEffOpSize'][0].sNewName);
801 oNewStmt.sName += '_THREADED';
802 if self.sVariation in (self.ksVariation_64, self.ksVariation_64_FsGs, self.ksVariation_64_Addr32):
803 oNewStmt.sName += '_PC64';
804 elif self.sVariation in (self.ksVariation_64f, self.ksVariation_64f_FsGs, self.ksVariation_64f_Addr32):
805 oNewStmt.sName += '_PC64_WITH_FLAGS';
806 elif self.sVariation == self.ksVariation_16_Pre386:
807 oNewStmt.sName += '_PC16';
808 elif self.sVariation == self.ksVariation_16f_Pre386:
809 oNewStmt.sName += '_PC16_WITH_FLAGS';
810 elif self.sVariation not in self.kdVariationsWithEflagsCheckingAndClearing:
811 assert self.sVariation != self.ksVariation_Default;
812 oNewStmt.sName += '_PC32';
813 else:
814 oNewStmt.sName += '_PC32_WITH_FLAGS';
815
816 # ... and IEM_MC_*_GREG_U8 into *_THREADED w/ reworked index taking REX into account
817 elif oNewStmt.sName.startswith('IEM_MC_') and oNewStmt.sName.find('_GREG_U8') > 0:
818 (idxReg, _, sStdRef) = self.analyze8BitGRegStmt(oStmt); # Don't use oNewStmt as it has been modified!
819 oNewStmt.asParams[idxReg] = self.dParamRefs[sStdRef][0].sNewName;
820 oNewStmt.sName += '_THREADED';
821
822 # ... and IEM_MC_CALL_CIMPL_[0-5] and IEM_MC_DEFER_TO_CIMPL_[0-5]_RET into *_THREADED ...
823 elif oNewStmt.sName.startswith('IEM_MC_CALL_CIMPL_') or oNewStmt.sName.startswith('IEM_MC_DEFER_TO_CIMPL_'):
824 oNewStmt.sName += '_THREADED';
825 oNewStmt.asParams.insert(0, self.dParamRefs['cbInstr'][0].sNewName);
826
827 # ... and in FLAT modes we must morph memory access into FLAT accesses ...
828 elif ( self.sVariation in self.kdVariationsWithFlatAddress
829 and ( oNewStmt.sName.startswith('IEM_MC_FETCH_MEM')
830 or (oNewStmt.sName.startswith('IEM_MC_STORE_MEM_') and oNewStmt.sName.find('_BY_REF') < 0)
831 or oNewStmt.sName.startswith('IEM_MC_MEM_MAP') )):
832 idxEffSeg = self.kdMemMcToFlatInfo[oNewStmt.sName][0];
833 if idxEffSeg != -1:
834 if ( oNewStmt.asParams[idxEffSeg].find('iEffSeg') < 0
835 and oNewStmt.asParams[idxEffSeg] not in ('X86_SREG_ES', ) ):
836 self.raiseProblem('Expected iEffSeg as param #%d to %s: %s'
837 % (idxEffSeg + 1, oNewStmt.sName, oNewStmt.asParams[idxEffSeg],));
838 oNewStmt.asParams.pop(idxEffSeg);
839 oNewStmt.sName = self.kdMemMcToFlatInfo[oNewStmt.sName][1];
840
841 # ... PUSH and POP also needs flat variants, but these differ a little.
842 elif ( self.sVariation in self.kdVariationsWithFlatAddress
843 and ( (oNewStmt.sName.startswith('IEM_MC_PUSH') and oNewStmt.sName.find('_FPU') < 0)
844 or oNewStmt.sName.startswith('IEM_MC_POP'))):
845 oNewStmt.sName = self.kdMemMcToFlatInfoStack[oNewStmt.sName][int(self.sVariation in (self.ksVariation_64,
846 self.ksVariation_64f,))];
847
848
849 # Process branches of conditionals recursively.
850 if isinstance(oStmt, iai.McStmtCond):
851 (oNewStmt.aoIfBranch, iParamRef) = self.analyzeMorphStmtForThreaded(oStmt.aoIfBranch, iParamRef);
852 if oStmt.aoElseBranch:
853 (oNewStmt.aoElseBranch, iParamRef) = self.analyzeMorphStmtForThreaded(oStmt.aoElseBranch, iParamRef);
854
855 return (aoThreadedStmts, iParamRef);
856
857
858 def analyzeConsolidateThreadedParamRefs(self):
859 """
860 Consolidate threaded function parameter references into a dictionary
861 with lists of the references to each variable/field.
862 """
863 # Gather unique parameters.
864 self.dParamRefs = {};
865 for oRef in self.aoParamRefs:
866 if oRef.sStdRef not in self.dParamRefs:
867 self.dParamRefs[oRef.sStdRef] = [oRef,];
868 else:
869 self.dParamRefs[oRef.sStdRef].append(oRef);
870
871 # Generate names for them for use in the threaded function.
872 dParamNames = {};
873 for sName, aoRefs in self.dParamRefs.items():
874 # Morph the reference expression into a name.
875 if sName.startswith('IEM_GET_MODRM_REG'): sName = 'bModRmRegP';
876 elif sName.startswith('IEM_GET_MODRM_RM'): sName = 'bModRmRmP';
877 elif sName.startswith('IEM_GET_MODRM_REG_8'): sName = 'bModRmReg8P';
878 elif sName.startswith('IEM_GET_MODRM_RM_8'): sName = 'bModRmRm8P';
879 elif sName.startswith('IEM_GET_EFFECTIVE_VVVV'): sName = 'bEffVvvvP';
880 elif sName.find('.') >= 0 or sName.find('->') >= 0:
881 sName = sName[max(sName.rfind('.'), sName.rfind('>')) + 1 : ] + 'P';
882 else:
883 sName += 'P';
884
885 # Ensure it's unique.
886 if sName in dParamNames:
887 for i in range(10):
888 if sName + str(i) not in dParamNames:
889 sName += str(i);
890 break;
891 dParamNames[sName] = True;
892
893 # Update all the references.
894 for oRef in aoRefs:
895 oRef.sNewName = sName;
896
897 # Organize them by size too for the purpose of optimize them.
898 dBySize = {} # type: Dict[str, str]
899 for sStdRef, aoRefs in self.dParamRefs.items():
900 if aoRefs[0].sType[0] != 'P':
901 cBits = g_kdTypeInfo[aoRefs[0].sType][0];
902 assert(cBits <= 64);
903 else:
904 cBits = 64;
905
906 if cBits not in dBySize:
907 dBySize[cBits] = [sStdRef,]
908 else:
909 dBySize[cBits].append(sStdRef);
910
911 # Pack the parameters as best as we can, starting with the largest ones
912 # and ASSUMING a 64-bit parameter size.
913 self.cMinParams = 0;
914 offNewParam = 0;
915 for cBits in sorted(dBySize.keys(), reverse = True):
916 for sStdRef in dBySize[cBits]:
917 if offNewParam == 0 or offNewParam + cBits > 64:
918 self.cMinParams += 1;
919 offNewParam = cBits;
920 else:
921 offNewParam += cBits;
922 assert(offNewParam <= 64);
923
924 for oRef in self.dParamRefs[sStdRef]:
925 oRef.iNewParam = self.cMinParams - 1;
926 oRef.offNewParam = offNewParam - cBits;
927
928 # Currently there are a few that requires 4 parameters, list these so we can figure out why:
929 if self.cMinParams >= 4:
930 print('debug: cMinParams=%s cRawParams=%s - %s:%d'
931 % (self.cMinParams, len(self.dParamRefs), self.oParent.oMcBlock.sSrcFile, self.oParent.oMcBlock.iBeginLine,));
932
933 return True;
934
935 ksHexDigits = '0123456789abcdefABCDEF';
936
937 def analyzeFindThreadedParamRefs(self, aoStmts): # pylint: disable=too-many-statements
938 """
939 Scans the statements for things that have to passed on to the threaded
940 function (populates self.aoParamRefs).
941 """
942 for oStmt in aoStmts:
943 # Some statements we can skip alltogether.
944 if isinstance(oStmt, iai.McCppPreProc):
945 continue;
946 if oStmt.isCppStmt() and oStmt.fDecode:
947 continue;
948 if oStmt.sName in ('IEM_MC_BEGIN',):
949 continue;
950
951 if isinstance(oStmt, iai.McStmtVar):
952 if oStmt.sConstValue is None:
953 continue;
954 aiSkipParams = { 0: True, 1: True, 3: True };
955 else:
956 aiSkipParams = {};
957
958 # Several statements have implicit parameters and some have different parameters.
959 if oStmt.sName in ('IEM_MC_ADVANCE_RIP_AND_FINISH', 'IEM_MC_REL_JMP_S8_AND_FINISH', 'IEM_MC_REL_JMP_S16_AND_FINISH',
960 'IEM_MC_REL_JMP_S32_AND_FINISH', 'IEM_MC_CALL_CIMPL_0', 'IEM_MC_CALL_CIMPL_1',
961 'IEM_MC_CALL_CIMPL_2', 'IEM_MC_CALL_CIMPL_3', 'IEM_MC_CALL_CIMPL_4', 'IEM_MC_CALL_CIMPL_5',
962 'IEM_MC_DEFER_TO_CIMPL_0_RET', 'IEM_MC_DEFER_TO_CIMPL_1_RET', 'IEM_MC_DEFER_TO_CIMPL_2_RET',
963 'IEM_MC_DEFER_TO_CIMPL_3_RET', 'IEM_MC_DEFER_TO_CIMPL_4_RET', 'IEM_MC_DEFER_TO_CIMPL_5_RET', ):
964 self.aoParamRefs.append(ThreadedParamRef('IEM_GET_INSTR_LEN(pVCpu)', 'uint4_t', oStmt, sStdRef = 'cbInstr'));
965
966 if ( oStmt.sName in ('IEM_MC_REL_JMP_S8_AND_FINISH',)
967 and self.sVariation not in (self.ksVariation_16_Pre386, self.ksVariation_16f_Pre386,)):
968 self.aoParamRefs.append(ThreadedParamRef('pVCpu->iem.s.enmEffOpSize', 'IEMMODE', oStmt));
969
970 if oStmt.sName == 'IEM_MC_CALC_RM_EFF_ADDR':
971 # This is being pretty presumptive about bRm always being the RM byte...
972 assert len(oStmt.asParams) == 3;
973 assert oStmt.asParams[1] == 'bRm';
974
975 if self.sVariation in self.kdVariationsWithFlatAddr16:
976 self.aoParamRefs.append(ThreadedParamRef('bRm', 'uint8_t', oStmt));
977 self.aoParamRefs.append(ThreadedParamRef('(uint16_t)uEffAddrInfo' ,
978 'uint16_t', oStmt, sStdRef = 'u16Disp'));
979 elif self.sVariation in self.kdVariationsWithFlatAddr32No64:
980 self.aoParamRefs.append(ThreadedParamRef('bRm', 'uint8_t', oStmt));
981 self.aoParamRefs.append(ThreadedParamRef('(uint8_t)(uEffAddrInfo >> 32)',
982 'uint8_t', oStmt, sStdRef = 'bSib'));
983 self.aoParamRefs.append(ThreadedParamRef('(uint32_t)uEffAddrInfo',
984 'uint32_t', oStmt, sStdRef = 'u32Disp'));
985 else:
986 assert self.sVariation in self.kasVariationsWithAddressOnly64;
987 self.aoParamRefs.append(ThreadedParamRef('IEM_GET_MODRM_EX(pVCpu, bRm)',
988 'uint8_t', oStmt, sStdRef = 'bRmEx'));
989 self.aoParamRefs.append(ThreadedParamRef('(uint8_t)(uEffAddrInfo >> 32)',
990 'uint8_t', oStmt, sStdRef = 'bSib'));
991 self.aoParamRefs.append(ThreadedParamRef('(uint32_t)uEffAddrInfo',
992 'uint32_t', oStmt, sStdRef = 'u32Disp'));
993 self.aoParamRefs.append(ThreadedParamRef('IEM_GET_INSTR_LEN(pVCpu)',
994 'uint4_t', oStmt, sStdRef = 'cbInstr'));
995 aiSkipParams[1] = True; # Skip the bRm parameter as it is being replaced by bRmEx.
996
997 # 8-bit register accesses needs to have their index argument reworked to take REX into account.
998 if oStmt.sName.startswith('IEM_MC_') and oStmt.sName.find('_GREG_U8') > 0:
999 (idxReg, sOrgRef, sStdRef) = self.analyze8BitGRegStmt(oStmt);
1000 self.aoParamRefs.append(ThreadedParamRef(sOrgRef, 'uint16_t', oStmt, idxReg, sStdRef = sStdRef));
1001 aiSkipParams[idxReg] = True; # Skip the parameter below.
1002
1003 # If in flat mode variation, ignore the effective segment parameter to memory MCs.
1004 if ( self.sVariation in self.kdVariationsWithFlatAddress
1005 and oStmt.sName in self.kdMemMcToFlatInfo
1006 and self.kdMemMcToFlatInfo[oStmt.sName][0] != -1):
1007 aiSkipParams[self.kdMemMcToFlatInfo[oStmt.sName][0]] = True;
1008
1009 # Inspect the target of calls to see if we need to pass down a
1010 # function pointer or function table pointer for it to work.
1011 if isinstance(oStmt, iai.McStmtCall):
1012 if oStmt.sFn[0] == 'p':
1013 self.aoParamRefs.append(ThreadedParamRef(oStmt.sFn, self.analyzeCallToType(oStmt.sFn), oStmt, oStmt.idxFn));
1014 elif ( oStmt.sFn[0] != 'i'
1015 and not oStmt.sFn.startswith('IEMTARGETCPU_EFL_BEHAVIOR_SELECT')
1016 and not oStmt.sFn.startswith('IEM_SELECT_HOST_OR_FALLBACK') ):
1017 self.raiseProblem('Bogus function name in %s: %s' % (oStmt.sName, oStmt.sFn,));
1018 aiSkipParams[oStmt.idxFn] = True;
1019
1020 # Skip the hint parameter (first) for IEM_MC_CALL_CIMPL_X.
1021 if oStmt.sName.startswith('IEM_MC_CALL_CIMPL_'):
1022 assert oStmt.idxFn == 1;
1023 aiSkipParams[0] = True;
1024
1025
1026 # Check all the parameters for bogus references.
1027 for iParam, sParam in enumerate(oStmt.asParams):
1028 if iParam not in aiSkipParams and sParam not in self.oParent.dVariables:
1029 # The parameter may contain a C expression, so we have to try
1030 # extract the relevant bits, i.e. variables and fields while
1031 # ignoring operators and parentheses.
1032 offParam = 0;
1033 while offParam < len(sParam):
1034 # Is it the start of an C identifier? If so, find the end, but don't stop on field separators (->, .).
1035 ch = sParam[offParam];
1036 if ch.isalpha() or ch == '_':
1037 offStart = offParam;
1038 offParam += 1;
1039 while offParam < len(sParam):
1040 ch = sParam[offParam];
1041 if not ch.isalnum() and ch != '_' and ch != '.':
1042 if ch != '-' or sParam[offParam + 1] != '>':
1043 # Special hack for the 'CTX_SUFF(pVM)' bit in pVCpu->CTX_SUFF(pVM)->xxxx:
1044 if ( ch == '('
1045 and sParam[offStart : offParam + len('(pVM)->')] == 'pVCpu->CTX_SUFF(pVM)->'):
1046 offParam += len('(pVM)->') - 1;
1047 else:
1048 break;
1049 offParam += 1;
1050 offParam += 1;
1051 sRef = sParam[offStart : offParam];
1052
1053 # For register references, we pass the full register indexes instead as macros
1054 # like IEM_GET_MODRM_REG implicitly references pVCpu->iem.s.uRexReg and the
1055 # threaded function will be more efficient if we just pass the register index
1056 # as a 4-bit param.
1057 if ( sRef.startswith('IEM_GET_MODRM')
1058 or sRef.startswith('IEM_GET_EFFECTIVE_VVVV') ):
1059 offParam = iai.McBlock.skipSpacesAt(sParam, offParam, len(sParam));
1060 if sParam[offParam] != '(':
1061 self.raiseProblem('Expected "(" following %s in "%s"' % (sRef, oStmt.renderCode(),));
1062 (asMacroParams, offCloseParam) = iai.McBlock.extractParams(sParam, offParam);
1063 if asMacroParams is None:
1064 self.raiseProblem('Unable to find ")" for %s in "%s"' % (sRef, oStmt.renderCode(),));
1065 offParam = offCloseParam + 1;
1066 self.aoParamRefs.append(ThreadedParamRef(sParam[offStart : offParam], 'uint8_t',
1067 oStmt, iParam, offStart));
1068
1069 # We can skip known variables.
1070 elif sRef in self.oParent.dVariables:
1071 pass;
1072
1073 # Skip certain macro invocations.
1074 elif sRef in ('IEM_GET_HOST_CPU_FEATURES',
1075 'IEM_GET_GUEST_CPU_FEATURES',
1076 'IEM_IS_GUEST_CPU_AMD',
1077 'IEM_IS_16BIT_CODE',
1078 'IEM_IS_32BIT_CODE',
1079 'IEM_IS_64BIT_CODE',
1080 ):
1081 offParam = iai.McBlock.skipSpacesAt(sParam, offParam, len(sParam));
1082 if sParam[offParam] != '(':
1083 self.raiseProblem('Expected "(" following %s in "%s"' % (sRef, oStmt.renderCode(),));
1084 (asMacroParams, offCloseParam) = iai.McBlock.extractParams(sParam, offParam);
1085 if asMacroParams is None:
1086 self.raiseProblem('Unable to find ")" for %s in "%s"' % (sRef, oStmt.renderCode(),));
1087 offParam = offCloseParam + 1;
1088
1089 # Skip any dereference following it, unless it's a predicate like IEM_IS_GUEST_CPU_AMD.
1090 if sRef not in ('IEM_IS_GUEST_CPU_AMD',
1091 'IEM_IS_16BIT_CODE',
1092 'IEM_IS_32BIT_CODE',
1093 'IEM_IS_64BIT_CODE',
1094 ):
1095 offParam = iai.McBlock.skipSpacesAt(sParam, offParam, len(sParam));
1096 if offParam + 2 <= len(sParam) and sParam[offParam : offParam + 2] == '->':
1097 offParam = iai.McBlock.skipSpacesAt(sParam, offParam + 2, len(sParam));
1098 while offParam < len(sParam) and (sParam[offParam].isalnum() or sParam[offParam] in '_.'):
1099 offParam += 1;
1100
1101 # Skip constants, globals, types (casts), sizeof and macros.
1102 elif ( sRef.startswith('IEM_OP_PRF_')
1103 or sRef.startswith('IEM_ACCESS_')
1104 or sRef.startswith('IEMINT_')
1105 or sRef.startswith('X86_GREG_')
1106 or sRef.startswith('X86_SREG_')
1107 or sRef.startswith('X86_EFL_')
1108 or sRef.startswith('X86_FSW_')
1109 or sRef.startswith('X86_FCW_')
1110 or sRef.startswith('X86_XCPT_')
1111 or sRef.startswith('IEMMODE_')
1112 or sRef.startswith('IEM_F_')
1113 or sRef.startswith('IEM_CIMPL_F_')
1114 or sRef.startswith('g_')
1115 or sRef.startswith('iemAImpl_')
1116 or sRef in ( 'int8_t', 'int16_t', 'int32_t',
1117 'INT8_C', 'INT16_C', 'INT32_C', 'INT64_C',
1118 'UINT8_C', 'UINT16_C', 'UINT32_C', 'UINT64_C',
1119 'UINT8_MAX', 'UINT16_MAX', 'UINT32_MAX', 'UINT64_MAX',
1120 'INT8_MAX', 'INT16_MAX', 'INT32_MAX', 'INT64_MAX',
1121 'INT8_MIN', 'INT16_MIN', 'INT32_MIN', 'INT64_MIN',
1122 'sizeof', 'NOREF', 'RT_NOREF', 'IEMMODE_64BIT',
1123 'RT_BIT_32', 'true', 'false', 'NIL_RTGCPTR',) ):
1124 pass;
1125
1126 # Skip certain macro invocations.
1127 # Any variable (non-field) and decoder fields in IEMCPU will need to be parameterized.
1128 elif ( ( '.' not in sRef
1129 and '-' not in sRef
1130 and sRef not in ('pVCpu', ) )
1131 or iai.McBlock.koReIemDecoderVars.search(sRef) is not None):
1132 self.aoParamRefs.append(ThreadedParamRef(sRef, self.analyzeReferenceToType(sRef),
1133 oStmt, iParam, offStart));
1134 # Number.
1135 elif ch.isdigit():
1136 if ( ch == '0'
1137 and offParam + 2 <= len(sParam)
1138 and sParam[offParam + 1] in 'xX'
1139 and sParam[offParam + 2] in self.ksHexDigits ):
1140 offParam += 2;
1141 while offParam < len(sParam) and sParam[offParam] in self.ksHexDigits:
1142 offParam += 1;
1143 else:
1144 while offParam < len(sParam) and sParam[offParam].isdigit():
1145 offParam += 1;
1146 # Comment?
1147 elif ( ch == '/'
1148 and offParam + 4 <= len(sParam)
1149 and sParam[offParam + 1] == '*'):
1150 offParam += 2;
1151 offNext = sParam.find('*/', offParam);
1152 if offNext < offParam:
1153 self.raiseProblem('Unable to find "*/" in "%s" ("%s")' % (sRef, oStmt.renderCode(),));
1154 offParam = offNext + 2;
1155 # Whatever else.
1156 else:
1157 offParam += 1;
1158
1159 # Traverse the branches of conditionals.
1160 if isinstance(oStmt, iai.McStmtCond):
1161 self.analyzeFindThreadedParamRefs(oStmt.aoIfBranch);
1162 self.analyzeFindThreadedParamRefs(oStmt.aoElseBranch);
1163 return True;
1164
1165 def analyzeVariation(self, aoStmts):
1166 """
1167 2nd part of the analysis, done on each variation.
1168
1169 The variations may differ in parameter requirements and will end up with
1170 slightly different MC sequences. Thus this is done on each individually.
1171
1172 Returns dummy True - raises exception on trouble.
1173 """
1174 # Now scan the code for variables and field references that needs to
1175 # be passed to the threaded function because they are related to the
1176 # instruction decoding.
1177 self.analyzeFindThreadedParamRefs(aoStmts);
1178 self.analyzeConsolidateThreadedParamRefs();
1179
1180 # Morph the statement stream for the block into what we'll be using in the threaded function.
1181 (self.aoStmtsForThreadedFunction, iParamRef) = self.analyzeMorphStmtForThreaded(aoStmts);
1182 if iParamRef != len(self.aoParamRefs):
1183 raise Exception('iParamRef=%s, expected %s!' % (iParamRef, len(self.aoParamRefs),));
1184
1185 return True;
1186
1187 def emitThreadedCallStmts(self, cchIndent, sCallVarNm = None):
1188 """
1189 Produces generic C++ statments that emits a call to the thread function
1190 variation and any subsequent checks that may be necessary after that.
1191
1192 The sCallVarNm is for emitting
1193 """
1194 aoStmts = [
1195 iai.McCppCall('IEM_MC2_BEGIN_EMIT_CALLS',
1196 ['1' if 'IEM_CIMPL_F_CHECK_IRQ_BEFORE' in self.oParent.dsCImplFlags else '0'],
1197 cchIndent = cchIndent), # Scope and a hook for various stuff.
1198 ];
1199
1200 # The call to the threaded function.
1201 asCallArgs = [ self.getIndexName() if not sCallVarNm else sCallVarNm, ];
1202 for iParam in range(self.cMinParams):
1203 asFrags = [];
1204 for aoRefs in self.dParamRefs.values():
1205 oRef = aoRefs[0];
1206 if oRef.iNewParam == iParam:
1207 sCast = '(uint64_t)'
1208 if oRef.sType in ('int8_t', 'int16_t', 'int32_t'): # Make sure these doesn't get sign-extended.
1209 sCast = '(uint64_t)(u' + oRef.sType + ')';
1210 if oRef.offNewParam == 0:
1211 asFrags.append(sCast + '(' + oRef.sOrgRef + ')');
1212 else:
1213 asFrags.append('(%s(%s) << %s)' % (sCast, oRef.sOrgRef, oRef.offNewParam));
1214 assert asFrags;
1215 asCallArgs.append(' | '.join(asFrags));
1216
1217 aoStmts.append(iai.McCppCall('IEM_MC2_EMIT_CALL_%s' % (len(asCallArgs) - 1,), asCallArgs, cchIndent = cchIndent));
1218
1219 # For CIMPL stuff, we need to consult the associated IEM_CIMPL_F_XXX
1220 # mask and maybe emit additional checks.
1221 if ( 'IEM_CIMPL_F_MODE' in self.oParent.dsCImplFlags
1222 or 'IEM_CIMPL_F_XCPT' in self.oParent.dsCImplFlags
1223 or 'IEM_CIMPL_F_VMEXIT' in self.oParent.dsCImplFlags):
1224 aoStmts.append(iai.McCppCall('IEM_MC2_EMIT_CALL_1', ( 'kIemThreadedFunc_BltIn_CheckMode', 'pVCpu->iem.s.fExec', ),
1225 cchIndent = cchIndent));
1226
1227 sCImplFlags = ' | '.join(self.oParent.dsCImplFlags.keys());
1228 if not sCImplFlags:
1229 sCImplFlags = '0'
1230 aoStmts.append(iai.McCppCall('IEM_MC2_END_EMIT_CALLS', ( sCImplFlags, ), cchIndent = cchIndent)); # For closing the scope.
1231
1232 # Emit fEndTb = true or fTbBranched = true if any of the CIMPL flags
1233 # indicates we should do so.
1234 # Note! iemThreadedRecompilerMcDeferToCImpl0 duplicates work done here.
1235 asEndTbFlags = [];
1236 asTbBranchedFlags = [];
1237 for sFlag in self.oParent.dsCImplFlags:
1238 if self.kdCImplFlags[sFlag] is True:
1239 asEndTbFlags.append(sFlag);
1240 elif sFlag.startswith('IEM_CIMPL_F_BRANCH_'):
1241 asTbBranchedFlags.append(sFlag);
1242 if asTbBranchedFlags:
1243 aoStmts.append(iai.McCppGeneric('iemThreadedSetBranched(pVCpu, %s);'
1244 % ((' | '.join(asTbBranchedFlags)).replace('IEM_CIMPL_F_BRANCH', 'IEMBRANCHED_F'),),
1245 cchIndent = cchIndent)); # Inline fn saves ~2 seconds for gcc 13/dbg (1m13s vs 1m15s).
1246 if asEndTbFlags:
1247 aoStmts.append(iai.McCppGeneric('pVCpu->iem.s.fEndTb = true; /* %s */' % (','.join(asEndTbFlags),),
1248 cchIndent = cchIndent));
1249
1250 if 'IEM_CIMPL_F_CHECK_IRQ_AFTER' in self.oParent.dsCImplFlags:
1251 aoStmts.append(iai.McCppGeneric('pVCpu->iem.s.cInstrTillIrqCheck = 0;', cchIndent = cchIndent));
1252
1253 return aoStmts;
1254
1255
1256class ThreadedFunction(object):
1257 """
1258 A threaded function.
1259 """
1260
1261 def __init__(self, oMcBlock: iai.McBlock) -> None:
1262 self.oMcBlock = oMcBlock # type: iai.McBlock
1263 # The remaining fields are only useful after analyze() has been called:
1264 ## Variations for this block. There is at least one.
1265 self.aoVariations = [] # type: List[ThreadedFunctionVariation]
1266 ## Variation dictionary containing the same as aoVariations.
1267 self.dVariations = {} # type: Dict[str, ThreadedFunctionVariation]
1268 ## Dictionary of local variables (IEM_MC_LOCAL[_CONST]) and call arguments (IEM_MC_ARG*).
1269 self.dVariables = {} # type: Dict[str, iai.McStmtVar]
1270 ## Dictionary with any IEM_CIMPL_F_XXX flags explicitly advertised in the code block
1271 ## and those determined by analyzeCodeOperation().
1272 self.dsCImplFlags = {} # type: Dict[str, bool]
1273
1274 @staticmethod
1275 def dummyInstance():
1276 """ Gets a dummy instance. """
1277 return ThreadedFunction(iai.McBlock('null', 999999999, 999999999,
1278 iai.DecoderFunction('null', 999999999, 'nil', ('','')), 999999999));
1279
1280 def raiseProblem(self, sMessage):
1281 """ Raises a problem. """
1282 raise Exception('%s:%s: error: %s' % (self.oMcBlock.sSrcFile, self.oMcBlock.iBeginLine, sMessage, ));
1283
1284 def warning(self, sMessage):
1285 """ Emits a warning. """
1286 print('%s:%s: warning: %s' % (self.oMcBlock.sSrcFile, self.oMcBlock.iBeginLine, sMessage, ));
1287
1288 def analyzeFindVariablesAndCallArgs(self, aoStmts: List[iai.McStmt]) -> bool:
1289 """ Scans the statements for MC variables and call arguments. """
1290 for oStmt in aoStmts:
1291 if isinstance(oStmt, iai.McStmtVar):
1292 if oStmt.sVarName in self.dVariables:
1293 raise Exception('Variable %s is defined more than once!' % (oStmt.sVarName,));
1294 self.dVariables[oStmt.sVarName] = oStmt.sVarName;
1295
1296 # There shouldn't be any variables or arguments declared inside if/
1297 # else blocks, but scan them too to be on the safe side.
1298 if isinstance(oStmt, iai.McStmtCond):
1299 cBefore = len(self.dVariables);
1300 self.analyzeFindVariablesAndCallArgs(oStmt.aoIfBranch);
1301 self.analyzeFindVariablesAndCallArgs(oStmt.aoElseBranch);
1302 if len(self.dVariables) != cBefore:
1303 raise Exception('Variables/arguments defined in conditional branches!');
1304 return True;
1305
1306 def analyzeCodeOperation(self, aoStmts: List[iai.McStmt], fSeenConditional = False) -> bool:
1307 """
1308 Analyzes the code looking clues as to additional side-effects.
1309
1310 Currently this is simply looking for branching and adding the relevant
1311 branch flags to dsCImplFlags. ASSUMES the caller pre-populates the
1312 dictionary with a copy of self.oMcBlock.dsCImplFlags.
1313 """
1314 for oStmt in aoStmts:
1315 # Set IEM_IMPL_C_F_BRANCH if we see any branching MCs.
1316 if oStmt.sName.startswith('IEM_MC_SET_RIP'):
1317 assert not fSeenConditional;
1318 self.dsCImplFlags['IEM_CIMPL_F_BRANCH_INDIRECT'] = True;
1319 elif oStmt.sName.startswith('IEM_MC_REL_JMP'):
1320 self.dsCImplFlags['IEM_CIMPL_F_BRANCH_RELATIVE'] = True;
1321 if fSeenConditional:
1322 self.dsCImplFlags['IEM_CIMPL_F_BRANCH_CONDITIONAL'] = True;
1323
1324 # Process branches of conditionals recursively.
1325 if isinstance(oStmt, iai.McStmtCond):
1326 self.analyzeCodeOperation(oStmt.aoIfBranch, True);
1327 if oStmt.aoElseBranch:
1328 self.analyzeCodeOperation(oStmt.aoElseBranch, True);
1329
1330 return True;
1331
1332 def analyze(self):
1333 """
1334 Analyzes the code, identifying the number of parameters it requires and such.
1335
1336 Returns dummy True - raises exception on trouble.
1337 """
1338
1339 # Check the block for errors before we proceed (will decode it).
1340 asErrors = self.oMcBlock.check();
1341 if asErrors:
1342 raise Exception('\n'.join(['%s:%s: error: %s' % (self.oMcBlock.sSrcFile, self.oMcBlock.iBeginLine, sError, )
1343 for sError in asErrors]));
1344
1345 # Decode the block into a list/tree of McStmt objects.
1346 aoStmts = self.oMcBlock.decode();
1347
1348 # Scan the statements for local variables and call arguments (self.dVariables).
1349 self.analyzeFindVariablesAndCallArgs(aoStmts);
1350
1351 # Scan the code for IEM_CIMPL_F_ and other clues.
1352 self.dsCImplFlags = self.oMcBlock.dsCImplFlags.copy();
1353 self.analyzeCodeOperation(aoStmts);
1354
1355 # Create variations as needed.
1356 if iai.McStmt.findStmtByNames(aoStmts,
1357 { 'IEM_MC_DEFER_TO_CIMPL_0_RET': True,
1358 'IEM_MC_DEFER_TO_CIMPL_1_RET': True,
1359 'IEM_MC_DEFER_TO_CIMPL_2_RET': True,
1360 'IEM_MC_DEFER_TO_CIMPL_3_RET': True, }):
1361 asVariations = (ThreadedFunctionVariation.ksVariation_Default,);
1362
1363 elif iai.McStmt.findStmtByNames(aoStmts, {'IEM_MC_CALC_RM_EFF_ADDR' : True,}):
1364 if 'IEM_MC_F_64BIT' in self.oMcBlock.dsMcFlags:
1365 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressOnly64;
1366 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags and 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
1367 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressNot286Not64;
1368 elif 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
1369 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressNot286;
1370 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags:
1371 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressNot64;
1372 elif 'IEM_MC_F_ONLY_8086' in self.oMcBlock.dsMcFlags:
1373 asVariations = ThreadedFunctionVariation.kasVariationsOnlyPre386;
1374 else:
1375 asVariations = ThreadedFunctionVariation.kasVariationsWithAddress;
1376 else:
1377 if 'IEM_MC_F_64BIT' in self.oMcBlock.dsMcFlags:
1378 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressOnly64;
1379 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags and 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
1380 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressNot286Not64;
1381 elif 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
1382 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressNot286;
1383 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags:
1384 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressNot64;
1385 elif 'IEM_MC_F_ONLY_8086' in self.oMcBlock.dsMcFlags:
1386 asVariations = ThreadedFunctionVariation.kasVariationsOnlyPre386;
1387 else:
1388 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddress;
1389
1390 if not iai.McStmt.findStmtByNames(aoStmts,
1391 { 'IEM_MC_ADVANCE_RIP_AND_FINISH': True,
1392 'IEM_MC_REL_JMP_S8_AND_FINISH': True,
1393 'IEM_MC_REL_JMP_S16_AND_FINISH': True,
1394 'IEM_MC_REL_JMP_S32_AND_FINISH': True,
1395 }):
1396 asVariations = [sVariation for sVariation in asVariations
1397 if sVariation not in ThreadedFunctionVariation.kdVariationsWithEflagsCheckingAndClearing];
1398
1399 self.aoVariations = [ThreadedFunctionVariation(self, sVar) for sVar in asVariations];
1400
1401 # Dictionary variant of the list.
1402 self.dVariations = { oVar.sVariation: oVar for oVar in self.aoVariations };
1403
1404 # Continue the analysis on each variation.
1405 for oVariation in self.aoVariations:
1406 oVariation.analyzeVariation(aoStmts);
1407
1408 return True;
1409
1410 ## Used by emitThreadedCallStmts.
1411 kdVariationsWithNeedForPrefixCheck = {
1412 ThreadedFunctionVariation.ksVariation_64_Addr32: True,
1413 ThreadedFunctionVariation.ksVariation_64f_Addr32: True,
1414 ThreadedFunctionVariation.ksVariation_64_FsGs: True,
1415 ThreadedFunctionVariation.ksVariation_64f_FsGs: True,
1416 ThreadedFunctionVariation.ksVariation_32_Addr16: True,
1417 ThreadedFunctionVariation.ksVariation_32f_Addr16: True,
1418 ThreadedFunctionVariation.ksVariation_32_Flat: True,
1419 ThreadedFunctionVariation.ksVariation_32f_Flat: True,
1420 ThreadedFunctionVariation.ksVariation_16_Addr32: True,
1421 ThreadedFunctionVariation.ksVariation_16f_Addr32: True,
1422 };
1423
1424 def emitThreadedCallStmts(self):
1425 """
1426 Worker for morphInputCode that returns a list of statements that emits
1427 the call to the threaded functions for the block.
1428 """
1429 # Special case for only default variation:
1430 if len(self.aoVariations) == 1 and self.aoVariations[0].sVariation == ThreadedFunctionVariation.ksVariation_Default:
1431 return self.aoVariations[0].emitThreadedCallStmts(0);
1432
1433 #
1434 # Case statement sub-class.
1435 #
1436 dByVari = self.dVariations;
1437 #fDbg = self.oMcBlock.sFunction == 'iemOpCommonPushSReg';
1438 class Case:
1439 def __init__(self, sCond, sVarNm = None):
1440 self.sCond = sCond;
1441 self.sVarNm = sVarNm;
1442 self.oVar = dByVari[sVarNm] if sVarNm else None;
1443 self.aoBody = self.oVar.emitThreadedCallStmts(8) if sVarNm else None;
1444
1445 def toCode(self):
1446 aoStmts = [ iai.McCppGeneric('case %s:' % (self.sCond), cchIndent = 4), ];
1447 if self.aoBody:
1448 aoStmts.extend(self.aoBody);
1449 aoStmts.append(iai.McCppGeneric('break;', cchIndent = 8));
1450 return aoStmts;
1451
1452 def toFunctionAssignment(self):
1453 aoStmts = [ iai.McCppGeneric('case %s:' % (self.sCond), cchIndent = 4), ];
1454 if self.aoBody:
1455 aoStmts.extend([
1456 iai.McCppGeneric('enmFunction = %s;' % (self.oVar.getIndexName(),), cchIndent = 8),
1457 iai.McCppGeneric('break;', cchIndent = 8),
1458 ]);
1459 return aoStmts;
1460
1461 def isSame(self, oThat):
1462 if not self.aoBody: # fall thru always matches.
1463 return True;
1464 if len(self.aoBody) != len(oThat.aoBody):
1465 #if fDbg: print('dbg: body len diff: %s vs %s' % (len(self.aoBody), len(oThat.aoBody),));
1466 return False;
1467 for iStmt, oStmt in enumerate(self.aoBody):
1468 oThatStmt = oThat.aoBody[iStmt] # type: iai.McStmt
1469 assert isinstance(oStmt, iai.McCppGeneric);
1470 assert not isinstance(oStmt, iai.McStmtCond);
1471 if isinstance(oStmt, iai.McStmtCond):
1472 return False;
1473 if oStmt.sName != oThatStmt.sName:
1474 #if fDbg: print('dbg: stmt #%s name: %s vs %s' % (iStmt, oStmt.sName, oThatStmt.sName,));
1475 return False;
1476 if len(oStmt.asParams) != len(oThatStmt.asParams):
1477 #if fDbg: print('dbg: stmt #%s param count: %s vs %s'
1478 # % (iStmt, len(oStmt.asParams), len(oThatStmt.asParams),));
1479 return False;
1480 for iParam, sParam in enumerate(oStmt.asParams):
1481 if ( sParam != oThatStmt.asParams[iParam]
1482 and ( iParam != 1
1483 or not isinstance(oStmt, iai.McCppCall)
1484 or not oStmt.asParams[0].startswith('IEM_MC2_EMIT_CALL_')
1485 or sParam != self.oVar.getIndexName()
1486 or oThatStmt.asParams[iParam] != oThat.oVar.getIndexName() )):
1487 #if fDbg: print('dbg: stmt #%s, param #%s: %s vs %s'
1488 # % (iStmt, iParam, sParam, oThatStmt.asParams[iParam],));
1489 return False;
1490 return True;
1491
1492 #
1493 # Determine what we're switch on.
1494 # This ASSUMES that (IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | IEM_F_MODE_CPUMODE_MASK) == 7!
1495 #
1496 fSimple = True;
1497 sSwitchValue = '(pVCpu->iem.s.fExec & (IEM_F_MODE_CPUMODE_MASK | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK))';
1498 if dByVari.keys() & self.kdVariationsWithNeedForPrefixCheck.keys():
1499 sSwitchValue += ' | (pVCpu->iem.s.enmEffAddrMode == (pVCpu->iem.s.fExec & IEM_F_MODE_CPUMODE_MASK) ? 0 : 8)';
1500 # Accesses via FS and GS and CS goes thru non-FLAT functions. (CS
1501 # is not writable in 32-bit mode (at least), thus the penalty mode
1502 # for any accesses via it (simpler this way).)
1503 sSwitchValue += ' | (pVCpu->iem.s.iEffSeg < X86_SREG_FS && pVCpu->iem.s.iEffSeg != X86_SREG_CS ? 0 : 16)';
1504 fSimple = False; # threaded functions.
1505 if dByVari.keys() & ThreadedFunctionVariation.kdVariationsWithEflagsCheckingAndClearing:
1506 sSwitchValue += ' | ((pVCpu->iem.s.fTbPrevInstr & (IEM_CIMPL_F_RFLAGS | IEM_CIMPL_F_INHIBIT_SHADOW)) || ' \
1507 + '(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_MASK) ? 32 : 0)';
1508
1509 #
1510 # Generate the case statements.
1511 #
1512 # pylintx: disable=x
1513 aoCases = [];
1514 if ThreadedFunctionVariation.ksVariation_64_Addr32 in dByVari:
1515 assert not fSimple;
1516 aoCases.extend([
1517 Case('IEMMODE_64BIT', ThrdFnVar.ksVariation_64),
1518 Case('IEMMODE_64BIT | 16', ThrdFnVar.ksVariation_64_FsGs),
1519 Case('IEMMODE_64BIT | 8 | 16', None), # fall thru
1520 Case('IEMMODE_64BIT | 8', ThrdFnVar.ksVariation_64_Addr32),
1521 ]);
1522 if ThreadedFunctionVariation.ksVariation_64f_Addr32 in dByVari:
1523 aoCases.extend([
1524 Case('IEMMODE_64BIT | 32', ThrdFnVar.ksVariation_64f),
1525 Case('IEMMODE_64BIT | 32 | 16', ThrdFnVar.ksVariation_64f_FsGs),
1526 Case('IEMMODE_64BIT | 32 | 8 | 16', None), # fall thru
1527 Case('IEMMODE_64BIT | 32 | 8', ThrdFnVar.ksVariation_64f_Addr32),
1528 ]);
1529 elif ThrdFnVar.ksVariation_64 in dByVari:
1530 assert fSimple;
1531 aoCases.append(Case('IEMMODE_64BIT', ThrdFnVar.ksVariation_64));
1532 if ThreadedFunctionVariation.ksVariation_64f in dByVari:
1533 aoCases.append(Case('IEMMODE_64BIT | 32', ThrdFnVar.ksVariation_64f));
1534
1535 if ThrdFnVar.ksVariation_32_Addr16 in dByVari:
1536 assert not fSimple;
1537 aoCases.extend([
1538 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK', ThrdFnVar.ksVariation_32_Flat),
1539 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 16', None), # fall thru
1540 Case('IEMMODE_32BIT | 16', None), # fall thru
1541 Case('IEMMODE_32BIT', ThrdFnVar.ksVariation_32),
1542 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 8', None), # fall thru
1543 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 8 | 16',None), # fall thru
1544 Case('IEMMODE_32BIT | 8 | 16',None), # fall thru
1545 Case('IEMMODE_32BIT | 8', ThrdFnVar.ksVariation_32_Addr16),
1546 ]);
1547 if ThrdFnVar.ksVariation_32f_Addr16 in dByVari:
1548 aoCases.extend([
1549 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32', ThrdFnVar.ksVariation_32f_Flat),
1550 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32 | 16', None), # fall thru
1551 Case('IEMMODE_32BIT | 32 | 16', None), # fall thru
1552 Case('IEMMODE_32BIT | 32', ThrdFnVar.ksVariation_32f),
1553 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32 | 8', None), # fall thru
1554 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32 | 8 | 16',None), # fall thru
1555 Case('IEMMODE_32BIT | 32 | 8 | 16',None), # fall thru
1556 Case('IEMMODE_32BIT | 32 | 8', ThrdFnVar.ksVariation_32f_Addr16),
1557 ]);
1558 elif ThrdFnVar.ksVariation_32 in dByVari:
1559 assert fSimple;
1560 aoCases.extend([
1561 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK', None), # fall thru
1562 Case('IEMMODE_32BIT', ThrdFnVar.ksVariation_32),
1563 ]);
1564 if ThrdFnVar.ksVariation_32f in dByVari:
1565 aoCases.extend([
1566 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32', None), # fall thru
1567 Case('IEMMODE_32BIT | 32', ThrdFnVar.ksVariation_32f),
1568 ]);
1569
1570 if ThrdFnVar.ksVariation_16_Addr32 in dByVari:
1571 assert not fSimple;
1572 aoCases.extend([
1573 Case('IEMMODE_16BIT | 16', None), # fall thru
1574 Case('IEMMODE_16BIT', ThrdFnVar.ksVariation_16),
1575 Case('IEMMODE_16BIT | 8 | 16', None), # fall thru
1576 Case('IEMMODE_16BIT | 8', ThrdFnVar.ksVariation_16_Addr32),
1577 ]);
1578 if ThrdFnVar.ksVariation_16f_Addr32 in dByVari:
1579 aoCases.extend([
1580 Case('IEMMODE_16BIT | 32 | 16', None), # fall thru
1581 Case('IEMMODE_16BIT | 32', ThrdFnVar.ksVariation_16f),
1582 Case('IEMMODE_16BIT | 32 | 8 | 16', None), # fall thru
1583 Case('IEMMODE_16BIT | 32 | 8', ThrdFnVar.ksVariation_16f_Addr32),
1584 ]);
1585 elif ThrdFnVar.ksVariation_16 in dByVari:
1586 assert fSimple;
1587 aoCases.append(Case('IEMMODE_16BIT', ThrdFnVar.ksVariation_16));
1588 if ThrdFnVar.ksVariation_16f in dByVari:
1589 aoCases.append(Case('IEMMODE_16BIT | 32', ThrdFnVar.ksVariation_16f));
1590
1591 if ThrdFnVar.ksVariation_16_Pre386 in dByVari:
1592 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK', ThrdFnVar.ksVariation_16_Pre386));
1593 if ThrdFnVar.ksVariation_16f_Pre386 in dByVari: # should be nested under previous if, but line too long.
1594 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32', ThrdFnVar.ksVariation_16f_Pre386));
1595
1596 #
1597 # If the case bodies are all the same, except for the function called,
1598 # we can reduce the code size and hopefully compile time.
1599 #
1600 iFirstCaseWithBody = 0;
1601 while not aoCases[iFirstCaseWithBody].aoBody:
1602 iFirstCaseWithBody += 1
1603 fAllSameCases = True
1604 for iCase in range(iFirstCaseWithBody + 1, len(aoCases)):
1605 fAllSameCases = fAllSameCases and aoCases[iCase].isSame(aoCases[iFirstCaseWithBody]);
1606 #if fDbg: print('fAllSameCases=%s %s' % (fAllSameCases, self.oMcBlock.sFunction,));
1607 if fAllSameCases:
1608 aoStmts = [
1609 iai.McCppGeneric('IEMTHREADEDFUNCS enmFunction;'),
1610 iai.McCppGeneric('switch (%s)' % (sSwitchValue,)),
1611 iai.McCppGeneric('{'),
1612 ];
1613 for oCase in aoCases:
1614 aoStmts.extend(oCase.toFunctionAssignment());
1615 aoStmts.extend([
1616 iai.McCppGeneric('IEM_NOT_REACHED_DEFAULT_CASE_RET();', cchIndent = 4),
1617 iai.McCppGeneric('}'),
1618 ]);
1619 aoStmts.extend(dByVari[aoCases[iFirstCaseWithBody].sVarNm].emitThreadedCallStmts(0, 'enmFunction'));
1620
1621 else:
1622 #
1623 # Generate the generic switch statement.
1624 #
1625 aoStmts = [
1626 iai.McCppGeneric('switch (%s)' % (sSwitchValue,)),
1627 iai.McCppGeneric('{'),
1628 ];
1629 for oCase in aoCases:
1630 aoStmts.extend(oCase.toCode());
1631 aoStmts.extend([
1632 iai.McCppGeneric('IEM_NOT_REACHED_DEFAULT_CASE_RET();', cchIndent = 4),
1633 iai.McCppGeneric('}'),
1634 ]);
1635
1636 return aoStmts;
1637
1638 def morphInputCode(self, aoStmts, fCallEmitted = False, cDepth = 0):
1639 """
1640 Adjusts (& copies) the statements for the input/decoder so it will emit
1641 calls to the right threaded functions for each block.
1642
1643 Returns list/tree of statements (aoStmts is not modified) and updated
1644 fCallEmitted status.
1645 """
1646 #print('McBlock at %s:%s' % (os.path.split(self.oMcBlock.sSrcFile)[1], self.oMcBlock.iBeginLine,));
1647 aoDecoderStmts = [];
1648
1649 for oStmt in aoStmts:
1650 # Copy the statement. Make a deep copy to make sure we've got our own
1651 # copies of all instance variables, even if a bit overkill at the moment.
1652 oNewStmt = copy.deepcopy(oStmt);
1653 aoDecoderStmts.append(oNewStmt);
1654 #print('oNewStmt %s %s' % (oNewStmt.sName, len(oNewStmt.asParams),));
1655 if oNewStmt.sName == 'IEM_MC_BEGIN' and self.dsCImplFlags:
1656 oNewStmt.asParams[3] = ' | '.join(sorted(self.dsCImplFlags.keys()));
1657
1658 # If we haven't emitted the threaded function call yet, look for
1659 # statements which it would naturally follow or preceed.
1660 if not fCallEmitted:
1661 if not oStmt.isCppStmt():
1662 if ( oStmt.sName.startswith('IEM_MC_MAYBE_RAISE_') \
1663 or (oStmt.sName.endswith('_AND_FINISH') and oStmt.sName.startswith('IEM_MC_'))
1664 or oStmt.sName.startswith('IEM_MC_CALL_CIMPL_')
1665 or oStmt.sName.startswith('IEM_MC_DEFER_TO_CIMPL_')
1666 or oStmt.sName in ('IEM_MC_RAISE_DIVIDE_ERROR',)):
1667 aoDecoderStmts.pop();
1668 aoDecoderStmts.extend(self.emitThreadedCallStmts());
1669 aoDecoderStmts.append(oNewStmt);
1670 fCallEmitted = True;
1671 elif ( oStmt.fDecode
1672 and ( oStmt.asParams[0].find('IEMOP_HLP_DONE_') >= 0
1673 or oStmt.asParams[0].find('IEMOP_HLP_DECODED_') >= 0)):
1674 aoDecoderStmts.extend(self.emitThreadedCallStmts());
1675 fCallEmitted = True;
1676
1677 # Process branches of conditionals recursively.
1678 if isinstance(oStmt, iai.McStmtCond):
1679 (oNewStmt.aoIfBranch, fCallEmitted1) = self.morphInputCode(oStmt.aoIfBranch, fCallEmitted, cDepth + 1);
1680 if oStmt.aoElseBranch:
1681 (oNewStmt.aoElseBranch, fCallEmitted2) = self.morphInputCode(oStmt.aoElseBranch, fCallEmitted, cDepth + 1);
1682 else:
1683 fCallEmitted2 = False;
1684 fCallEmitted = fCallEmitted or (fCallEmitted1 and fCallEmitted2);
1685
1686 if not fCallEmitted and cDepth == 0:
1687 self.raiseProblem('Unable to insert call to threaded function.');
1688
1689 return (aoDecoderStmts, fCallEmitted);
1690
1691
1692 def generateInputCode(self):
1693 """
1694 Modifies the input code.
1695 """
1696 cchIndent = (self.oMcBlock.cchIndent + 3) // 4 * 4;
1697
1698 if len(self.oMcBlock.aoStmts) == 1:
1699 # IEM_MC_DEFER_TO_CIMPL_X_RET - need to wrap in {} to make it safe to insert into random code.
1700 sCode = ' ' * cchIndent + 'pVCpu->iem.s.fTbCurInstr = ';
1701 if self.dsCImplFlags:
1702 sCode += ' | '.join(sorted(self.dsCImplFlags.keys())) + ';\n';
1703 else:
1704 sCode += '0;\n';
1705 sCode += iai.McStmt.renderCodeForList(self.morphInputCode(self.oMcBlock.aoStmts)[0],
1706 cchIndent = cchIndent).replace('\n', ' /* gen */\n', 1);
1707 sIndent = ' ' * (min(cchIndent, 2) - 2);
1708 sCode = sIndent + '{\n' + sCode + sIndent + '}\n';
1709 return sCode;
1710
1711 # IEM_MC_BEGIN/END block
1712 assert len(self.oMcBlock.asLines) > 2, "asLines=%s" % (self.oMcBlock.asLines,);
1713 return iai.McStmt.renderCodeForList(self.morphInputCode(self.oMcBlock.aoStmts)[0],
1714 cchIndent = cchIndent).replace('\n', ' /* gen */\n', 1);
1715
1716# Short alias for ThreadedFunctionVariation.
1717ThrdFnVar = ThreadedFunctionVariation;
1718
1719
1720class IEMThreadedGenerator(object):
1721 """
1722 The threaded code generator & annotator.
1723 """
1724
1725 def __init__(self):
1726 self.aoThreadedFuncs = [] # type: List[ThreadedFunction]
1727 self.oOptions = None # type: argparse.Namespace
1728 self.aoParsers = [] # type: List[IEMAllInstPython.SimpleParser]
1729 self.aidxFirstFunctions = [] # type: List[int] ##< Runs parallel to aoParser giving the index of the first function.
1730
1731 #
1732 # Processing.
1733 #
1734
1735 def processInputFiles(self, sNativeRecompilerArch = None):
1736 """
1737 Process the input files.
1738 """
1739
1740 # Parse the files.
1741 self.aoParsers = iai.parseFiles(self.oOptions.asInFiles);
1742
1743 # Create threaded functions for the MC blocks.
1744 self.aoThreadedFuncs = [ThreadedFunction(oMcBlock) for oMcBlock in iai.g_aoMcBlocks];
1745
1746 # Analyze the threaded functions.
1747 dRawParamCounts = {};
1748 dMinParamCounts = {};
1749 for oThreadedFunction in self.aoThreadedFuncs:
1750 oThreadedFunction.analyze();
1751 for oVariation in oThreadedFunction.aoVariations:
1752 dRawParamCounts[len(oVariation.dParamRefs)] = dRawParamCounts.get(len(oVariation.dParamRefs), 0) + 1;
1753 dMinParamCounts[oVariation.cMinParams] = dMinParamCounts.get(oVariation.cMinParams, 0) + 1;
1754 print('debug: param count distribution, raw and optimized:', file = sys.stderr);
1755 for cCount in sorted({cBits: True for cBits in list(dRawParamCounts.keys()) + list(dMinParamCounts.keys())}.keys()):
1756 print('debug: %s params: %4s raw, %4s min'
1757 % (cCount, dRawParamCounts.get(cCount, 0), dMinParamCounts.get(cCount, 0)),
1758 file = sys.stderr);
1759
1760 # Populate aidxFirstFunctions. This is ASSUMING that
1761 # g_aoMcBlocks/self.aoThreadedFuncs are in self.aoParsers order.
1762 iThreadedFunction = 0;
1763 oThreadedFunction = self.getThreadedFunctionByIndex(0);
1764 self.aidxFirstFunctions = [];
1765 for oParser in self.aoParsers:
1766 self.aidxFirstFunctions.append(iThreadedFunction);
1767
1768 while oThreadedFunction.oMcBlock.sSrcFile == oParser.sSrcFile:
1769 iThreadedFunction += 1;
1770 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
1771
1772 # Analyze the threaded functions and their variations for native recompilation.
1773 if sNativeRecompilerArch:
1774 cTotal = 0;
1775 cNative = 0;
1776 for oThreadedFunction in self.aoThreadedFuncs:
1777 for oVariation in oThreadedFunction.aoVariations:
1778 cTotal += 1;
1779 oVariation.oNativeRecomp = ian.analyzeVariantForNativeRecomp(oVariation, sNativeRecompilerArch);
1780 if oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
1781 cNative += 1;
1782 print('debug: %.1f%% / %u out of %u threaded function variations are recompilable'
1783 % (cNative * 100.0 / cTotal, cNative, cTotal));
1784
1785 # Gather arguments + variable statistics for the MC blocks.
1786 cMaxArgs = 0;
1787 cMaxVars = 0;
1788 cMaxVarsAndArgs = 0;
1789 cbMaxArgs = 0;
1790 cbMaxVars = 0;
1791 cbMaxVarsAndArgs = 0;
1792 for oThreadedFunction in self.aoThreadedFuncs:
1793 if oThreadedFunction.oMcBlock.cLocals >= 0:
1794 assert oThreadedFunction.oMcBlock.cArgs >= 0;
1795 cMaxVars = max(cMaxVars, oThreadedFunction.oMcBlock.cLocals);
1796 cMaxArgs = max(cMaxArgs, oThreadedFunction.oMcBlock.cArgs);
1797 cMaxVarsAndArgs = max(cMaxVarsAndArgs, oThreadedFunction.oMcBlock.cLocals + oThreadedFunction.oMcBlock.cArgs);
1798 # Calc stack allocation size:
1799 cbArgs = 0;
1800 for oArg in oThreadedFunction.oMcBlock.aoArgs:
1801 cbArgs += (getTypeBitCount(oArg.sType) + 63) // 64 * 8;
1802 cbVars = 0;
1803 for oVar in oThreadedFunction.oMcBlock.aoLocals:
1804 cbVars += (getTypeBitCount(oVar.sType) + 63) // 64 * 8;
1805 cbMaxVars = max(cbMaxVars, cbVars);
1806 cbMaxArgs = max(cbMaxArgs, cbArgs);
1807 cbMaxVarsAndArgs = max(cbMaxVarsAndArgs, cbVars + cbArgs);
1808 if cbMaxVarsAndArgs >= 0xc0:
1809 raise Exception('%s potentially uses too much stack: cbMaxVars=%#x cbMaxArgs=%#x'
1810 % (oThreadedFunction.oMcBlock.oFunction.sName, cbMaxVars, cbMaxArgs,));
1811
1812 print('debug: max vars+args: %u bytes / %u; max vars: %u bytes / %u; max args: %u bytes / %u'
1813 % (cbMaxVarsAndArgs, cMaxVarsAndArgs, cbMaxVars, cMaxVars, cbMaxArgs, cMaxArgs,));
1814
1815 return True;
1816
1817 #
1818 # Output
1819 #
1820
1821 def generateLicenseHeader(self):
1822 """
1823 Returns the lines for a license header.
1824 """
1825 return [
1826 '/*',
1827 ' * Autogenerated by $Id: IEMAllThrdPython.py 101484 2023-10-18 01:32:17Z vboxsync $ ',
1828 ' * Do not edit!',
1829 ' */',
1830 '',
1831 '/*',
1832 ' * Copyright (C) 2023-' + str(datetime.date.today().year) + ' Oracle and/or its affiliates.',
1833 ' *',
1834 ' * This file is part of VirtualBox base platform packages, as',
1835 ' * available from https://www.alldomusa.eu.org.',
1836 ' *',
1837 ' * This program is free software; you can redistribute it and/or',
1838 ' * modify it under the terms of the GNU General Public License',
1839 ' * as published by the Free Software Foundation, in version 3 of the',
1840 ' * License.',
1841 ' *',
1842 ' * This program is distributed in the hope that it will be useful, but',
1843 ' * WITHOUT ANY WARRANTY; without even the implied warranty of',
1844 ' * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU',
1845 ' * General Public License for more details.',
1846 ' *',
1847 ' * You should have received a copy of the GNU General Public License',
1848 ' * along with this program; if not, see <https://www.gnu.org/licenses>.',
1849 ' *',
1850 ' * The contents of this file may alternatively be used under the terms',
1851 ' * of the Common Development and Distribution License Version 1.0',
1852 ' * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included',
1853 ' * in the VirtualBox distribution, in which case the provisions of the',
1854 ' * CDDL are applicable instead of those of the GPL.',
1855 ' *',
1856 ' * You may elect to license modified versions of this file under the',
1857 ' * terms and conditions of either the GPL or the CDDL or both.',
1858 ' *',
1859 ' * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0',
1860 ' */',
1861 '',
1862 '',
1863 '',
1864 ];
1865
1866 ## List of built-in threaded functions with user argument counts and
1867 ## whether it has a native recompiler implementation.
1868 katBltIns = (
1869 ( 'DeferToCImpl0', 2, True ),
1870 ( 'CheckIrq', 0, False ),
1871 ( 'CheckMode', 1, False ),
1872 ( 'CheckHwInstrBps', 0, False ),
1873 ( 'CheckCsLim', 1, False ),
1874
1875 ( 'CheckCsLimAndOpcodes', 3, False ),
1876 ( 'CheckOpcodes', 3, False ),
1877 ( 'CheckOpcodesConsiderCsLim', 3, False ),
1878
1879 ( 'CheckCsLimAndPcAndOpcodes', 3, False ),
1880 ( 'CheckPcAndOpcodes', 3, False ),
1881 ( 'CheckPcAndOpcodesConsiderCsLim', 3, False ),
1882
1883 ( 'CheckCsLimAndOpcodesAcrossPageLoadingTlb', 3, False ),
1884 ( 'CheckOpcodesAcrossPageLoadingTlb', 3, False ),
1885 ( 'CheckOpcodesAcrossPageLoadingTlbConsiderCsLim', 2, False ),
1886
1887 ( 'CheckCsLimAndOpcodesLoadingTlb', 3, False ),
1888 ( 'CheckOpcodesLoadingTlb', 3, False ),
1889 ( 'CheckOpcodesLoadingTlbConsiderCsLim', 3, False ),
1890
1891 ( 'CheckCsLimAndOpcodesOnNextPageLoadingTlb', 2, False ),
1892 ( 'CheckOpcodesOnNextPageLoadingTlb', 2, False ),
1893 ( 'CheckOpcodesOnNextPageLoadingTlbConsiderCsLim', 2, False ),
1894
1895 ( 'CheckCsLimAndOpcodesOnNewPageLoadingTlb', 2, False ),
1896 ( 'CheckOpcodesOnNewPageLoadingTlb', 2, False ),
1897 ( 'CheckOpcodesOnNewPageLoadingTlbConsiderCsLim', 2, False ),
1898 );
1899
1900 def generateThreadedFunctionsHeader(self, oOut):
1901 """
1902 Generates the threaded functions header file.
1903 Returns success indicator.
1904 """
1905
1906 asLines = self.generateLicenseHeader();
1907
1908 # Generate the threaded function table indexes.
1909 asLines += [
1910 'typedef enum IEMTHREADEDFUNCS',
1911 '{',
1912 ' kIemThreadedFunc_Invalid = 0,',
1913 '',
1914 ' /*',
1915 ' * Predefined',
1916 ' */',
1917 ];
1918 asLines += [' kIemThreadedFunc_BltIn_%s,' % (sFuncNm,) for sFuncNm, _, _ in self.katBltIns];
1919
1920 iThreadedFunction = 1 + len(self.katBltIns);
1921 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
1922 asLines += [
1923 '',
1924 ' /*',
1925 ' * Variation: ' + ThreadedFunctionVariation.kdVariationNames[sVariation] + '',
1926 ' */',
1927 ];
1928 for oThreadedFunction in self.aoThreadedFuncs:
1929 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
1930 if oVariation:
1931 iThreadedFunction += 1;
1932 oVariation.iEnumValue = iThreadedFunction;
1933 asLines.append(' ' + oVariation.getIndexName() + ',');
1934 asLines += [
1935 ' kIemThreadedFunc_End',
1936 '} IEMTHREADEDFUNCS;',
1937 '',
1938 ];
1939
1940 # Prototype the function table.
1941 asLines += [
1942 'extern const PFNIEMTHREADEDFUNC g_apfnIemThreadedFunctions[kIemThreadedFunc_End];',
1943 '#if defined(IN_RING3) || defined(LOG_ENABLED)',
1944 'extern const char * const g_apszIemThreadedFunctions[kIemThreadedFunc_End];',
1945 '#endif',
1946 'extern uint8_t const g_acIemThreadedFunctionUsedArgs[kIemThreadedFunc_End];',
1947 ];
1948
1949 oOut.write('\n'.join(asLines));
1950 return True;
1951
1952 ksBitsToIntMask = {
1953 1: "UINT64_C(0x1)",
1954 2: "UINT64_C(0x3)",
1955 4: "UINT64_C(0xf)",
1956 8: "UINT64_C(0xff)",
1957 16: "UINT64_C(0xffff)",
1958 32: "UINT64_C(0xffffffff)",
1959 };
1960
1961 def generateFunctionParameterUnpacking(self, oVariation, oOut, asParams):
1962 """
1963 Outputs code for unpacking parameters.
1964 This is shared by the threaded and native code generators.
1965 """
1966 aasVars = [];
1967 for aoRefs in oVariation.dParamRefs.values():
1968 oRef = aoRefs[0];
1969 if oRef.sType[0] != 'P':
1970 cBits = g_kdTypeInfo[oRef.sType][0];
1971 sType = g_kdTypeInfo[oRef.sType][2];
1972 else:
1973 cBits = 64;
1974 sType = oRef.sType;
1975
1976 sTypeDecl = sType + ' const';
1977
1978 if cBits == 64:
1979 assert oRef.offNewParam == 0;
1980 if sType == 'uint64_t':
1981 sUnpack = '%s;' % (asParams[oRef.iNewParam],);
1982 else:
1983 sUnpack = '(%s)%s;' % (sType, asParams[oRef.iNewParam],);
1984 elif oRef.offNewParam == 0:
1985 sUnpack = '(%s)(%s & %s);' % (sType, asParams[oRef.iNewParam], self.ksBitsToIntMask[cBits]);
1986 else:
1987 sUnpack = '(%s)((%s >> %s) & %s);' \
1988 % (sType, asParams[oRef.iNewParam], oRef.offNewParam, self.ksBitsToIntMask[cBits]);
1989
1990 sComment = '/* %s - %s ref%s */' % (oRef.sOrgRef, len(aoRefs), 's' if len(aoRefs) != 1 else '',);
1991
1992 aasVars.append([ '%s:%02u' % (oRef.iNewParam, oRef.offNewParam),
1993 sTypeDecl, oRef.sNewName, sUnpack, sComment ]);
1994 acchVars = [0, 0, 0, 0, 0];
1995 for asVar in aasVars:
1996 for iCol, sStr in enumerate(asVar):
1997 acchVars[iCol] = max(acchVars[iCol], len(sStr));
1998 sFmt = ' %%-%ss %%-%ss = %%-%ss %%s\n' % (acchVars[1], acchVars[2], acchVars[3]);
1999 for asVar in sorted(aasVars):
2000 oOut.write(sFmt % (asVar[1], asVar[2], asVar[3], asVar[4],));
2001 return True;
2002
2003 kasThreadedParamNames = ('uParam0', 'uParam1', 'uParam2');
2004 def generateThreadedFunctionsSource(self, oOut):
2005 """
2006 Generates the threaded functions source file.
2007 Returns success indicator.
2008 """
2009
2010 asLines = self.generateLicenseHeader();
2011 oOut.write('\n'.join(asLines));
2012
2013 #
2014 # Emit the function definitions.
2015 #
2016 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
2017 sVarName = ThreadedFunctionVariation.kdVariationNames[sVariation];
2018 oOut.write( '\n'
2019 + '\n'
2020 + '\n'
2021 + '\n'
2022 + '/*' + '*' * 128 + '\n'
2023 + '* Variation: ' + sVarName + ' ' * (129 - len(sVarName) - 15) + '*\n'
2024 + '*' * 128 + '*/\n');
2025
2026 for oThreadedFunction in self.aoThreadedFuncs:
2027 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
2028 if oVariation:
2029 oMcBlock = oThreadedFunction.oMcBlock;
2030
2031 # Function header
2032 oOut.write( '\n'
2033 + '\n'
2034 + '/**\n'
2035 + ' * #%u: %s at line %s offset %s in %s%s\n'
2036 % (oVariation.iEnumValue, oMcBlock.sFunction, oMcBlock.iBeginLine, oMcBlock.offBeginLine,
2037 os.path.split(oMcBlock.sSrcFile)[1],
2038 ' (macro expansion)' if oMcBlock.iBeginLine == oMcBlock.iEndLine else '')
2039 + ' */\n'
2040 + 'static IEM_DECL_IEMTHREADEDFUNC_DEF(' + oVariation.getThreadedFunctionName() + ')\n'
2041 + '{\n');
2042
2043 # Unpack parameters.
2044 self.generateFunctionParameterUnpacking(oVariation, oOut, self.kasThreadedParamNames);
2045
2046 # RT_NOREF for unused parameters.
2047 if oVariation.cMinParams < g_kcThreadedParams:
2048 oOut.write(' RT_NOREF(' + ', '.join(self.kasThreadedParamNames[oVariation.cMinParams:]) + ');\n');
2049
2050 # Now for the actual statements.
2051 oOut.write(iai.McStmt.renderCodeForList(oVariation.aoStmtsForThreadedFunction, cchIndent = 4));
2052
2053 oOut.write('}\n');
2054
2055
2056 #
2057 # Generate the output tables in parallel.
2058 #
2059 asFuncTable = [
2060 '/**',
2061 ' * Function pointer table.',
2062 ' */',
2063 'PFNIEMTHREADEDFUNC const g_apfnIemThreadedFunctions[kIemThreadedFunc_End] =',
2064 '{',
2065 ' /*Invalid*/ NULL,',
2066 ];
2067 asNameTable = [
2068 '/**',
2069 ' * Function name table.',
2070 ' */',
2071 'const char * const g_apszIemThreadedFunctions[kIemThreadedFunc_End] =',
2072 '{',
2073 ' "Invalid",',
2074 ];
2075 asArgCntTab = [
2076 '/**',
2077 ' * Argument count table.',
2078 ' */',
2079 'uint8_t const g_acIemThreadedFunctionUsedArgs[kIemThreadedFunc_End] =',
2080 '{',
2081 ' 0, /*Invalid*/',
2082 ];
2083 aasTables = (asFuncTable, asNameTable, asArgCntTab,);
2084
2085 for asTable in aasTables:
2086 asTable.extend((
2087 '',
2088 ' /*',
2089 ' * Predefined.',
2090 ' */',
2091 ));
2092 for sFuncNm, cArgs, _ in self.katBltIns:
2093 asFuncTable.append(' iemThreadedFunc_BltIn_%s,' % (sFuncNm,));
2094 asNameTable.append(' "BltIn_%s",' % (sFuncNm,));
2095 asArgCntTab.append(' %d, /*BltIn_%s*/' % (cArgs, sFuncNm,));
2096
2097 iThreadedFunction = 1 + len(self.katBltIns);
2098 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
2099 for asTable in aasTables:
2100 asTable.extend((
2101 '',
2102 ' /*',
2103 ' * Variation: ' + ThreadedFunctionVariation.kdVariationNames[sVariation],
2104 ' */',
2105 ));
2106 for oThreadedFunction in self.aoThreadedFuncs:
2107 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
2108 if oVariation:
2109 iThreadedFunction += 1;
2110 assert oVariation.iEnumValue == iThreadedFunction;
2111 sName = oVariation.getThreadedFunctionName();
2112 asFuncTable.append(' /*%4u*/ %s,' % (iThreadedFunction, sName,));
2113 asNameTable.append(' /*%4u*/ "%s",' % (iThreadedFunction, sName,));
2114 asArgCntTab.append(' /*%4u*/ %d, /*%s*/' % (iThreadedFunction, oVariation.cMinParams, sName,));
2115
2116 for asTable in aasTables:
2117 asTable.append('};');
2118
2119 #
2120 # Output the tables.
2121 #
2122 oOut.write( '\n'
2123 + '\n');
2124 oOut.write('\n'.join(asFuncTable));
2125 oOut.write( '\n'
2126 + '\n'
2127 + '\n'
2128 + '#if defined(IN_RING3) || defined(LOG_ENABLED)\n');
2129 oOut.write('\n'.join(asNameTable));
2130 oOut.write( '\n'
2131 + '#endif /* IN_RING3 || LOG_ENABLED */\n'
2132 + '\n'
2133 + '\n');
2134 oOut.write('\n'.join(asArgCntTab));
2135 oOut.write('\n');
2136
2137 return True;
2138
2139 def generateNativeFunctionsHeader(self, oOut):
2140 """
2141 Generates the native recompiler functions header file.
2142 Returns success indicator.
2143 """
2144 if not self.oOptions.sNativeRecompilerArch:
2145 return True;
2146
2147 asLines = self.generateLicenseHeader();
2148
2149 # Prototype the function table.
2150 asLines += [
2151 'extern const PFNIEMNATIVERECOMPFUNC g_apfnIemNativeRecompileFunctions[kIemThreadedFunc_End];',
2152 '',
2153 ];
2154
2155 oOut.write('\n'.join(asLines));
2156 return True;
2157
2158 def generateNativeFunctionsSource(self, oOut):
2159 """
2160 Generates the native recompiler functions source file.
2161 Returns success indicator.
2162 """
2163 if not self.oOptions.sNativeRecompilerArch:
2164 return True;
2165
2166 #
2167 # The file header.
2168 #
2169 oOut.write('\n'.join(self.generateLicenseHeader()));
2170
2171 #
2172 # Emit the functions.
2173 #
2174 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
2175 sVarName = ThreadedFunctionVariation.kdVariationNames[sVariation];
2176 oOut.write( '\n'
2177 + '\n'
2178 + '\n'
2179 + '\n'
2180 + '/*' + '*' * 128 + '\n'
2181 + '* Variation: ' + sVarName + ' ' * (129 - len(sVarName) - 15) + '*\n'
2182 + '*' * 128 + '*/\n');
2183
2184 for oThreadedFunction in self.aoThreadedFuncs:
2185 oVariation = oThreadedFunction.dVariations.get(sVariation, None) # type: ThreadedFunctionVariation
2186 if oVariation and oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
2187 oMcBlock = oThreadedFunction.oMcBlock;
2188
2189 # Function header
2190 oOut.write( '\n'
2191 + '\n'
2192 + '/**\n'
2193 + ' * #%u: %s at line %s offset %s in %s%s\n'
2194 % (oVariation.iEnumValue, oMcBlock.sFunction, oMcBlock.iBeginLine, oMcBlock.offBeginLine,
2195 os.path.split(oMcBlock.sSrcFile)[1],
2196 ' (macro expansion)' if oMcBlock.iBeginLine == oMcBlock.iEndLine else '')
2197 + ' */\n'
2198 + 'static IEM_DECL_IEMNATIVERECOMPFUNC_DEF(' + oVariation.getNativeFunctionName() + ')\n'
2199 + '{\n');
2200
2201 # Unpack parameters.
2202 self.generateFunctionParameterUnpacking(oVariation, oOut,
2203 ('pCallEntry->auParams[0]',
2204 'pCallEntry->auParams[1]',
2205 'pCallEntry->auParams[2]',));
2206
2207 # Now for the actual statements.
2208 oOut.write(oVariation.oNativeRecomp.renderCode(cchIndent = 4));
2209
2210 oOut.write('}\n');
2211
2212 #
2213 # Output the function table.
2214 #
2215 oOut.write( '\n'
2216 + '\n'
2217 + '/*\n'
2218 + ' * Function table running parallel to g_apfnIemThreadedFunctions and friends.\n'
2219 + ' */\n'
2220 + 'const PFNIEMNATIVERECOMPFUNC g_apfnIemNativeRecompileFunctions[kIemThreadedFunc_End] =\n'
2221 + '{\n'
2222 + ' /*Invalid*/ NULL,'
2223 + '\n'
2224 + ' /*\n'
2225 + ' * Predefined.\n'
2226 + ' */\n'
2227 );
2228 for sFuncNm, _, fHaveRecompFunc in self.katBltIns:
2229 if fHaveRecompFunc:
2230 oOut.write(' iemNativeRecompFunc_BltIn_%s,\n' % (sFuncNm,))
2231 else:
2232 oOut.write(' NULL, /*BltIn_%s*/\n' % (sFuncNm,))
2233
2234 iThreadedFunction = 1 + len(self.katBltIns);
2235 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
2236 oOut.write( ' /*\n'
2237 + ' * Variation: ' + ThreadedFunctionVariation.kdVariationNames[sVariation] + '\n'
2238 + ' */\n');
2239 for oThreadedFunction in self.aoThreadedFuncs:
2240 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
2241 if oVariation:
2242 iThreadedFunction += 1;
2243 assert oVariation.iEnumValue == iThreadedFunction;
2244 sName = oVariation.getNativeFunctionName();
2245 if oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
2246 oOut.write(' /*%4u*/ %s,\n' % (iThreadedFunction, sName,));
2247 else:
2248 oOut.write(' /*%4u*/ NULL /*%s*/,\n' % (iThreadedFunction, sName,));
2249
2250 oOut.write( '};\n'
2251 + '\n');
2252 return True;
2253
2254
2255 def getThreadedFunctionByIndex(self, idx):
2256 """
2257 Returns a ThreadedFunction object for the given index. If the index is
2258 out of bounds, a dummy is returned.
2259 """
2260 if idx < len(self.aoThreadedFuncs):
2261 return self.aoThreadedFuncs[idx];
2262 return ThreadedFunction.dummyInstance();
2263
2264 def generateModifiedInput(self, oOut, idxFile):
2265 """
2266 Generates the combined modified input source/header file.
2267 Returns success indicator.
2268 """
2269 #
2270 # File header and assert assumptions.
2271 #
2272 oOut.write('\n'.join(self.generateLicenseHeader()));
2273 oOut.write('AssertCompile((IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | IEM_F_MODE_CPUMODE_MASK) == 7);\n');
2274
2275 #
2276 # Iterate all parsers (input files) and output the ones related to the
2277 # file set given by idxFile.
2278 #
2279 for idxParser, oParser in enumerate(self.aoParsers): # type: int, IEMAllInstPython.SimpleParser
2280 # Is this included in the file set?
2281 sSrcBaseFile = os.path.basename(oParser.sSrcFile).lower();
2282 fInclude = -1;
2283 for aoInfo in iai.g_aaoAllInstrFilesAndDefaultMapAndSet:
2284 if sSrcBaseFile == aoInfo[0].lower():
2285 fInclude = aoInfo[2] in (-1, idxFile);
2286 break;
2287 if fInclude is not True:
2288 assert fInclude is False;
2289 continue;
2290
2291 # Output it.
2292 oOut.write("\n\n/* ****** BEGIN %s ******* */\n" % (oParser.sSrcFile,));
2293
2294 iThreadedFunction = self.aidxFirstFunctions[idxParser];
2295 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
2296 iLine = 0;
2297 while iLine < len(oParser.asLines):
2298 sLine = oParser.asLines[iLine];
2299 iLine += 1; # iBeginLine and iEndLine are 1-based.
2300
2301 # Can we pass it thru?
2302 if ( iLine not in [oThreadedFunction.oMcBlock.iBeginLine, oThreadedFunction.oMcBlock.iEndLine]
2303 or oThreadedFunction.oMcBlock.sSrcFile != oParser.sSrcFile):
2304 oOut.write(sLine);
2305 #
2306 # Single MC block. Just extract it and insert the replacement.
2307 #
2308 elif oThreadedFunction.oMcBlock.iBeginLine != oThreadedFunction.oMcBlock.iEndLine:
2309 assert sLine.count('IEM_MC_') - sLine.count('IEM_MC_F_') == 1, 'sLine="%s"' % (sLine,);
2310 oOut.write(sLine[:oThreadedFunction.oMcBlock.offBeginLine]);
2311 sModified = oThreadedFunction.generateInputCode().strip();
2312 oOut.write(sModified);
2313
2314 iLine = oThreadedFunction.oMcBlock.iEndLine;
2315 sLine = oParser.asLines[iLine - 1];
2316 assert sLine.count('IEM_MC_') - sLine.count('IEM_MC_F_') == 1 or len(oThreadedFunction.oMcBlock.aoStmts) == 1;
2317 oOut.write(sLine[oThreadedFunction.oMcBlock.offAfterEnd : ]);
2318
2319 # Advance
2320 iThreadedFunction += 1;
2321 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
2322 #
2323 # Macro expansion line that have sublines and may contain multiple MC blocks.
2324 #
2325 else:
2326 offLine = 0;
2327 while iLine == oThreadedFunction.oMcBlock.iBeginLine:
2328 oOut.write(sLine[offLine : oThreadedFunction.oMcBlock.offBeginLine]);
2329
2330 sModified = oThreadedFunction.generateInputCode().strip();
2331 assert ( sModified.startswith('IEM_MC_BEGIN')
2332 or (sModified.find('IEM_MC_DEFER_TO_CIMPL_') > 0 and sModified.strip().startswith('{\n'))
2333 or sModified.startswith('pVCpu->iem.s.fEndTb = true')
2334 or sModified.startswith('pVCpu->iem.s.fTbCurInstr = ')
2335 ), 'sModified="%s"' % (sModified,);
2336 oOut.write(sModified);
2337
2338 offLine = oThreadedFunction.oMcBlock.offAfterEnd;
2339
2340 # Advance
2341 iThreadedFunction += 1;
2342 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
2343
2344 # Last line segment.
2345 if offLine < len(sLine):
2346 oOut.write(sLine[offLine : ]);
2347
2348 oOut.write("/* ****** END %s ******* */\n" % (oParser.sSrcFile,));
2349
2350 return True;
2351
2352 def generateModifiedInput1(self, oOut):
2353 """
2354 Generates the combined modified input source/header file, part 1.
2355 Returns success indicator.
2356 """
2357 return self.generateModifiedInput(oOut, 1);
2358
2359 def generateModifiedInput2(self, oOut):
2360 """
2361 Generates the combined modified input source/header file, part 2.
2362 Returns success indicator.
2363 """
2364 return self.generateModifiedInput(oOut, 2);
2365
2366 def generateModifiedInput3(self, oOut):
2367 """
2368 Generates the combined modified input source/header file, part 3.
2369 Returns success indicator.
2370 """
2371 return self.generateModifiedInput(oOut, 3);
2372
2373 def generateModifiedInput4(self, oOut):
2374 """
2375 Generates the combined modified input source/header file, part 4.
2376 Returns success indicator.
2377 """
2378 return self.generateModifiedInput(oOut, 4);
2379
2380
2381 #
2382 # Main
2383 #
2384
2385 def main(self, asArgs):
2386 """
2387 C-like main function.
2388 Returns exit code.
2389 """
2390
2391 #
2392 # Parse arguments
2393 #
2394 sScriptDir = os.path.dirname(__file__);
2395 oParser = argparse.ArgumentParser(add_help = False);
2396 oParser.add_argument('asInFiles',
2397 metavar = 'input.cpp.h',
2398 nargs = '*',
2399 default = [os.path.join(sScriptDir, aoInfo[0])
2400 for aoInfo in iai.g_aaoAllInstrFilesAndDefaultMapAndSet],
2401 help = "Selection of VMMAll/IEMAllInst*.cpp.h files to use as input.");
2402 oParser.add_argument('--out-thrd-funcs-hdr',
2403 metavar = 'file-thrd-funcs.h',
2404 dest = 'sOutFileThrdFuncsHdr',
2405 action = 'store',
2406 default = '-',
2407 help = 'The output header file for the threaded functions.');
2408 oParser.add_argument('--out-thrd-funcs-cpp',
2409 metavar = 'file-thrd-funcs.cpp',
2410 dest = 'sOutFileThrdFuncsCpp',
2411 action = 'store',
2412 default = '-',
2413 help = 'The output C++ file for the threaded functions.');
2414 oParser.add_argument('--out-n8ve-funcs-hdr',
2415 metavar = 'file-n8tv-funcs.h',
2416 dest = 'sOutFileN8veFuncsHdr',
2417 action = 'store',
2418 default = '-',
2419 help = 'The output header file for the native recompiler functions.');
2420 oParser.add_argument('--out-n8ve-funcs-cpp',
2421 metavar = 'file-n8tv-funcs.cpp',
2422 dest = 'sOutFileN8veFuncsCpp',
2423 action = 'store',
2424 default = '-',
2425 help = 'The output C++ file for the native recompiler functions.');
2426 oParser.add_argument('--native-arch',
2427 metavar = 'arch',
2428 dest = 'sNativeRecompilerArch',
2429 action = 'store',
2430 default = None,
2431 help = 'The host architecture for the native recompiler. No default as it enables/disables '
2432 + 'generating the files related to native recompilation.');
2433 oParser.add_argument('--out-mod-input1',
2434 metavar = 'file-instr.cpp.h',
2435 dest = 'sOutFileModInput1',
2436 action = 'store',
2437 default = '-',
2438 help = 'The output C++/header file for modified input instruction files part 1.');
2439 oParser.add_argument('--out-mod-input2',
2440 metavar = 'file-instr.cpp.h',
2441 dest = 'sOutFileModInput2',
2442 action = 'store',
2443 default = '-',
2444 help = 'The output C++/header file for modified input instruction files part 2.');
2445 oParser.add_argument('--out-mod-input3',
2446 metavar = 'file-instr.cpp.h',
2447 dest = 'sOutFileModInput3',
2448 action = 'store',
2449 default = '-',
2450 help = 'The output C++/header file for modified input instruction files part 3.');
2451 oParser.add_argument('--out-mod-input4',
2452 metavar = 'file-instr.cpp.h',
2453 dest = 'sOutFileModInput4',
2454 action = 'store',
2455 default = '-',
2456 help = 'The output C++/header file for modified input instruction files part 4.');
2457 oParser.add_argument('--help', '-h', '-?',
2458 action = 'help',
2459 help = 'Display help and exit.');
2460 oParser.add_argument('--version', '-V',
2461 action = 'version',
2462 version = 'r%s (IEMAllThreadedPython.py), r%s (IEMAllInstPython.py)'
2463 % (__version__.split()[1], iai.__version__.split()[1],),
2464 help = 'Displays the version/revision of the script and exit.');
2465 self.oOptions = oParser.parse_args(asArgs[1:]);
2466 print("oOptions=%s" % (self.oOptions,));
2467
2468 #
2469 # Process the instructions specified in the IEM sources.
2470 #
2471 if self.processInputFiles(self.oOptions.sNativeRecompilerArch):
2472 #
2473 # Generate the output files.
2474 #
2475 aaoOutputFiles = (
2476 ( self.oOptions.sOutFileThrdFuncsHdr, self.generateThreadedFunctionsHeader ),
2477 ( self.oOptions.sOutFileThrdFuncsCpp, self.generateThreadedFunctionsSource ),
2478 ( self.oOptions.sOutFileN8veFuncsHdr, self.generateNativeFunctionsHeader ),
2479 ( self.oOptions.sOutFileN8veFuncsCpp, self.generateNativeFunctionsSource ),
2480 ( self.oOptions.sOutFileModInput1, self.generateModifiedInput1 ),
2481 ( self.oOptions.sOutFileModInput2, self.generateModifiedInput2 ),
2482 ( self.oOptions.sOutFileModInput3, self.generateModifiedInput3 ),
2483 ( self.oOptions.sOutFileModInput4, self.generateModifiedInput4 ),
2484 );
2485 fRc = True;
2486 for sOutFile, fnGenMethod in aaoOutputFiles:
2487 if sOutFile == '-':
2488 fRc = fnGenMethod(sys.stdout) and fRc;
2489 else:
2490 try:
2491 oOut = open(sOutFile, 'w'); # pylint: disable=consider-using-with,unspecified-encoding
2492 except Exception as oXcpt:
2493 print('error! Failed open "%s" for writing: %s' % (sOutFile, oXcpt,), file = sys.stderr);
2494 return 1;
2495 fRc = fnGenMethod(oOut) and fRc;
2496 oOut.close();
2497 if fRc:
2498 return 0;
2499
2500 return 1;
2501
2502
2503if __name__ == '__main__':
2504 sys.exit(IEMThreadedGenerator().main(sys.argv));
2505
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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