VirtualBox

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

Last change on this file since 103852 was 103842, checked in by vboxsync, 9 months ago

Fix IEMAllThrdPython.py crash in threaded recompiler build, bugref:9898

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

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