VirtualBox

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

Last change on this file since 103917 was 103909, checked in by vboxsync, 13 months ago

VMM/IEM: Implement 'microcoded' vpextr[bwdq] instruction decode, dispatch & emulation, bugref:9898

  • eliminate '256 immediate instructions' jumptable implementations of pextrw, vpextrw
  • eliminate 'fallback' C implementations of pextrw, vpextrw
  • add 'IEM_MC_FETCH_MREG_U16' micro-op
  • fix 'IEM_MC_FETCH_MREG_U32' micro-op to take 'a_iDWord' arg
  • 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 103909 2024-03-19 09:07:55Z 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: 103909 $"
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_FETCH_MREG_U16': '__mreg16',
1765 'IEM_MC_STORE_MREG_U64': '__mreg64',
1766 'IEM_MC_STORE_MREG_U32_ZX_U64': '__mreg32zx64',
1767 'IEM_MC_REF_MREG_U64': '__mreg64',
1768 'IEM_MC_REF_MREG_U64_CONST': '__mreg64',
1769 'IEM_MC_REF_MREG_U32_CONST': '__mreg32',
1770
1771 'IEM_MC_CLEAR_XREG_U32_MASK': '__xreg32x4',
1772 'IEM_MC_FETCH_XREG_U128': '__xreg128',
1773 'IEM_MC_FETCH_XREG_XMM': '__xreg128',
1774 'IEM_MC_FETCH_XREG_U64': '__xreg64',
1775 'IEM_MC_FETCH_XREG_U32': '__xreg32',
1776 'IEM_MC_FETCH_XREG_U16': '__xreg16',
1777 'IEM_MC_FETCH_XREG_U8': '__xreg8',
1778 'IEM_MC_FETCH_XREG_PAIR_U128': '__xreg128p',
1779 'IEM_MC_FETCH_XREG_PAIR_XMM': '__xreg128p',
1780 'IEM_MC_FETCH_XREG_PAIR_U128_AND_RAX_RDX_U64': '__xreg128p',
1781 'IEM_MC_FETCH_XREG_PAIR_U128_AND_EAX_EDX_U32_SX_U64': '__xreg128p',
1782
1783 'IEM_MC_STORE_XREG_U32_U128': '__xreg32',
1784 'IEM_MC_STORE_XREG_U128': '__xreg128',
1785 'IEM_MC_STORE_XREG_XMM': '__xreg128',
1786 'IEM_MC_STORE_XREG_XMM_U32': '__xreg32',
1787 'IEM_MC_STORE_XREG_XMM_U64': '__xreg64',
1788 'IEM_MC_STORE_XREG_U64': '__xreg64',
1789 'IEM_MC_STORE_XREG_U64_ZX_U128': '__xreg64zx128',
1790 'IEM_MC_STORE_XREG_U32': '__xreg32',
1791 'IEM_MC_STORE_XREG_U16': '__xreg16',
1792 'IEM_MC_STORE_XREG_U8': '__xreg8',
1793 'IEM_MC_STORE_XREG_U32_ZX_U128': '__xreg32zx128',
1794 'IEM_MC_STORE_XREG_R32': '__xreg32',
1795 'IEM_MC_STORE_XREG_R64': '__xreg64',
1796 'IEM_MC_BROADCAST_XREG_U8_ZX_VLMAX': '__xreg8zx',
1797 'IEM_MC_BROADCAST_XREG_U16_ZX_VLMAX': '__xreg16zx',
1798 'IEM_MC_BROADCAST_XREG_U32_ZX_VLMAX': '__xreg32zx',
1799 'IEM_MC_BROADCAST_XREG_U64_ZX_VLMAX': '__xreg64zx',
1800 'IEM_MC_BROADCAST_XREG_U128_ZX_VLMAX': '__xreg128zx',
1801 'IEM_MC_REF_XREG_U128': '__xreg128',
1802 'IEM_MC_REF_XREG_U128_CONST': '__xreg128',
1803 'IEM_MC_REF_XREG_U32_CONST': '__xreg32',
1804 'IEM_MC_REF_XREG_U64_CONST': '__xreg64',
1805 'IEM_MC_REF_XREG_R32_CONST': '__xreg32',
1806 'IEM_MC_REF_XREG_R64_CONST': '__xreg64',
1807 'IEM_MC_REF_XREG_XMM_CONST': '__xreg128',
1808 'IEM_MC_COPY_XREG_U128': '__xreg128',
1809
1810 'IEM_MC_FETCH_YREG_U256': '__yreg256',
1811 'IEM_MC_FETCH_YREG_U128': '__yreg128',
1812 'IEM_MC_FETCH_YREG_U64': '__yreg64',
1813 'IEM_MC_FETCH_YREG_U32': '__yreg32',
1814 'IEM_MC_STORE_YREG_U128': '__yreg128',
1815 'IEM_MC_STORE_YREG_U32_ZX_VLMAX': '__yreg32zx',
1816 'IEM_MC_STORE_YREG_U64_ZX_VLMAX': '__yreg64zx',
1817 'IEM_MC_STORE_YREG_U128_ZX_VLMAX': '__yreg128zx',
1818 'IEM_MC_STORE_YREG_U256_ZX_VLMAX': '__yreg256zx',
1819 'IEM_MC_BROADCAST_YREG_U8_ZX_VLMAX': '__yreg8',
1820 'IEM_MC_BROADCAST_YREG_U16_ZX_VLMAX': '__yreg16',
1821 'IEM_MC_BROADCAST_YREG_U32_ZX_VLMAX': '__yreg32',
1822 'IEM_MC_BROADCAST_YREG_U64_ZX_VLMAX': '__yreg64',
1823 'IEM_MC_BROADCAST_YREG_U128_ZX_VLMAX': '__yreg128',
1824 'IEM_MC_REF_YREG_U128': '__yreg128',
1825 'IEM_MC_REF_YREG_U128_CONST': '__yreg128',
1826 'IEM_MC_REF_YREG_U64_CONST': '__yreg64',
1827 'IEM_MC_COPY_YREG_U256_ZX_VLMAX': '__yreg256zx',
1828 'IEM_MC_COPY_YREG_U128_ZX_VLMAX': '__yreg128zx',
1829 'IEM_MC_COPY_YREG_U64_ZX_VLMAX': '__yreg64zx',
1830 'IEM_MC_MERGE_YREG_U32_U96_ZX_VLMAX': '__yreg3296',
1831 'IEM_MC_MERGE_YREG_U64_U64_ZX_VLMAX': '__yreg6464',
1832 'IEM_MC_MERGE_YREG_U64HI_U64HI_ZX_VLMAX': '__yreg64hi64hi',
1833 'IEM_MC_MERGE_YREG_U64LO_U64LO_ZX_VLMAX': '__yreg64lo64lo',
1834 'IEM_MC_MERGE_YREG_U64LO_U64LOCAL_ZX_VLMAX':'__yreg64',
1835 'IEM_MC_MERGE_YREG_U64LOCAL_U64HI_ZX_VLMAX':'__yreg64',
1836 };
1837 kdAnnotateNameCallStmts = {
1838 'IEM_MC_CALL_CIMPL_0': '__cimpl',
1839 'IEM_MC_CALL_CIMPL_1': '__cimpl',
1840 'IEM_MC_CALL_CIMPL_2': '__cimpl',
1841 'IEM_MC_CALL_CIMPL_3': '__cimpl',
1842 'IEM_MC_CALL_CIMPL_4': '__cimpl',
1843 'IEM_MC_CALL_CIMPL_5': '__cimpl',
1844 'IEM_MC_CALL_CIMPL_6': '__cimpl',
1845 'IEM_MC_CALL_CIMPL_7': '__cimpl',
1846 'IEM_MC_DEFER_TO_CIMPL_0_RET': '__cimpl_defer',
1847 'IEM_MC_DEFER_TO_CIMPL_1_RET': '__cimpl_defer',
1848 'IEM_MC_DEFER_TO_CIMPL_2_RET': '__cimpl_defer',
1849 'IEM_MC_DEFER_TO_CIMPL_3_RET': '__cimpl_defer',
1850 'IEM_MC_DEFER_TO_CIMPL_4_RET': '__cimpl_defer',
1851 'IEM_MC_DEFER_TO_CIMPL_5_RET': '__cimpl_defer',
1852 'IEM_MC_DEFER_TO_CIMPL_6_RET': '__cimpl_defer',
1853 'IEM_MC_DEFER_TO_CIMPL_7_RET': '__cimpl_defer',
1854 'IEM_MC_CALL_VOID_AIMPL_0': '__aimpl',
1855 'IEM_MC_CALL_VOID_AIMPL_1': '__aimpl',
1856 'IEM_MC_CALL_VOID_AIMPL_2': '__aimpl',
1857 'IEM_MC_CALL_VOID_AIMPL_3': '__aimpl',
1858 'IEM_MC_CALL_VOID_AIMPL_4': '__aimpl',
1859 'IEM_MC_CALL_VOID_AIMPL_5': '__aimpl',
1860 'IEM_MC_CALL_AIMPL_0': '__aimpl_ret',
1861 'IEM_MC_CALL_AIMPL_1': '__aimpl_ret',
1862 'IEM_MC_CALL_AIMPL_2': '__aimpl_ret',
1863 'IEM_MC_CALL_AIMPL_3': '__aimpl_ret',
1864 'IEM_MC_CALL_AIMPL_4': '__aimpl_ret',
1865 'IEM_MC_CALL_AIMPL_5': '__aimpl_ret',
1866 'IEM_MC_CALL_AIMPL_6': '__aimpl_ret',
1867 'IEM_MC_CALL_VOID_AIMPL_6': '__aimpl_fpu',
1868 'IEM_MC_CALL_FPU_AIMPL_0': '__aimpl_fpu',
1869 'IEM_MC_CALL_FPU_AIMPL_1': '__aimpl_fpu',
1870 'IEM_MC_CALL_FPU_AIMPL_2': '__aimpl_fpu',
1871 'IEM_MC_CALL_FPU_AIMPL_3': '__aimpl_fpu',
1872 'IEM_MC_CALL_FPU_AIMPL_4': '__aimpl_fpu',
1873 'IEM_MC_CALL_FPU_AIMPL_5': '__aimpl_fpu',
1874 'IEM_MC_CALL_MMX_AIMPL_0': '__aimpl_mmx',
1875 'IEM_MC_CALL_MMX_AIMPL_1': '__aimpl_mmx',
1876 'IEM_MC_CALL_MMX_AIMPL_2': '__aimpl_mmx',
1877 'IEM_MC_CALL_MMX_AIMPL_3': '__aimpl_mmx',
1878 'IEM_MC_CALL_MMX_AIMPL_4': '__aimpl_mmx',
1879 'IEM_MC_CALL_MMX_AIMPL_5': '__aimpl_mmx',
1880 'IEM_MC_CALL_SSE_AIMPL_0': '__aimpl_sse',
1881 'IEM_MC_CALL_SSE_AIMPL_1': '__aimpl_sse',
1882 'IEM_MC_CALL_SSE_AIMPL_2': '__aimpl_sse',
1883 'IEM_MC_CALL_SSE_AIMPL_3': '__aimpl_sse',
1884 'IEM_MC_CALL_SSE_AIMPL_4': '__aimpl_sse',
1885 'IEM_MC_CALL_SSE_AIMPL_5': '__aimpl_sse',
1886 'IEM_MC_CALL_AVX_AIMPL_0': '__aimpl_avx',
1887 'IEM_MC_CALL_AVX_AIMPL_1': '__aimpl_avx',
1888 'IEM_MC_CALL_AVX_AIMPL_2': '__aimpl_avx',
1889 'IEM_MC_CALL_AVX_AIMPL_3': '__aimpl_avx',
1890 'IEM_MC_CALL_AVX_AIMPL_4': '__aimpl_avx',
1891 'IEM_MC_CALL_AVX_AIMPL_5': '__aimpl_avx',
1892 };
1893 def analyzeAndAnnotateName(self, aoStmts: List[iai.McStmt]):
1894 """
1895 Scans the statements and variation lists for clues about the threaded function,
1896 and sets self.sSubName if successfull.
1897 """
1898 # Operand base naming:
1899 dHits = {};
1900 cHits = iai.McStmt.countStmtsByName(aoStmts, self.kdAnnotateNameMemStmts, dHits);
1901 if cHits > 0:
1902 sStmtNm = sorted(dHits.keys())[-1]; # priority: STORE, MEM_MAP, FETCH.
1903 sName = self.kdAnnotateNameMemStmts[sStmtNm];
1904 else:
1905 cHits = iai.McStmt.countStmtsByName(aoStmts, self.kdAnnotateNameRegStmts, dHits);
1906 if cHits > 0:
1907 sStmtNm = sorted(dHits.keys())[-1]; # priority: STORE, MEM_MAP, FETCH.
1908 sName = self.kdAnnotateNameRegStmts[sStmtNm];
1909 else:
1910 # No op details, try name it by call type...
1911 cHits = iai.McStmt.countStmtsByName(aoStmts, self.kdAnnotateNameCallStmts, dHits);
1912 if cHits > 0:
1913 sStmtNm = sorted(dHits.keys())[-1]; # Not really necessary to sort, but simple this way.
1914 self.sSubName = self.kdAnnotateNameCallStmts[sStmtNm];
1915 return;
1916
1917 # Add call info if any:
1918 dHits = {};
1919 cHits = iai.McStmt.countStmtsByName(aoStmts, self.kdAnnotateNameCallStmts, dHits);
1920 if cHits > 0:
1921 sStmtNm = sorted(dHits.keys())[-1]; # Not really necessary to sort, but simple this way.
1922 sName += self.kdAnnotateNameCallStmts[sStmtNm][1:];
1923
1924 self.sSubName = sName;
1925 return;
1926
1927 def analyzeFindVariablesAndCallArgs(self, aoStmts: List[iai.McStmt]) -> bool:
1928 """ Scans the statements for MC variables and call arguments. """
1929 for oStmt in aoStmts:
1930 if isinstance(oStmt, iai.McStmtVar):
1931 if oStmt.sVarName in self.dVariables:
1932 raise Exception('Variable %s is defined more than once!' % (oStmt.sVarName,));
1933 self.dVariables[oStmt.sVarName] = oStmt.sVarName;
1934
1935 # There shouldn't be any variables or arguments declared inside if/
1936 # else blocks, but scan them too to be on the safe side.
1937 if isinstance(oStmt, iai.McStmtCond):
1938 #cBefore = len(self.dVariables);
1939 self.analyzeFindVariablesAndCallArgs(oStmt.aoIfBranch);
1940 self.analyzeFindVariablesAndCallArgs(oStmt.aoElseBranch);
1941 #if len(self.dVariables) != cBefore:
1942 # raise Exception('Variables/arguments defined in conditional branches!');
1943 return True;
1944
1945 def analyzeCodeOperation(self, aoStmts: List[iai.McStmt], dEflStmts, fSeenConditional = False) -> bool:
1946 """
1947 Analyzes the code looking clues as to additional side-effects.
1948
1949 Currently this is simply looking for branching and adding the relevant
1950 branch flags to dsCImplFlags. ASSUMES the caller pre-populates the
1951 dictionary with a copy of self.oMcBlock.dsCImplFlags.
1952
1953 This also sets McStmtCond.oIfBranchAnnotation & McStmtCond.oElseBranchAnnotation.
1954
1955 Returns annotation on return style.
1956 """
1957 sAnnotation = None;
1958 for oStmt in aoStmts:
1959 # Set IEM_IMPL_C_F_BRANCH if we see any branching MCs.
1960 if oStmt.sName.startswith('IEM_MC_SET_RIP'):
1961 assert not fSeenConditional;
1962 self.dsCImplFlags['IEM_CIMPL_F_BRANCH_INDIRECT'] = True;
1963 elif oStmt.sName.startswith('IEM_MC_REL_JMP'):
1964 self.dsCImplFlags['IEM_CIMPL_F_BRANCH_RELATIVE'] = True;
1965 if fSeenConditional:
1966 self.dsCImplFlags['IEM_CIMPL_F_BRANCH_CONDITIONAL'] = True;
1967
1968 # Check for CIMPL and AIMPL calls.
1969 if oStmt.sName.startswith('IEM_MC_CALL_'):
1970 if oStmt.sName.startswith('IEM_MC_CALL_CIMPL_'):
1971 self.dsCImplFlags['IEM_CIMPL_F_CALLS_CIMPL'] = True;
1972 elif ( oStmt.sName.startswith('IEM_MC_CALL_VOID_AIMPL_')
1973 or oStmt.sName.startswith('IEM_MC_CALL_AIMPL_')
1974 or oStmt.sName.startswith('IEM_MC_CALL_AVX_AIMPL_')):
1975 self.dsCImplFlags['IEM_CIMPL_F_CALLS_AIMPL'] = True;
1976 elif ( oStmt.sName.startswith('IEM_MC_CALL_SSE_AIMPL_')
1977 or oStmt.sName.startswith('IEM_MC_CALL_MMX_AIMPL_')
1978 or oStmt.sName.startswith('IEM_MC_CALL_FPU_AIMPL_')):
1979 self.dsCImplFlags['IEM_CIMPL_F_CALLS_AIMPL_WITH_FXSTATE'] = True;
1980 else:
1981 raise Exception('Unknown IEM_MC_CALL_* statement: %s' % (oStmt.sName,));
1982
1983 # Check for return statements.
1984 if oStmt.sName in ('IEM_MC_ADVANCE_RIP_AND_FINISH',):
1985 assert sAnnotation is None;
1986 sAnnotation = g_ksFinishAnnotation_Advance;
1987 elif oStmt.sName in ('IEM_MC_REL_JMP_S8_AND_FINISH', 'IEM_MC_REL_JMP_S16_AND_FINISH',
1988 'IEM_MC_REL_JMP_S32_AND_FINISH',):
1989 assert sAnnotation is None;
1990 sAnnotation = g_ksFinishAnnotation_RelJmp;
1991 elif oStmt.sName in ('IEM_MC_SET_RIP_U16_AND_FINISH', 'IEM_MC_SET_RIP_U32_AND_FINISH',
1992 'IEM_MC_SET_RIP_U64_AND_FINISH',):
1993 assert sAnnotation is None;
1994 sAnnotation = g_ksFinishAnnotation_SetJmp;
1995 elif oStmt.sName.startswith('IEM_MC_DEFER_TO_CIMPL_'):
1996 assert sAnnotation is None;
1997 sAnnotation = g_ksFinishAnnotation_DeferToCImpl;
1998
1999 # Collect MCs working on EFLAGS. Caller will check this.
2000 if oStmt.sName in ('IEM_MC_FETCH_EFLAGS', 'IEM_MC_FETCH_EFLAGS_U8', 'IEM_MC_COMMIT_EFLAGS',
2001 'IEM_MC_COMMIT_EFLAGS_OPT', 'IEM_MC_REF_EFLAGS', 'IEM_MC_ARG_LOCAL_EFLAGS', ):
2002 dEflStmts[oStmt.sName] = oStmt;
2003 elif isinstance(oStmt, iai.McStmtCall):
2004 if oStmt.sName in ('IEM_MC_CALL_CIMPL_0', 'IEM_MC_CALL_CIMPL_1', 'IEM_MC_CALL_CIMPL_2',
2005 'IEM_MC_CALL_CIMPL_3', 'IEM_MC_CALL_CIMPL_4', 'IEM_MC_CALL_CIMPL_5',):
2006 if ( oStmt.asParams[0].find('IEM_CIMPL_F_RFLAGS') >= 0
2007 or oStmt.asParams[0].find('IEM_CIMPL_F_STATUS_FLAGS') >= 0):
2008 dEflStmts[oStmt.sName] = oStmt;
2009
2010 # Process branches of conditionals recursively.
2011 if isinstance(oStmt, iai.McStmtCond):
2012 oStmt.oIfBranchAnnotation = self.analyzeCodeOperation(oStmt.aoIfBranch, dEflStmts, True);
2013 if oStmt.aoElseBranch:
2014 oStmt.oElseBranchAnnotation = self.analyzeCodeOperation(oStmt.aoElseBranch, dEflStmts, True);
2015
2016 return sAnnotation;
2017
2018 def analyzeThreadedFunction(self, oGenerator):
2019 """
2020 Analyzes the code, identifying the number of parameters it requires and such.
2021
2022 Returns dummy True - raises exception on trouble.
2023 """
2024
2025 #
2026 # Decode the block into a list/tree of McStmt objects.
2027 #
2028 aoStmts = self.oMcBlock.decode();
2029
2030 #
2031 # Check the block for errors before we proceed (will decode it).
2032 #
2033 asErrors = self.oMcBlock.check();
2034 if asErrors:
2035 raise Exception('\n'.join(['%s:%s: error: %s' % (self.oMcBlock.sSrcFile, self.oMcBlock.iBeginLine, sError, )
2036 for sError in asErrors]));
2037
2038 #
2039 # Scan the statements for local variables and call arguments (self.dVariables).
2040 #
2041 self.analyzeFindVariablesAndCallArgs(aoStmts);
2042
2043 #
2044 # Scan the code for IEM_CIMPL_F_ and other clues.
2045 #
2046 self.dsCImplFlags = self.oMcBlock.dsCImplFlags.copy();
2047 dEflStmts = {};
2048 self.analyzeCodeOperation(aoStmts, dEflStmts);
2049 if ( ('IEM_CIMPL_F_CALLS_CIMPL' in self.dsCImplFlags)
2050 + ('IEM_CIMPL_F_CALLS_AIMPL' in self.dsCImplFlags)
2051 + ('IEM_CIMPL_F_CALLS_AIMPL_WITH_FXSTATE' in self.dsCImplFlags) > 1):
2052 self.error('Mixing CIMPL/AIMPL/AIMPL_WITH_FXSTATE calls', oGenerator);
2053
2054 #
2055 # Analyse EFLAGS related MCs and @opflmodify and friends.
2056 #
2057 if dEflStmts:
2058 oInstruction = self.oMcBlock.oInstruction; # iai.Instruction
2059 if ( oInstruction is None
2060 or (oInstruction.asFlTest is None and oInstruction.asFlModify is None)):
2061 sMcNames = '+'.join(dEflStmts.keys());
2062 if len(dEflStmts) != 1 or not sMcNames.startswith('IEM_MC_CALL_CIMPL_'): # Hack for far calls
2063 self.error('Uses %s but has no @opflmodify, @opfltest or @opflclass with details!' % (sMcNames,), oGenerator);
2064 elif 'IEM_MC_COMMIT_EFLAGS' in dEflStmts or 'IEM_MC_COMMIT_EFLAGS_OPT' in dEflStmts:
2065 if not oInstruction.asFlModify:
2066 if oInstruction.sMnemonic not in [ 'not', ]:
2067 self.error('Uses IEM_MC_COMMIT_EFLAGS[_OPT] but has no flags in @opflmodify!', oGenerator);
2068 elif ( 'IEM_MC_CALL_CIMPL_0' in dEflStmts
2069 or 'IEM_MC_CALL_CIMPL_1' in dEflStmts
2070 or 'IEM_MC_CALL_CIMPL_2' in dEflStmts
2071 or 'IEM_MC_CALL_CIMPL_3' in dEflStmts
2072 or 'IEM_MC_CALL_CIMPL_4' in dEflStmts
2073 or 'IEM_MC_CALL_CIMPL_5' in dEflStmts ):
2074 if not oInstruction.asFlModify:
2075 self.error('Uses IEM_MC_CALL_CIMPL_x or IEM_MC_DEFER_TO_CIMPL_5_RET with IEM_CIMPL_F_STATUS_FLAGS '
2076 'or IEM_CIMPL_F_RFLAGS but has no flags in @opflmodify!', oGenerator);
2077 elif 'IEM_MC_REF_EFLAGS' not in dEflStmts:
2078 if not oInstruction.asFlTest:
2079 if oInstruction.sMnemonic not in [ 'not', ]:
2080 self.error('Expected @opfltest!', oGenerator);
2081 if oInstruction and oInstruction.asFlSet:
2082 for sFlag in oInstruction.asFlSet:
2083 if sFlag not in oInstruction.asFlModify:
2084 self.error('"%s" in @opflset but missing from @opflmodify (%s)!'
2085 % (sFlag, ', '.join(oInstruction.asFlModify)), oGenerator);
2086 if oInstruction and oInstruction.asFlClear:
2087 for sFlag in oInstruction.asFlClear:
2088 if sFlag not in oInstruction.asFlModify:
2089 self.error('"%s" in @opflclear but missing from @opflmodify (%s)!'
2090 % (sFlag, ', '.join(oInstruction.asFlModify)), oGenerator);
2091
2092 #
2093 # Create variations as needed.
2094 #
2095 if iai.McStmt.findStmtByNames(aoStmts,
2096 { 'IEM_MC_DEFER_TO_CIMPL_0_RET': True,
2097 'IEM_MC_DEFER_TO_CIMPL_1_RET': True,
2098 'IEM_MC_DEFER_TO_CIMPL_2_RET': True,
2099 'IEM_MC_DEFER_TO_CIMPL_3_RET': True, }):
2100 asVariations = (ThreadedFunctionVariation.ksVariation_Default,);
2101
2102 elif iai.McStmt.findStmtByNames(aoStmts, { 'IEM_MC_CALC_RM_EFF_ADDR' : True,
2103 'IEM_MC_FETCH_MEM_U8' : True, # mov_AL_Ob ++
2104 'IEM_MC_FETCH_MEM_U16' : True, # mov_rAX_Ov ++
2105 'IEM_MC_FETCH_MEM_U32' : True,
2106 'IEM_MC_FETCH_MEM_U64' : True,
2107 'IEM_MC_STORE_MEM_U8' : True, # mov_Ob_AL ++
2108 'IEM_MC_STORE_MEM_U16' : True, # mov_Ov_rAX ++
2109 'IEM_MC_STORE_MEM_U32' : True,
2110 'IEM_MC_STORE_MEM_U64' : True, }):
2111 if 'IEM_MC_F_64BIT' in self.oMcBlock.dsMcFlags:
2112 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressOnly64;
2113 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags and 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
2114 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressNot286Not64;
2115 elif 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
2116 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressNot286;
2117 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags:
2118 asVariations = ThreadedFunctionVariation.kasVariationsWithAddressNot64;
2119 elif 'IEM_MC_F_ONLY_8086' in self.oMcBlock.dsMcFlags:
2120 asVariations = ThreadedFunctionVariation.kasVariationsOnlyPre386;
2121 else:
2122 asVariations = ThreadedFunctionVariation.kasVariationsWithAddress;
2123 else:
2124 if 'IEM_MC_F_64BIT' in self.oMcBlock.dsMcFlags:
2125 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressOnly64;
2126 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags and 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
2127 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressNot286Not64;
2128 elif 'IEM_MC_F_NOT_286_OR_OLDER' in self.oMcBlock.dsMcFlags:
2129 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressNot286;
2130 elif 'IEM_MC_F_NOT_64BIT' in self.oMcBlock.dsMcFlags:
2131 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddressNot64;
2132 elif 'IEM_MC_F_ONLY_8086' in self.oMcBlock.dsMcFlags:
2133 asVariations = ThreadedFunctionVariation.kasVariationsOnlyPre386;
2134 else:
2135 asVariations = ThreadedFunctionVariation.kasVariationsWithoutAddress;
2136
2137 if ( 'IEM_CIMPL_F_BRANCH_CONDITIONAL' in self.dsCImplFlags
2138 and 'IEM_CIMPL_F_BRANCH_RELATIVE' in self.dsCImplFlags): # (latter to avoid iemOp_into)
2139 assert set(asVariations).issubset(ThreadedFunctionVariation.kasVariationsWithoutAddress), \
2140 '%s: vars=%s McFlags=%s' % (self.oMcBlock.oFunction.sName, asVariations, self.oMcBlock.dsMcFlags);
2141 asVariationsBase = asVariations;
2142 asVariations = [];
2143 for sVariation in asVariationsBase:
2144 asVariations.extend([sVariation + '_Jmp', sVariation + '_NoJmp']);
2145 assert set(asVariations).issubset(ThreadedFunctionVariation.kdVariationsWithConditional);
2146
2147 if not iai.McStmt.findStmtByNames(aoStmts,
2148 { 'IEM_MC_ADVANCE_RIP_AND_FINISH': True,
2149 'IEM_MC_REL_JMP_S8_AND_FINISH': True,
2150 'IEM_MC_REL_JMP_S16_AND_FINISH': True,
2151 'IEM_MC_REL_JMP_S32_AND_FINISH': True,
2152 'IEM_MC_SET_RIP_U16_AND_FINISH': True,
2153 'IEM_MC_SET_RIP_U32_AND_FINISH': True,
2154 'IEM_MC_SET_RIP_U64_AND_FINISH': True,
2155 }):
2156 asVariations = [sVariation for sVariation in asVariations
2157 if sVariation not in ThreadedFunctionVariation.kdVariationsWithEflagsCheckingAndClearing];
2158
2159 self.aoVariations = [ThreadedFunctionVariation(self, sVar) for sVar in asVariations];
2160
2161 # Dictionary variant of the list.
2162 self.dVariations = { oVar.sVariation: oVar for oVar in self.aoVariations };
2163
2164 #
2165 # Try annotate the threaded function name.
2166 #
2167 self.analyzeAndAnnotateName(aoStmts);
2168
2169 #
2170 # Continue the analysis on each variation.
2171 #
2172 for oVariation in self.aoVariations:
2173 oVariation.analyzeVariation(aoStmts);
2174
2175 return True;
2176
2177 ## Used by emitThreadedCallStmts.
2178 kdVariationsWithNeedForPrefixCheck = {
2179 ThreadedFunctionVariation.ksVariation_64_Addr32: True,
2180 ThreadedFunctionVariation.ksVariation_64f_Addr32: True,
2181 ThreadedFunctionVariation.ksVariation_64_FsGs: True,
2182 ThreadedFunctionVariation.ksVariation_64f_FsGs: True,
2183 ThreadedFunctionVariation.ksVariation_32_Addr16: True,
2184 ThreadedFunctionVariation.ksVariation_32f_Addr16: True,
2185 ThreadedFunctionVariation.ksVariation_32_Flat: True,
2186 ThreadedFunctionVariation.ksVariation_32f_Flat: True,
2187 ThreadedFunctionVariation.ksVariation_16_Addr32: True,
2188 ThreadedFunctionVariation.ksVariation_16f_Addr32: True,
2189 };
2190
2191 def emitThreadedCallStmts(self, sBranch = None): # pylint: disable=too-many-statements
2192 """
2193 Worker for morphInputCode that returns a list of statements that emits
2194 the call to the threaded functions for the block.
2195
2196 The sBranch parameter is used with conditional branches where we'll emit
2197 different threaded calls depending on whether we're in the jump-taken or
2198 no-jump code path.
2199 """
2200 # Special case for only default variation:
2201 if len(self.aoVariations) == 1 and self.aoVariations[0].sVariation == ThreadedFunctionVariation.ksVariation_Default:
2202 assert not sBranch;
2203 return self.aoVariations[0].emitThreadedCallStmts(0);
2204
2205 #
2206 # Case statement sub-class.
2207 #
2208 dByVari = self.dVariations;
2209 #fDbg = self.oMcBlock.sFunction == 'iemOpCommonPushSReg';
2210 class Case:
2211 def __init__(self, sCond, sVarNm = None):
2212 self.sCond = sCond;
2213 self.sVarNm = sVarNm;
2214 self.oVar = dByVari[sVarNm] if sVarNm else None;
2215 self.aoBody = self.oVar.emitThreadedCallStmts(8) if sVarNm else None;
2216
2217 def toCode(self):
2218 aoStmts = [ iai.McCppGeneric('case %s:' % (self.sCond), cchIndent = 4), ];
2219 if self.aoBody:
2220 aoStmts.extend(self.aoBody);
2221 aoStmts.append(iai.McCppGeneric('break;', cchIndent = 8));
2222 return aoStmts;
2223
2224 def toFunctionAssignment(self):
2225 aoStmts = [ iai.McCppGeneric('case %s:' % (self.sCond), cchIndent = 4), ];
2226 if self.aoBody:
2227 aoStmts.extend([
2228 iai.McCppGeneric('enmFunction = %s;' % (self.oVar.getIndexName(),), cchIndent = 8),
2229 iai.McCppGeneric('break;', cchIndent = 8),
2230 ]);
2231 return aoStmts;
2232
2233 def isSame(self, oThat):
2234 if not self.aoBody: # fall thru always matches.
2235 return True;
2236 if len(self.aoBody) != len(oThat.aoBody):
2237 #if fDbg: print('dbg: body len diff: %s vs %s' % (len(self.aoBody), len(oThat.aoBody),));
2238 return False;
2239 for iStmt, oStmt in enumerate(self.aoBody):
2240 oThatStmt = oThat.aoBody[iStmt] # type: iai.McStmt
2241 assert isinstance(oStmt, iai.McCppGeneric);
2242 assert not isinstance(oStmt, iai.McStmtCond);
2243 if isinstance(oStmt, iai.McStmtCond):
2244 return False;
2245 if oStmt.sName != oThatStmt.sName:
2246 #if fDbg: print('dbg: stmt #%s name: %s vs %s' % (iStmt, oStmt.sName, oThatStmt.sName,));
2247 return False;
2248 if len(oStmt.asParams) != len(oThatStmt.asParams):
2249 #if fDbg: print('dbg: stmt #%s param count: %s vs %s'
2250 # % (iStmt, len(oStmt.asParams), len(oThatStmt.asParams),));
2251 return False;
2252 for iParam, sParam in enumerate(oStmt.asParams):
2253 if ( sParam != oThatStmt.asParams[iParam]
2254 and ( iParam != 1
2255 or not isinstance(oStmt, iai.McCppCall)
2256 or not oStmt.asParams[0].startswith('IEM_MC2_EMIT_CALL_')
2257 or sParam != self.oVar.getIndexName()
2258 or oThatStmt.asParams[iParam] != oThat.oVar.getIndexName() )):
2259 #if fDbg: print('dbg: stmt #%s, param #%s: %s vs %s'
2260 # % (iStmt, iParam, sParam, oThatStmt.asParams[iParam],));
2261 return False;
2262 return True;
2263
2264 #
2265 # Determine what we're switch on.
2266 # This ASSUMES that (IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | IEM_F_MODE_CPUMODE_MASK) == 7!
2267 #
2268 fSimple = True;
2269 sSwitchValue = '(pVCpu->iem.s.fExec & (IEM_F_MODE_CPUMODE_MASK | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK))';
2270 if dByVari.keys() & self.kdVariationsWithNeedForPrefixCheck.keys():
2271 sSwitchValue += ' | (pVCpu->iem.s.enmEffAddrMode == (pVCpu->iem.s.fExec & IEM_F_MODE_CPUMODE_MASK) ? 0 : 8)';
2272 # Accesses via FS and GS and CS goes thru non-FLAT functions. (CS
2273 # is not writable in 32-bit mode (at least), thus the penalty mode
2274 # for any accesses via it (simpler this way).)
2275 sSwitchValue += ' | (pVCpu->iem.s.iEffSeg < X86_SREG_FS && pVCpu->iem.s.iEffSeg != X86_SREG_CS ? 0 : 16)';
2276 fSimple = False; # threaded functions.
2277 if dByVari.keys() & ThreadedFunctionVariation.kdVariationsWithEflagsCheckingAndClearing:
2278 sSwitchValue += ' | ((pVCpu->iem.s.fTbPrevInstr & (IEM_CIMPL_F_RFLAGS | IEM_CIMPL_F_INHIBIT_SHADOW)) || ' \
2279 + '(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_MASK) ? 32 : 0)';
2280
2281 #
2282 # Generate the case statements.
2283 #
2284 # pylintx: disable=x
2285 aoCases = [];
2286 if ThreadedFunctionVariation.ksVariation_64_Addr32 in dByVari:
2287 assert not fSimple and not sBranch;
2288 aoCases.extend([
2289 Case('IEMMODE_64BIT', ThrdFnVar.ksVariation_64),
2290 Case('IEMMODE_64BIT | 16', ThrdFnVar.ksVariation_64_FsGs),
2291 Case('IEMMODE_64BIT | 8 | 16', None), # fall thru
2292 Case('IEMMODE_64BIT | 8', ThrdFnVar.ksVariation_64_Addr32),
2293 ]);
2294 if ThreadedFunctionVariation.ksVariation_64f_Addr32 in dByVari:
2295 aoCases.extend([
2296 Case('IEMMODE_64BIT | 32', ThrdFnVar.ksVariation_64f),
2297 Case('IEMMODE_64BIT | 32 | 16', ThrdFnVar.ksVariation_64f_FsGs),
2298 Case('IEMMODE_64BIT | 32 | 8 | 16', None), # fall thru
2299 Case('IEMMODE_64BIT | 32 | 8', ThrdFnVar.ksVariation_64f_Addr32),
2300 ]);
2301 elif ThrdFnVar.ksVariation_64 in dByVari:
2302 assert fSimple and not sBranch;
2303 aoCases.append(Case('IEMMODE_64BIT', ThrdFnVar.ksVariation_64));
2304 if ThreadedFunctionVariation.ksVariation_64f in dByVari:
2305 aoCases.append(Case('IEMMODE_64BIT | 32', ThrdFnVar.ksVariation_64f));
2306 elif ThrdFnVar.ksVariation_64_Jmp in dByVari:
2307 assert fSimple and sBranch;
2308 aoCases.append(Case('IEMMODE_64BIT',
2309 ThrdFnVar.ksVariation_64_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_64_NoJmp));
2310 if ThreadedFunctionVariation.ksVariation_64f_Jmp in dByVari:
2311 aoCases.append(Case('IEMMODE_64BIT | 32',
2312 ThrdFnVar.ksVariation_64f_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_64f_NoJmp));
2313
2314 if ThrdFnVar.ksVariation_32_Addr16 in dByVari:
2315 assert not fSimple and not sBranch;
2316 aoCases.extend([
2317 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK', ThrdFnVar.ksVariation_32_Flat),
2318 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 16', None), # fall thru
2319 Case('IEMMODE_32BIT | 16', None), # fall thru
2320 Case('IEMMODE_32BIT', ThrdFnVar.ksVariation_32),
2321 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 8', None), # fall thru
2322 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 8 | 16',None), # fall thru
2323 Case('IEMMODE_32BIT | 8 | 16',None), # fall thru
2324 Case('IEMMODE_32BIT | 8', ThrdFnVar.ksVariation_32_Addr16),
2325 ]);
2326 if ThrdFnVar.ksVariation_32f_Addr16 in dByVari:
2327 aoCases.extend([
2328 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32', ThrdFnVar.ksVariation_32f_Flat),
2329 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32 | 16', None), # fall thru
2330 Case('IEMMODE_32BIT | 32 | 16', None), # fall thru
2331 Case('IEMMODE_32BIT | 32', ThrdFnVar.ksVariation_32f),
2332 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32 | 8', None), # fall thru
2333 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32 | 8 | 16',None), # fall thru
2334 Case('IEMMODE_32BIT | 32 | 8 | 16',None), # fall thru
2335 Case('IEMMODE_32BIT | 32 | 8', ThrdFnVar.ksVariation_32f_Addr16),
2336 ]);
2337 elif ThrdFnVar.ksVariation_32 in dByVari:
2338 assert fSimple and not sBranch;
2339 aoCases.extend([
2340 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK', None), # fall thru
2341 Case('IEMMODE_32BIT', ThrdFnVar.ksVariation_32),
2342 ]);
2343 if ThrdFnVar.ksVariation_32f in dByVari:
2344 aoCases.extend([
2345 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32', None), # fall thru
2346 Case('IEMMODE_32BIT | 32', ThrdFnVar.ksVariation_32f),
2347 ]);
2348 elif ThrdFnVar.ksVariation_32_Jmp in dByVari:
2349 assert fSimple and sBranch;
2350 aoCases.extend([
2351 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK', None), # fall thru
2352 Case('IEMMODE_32BIT',
2353 ThrdFnVar.ksVariation_32_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_32_NoJmp),
2354 ]);
2355 if ThrdFnVar.ksVariation_32f_Jmp in dByVari:
2356 aoCases.extend([
2357 Case('IEMMODE_32BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32', None), # fall thru
2358 Case('IEMMODE_32BIT | 32',
2359 ThrdFnVar.ksVariation_32f_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_32f_NoJmp),
2360 ]);
2361
2362 if ThrdFnVar.ksVariation_16_Addr32 in dByVari:
2363 assert not fSimple and not sBranch;
2364 aoCases.extend([
2365 Case('IEMMODE_16BIT | 16', None), # fall thru
2366 Case('IEMMODE_16BIT', ThrdFnVar.ksVariation_16),
2367 Case('IEMMODE_16BIT | 8 | 16', None), # fall thru
2368 Case('IEMMODE_16BIT | 8', ThrdFnVar.ksVariation_16_Addr32),
2369 ]);
2370 if ThrdFnVar.ksVariation_16f_Addr32 in dByVari:
2371 aoCases.extend([
2372 Case('IEMMODE_16BIT | 32 | 16', None), # fall thru
2373 Case('IEMMODE_16BIT | 32', ThrdFnVar.ksVariation_16f),
2374 Case('IEMMODE_16BIT | 32 | 8 | 16', None), # fall thru
2375 Case('IEMMODE_16BIT | 32 | 8', ThrdFnVar.ksVariation_16f_Addr32),
2376 ]);
2377 elif ThrdFnVar.ksVariation_16 in dByVari:
2378 assert fSimple and not sBranch;
2379 aoCases.append(Case('IEMMODE_16BIT', ThrdFnVar.ksVariation_16));
2380 if ThrdFnVar.ksVariation_16f in dByVari:
2381 aoCases.append(Case('IEMMODE_16BIT | 32', ThrdFnVar.ksVariation_16f));
2382 elif ThrdFnVar.ksVariation_16_Jmp in dByVari:
2383 assert fSimple and sBranch;
2384 aoCases.append(Case('IEMMODE_16BIT',
2385 ThrdFnVar.ksVariation_16_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_16_NoJmp));
2386 if ThrdFnVar.ksVariation_16f_Jmp in dByVari:
2387 aoCases.append(Case('IEMMODE_16BIT | 32',
2388 ThrdFnVar.ksVariation_16f_Jmp if sBranch == 'Jmp' else ThrdFnVar.ksVariation_16f_NoJmp));
2389
2390
2391 if ThrdFnVar.ksVariation_16_Pre386 in dByVari:
2392 if not fSimple:
2393 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 16', None)); # fall thru
2394 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK', ThrdFnVar.ksVariation_16_Pre386));
2395 if ThrdFnVar.ksVariation_16f_Pre386 in dByVari: # should be nested under previous if, but line too long.
2396 if not fSimple:
2397 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32 | 16', None)); # fall thru
2398 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32', ThrdFnVar.ksVariation_16f_Pre386));
2399
2400 if ThrdFnVar.ksVariation_16_Pre386_Jmp in dByVari:
2401 assert fSimple and sBranch;
2402 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK',
2403 ThrdFnVar.ksVariation_16_Pre386_Jmp if sBranch == 'Jmp'
2404 else ThrdFnVar.ksVariation_16_Pre386_NoJmp));
2405 if ThrdFnVar.ksVariation_16f_Pre386_Jmp in dByVari:
2406 assert fSimple and sBranch;
2407 aoCases.append(Case('IEMMODE_16BIT | IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | 32',
2408 ThrdFnVar.ksVariation_16f_Pre386_Jmp if sBranch == 'Jmp'
2409 else ThrdFnVar.ksVariation_16f_Pre386_NoJmp));
2410
2411 #
2412 # If the case bodies are all the same, except for the function called,
2413 # we can reduce the code size and hopefully compile time.
2414 #
2415 iFirstCaseWithBody = 0;
2416 while not aoCases[iFirstCaseWithBody].aoBody:
2417 iFirstCaseWithBody += 1
2418 fAllSameCases = True
2419 for iCase in range(iFirstCaseWithBody + 1, len(aoCases)):
2420 fAllSameCases = fAllSameCases and aoCases[iCase].isSame(aoCases[iFirstCaseWithBody]);
2421 #if fDbg: print('fAllSameCases=%s %s' % (fAllSameCases, self.oMcBlock.sFunction,));
2422 if fAllSameCases:
2423 aoStmts = [
2424 iai.McCppGeneric('IEMTHREADEDFUNCS enmFunction;'),
2425 iai.McCppGeneric('switch (%s)' % (sSwitchValue,)),
2426 iai.McCppGeneric('{'),
2427 ];
2428 for oCase in aoCases:
2429 aoStmts.extend(oCase.toFunctionAssignment());
2430 aoStmts.extend([
2431 iai.McCppGeneric('IEM_NOT_REACHED_DEFAULT_CASE_RET();', cchIndent = 4),
2432 iai.McCppGeneric('}'),
2433 ]);
2434 aoStmts.extend(dByVari[aoCases[iFirstCaseWithBody].sVarNm].emitThreadedCallStmts(0, 'enmFunction'));
2435
2436 else:
2437 #
2438 # Generate the generic switch statement.
2439 #
2440 aoStmts = [
2441 iai.McCppGeneric('switch (%s)' % (sSwitchValue,)),
2442 iai.McCppGeneric('{'),
2443 ];
2444 for oCase in aoCases:
2445 aoStmts.extend(oCase.toCode());
2446 aoStmts.extend([
2447 iai.McCppGeneric('IEM_NOT_REACHED_DEFAULT_CASE_RET();', cchIndent = 4),
2448 iai.McCppGeneric('}'),
2449 ]);
2450
2451 return aoStmts;
2452
2453 def morphInputCode(self, aoStmts, fIsConditional = False, fCallEmitted = False, cDepth = 0, sBranchAnnotation = None):
2454 """
2455 Adjusts (& copies) the statements for the input/decoder so it will emit
2456 calls to the right threaded functions for each block.
2457
2458 Returns list/tree of statements (aoStmts is not modified) and updated
2459 fCallEmitted status.
2460 """
2461 #print('McBlock at %s:%s' % (os.path.split(self.oMcBlock.sSrcFile)[1], self.oMcBlock.iBeginLine,));
2462 aoDecoderStmts = [];
2463
2464 for iStmt, oStmt in enumerate(aoStmts):
2465 # Copy the statement. Make a deep copy to make sure we've got our own
2466 # copies of all instance variables, even if a bit overkill at the moment.
2467 oNewStmt = copy.deepcopy(oStmt);
2468 aoDecoderStmts.append(oNewStmt);
2469 #print('oNewStmt %s %s' % (oNewStmt.sName, len(oNewStmt.asParams),));
2470 if oNewStmt.sName == 'IEM_MC_BEGIN' and self.dsCImplFlags:
2471 oNewStmt.asParams[3] = ' | '.join(sorted(self.dsCImplFlags.keys()));
2472
2473 # If we haven't emitted the threaded function call yet, look for
2474 # statements which it would naturally follow or preceed.
2475 if not fCallEmitted:
2476 if not oStmt.isCppStmt():
2477 if ( oStmt.sName.startswith('IEM_MC_MAYBE_RAISE_') \
2478 or (oStmt.sName.endswith('_AND_FINISH') and oStmt.sName.startswith('IEM_MC_'))
2479 or oStmt.sName.startswith('IEM_MC_CALL_CIMPL_')
2480 or oStmt.sName.startswith('IEM_MC_DEFER_TO_CIMPL_')
2481 or oStmt.sName in ('IEM_MC_RAISE_DIVIDE_ERROR',)):
2482 aoDecoderStmts.pop();
2483 if not fIsConditional:
2484 aoDecoderStmts.extend(self.emitThreadedCallStmts());
2485 elif oStmt.sName == 'IEM_MC_ADVANCE_RIP_AND_FINISH':
2486 aoDecoderStmts.extend(self.emitThreadedCallStmts('NoJmp'));
2487 else:
2488 assert oStmt.sName in { 'IEM_MC_REL_JMP_S8_AND_FINISH': True,
2489 'IEM_MC_REL_JMP_S16_AND_FINISH': True,
2490 'IEM_MC_REL_JMP_S32_AND_FINISH': True, };
2491 aoDecoderStmts.extend(self.emitThreadedCallStmts('Jmp'));
2492 aoDecoderStmts.append(oNewStmt);
2493 fCallEmitted = True;
2494
2495 elif iai.g_dMcStmtParsers[oStmt.sName][2]:
2496 # This is for Jmp/NoJmp with loopne and friends which modifies state other than RIP.
2497 if not sBranchAnnotation:
2498 self.raiseProblem('Modifying state before emitting calls! %s' % (oStmt.sName,));
2499 assert fIsConditional;
2500 aoDecoderStmts.pop();
2501 if sBranchAnnotation == g_ksFinishAnnotation_Advance:
2502 assert iai.McStmt.findStmtByNames(aoStmts[iStmt:], {'IEM_MC_ADVANCE_RIP_AND_FINISH':1,})
2503 aoDecoderStmts.extend(self.emitThreadedCallStmts('NoJmp'));
2504 elif sBranchAnnotation == g_ksFinishAnnotation_RelJmp:
2505 assert iai.McStmt.findStmtByNames(aoStmts[iStmt:],
2506 { 'IEM_MC_REL_JMP_S8_AND_FINISH': 1,
2507 'IEM_MC_REL_JMP_S16_AND_FINISH': 1,
2508 'IEM_MC_REL_JMP_S32_AND_FINISH': 1, });
2509 aoDecoderStmts.extend(self.emitThreadedCallStmts('Jmp'));
2510 else:
2511 self.raiseProblem('Modifying state before emitting calls! %s' % (oStmt.sName,));
2512 aoDecoderStmts.append(oNewStmt);
2513 fCallEmitted = True;
2514
2515 elif ( not fIsConditional
2516 and oStmt.fDecode
2517 and ( oStmt.asParams[0].find('IEMOP_HLP_DONE_') >= 0
2518 or oStmt.asParams[0].find('IEMOP_HLP_DECODED_') >= 0)):
2519 aoDecoderStmts.extend(self.emitThreadedCallStmts());
2520 fCallEmitted = True;
2521
2522 # Process branches of conditionals recursively.
2523 if isinstance(oStmt, iai.McStmtCond):
2524 (oNewStmt.aoIfBranch, fCallEmitted1) = self.morphInputCode(oStmt.aoIfBranch, fIsConditional,
2525 fCallEmitted, cDepth + 1, oStmt.oIfBranchAnnotation);
2526 if oStmt.aoElseBranch:
2527 (oNewStmt.aoElseBranch, fCallEmitted2) = self.morphInputCode(oStmt.aoElseBranch, fIsConditional,
2528 fCallEmitted, cDepth + 1,
2529 oStmt.oElseBranchAnnotation);
2530 else:
2531 fCallEmitted2 = False;
2532 fCallEmitted = fCallEmitted or (fCallEmitted1 and fCallEmitted2);
2533
2534 if not fCallEmitted and cDepth == 0:
2535 self.raiseProblem('Unable to insert call to threaded function.');
2536
2537 return (aoDecoderStmts, fCallEmitted);
2538
2539
2540 def generateInputCode(self):
2541 """
2542 Modifies the input code.
2543 """
2544 cchIndent = (self.oMcBlock.cchIndent + 3) // 4 * 4;
2545
2546 if len(self.oMcBlock.aoStmts) == 1:
2547 # IEM_MC_DEFER_TO_CIMPL_X_RET - need to wrap in {} to make it safe to insert into random code.
2548 sCode = ' ' * cchIndent + 'pVCpu->iem.s.fTbCurInstr = ';
2549 if self.dsCImplFlags:
2550 sCode += ' | '.join(sorted(self.dsCImplFlags.keys())) + ';\n';
2551 else:
2552 sCode += '0;\n';
2553 sCode += iai.McStmt.renderCodeForList(self.morphInputCode(self.oMcBlock.aoStmts)[0],
2554 cchIndent = cchIndent).replace('\n', ' /* gen */\n', 1);
2555 sIndent = ' ' * (min(cchIndent, 2) - 2);
2556 sCode = sIndent + '{\n' + sCode + sIndent + '}\n';
2557 return sCode;
2558
2559 # IEM_MC_BEGIN/END block
2560 assert len(self.oMcBlock.asLines) > 2, "asLines=%s" % (self.oMcBlock.asLines,);
2561 fIsConditional = ( 'IEM_CIMPL_F_BRANCH_CONDITIONAL' in self.dsCImplFlags
2562 and 'IEM_CIMPL_F_BRANCH_RELATIVE' in self.dsCImplFlags); # (latter to avoid iemOp_into)
2563 return iai.McStmt.renderCodeForList(self.morphInputCode(self.oMcBlock.aoStmts, fIsConditional)[0],
2564 cchIndent = cchIndent).replace('\n', ' /* gen */\n', 1);
2565
2566# Short alias for ThreadedFunctionVariation.
2567ThrdFnVar = ThreadedFunctionVariation;
2568
2569
2570class IEMThreadedGenerator(object):
2571 """
2572 The threaded code generator & annotator.
2573 """
2574
2575 def __init__(self):
2576 self.aoThreadedFuncs = [] # type: List[ThreadedFunction]
2577 self.oOptions = None # type: argparse.Namespace
2578 self.aoParsers = [] # type: List[IEMAllInstPython.SimpleParser]
2579 self.aidxFirstFunctions = [] # type: List[int] ##< Runs parallel to aoParser giving the index of the first function.
2580 self.cErrors = 0;
2581
2582 #
2583 # Error reporting.
2584 #
2585
2586 def rawError(self, sCompleteMessage):
2587 """ Output a raw error and increment the error counter. """
2588 print(sCompleteMessage, file = sys.stderr);
2589 self.cErrors += 1;
2590 return False;
2591
2592 #
2593 # Processing.
2594 #
2595
2596 def processInputFiles(self, sHostArch, fNativeRecompilerEnabled):
2597 """
2598 Process the input files.
2599 """
2600
2601 # Parse the files.
2602 self.aoParsers = iai.parseFiles(self.oOptions.asInFiles, sHostArch);
2603
2604 # Create threaded functions for the MC blocks.
2605 self.aoThreadedFuncs = [ThreadedFunction(oMcBlock) for oMcBlock in iai.g_aoMcBlocks];
2606
2607 # Analyze the threaded functions.
2608 dRawParamCounts = {};
2609 dMinParamCounts = {};
2610 for oThreadedFunction in self.aoThreadedFuncs:
2611 oThreadedFunction.analyzeThreadedFunction(self);
2612 for oVariation in oThreadedFunction.aoVariations:
2613 dRawParamCounts[len(oVariation.dParamRefs)] = dRawParamCounts.get(len(oVariation.dParamRefs), 0) + 1;
2614 dMinParamCounts[oVariation.cMinParams] = dMinParamCounts.get(oVariation.cMinParams, 0) + 1;
2615 print('debug: param count distribution, raw and optimized:', file = sys.stderr);
2616 for cCount in sorted({cBits: True for cBits in list(dRawParamCounts.keys()) + list(dMinParamCounts.keys())}.keys()):
2617 print('debug: %s params: %4s raw, %4s min'
2618 % (cCount, dRawParamCounts.get(cCount, 0), dMinParamCounts.get(cCount, 0)),
2619 file = sys.stderr);
2620
2621 # Do another pass over the threaded functions to settle the name suffix.
2622 iThreadedFn = 0;
2623 while iThreadedFn < len(self.aoThreadedFuncs):
2624 oFunction = self.aoThreadedFuncs[iThreadedFn].oMcBlock.oFunction;
2625 assert oFunction;
2626 iThreadedFnNext = iThreadedFn + 1;
2627 dSubNames = { self.aoThreadedFuncs[iThreadedFn].sSubName: 1 };
2628 while ( iThreadedFnNext < len(self.aoThreadedFuncs)
2629 and self.aoThreadedFuncs[iThreadedFnNext].oMcBlock.oFunction == oFunction):
2630 dSubNames[self.aoThreadedFuncs[iThreadedFnNext].sSubName] = 1;
2631 iThreadedFnNext += 1;
2632 if iThreadedFnNext - iThreadedFn > len(dSubNames):
2633 iSubName = 0;
2634 while iThreadedFn + iSubName < iThreadedFnNext:
2635 self.aoThreadedFuncs[iThreadedFn + iSubName].sSubName += '_%s' % (iSubName,);
2636 iSubName += 1;
2637 iThreadedFn = iThreadedFnNext;
2638
2639 # Populate aidxFirstFunctions. This is ASSUMING that
2640 # g_aoMcBlocks/self.aoThreadedFuncs are in self.aoParsers order.
2641 iThreadedFunction = 0;
2642 oThreadedFunction = self.getThreadedFunctionByIndex(0);
2643 self.aidxFirstFunctions = [];
2644 for oParser in self.aoParsers:
2645 self.aidxFirstFunctions.append(iThreadedFunction);
2646
2647 while oThreadedFunction.oMcBlock.sSrcFile == oParser.sSrcFile:
2648 iThreadedFunction += 1;
2649 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
2650
2651 # Analyze the threaded functions and their variations for native recompilation.
2652 if fNativeRecompilerEnabled:
2653 ian.analyzeThreadedFunctionsForNativeRecomp(self.aoThreadedFuncs, sHostArch);
2654
2655 # Gather arguments + variable statistics for the MC blocks.
2656 cMaxArgs = 0;
2657 cMaxVars = 0;
2658 cMaxVarsAndArgs = 0;
2659 cbMaxArgs = 0;
2660 cbMaxVars = 0;
2661 cbMaxVarsAndArgs = 0;
2662 for oThreadedFunction in self.aoThreadedFuncs:
2663 if oThreadedFunction.oMcBlock.cLocals >= 0:
2664 # Counts.
2665 assert oThreadedFunction.oMcBlock.cArgs >= 0;
2666 cMaxVars = max(cMaxVars, oThreadedFunction.oMcBlock.cLocals);
2667 cMaxArgs = max(cMaxArgs, oThreadedFunction.oMcBlock.cArgs);
2668 cMaxVarsAndArgs = max(cMaxVarsAndArgs, oThreadedFunction.oMcBlock.cLocals + oThreadedFunction.oMcBlock.cArgs);
2669 if cMaxVarsAndArgs > 9:
2670 raise Exception('%s potentially uses too many variables / args: %u, max 10 - %u vars and %u args'
2671 % (oThreadedFunction.oMcBlock.oFunction.sName, cMaxVarsAndArgs,
2672 oThreadedFunction.oMcBlock.cLocals, oThreadedFunction.oMcBlock.cArgs));
2673 # Calc stack allocation size:
2674 cbArgs = 0;
2675 for oArg in oThreadedFunction.oMcBlock.aoArgs:
2676 cbArgs += (getTypeBitCount(oArg.sType) + 63) // 64 * 8;
2677 cbVars = 0;
2678 for oVar in oThreadedFunction.oMcBlock.aoLocals:
2679 cbVars += (getTypeBitCount(oVar.sType) + 63) // 64 * 8;
2680 cbMaxVars = max(cbMaxVars, cbVars);
2681 cbMaxArgs = max(cbMaxArgs, cbArgs);
2682 cbMaxVarsAndArgs = max(cbMaxVarsAndArgs, cbVars + cbArgs);
2683 if cbMaxVarsAndArgs >= 0xc0:
2684 raise Exception('%s potentially uses too much stack: cbMaxVars=%#x cbMaxArgs=%#x'
2685 % (oThreadedFunction.oMcBlock.oFunction.sName, cbMaxVars, cbMaxArgs,));
2686
2687 print('debug: max vars+args: %u bytes / %u; max vars: %u bytes / %u; max args: %u bytes / %u'
2688 % (cbMaxVarsAndArgs, cMaxVarsAndArgs, cbMaxVars, cMaxVars, cbMaxArgs, cMaxArgs,), file = sys.stderr);
2689
2690 if self.cErrors > 0:
2691 print('fatal error: %u error%s during processing. Details above.'
2692 % (self.cErrors, 's' if self.cErrors > 1 else '',), file = sys.stderr);
2693 return False;
2694 return True;
2695
2696 #
2697 # Output
2698 #
2699
2700 def generateLicenseHeader(self):
2701 """
2702 Returns the lines for a license header.
2703 """
2704 return [
2705 '/*',
2706 ' * Autogenerated by $Id: IEMAllThrdPython.py 103909 2024-03-19 09:07:55Z vboxsync $ ',
2707 ' * Do not edit!',
2708 ' */',
2709 '',
2710 '/*',
2711 ' * Copyright (C) 2023-' + str(datetime.date.today().year) + ' Oracle and/or its affiliates.',
2712 ' *',
2713 ' * This file is part of VirtualBox base platform packages, as',
2714 ' * available from https://www.virtualbox.org.',
2715 ' *',
2716 ' * This program is free software; you can redistribute it and/or',
2717 ' * modify it under the terms of the GNU General Public License',
2718 ' * as published by the Free Software Foundation, in version 3 of the',
2719 ' * License.',
2720 ' *',
2721 ' * This program is distributed in the hope that it will be useful, but',
2722 ' * WITHOUT ANY WARRANTY; without even the implied warranty of',
2723 ' * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU',
2724 ' * General Public License for more details.',
2725 ' *',
2726 ' * You should have received a copy of the GNU General Public License',
2727 ' * along with this program; if not, see <https://www.gnu.org/licenses>.',
2728 ' *',
2729 ' * The contents of this file may alternatively be used under the terms',
2730 ' * of the Common Development and Distribution License Version 1.0',
2731 ' * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included',
2732 ' * in the VirtualBox distribution, in which case the provisions of the',
2733 ' * CDDL are applicable instead of those of the GPL.',
2734 ' *',
2735 ' * You may elect to license modified versions of this file under the',
2736 ' * terms and conditions of either the GPL or the CDDL or both.',
2737 ' *',
2738 ' * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0',
2739 ' */',
2740 '',
2741 '',
2742 '',
2743 ];
2744
2745 ## List of built-in threaded functions with user argument counts and
2746 ## whether it has a native recompiler implementation.
2747 katBltIns = (
2748 ( 'Nop', 0, True ),
2749 ( 'LogCpuState', 0, True ),
2750
2751 ( 'DeferToCImpl0', 2, True ),
2752 ( 'CheckIrq', 0, True ),
2753 ( 'CheckMode', 1, True ),
2754 ( 'CheckHwInstrBps', 0, False ),
2755 ( 'CheckCsLim', 1, True ),
2756
2757 ( 'CheckCsLimAndOpcodes', 3, True ),
2758 ( 'CheckOpcodes', 3, True ),
2759 ( 'CheckOpcodesConsiderCsLim', 3, True ),
2760
2761 ( 'CheckCsLimAndPcAndOpcodes', 3, True ),
2762 ( 'CheckPcAndOpcodes', 3, True ),
2763 ( 'CheckPcAndOpcodesConsiderCsLim', 3, True ),
2764
2765 ( 'CheckCsLimAndOpcodesAcrossPageLoadingTlb', 3, True ),
2766 ( 'CheckOpcodesAcrossPageLoadingTlb', 3, True ),
2767 ( 'CheckOpcodesAcrossPageLoadingTlbConsiderCsLim', 2, True ),
2768
2769 ( 'CheckCsLimAndOpcodesLoadingTlb', 3, True ),
2770 ( 'CheckOpcodesLoadingTlb', 3, True ),
2771 ( 'CheckOpcodesLoadingTlbConsiderCsLim', 3, True ),
2772
2773 ( 'CheckCsLimAndOpcodesOnNextPageLoadingTlb', 2, True ),
2774 ( 'CheckOpcodesOnNextPageLoadingTlb', 2, True ),
2775 ( 'CheckOpcodesOnNextPageLoadingTlbConsiderCsLim', 2, True ),
2776
2777 ( 'CheckCsLimAndOpcodesOnNewPageLoadingTlb', 2, True ),
2778 ( 'CheckOpcodesOnNewPageLoadingTlb', 2, True ),
2779 ( 'CheckOpcodesOnNewPageLoadingTlbConsiderCsLim', 2, True ),
2780 );
2781
2782 def generateThreadedFunctionsHeader(self, oOut, _):
2783 """
2784 Generates the threaded functions header file.
2785 Returns success indicator.
2786 """
2787
2788 asLines = self.generateLicenseHeader();
2789
2790 # Generate the threaded function table indexes.
2791 asLines += [
2792 'typedef enum IEMTHREADEDFUNCS',
2793 '{',
2794 ' kIemThreadedFunc_Invalid = 0,',
2795 '',
2796 ' /*',
2797 ' * Predefined',
2798 ' */',
2799 ];
2800 asLines += [' kIemThreadedFunc_BltIn_%s,' % (sFuncNm,) for sFuncNm, _, _ in self.katBltIns];
2801
2802 iThreadedFunction = 1 + len(self.katBltIns);
2803 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
2804 asLines += [
2805 '',
2806 ' /*',
2807 ' * Variation: ' + ThreadedFunctionVariation.kdVariationNames[sVariation] + '',
2808 ' */',
2809 ];
2810 for oThreadedFunction in self.aoThreadedFuncs:
2811 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
2812 if oVariation:
2813 iThreadedFunction += 1;
2814 oVariation.iEnumValue = iThreadedFunction;
2815 asLines.append(' ' + oVariation.getIndexName() + ',');
2816 asLines += [
2817 ' kIemThreadedFunc_End',
2818 '} IEMTHREADEDFUNCS;',
2819 '',
2820 ];
2821
2822 # Prototype the function table.
2823 asLines += [
2824 'extern const PFNIEMTHREADEDFUNC g_apfnIemThreadedFunctions[kIemThreadedFunc_End];',
2825 'extern uint8_t const g_acIemThreadedFunctionUsedArgs[kIemThreadedFunc_End];',
2826 '#if defined(IN_RING3) || defined(LOG_ENABLED)',
2827 'extern const char * const g_apszIemThreadedFunctions[kIemThreadedFunc_End];',
2828 '#endif',
2829 '#if defined(IN_RING3)',
2830 'extern const char * const g_apszIemThreadedFunctionStats[kIemThreadedFunc_End];',
2831 '#endif',
2832 ];
2833
2834 oOut.write('\n'.join(asLines));
2835 return True;
2836
2837 ksBitsToIntMask = {
2838 1: "UINT64_C(0x1)",
2839 2: "UINT64_C(0x3)",
2840 4: "UINT64_C(0xf)",
2841 8: "UINT64_C(0xff)",
2842 16: "UINT64_C(0xffff)",
2843 32: "UINT64_C(0xffffffff)",
2844 };
2845
2846 def generateFunctionParameterUnpacking(self, oVariation, oOut, asParams):
2847 """
2848 Outputs code for unpacking parameters.
2849 This is shared by the threaded and native code generators.
2850 """
2851 aasVars = [];
2852 for aoRefs in oVariation.dParamRefs.values():
2853 oRef = aoRefs[0];
2854 if oRef.sType[0] != 'P':
2855 cBits = g_kdTypeInfo[oRef.sType][0];
2856 sType = g_kdTypeInfo[oRef.sType][2];
2857 else:
2858 cBits = 64;
2859 sType = oRef.sType;
2860
2861 sTypeDecl = sType + ' const';
2862
2863 if cBits == 64:
2864 assert oRef.offNewParam == 0;
2865 if sType == 'uint64_t':
2866 sUnpack = '%s;' % (asParams[oRef.iNewParam],);
2867 else:
2868 sUnpack = '(%s)%s;' % (sType, asParams[oRef.iNewParam],);
2869 elif oRef.offNewParam == 0:
2870 sUnpack = '(%s)(%s & %s);' % (sType, asParams[oRef.iNewParam], self.ksBitsToIntMask[cBits]);
2871 else:
2872 sUnpack = '(%s)((%s >> %s) & %s);' \
2873 % (sType, asParams[oRef.iNewParam], oRef.offNewParam, self.ksBitsToIntMask[cBits]);
2874
2875 sComment = '/* %s - %s ref%s */' % (oRef.sOrgRef, len(aoRefs), 's' if len(aoRefs) != 1 else '',);
2876
2877 aasVars.append([ '%s:%02u' % (oRef.iNewParam, oRef.offNewParam),
2878 sTypeDecl, oRef.sNewName, sUnpack, sComment ]);
2879 acchVars = [0, 0, 0, 0, 0];
2880 for asVar in aasVars:
2881 for iCol, sStr in enumerate(asVar):
2882 acchVars[iCol] = max(acchVars[iCol], len(sStr));
2883 sFmt = ' %%-%ss %%-%ss = %%-%ss %%s\n' % (acchVars[1], acchVars[2], acchVars[3]);
2884 for asVar in sorted(aasVars):
2885 oOut.write(sFmt % (asVar[1], asVar[2], asVar[3], asVar[4],));
2886 return True;
2887
2888 kasThreadedParamNames = ('uParam0', 'uParam1', 'uParam2');
2889 def generateThreadedFunctionsSource(self, oOut, _):
2890 """
2891 Generates the threaded functions source file.
2892 Returns success indicator.
2893 """
2894
2895 asLines = self.generateLicenseHeader();
2896 oOut.write('\n'.join(asLines));
2897
2898 #
2899 # Emit the function definitions.
2900 #
2901 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
2902 sVarName = ThreadedFunctionVariation.kdVariationNames[sVariation];
2903 oOut.write( '\n'
2904 + '\n'
2905 + '\n'
2906 + '\n'
2907 + '/*' + '*' * 128 + '\n'
2908 + '* Variation: ' + sVarName + ' ' * (129 - len(sVarName) - 15) + '*\n'
2909 + '*' * 128 + '*/\n');
2910
2911 for oThreadedFunction in self.aoThreadedFuncs:
2912 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
2913 if oVariation:
2914 oMcBlock = oThreadedFunction.oMcBlock;
2915
2916 # Function header
2917 oOut.write( '\n'
2918 + '\n'
2919 + '/**\n'
2920 + ' * #%u: %s at line %s offset %s in %s%s\n'
2921 % (oVariation.iEnumValue, oMcBlock.sFunction, oMcBlock.iBeginLine, oMcBlock.offBeginLine,
2922 os.path.split(oMcBlock.sSrcFile)[1],
2923 ' (macro expansion)' if oMcBlock.iBeginLine == oMcBlock.iEndLine else '')
2924 + ' */\n'
2925 + 'static IEM_DECL_IEMTHREADEDFUNC_DEF(' + oVariation.getThreadedFunctionName() + ')\n'
2926 + '{\n');
2927
2928 # Unpack parameters.
2929 self.generateFunctionParameterUnpacking(oVariation, oOut, self.kasThreadedParamNames);
2930
2931 # RT_NOREF for unused parameters.
2932 if oVariation.cMinParams < g_kcThreadedParams:
2933 oOut.write(' RT_NOREF(' + ', '.join(self.kasThreadedParamNames[oVariation.cMinParams:]) + ');\n');
2934
2935 # Now for the actual statements.
2936 oOut.write(iai.McStmt.renderCodeForList(oVariation.aoStmtsForThreadedFunction, cchIndent = 4));
2937
2938 oOut.write('}\n');
2939
2940
2941 #
2942 # Generate the output tables in parallel.
2943 #
2944 asFuncTable = [
2945 '/**',
2946 ' * Function pointer table.',
2947 ' */',
2948 'PFNIEMTHREADEDFUNC const g_apfnIemThreadedFunctions[kIemThreadedFunc_End] =',
2949 '{',
2950 ' /*Invalid*/ NULL,',
2951 ];
2952 asArgCntTab = [
2953 '/**',
2954 ' * Argument count table.',
2955 ' */',
2956 'uint8_t const g_acIemThreadedFunctionUsedArgs[kIemThreadedFunc_End] =',
2957 '{',
2958 ' 0, /*Invalid*/',
2959 ];
2960 asNameTable = [
2961 '/**',
2962 ' * Function name table.',
2963 ' */',
2964 'const char * const g_apszIemThreadedFunctions[kIemThreadedFunc_End] =',
2965 '{',
2966 ' "Invalid",',
2967 ];
2968 asStatTable = [
2969 '/**',
2970 ' * Function statistics name table.',
2971 ' */',
2972 'const char * const g_apszIemThreadedFunctionStats[kIemThreadedFunc_End] =',
2973 '{',
2974 ' NULL,',
2975 ];
2976 aasTables = (asFuncTable, asArgCntTab, asNameTable, asStatTable,);
2977
2978 for asTable in aasTables:
2979 asTable.extend((
2980 '',
2981 ' /*',
2982 ' * Predefined.',
2983 ' */',
2984 ));
2985 for sFuncNm, cArgs, _ in self.katBltIns:
2986 asFuncTable.append(' iemThreadedFunc_BltIn_%s,' % (sFuncNm,));
2987 asArgCntTab.append(' %d, /*BltIn_%s*/' % (cArgs, sFuncNm,));
2988 asNameTable.append(' "BltIn_%s",' % (sFuncNm,));
2989 asStatTable.append(' "BltIn/%s",' % (sFuncNm,));
2990
2991 iThreadedFunction = 1 + len(self.katBltIns);
2992 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
2993 for asTable in aasTables:
2994 asTable.extend((
2995 '',
2996 ' /*',
2997 ' * Variation: ' + ThreadedFunctionVariation.kdVariationNames[sVariation],
2998 ' */',
2999 ));
3000 for oThreadedFunction in self.aoThreadedFuncs:
3001 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
3002 if oVariation:
3003 iThreadedFunction += 1;
3004 assert oVariation.iEnumValue == iThreadedFunction;
3005 sName = oVariation.getThreadedFunctionName();
3006 asFuncTable.append(' /*%4u*/ %s,' % (iThreadedFunction, sName,));
3007 asNameTable.append(' /*%4u*/ "%s",' % (iThreadedFunction, sName,));
3008 asArgCntTab.append(' /*%4u*/ %d, /*%s*/' % (iThreadedFunction, oVariation.cMinParams, sName,));
3009 asStatTable.append(' "%s",' % (oVariation.getThreadedFunctionStatisticsName(),));
3010
3011 for asTable in aasTables:
3012 asTable.append('};');
3013
3014 #
3015 # Output the tables.
3016 #
3017 oOut.write( '\n'
3018 + '\n');
3019 oOut.write('\n'.join(asFuncTable));
3020 oOut.write( '\n'
3021 + '\n'
3022 + '\n');
3023 oOut.write('\n'.join(asArgCntTab));
3024 oOut.write( '\n'
3025 + '\n'
3026 + '#if defined(IN_RING3) || defined(LOG_ENABLED)\n');
3027 oOut.write('\n'.join(asNameTable));
3028 oOut.write( '\n'
3029 + '#endif /* IN_RING3 || LOG_ENABLED */\n'
3030 + '\n'
3031 + '\n'
3032 + '#if defined(IN_RING3)\n');
3033 oOut.write('\n'.join(asStatTable));
3034 oOut.write( '\n'
3035 + '#endif /* IN_RING3 */\n');
3036
3037 return True;
3038
3039 def generateNativeFunctionsHeader(self, oOut, _):
3040 """
3041 Generates the native recompiler functions header file.
3042 Returns success indicator.
3043 """
3044 if not self.oOptions.fNativeRecompilerEnabled:
3045 return True;
3046
3047 asLines = self.generateLicenseHeader();
3048
3049 # Prototype the function table.
3050 asLines += [
3051 'extern const PFNIEMNATIVERECOMPFUNC g_apfnIemNativeRecompileFunctions[kIemThreadedFunc_End];',
3052 'extern const PFNIEMNATIVELIVENESSFUNC g_apfnIemNativeLivenessFunctions[kIemThreadedFunc_End];',
3053 '',
3054 ];
3055
3056 # Emit indicators as to which of the builtin functions have a native
3057 # recompiler function and which not. (We only really need this for
3058 # kIemThreadedFunc_BltIn_CheckMode, but do all just for simplicity.)
3059 for atBltIn in self.katBltIns:
3060 if atBltIn[1]:
3061 asLines.append('#define IEMNATIVE_WITH_BLTIN_' + atBltIn[0].upper())
3062 else:
3063 asLines.append('#define IEMNATIVE_WITHOUT_BLTIN_' + atBltIn[0].upper())
3064
3065 # Emit prototypes for the builtin functions we use in tables.
3066 asLines += [
3067 '',
3068 '/* Prototypes for built-in functions used in the above tables. */',
3069 ];
3070 for sFuncNm, _, fHaveRecompFunc in self.katBltIns:
3071 if fHaveRecompFunc:
3072 asLines += [
3073 'IEM_DECL_IEMNATIVERECOMPFUNC_PROTO( iemNativeRecompFunc_BltIn_%s);' % (sFuncNm,),
3074 'IEM_DECL_IEMNATIVELIVENESSFUNC_PROTO(iemNativeLivenessFunc_BltIn_%s);' % (sFuncNm,),
3075 ];
3076
3077 # Emit prototypes for table function.
3078 asLines += [
3079 '',
3080 '#ifdef IEMNATIVE_INCL_TABLE_FUNCTION_PROTOTYPES'
3081 ]
3082 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
3083 sVarName = ThreadedFunctionVariation.kdVariationNames[sVariation];
3084 asLines += [
3085 '',
3086 '/* Variation: ' + sVarName + ' */',
3087 ];
3088 for oThreadedFunction in self.aoThreadedFuncs:
3089 oVariation = oThreadedFunction.dVariations.get(sVariation, None) # type: ThreadedFunctionVariation
3090 if oVariation and oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
3091 asLines.append('IEM_DECL_IEMNATIVERECOMPFUNC_PROTO(' + oVariation.getNativeFunctionName() + ');');
3092 asLines += [
3093 '',
3094 '#endif /* IEMNATIVE_INCL_TABLE_FUNCTION_PROTOTYPES */',
3095 ]
3096
3097 oOut.write('\n'.join(asLines));
3098 return True;
3099
3100 def generateNativeFunctionsSource(self, oOut, idxPart):
3101 """
3102 Generates the native recompiler functions source file.
3103 Returns success indicator.
3104 """
3105 cParts = 4;
3106 assert(idxPart in range(cParts));
3107 if not self.oOptions.fNativeRecompilerEnabled:
3108 return True;
3109
3110 #
3111 # The file header.
3112 #
3113 oOut.write('\n'.join(self.generateLicenseHeader()));
3114
3115 #
3116 # Emit the functions.
3117 #
3118 # The files are split up by threaded variation as that's the simplest way to
3119 # do it, even if the distribution isn't entirely even (ksVariation_Default
3120 # only has the defer to cimpl bits and the pre-386 variants will naturally
3121 # have fewer instructions).
3122 #
3123 cVariationsPerFile = len(ThreadedFunctionVariation.kasVariationsEmitOrder) // cParts;
3124 idxFirstVar = idxPart * cVariationsPerFile;
3125 idxEndVar = idxFirstVar + cVariationsPerFile;
3126 if idxPart + 1 >= cParts:
3127 idxEndVar = len(ThreadedFunctionVariation.kasVariationsEmitOrder);
3128 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder[idxFirstVar:idxEndVar]:
3129 sVarName = ThreadedFunctionVariation.kdVariationNames[sVariation];
3130 oOut.write( '\n'
3131 + '\n'
3132 + '\n'
3133 + '\n'
3134 + '/*' + '*' * 128 + '\n'
3135 + '* Variation: ' + sVarName + ' ' * (129 - len(sVarName) - 15) + '*\n'
3136 + '*' * 128 + '*/\n');
3137
3138 for oThreadedFunction in self.aoThreadedFuncs:
3139 oVariation = oThreadedFunction.dVariations.get(sVariation, None) # type: ThreadedFunctionVariation
3140 if oVariation and oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
3141 oMcBlock = oThreadedFunction.oMcBlock;
3142
3143 # Function header
3144 oOut.write( '\n'
3145 + '\n'
3146 + '/**\n'
3147 + ' * #%u: %s at line %s offset %s in %s%s\n'
3148 % (oVariation.iEnumValue, oMcBlock.sFunction, oMcBlock.iBeginLine, oMcBlock.offBeginLine,
3149 os.path.split(oMcBlock.sSrcFile)[1],
3150 ' (macro expansion)' if oMcBlock.iBeginLine == oMcBlock.iEndLine else '')
3151 + ' */\n'
3152 + 'IEM_DECL_IEMNATIVERECOMPFUNC_DEF(' + oVariation.getNativeFunctionName() + ')\n'
3153 + '{\n');
3154
3155 # Unpack parameters.
3156 self.generateFunctionParameterUnpacking(oVariation, oOut,
3157 ('pCallEntry->auParams[0]',
3158 'pCallEntry->auParams[1]',
3159 'pCallEntry->auParams[2]',));
3160
3161 # Now for the actual statements.
3162 oOut.write(oVariation.oNativeRecomp.renderCode(cchIndent = 4));
3163
3164 oOut.write('}\n');
3165
3166 #
3167 # Output the function table if this is the first file.
3168 #
3169 if idxPart == 0:
3170 oOut.write( '\n'
3171 + '\n'
3172 + '/*\n'
3173 + ' * Function table running parallel to g_apfnIemThreadedFunctions and friends.\n'
3174 + ' */\n'
3175 + 'const PFNIEMNATIVERECOMPFUNC g_apfnIemNativeRecompileFunctions[kIemThreadedFunc_End] =\n'
3176 + '{\n'
3177 + ' /*Invalid*/ NULL,'
3178 + '\n'
3179 + ' /*\n'
3180 + ' * Predefined.\n'
3181 + ' */\n'
3182 );
3183 for sFuncNm, _, fHaveRecompFunc in self.katBltIns:
3184 if fHaveRecompFunc:
3185 oOut.write(' iemNativeRecompFunc_BltIn_%s,\n' % (sFuncNm,))
3186 else:
3187 oOut.write(' NULL, /*BltIn_%s*/\n' % (sFuncNm,))
3188
3189 iThreadedFunction = 1 + len(self.katBltIns);
3190 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
3191 oOut.write( ' /*\n'
3192 + ' * Variation: ' + ThreadedFunctionVariation.kdVariationNames[sVariation] + '\n'
3193 + ' */\n');
3194 for oThreadedFunction in self.aoThreadedFuncs:
3195 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
3196 if oVariation:
3197 iThreadedFunction += 1;
3198 assert oVariation.iEnumValue == iThreadedFunction;
3199 sName = oVariation.getNativeFunctionName();
3200 if oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
3201 oOut.write(' /*%4u*/ %s,\n' % (iThreadedFunction, sName,));
3202 else:
3203 oOut.write(' /*%4u*/ NULL /*%s*/,\n' % (iThreadedFunction, sName,));
3204
3205 oOut.write( '};\n');
3206
3207 oOut.write('\n');
3208 return True;
3209
3210 def generateNativeLivenessSource(self, oOut, _):
3211 """
3212 Generates the native recompiler liveness analysis functions source file.
3213 Returns success indicator.
3214 """
3215 if not self.oOptions.fNativeRecompilerEnabled:
3216 return True;
3217
3218 #
3219 # The file header.
3220 #
3221 oOut.write('\n'.join(self.generateLicenseHeader()));
3222
3223 #
3224 # Emit the functions.
3225 #
3226 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
3227 sVarName = ThreadedFunctionVariation.kdVariationNames[sVariation];
3228 oOut.write( '\n'
3229 + '\n'
3230 + '\n'
3231 + '\n'
3232 + '/*' + '*' * 128 + '\n'
3233 + '* Variation: ' + sVarName + ' ' * (129 - len(sVarName) - 15) + '*\n'
3234 + '*' * 128 + '*/\n');
3235
3236 for oThreadedFunction in self.aoThreadedFuncs:
3237 oVariation = oThreadedFunction.dVariations.get(sVariation, None) # type: ThreadedFunctionVariation
3238 if oVariation and oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
3239 oMcBlock = oThreadedFunction.oMcBlock;
3240
3241 # Function header
3242 oOut.write( '\n'
3243 + '\n'
3244 + '/**\n'
3245 + ' * #%u: %s at line %s offset %s in %s%s\n'
3246 % (oVariation.iEnumValue, oMcBlock.sFunction, oMcBlock.iBeginLine, oMcBlock.offBeginLine,
3247 os.path.split(oMcBlock.sSrcFile)[1],
3248 ' (macro expansion)' if oMcBlock.iBeginLine == oMcBlock.iEndLine else '')
3249 + ' */\n'
3250 + 'static IEM_DECL_IEMNATIVELIVENESSFUNC_DEF(' + oVariation.getLivenessFunctionName() + ')\n'
3251 + '{\n');
3252
3253 # Unpack parameters.
3254 self.generateFunctionParameterUnpacking(oVariation, oOut,
3255 ('pCallEntry->auParams[0]',
3256 'pCallEntry->auParams[1]',
3257 'pCallEntry->auParams[2]',));
3258 asNoRefs = []; #[ 'RT_NOREF_PV(pReNative);', ];
3259 for aoRefs in oVariation.dParamRefs.values():
3260 asNoRefs.append('RT_NOREF_PV(%s);' % (aoRefs[0].sNewName,));
3261 oOut.write(' %s\n' % (' '.join(asNoRefs),));
3262
3263 # Now for the actual statements.
3264 oOut.write(oVariation.oNativeRecomp.renderCode(cchIndent = 4));
3265
3266 oOut.write('}\n');
3267
3268 #
3269 # Output the function table.
3270 #
3271 oOut.write( '\n'
3272 + '\n'
3273 + '/*\n'
3274 + ' * Liveness analysis function table running parallel to g_apfnIemThreadedFunctions and friends.\n'
3275 + ' */\n'
3276 + 'const PFNIEMNATIVELIVENESSFUNC g_apfnIemNativeLivenessFunctions[kIemThreadedFunc_End] =\n'
3277 + '{\n'
3278 + ' /*Invalid*/ NULL,'
3279 + '\n'
3280 + ' /*\n'
3281 + ' * Predefined.\n'
3282 + ' */\n'
3283 );
3284 for sFuncNm, _, fHaveRecompFunc in self.katBltIns:
3285 if fHaveRecompFunc:
3286 oOut.write(' iemNativeLivenessFunc_BltIn_%s,\n' % (sFuncNm,))
3287 else:
3288 oOut.write(' NULL, /*BltIn_%s*/\n' % (sFuncNm,))
3289
3290 iThreadedFunction = 1 + len(self.katBltIns);
3291 for sVariation in ThreadedFunctionVariation.kasVariationsEmitOrder:
3292 oOut.write( ' /*\n'
3293 + ' * Variation: ' + ThreadedFunctionVariation.kdVariationNames[sVariation] + '\n'
3294 + ' */\n');
3295 for oThreadedFunction in self.aoThreadedFuncs:
3296 oVariation = oThreadedFunction.dVariations.get(sVariation, None);
3297 if oVariation:
3298 iThreadedFunction += 1;
3299 assert oVariation.iEnumValue == iThreadedFunction;
3300 sName = oVariation.getLivenessFunctionName();
3301 if oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
3302 oOut.write(' /*%4u*/ %s,\n' % (iThreadedFunction, sName,));
3303 else:
3304 oOut.write(' /*%4u*/ NULL /*%s*/,\n' % (iThreadedFunction, sName,));
3305
3306 oOut.write( '};\n'
3307 + '\n');
3308 return True;
3309
3310
3311 def getThreadedFunctionByIndex(self, idx):
3312 """
3313 Returns a ThreadedFunction object for the given index. If the index is
3314 out of bounds, a dummy is returned.
3315 """
3316 if idx < len(self.aoThreadedFuncs):
3317 return self.aoThreadedFuncs[idx];
3318 return ThreadedFunction.dummyInstance();
3319
3320 def generateModifiedInput(self, oOut, idxFile):
3321 """
3322 Generates the combined modified input source/header file.
3323 Returns success indicator.
3324 """
3325 #
3326 # File header and assert assumptions.
3327 #
3328 oOut.write('\n'.join(self.generateLicenseHeader()));
3329 oOut.write('AssertCompile((IEM_F_MODE_X86_FLAT_OR_PRE_386_MASK | IEM_F_MODE_CPUMODE_MASK) == 7);\n');
3330
3331 #
3332 # Iterate all parsers (input files) and output the ones related to the
3333 # file set given by idxFile.
3334 #
3335 for idxParser, oParser in enumerate(self.aoParsers): # type: int, IEMAllInstPython.SimpleParser
3336 # Is this included in the file set?
3337 sSrcBaseFile = os.path.basename(oParser.sSrcFile).lower();
3338 fInclude = -1;
3339 for aoInfo in iai.g_aaoAllInstrFilesAndDefaultMapAndSet:
3340 if sSrcBaseFile == aoInfo[0].lower():
3341 fInclude = aoInfo[2] in (-1, idxFile);
3342 break;
3343 if fInclude is not True:
3344 assert fInclude is False;
3345 continue;
3346
3347 # Output it.
3348 oOut.write("\n\n/* ****** BEGIN %s ******* */\n" % (oParser.sSrcFile,));
3349
3350 iThreadedFunction = self.aidxFirstFunctions[idxParser];
3351 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
3352 iLine = 0;
3353 while iLine < len(oParser.asLines):
3354 sLine = oParser.asLines[iLine];
3355 iLine += 1; # iBeginLine and iEndLine are 1-based.
3356
3357 # Can we pass it thru?
3358 if ( iLine not in [oThreadedFunction.oMcBlock.iBeginLine, oThreadedFunction.oMcBlock.iEndLine]
3359 or oThreadedFunction.oMcBlock.sSrcFile != oParser.sSrcFile):
3360 oOut.write(sLine);
3361 #
3362 # Single MC block. Just extract it and insert the replacement.
3363 #
3364 elif oThreadedFunction.oMcBlock.iBeginLine != oThreadedFunction.oMcBlock.iEndLine:
3365 assert ( (sLine.count('IEM_MC_') - sLine.count('IEM_MC_F_') == 1)
3366 or oThreadedFunction.oMcBlock.iMacroExp == iai.McBlock.kiMacroExp_Partial), 'sLine="%s"' % (sLine,);
3367 oOut.write(sLine[:oThreadedFunction.oMcBlock.offBeginLine]);
3368 sModified = oThreadedFunction.generateInputCode().strip();
3369 oOut.write(sModified);
3370
3371 iLine = oThreadedFunction.oMcBlock.iEndLine;
3372 sLine = oParser.asLines[iLine - 1];
3373 assert ( sLine.count('IEM_MC_') - sLine.count('IEM_MC_F_') == 1
3374 or len(oThreadedFunction.oMcBlock.aoStmts) == 1
3375 or oThreadedFunction.oMcBlock.iMacroExp == iai.McBlock.kiMacroExp_Partial);
3376 oOut.write(sLine[oThreadedFunction.oMcBlock.offAfterEnd : ]);
3377
3378 # Advance
3379 iThreadedFunction += 1;
3380 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
3381 #
3382 # Macro expansion line that have sublines and may contain multiple MC blocks.
3383 #
3384 else:
3385 offLine = 0;
3386 while iLine == oThreadedFunction.oMcBlock.iBeginLine:
3387 oOut.write(sLine[offLine : oThreadedFunction.oMcBlock.offBeginLine]);
3388
3389 sModified = oThreadedFunction.generateInputCode().strip();
3390 assert ( sModified.startswith('IEM_MC_BEGIN')
3391 or (sModified.find('IEM_MC_DEFER_TO_CIMPL_') > 0 and sModified.strip().startswith('{\n'))
3392 or sModified.startswith('pVCpu->iem.s.fEndTb = true')
3393 or sModified.startswith('pVCpu->iem.s.fTbCurInstr = ')
3394 ), 'sModified="%s"' % (sModified,);
3395 oOut.write(sModified);
3396
3397 offLine = oThreadedFunction.oMcBlock.offAfterEnd;
3398
3399 # Advance
3400 iThreadedFunction += 1;
3401 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
3402
3403 # Last line segment.
3404 if offLine < len(sLine):
3405 oOut.write(sLine[offLine : ]);
3406
3407 oOut.write("/* ****** END %s ******* */\n" % (oParser.sSrcFile,));
3408
3409 return True;
3410
3411
3412 #
3413 # Main
3414 #
3415
3416 def main(self, asArgs):
3417 """
3418 C-like main function.
3419 Returns exit code.
3420 """
3421
3422 #
3423 # Parse arguments
3424 #
3425 sScriptDir = os.path.dirname(__file__);
3426 oParser = argparse.ArgumentParser(add_help = False);
3427 oParser.add_argument('asInFiles',
3428 metavar = 'input.cpp.h',
3429 nargs = '*',
3430 default = [os.path.join(sScriptDir, aoInfo[0])
3431 for aoInfo in iai.g_aaoAllInstrFilesAndDefaultMapAndSet],
3432 help = "Selection of VMMAll/IEMAllInst*.cpp.h files to use as input.");
3433 oParser.add_argument('--host-arch',
3434 metavar = 'arch',
3435 dest = 'sHostArch',
3436 action = 'store',
3437 default = None,
3438 help = 'The host architecture.');
3439
3440 oParser.add_argument('--out-thrd-funcs-hdr',
3441 metavar = 'file-thrd-funcs.h',
3442 dest = 'sOutFileThrdFuncsHdr',
3443 action = 'store',
3444 default = '-',
3445 help = 'The output header file for the threaded functions.');
3446 oParser.add_argument('--out-thrd-funcs-cpp',
3447 metavar = 'file-thrd-funcs.cpp',
3448 dest = 'sOutFileThrdFuncsCpp',
3449 action = 'store',
3450 default = '-',
3451 help = 'The output C++ file for the threaded functions.');
3452 oParser.add_argument('--out-n8ve-funcs-hdr',
3453 metavar = 'file-n8tv-funcs.h',
3454 dest = 'sOutFileN8veFuncsHdr',
3455 action = 'store',
3456 default = '-',
3457 help = 'The output header file for the native recompiler functions.');
3458 oParser.add_argument('--out-n8ve-funcs-cpp1',
3459 metavar = 'file-n8tv-funcs1.cpp',
3460 dest = 'sOutFileN8veFuncsCpp1',
3461 action = 'store',
3462 default = '-',
3463 help = 'The output C++ file for the native recompiler functions part 1.');
3464 oParser.add_argument('--out-n8ve-funcs-cpp2',
3465 metavar = 'file-n8ve-funcs2.cpp',
3466 dest = 'sOutFileN8veFuncsCpp2',
3467 action = 'store',
3468 default = '-',
3469 help = 'The output C++ file for the native recompiler functions part 2.');
3470 oParser.add_argument('--out-n8ve-funcs-cpp3',
3471 metavar = 'file-n8ve-funcs3.cpp',
3472 dest = 'sOutFileN8veFuncsCpp3',
3473 action = 'store',
3474 default = '-',
3475 help = 'The output C++ file for the native recompiler functions part 3.');
3476 oParser.add_argument('--out-n8ve-funcs-cpp4',
3477 metavar = 'file-n8ve-funcs4.cpp',
3478 dest = 'sOutFileN8veFuncsCpp4',
3479 action = 'store',
3480 default = '-',
3481 help = 'The output C++ file for the native recompiler functions part 4.');
3482 oParser.add_argument('--out-n8ve-liveness-cpp',
3483 metavar = 'file-n8ve-liveness.cpp',
3484 dest = 'sOutFileN8veLivenessCpp',
3485 action = 'store',
3486 default = '-',
3487 help = 'The output C++ file for the native recompiler liveness analysis functions.');
3488 oParser.add_argument('--native',
3489 dest = 'fNativeRecompilerEnabled',
3490 action = 'store_true',
3491 default = False,
3492 help = 'Enables generating the files related to native recompilation.');
3493 oParser.add_argument('--out-mod-input1',
3494 metavar = 'file-instr.cpp.h',
3495 dest = 'sOutFileModInput1',
3496 action = 'store',
3497 default = '-',
3498 help = 'The output C++/header file for modified input instruction files part 1.');
3499 oParser.add_argument('--out-mod-input2',
3500 metavar = 'file-instr.cpp.h',
3501 dest = 'sOutFileModInput2',
3502 action = 'store',
3503 default = '-',
3504 help = 'The output C++/header file for modified input instruction files part 2.');
3505 oParser.add_argument('--out-mod-input3',
3506 metavar = 'file-instr.cpp.h',
3507 dest = 'sOutFileModInput3',
3508 action = 'store',
3509 default = '-',
3510 help = 'The output C++/header file for modified input instruction files part 3.');
3511 oParser.add_argument('--out-mod-input4',
3512 metavar = 'file-instr.cpp.h',
3513 dest = 'sOutFileModInput4',
3514 action = 'store',
3515 default = '-',
3516 help = 'The output C++/header file for modified input instruction files part 4.');
3517 oParser.add_argument('--help', '-h', '-?',
3518 action = 'help',
3519 help = 'Display help and exit.');
3520 oParser.add_argument('--version', '-V',
3521 action = 'version',
3522 version = 'r%s (IEMAllThreadedPython.py), r%s (IEMAllInstPython.py)'
3523 % (__version__.split()[1], iai.__version__.split()[1],),
3524 help = 'Displays the version/revision of the script and exit.');
3525 self.oOptions = oParser.parse_args(asArgs[1:]);
3526 print("oOptions=%s" % (self.oOptions,), file = sys.stderr);
3527
3528 if self.oOptions.sHostArch not in ('amd64', 'arm64'):
3529 print('error! Unsupported (or missing) host architecture: %s' % (self.oOptions.sHostArch,), file = sys.stderr);
3530 return 1;
3531
3532 #
3533 # Process the instructions specified in the IEM sources.
3534 #
3535 if self.processInputFiles(self.oOptions.sHostArch, self.oOptions.fNativeRecompilerEnabled):
3536 #
3537 # Generate the output files.
3538 #
3539 aaoOutputFiles = (
3540 ( self.oOptions.sOutFileThrdFuncsHdr, self.generateThreadedFunctionsHeader, 0, ),
3541 ( self.oOptions.sOutFileThrdFuncsCpp, self.generateThreadedFunctionsSource, 0, ),
3542 ( self.oOptions.sOutFileN8veFuncsHdr, self.generateNativeFunctionsHeader, 0, ),
3543 ( self.oOptions.sOutFileN8veFuncsCpp1, self.generateNativeFunctionsSource, 0, ),
3544 ( self.oOptions.sOutFileN8veFuncsCpp2, self.generateNativeFunctionsSource, 1, ),
3545 ( self.oOptions.sOutFileN8veFuncsCpp3, self.generateNativeFunctionsSource, 2, ),
3546 ( self.oOptions.sOutFileN8veFuncsCpp4, self.generateNativeFunctionsSource, 3, ),
3547 ( self.oOptions.sOutFileN8veLivenessCpp, self.generateNativeLivenessSource, 0, ),
3548 ( self.oOptions.sOutFileModInput1, self.generateModifiedInput, 1, ),
3549 ( self.oOptions.sOutFileModInput2, self.generateModifiedInput, 2, ),
3550 ( self.oOptions.sOutFileModInput3, self.generateModifiedInput, 3, ),
3551 ( self.oOptions.sOutFileModInput4, self.generateModifiedInput, 4, ),
3552 );
3553 fRc = True;
3554 for sOutFile, fnGenMethod, iPartNo in aaoOutputFiles:
3555 if sOutFile == '-':
3556 fRc = fnGenMethod(sys.stdout, iPartNo) and fRc;
3557 else:
3558 try:
3559 oOut = open(sOutFile, 'w'); # pylint: disable=consider-using-with,unspecified-encoding
3560 except Exception as oXcpt:
3561 print('error! Failed open "%s" for writing: %s' % (sOutFile, oXcpt,), file = sys.stderr);
3562 return 1;
3563 fRc = fnGenMethod(oOut, iPartNo) and fRc;
3564 oOut.close();
3565 if fRc:
3566 return 0;
3567
3568 return 1;
3569
3570
3571if __name__ == '__main__':
3572 sys.exit(IEMThreadedGenerator().main(sys.argv));
3573
Note: See TracBrowser for help on using the repository browser.

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