VirtualBox

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

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

VMM/IEM: Added a new class of threaded function variants, the 16f/32f/64f variants that will clear RF (and vbox internal friends) and check for TF (and vbox internal friends). The variants w/o the 'f' after the bitcount will skip this test+branch. The motivation of this was to deal with this issue that the threaded recompiler level rather than try optimize away the test+branch++ code when generating native code, make the IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC32 a very simple place to start emitting native code (compared to IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC32_WITH_FLAGS). bugref:10371

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

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