VirtualBox

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

Last change on this file since 107631 was 107218, checked in by vboxsync, 7 weeks ago

ValidationKit/bootsectors: fix IEM implementation of vcmpp[sd]; bugref: 10658; jiraref:VBP-1208

  • part 3 of previous fix (r166170)
  • add microcode macros to fetch media register + memory without alignment checks:
  • add IEM_MC_FETCH_MEM_YMM_NO_AC_AND_YREG_YMM
  • add IEM_MC_FETCH_MEM_XMM_NO_AC_AND_XREG_XMM
  • add IEM_MC_FETCH_MEM_FLAT_XMM_NO_AC_AND_XREG_XMM
  • remove unused IEM_MC_FETCH_MEM_YMM_ALIGN_AVX_AND_YREG_YMM
  • remove unused IEM_MC_FETCH_MEM_XMM_ALIGN_AVX_AND_XREG_XMM

(this commit breaks the build until immediately following vdpp[sd] commit)

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

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