VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IEMAllN8vePython.py@ 102447

Last change on this file since 102447 was 102447, checked in by vboxsync, 17 months ago

VMM/IEM: movsx & movzx from registers. bugref:10371

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 32.3 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllN8vePython.py 102447 2023-12-04 13:05:53Z vboxsync $
4# pylint: disable=invalid-name
5
6"""
7Native recompiler side-kick for IEMAllThrdPython.py.
8
9Analyzes the each threaded function variant to see if we can we're able to
10recompile it, then provides modifies MC block code for doing so.
11"""
12
13from __future__ import print_function;
14
15__copyright__ = \
16"""
17Copyright (C) 2023 Oracle and/or its affiliates.
18
19This file is part of VirtualBox base platform packages, as
20available from https://www.virtualbox.org.
21
22This program is free software; you can redistribute it and/or
23modify it under the terms of the GNU General Public License
24as published by the Free Software Foundation, in version 3 of the
25License.
26
27This program is distributed in the hope that it will be useful, but
28WITHOUT ANY WARRANTY; without even the implied warranty of
29MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30General Public License for more details.
31
32You should have received a copy of the GNU General Public License
33along with this program; if not, see <https://www.gnu.org/licenses>.
34
35SPDX-License-Identifier: GPL-3.0-only
36"""
37__version__ = "$Revision: 102447 $"
38
39# Standard python imports:
40import copy;
41import sys;
42
43# Out python imports:
44import IEMAllInstPython as iai;
45
46
47## Supplememnts g_dMcStmtParsers.
48g_dMcStmtThreaded = {
49 'IEM_MC_DEFER_TO_CIMPL_0_RET_THREADED': (None, True, True, ),
50 'IEM_MC_DEFER_TO_CIMPL_1_RET_THREADED': (None, True, True, ),
51 'IEM_MC_DEFER_TO_CIMPL_2_RET_THREADED': (None, True, True, ),
52 'IEM_MC_DEFER_TO_CIMPL_3_RET_THREADED': (None, True, True, ),
53
54 'IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC16': (None, True, True, ),
55 'IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC32': (None, True, True, ),
56 'IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC64': (None, True, True, ),
57
58 'IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC16_WITH_FLAGS': (None, True, True, ),
59 'IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC32_WITH_FLAGS': (None, True, True, ),
60 'IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC64_WITH_FLAGS': (None, True, True, ),
61
62 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_16': (None, False, True, ),
63 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_32': (None, False, True, ),
64 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64_ADDR32': (None, False, False, ),
65 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64_FSGS': (None, False, False, ),
66 'IEM_MC_CALC_RM_EFF_ADDR_THREADED_64': (None, False, False, ),
67
68 'IEM_MC_CALL_CIMPL_1_THREADED': (None, True, True, ),
69 'IEM_MC_CALL_CIMPL_2_THREADED': (None, True, True, ),
70 'IEM_MC_CALL_CIMPL_3_THREADED': (None, True, True, ),
71 'IEM_MC_CALL_CIMPL_4_THREADED': (None, True, True, ),
72 'IEM_MC_CALL_CIMPL_5_THREADED': (None, True, True, ),
73
74 'IEM_MC_REL_JMP_S8_AND_FINISH_THREADED_PC16': (None, True, True, ),
75 'IEM_MC_REL_JMP_S8_AND_FINISH_THREADED_PC32': (None, True, True, ),
76 'IEM_MC_REL_JMP_S8_AND_FINISH_THREADED_PC64': (None, True, True, ),
77 'IEM_MC_REL_JMP_S16_AND_FINISH_THREADED_PC16': (None, True, True, ),
78 'IEM_MC_REL_JMP_S16_AND_FINISH_THREADED_PC32': (None, True, True, ),
79 'IEM_MC_REL_JMP_S16_AND_FINISH_THREADED_PC64': (None, True, True, ),
80 'IEM_MC_REL_JMP_S32_AND_FINISH_THREADED_PC32': (None, True, True, ),
81 'IEM_MC_REL_JMP_S32_AND_FINISH_THREADED_PC64': (None, True, True, ),
82
83 'IEM_MC_REL_JMP_S8_AND_FINISH_THREADED_PC16_WITH_FLAGS': (None, True, True, ),
84 'IEM_MC_REL_JMP_S8_AND_FINISH_THREADED_PC32_WITH_FLAGS': (None, True, True, ),
85 'IEM_MC_REL_JMP_S8_AND_FINISH_THREADED_PC64_WITH_FLAGS': (None, True, True, ),
86 'IEM_MC_REL_JMP_S16_AND_FINISH_THREADED_PC16_WITH_FLAGS': (None, True, True, ),
87 'IEM_MC_REL_JMP_S16_AND_FINISH_THREADED_PC32_WITH_FLAGS': (None, True, True, ),
88 'IEM_MC_REL_JMP_S16_AND_FINISH_THREADED_PC64_WITH_FLAGS': (None, True, True, ),
89 'IEM_MC_REL_JMP_S32_AND_FINISH_THREADED_PC32_WITH_FLAGS': (None, True, True, ),
90 'IEM_MC_REL_JMP_S32_AND_FINISH_THREADED_PC64_WITH_FLAGS': (None, True, True, ),
91
92 'IEM_MC_STORE_GREG_U8_THREADED': (None, True, True, ),
93 'IEM_MC_STORE_GREG_U8_CONST_THREADED': (None, True, True, ),
94 'IEM_MC_FETCH_GREG_U8_THREADED': (None, False, True, ),
95 'IEM_MC_FETCH_GREG_U8_SX_U16_THREADED': (None, False, True, ),
96 'IEM_MC_FETCH_GREG_U8_SX_U32_THREADED': (None, False, True, ),
97 'IEM_MC_FETCH_GREG_U8_SX_U64_THREADED': (None, False, True, ),
98 'IEM_MC_FETCH_GREG_U8_ZX_U16_THREADED': (None, False, True, ),
99 'IEM_MC_FETCH_GREG_U8_ZX_U32_THREADED': (None, False, True, ),
100 'IEM_MC_FETCH_GREG_U8_ZX_U64_THREADED': (None, False, True, ),
101 'IEM_MC_REF_GREG_U8_THREADED': (None, True, True, ),
102
103 # Flat Mem:
104 'IEM_MC_FETCH_MEM16_FLAT_U8': (None, True, False, ),
105 'IEM_MC_FETCH_MEM32_FLAT_U8': (None, True, False, ),
106 'IEM_MC_FETCH_MEM_FLAT_D80': (None, True, False, ),
107 'IEM_MC_FETCH_MEM_FLAT_I16': (None, True, False, ),
108 'IEM_MC_FETCH_MEM_FLAT_I32': (None, True, False, ),
109 'IEM_MC_FETCH_MEM_FLAT_I64': (None, True, False, ),
110 'IEM_MC_FETCH_MEM_FLAT_R32': (None, True, False, ),
111 'IEM_MC_FETCH_MEM_FLAT_R64': (None, True, False, ),
112 'IEM_MC_FETCH_MEM_FLAT_R80': (None, True, False, ),
113 'IEM_MC_FETCH_MEM_FLAT_U128_ALIGN_SSE': (None, True, False, ),
114 'IEM_MC_FETCH_MEM_FLAT_U128_NO_AC': (None, True, False, ),
115 'IEM_MC_FETCH_MEM_FLAT_U128': (None, True, False, ),
116 'IEM_MC_FETCH_MEM_FLAT_U16_DISP': (None, True, True, ),
117 'IEM_MC_FETCH_MEM_FLAT_U16_SX_U32': (None, True, True, ),
118 'IEM_MC_FETCH_MEM_FLAT_U16_SX_U64': (None, True, True, ),
119 'IEM_MC_FETCH_MEM_FLAT_U16': (None, True, True, ),
120 'IEM_MC_FETCH_MEM_FLAT_U16_ZX_U32': (None, True, True, ),
121 'IEM_MC_FETCH_MEM_FLAT_U16_ZX_U64': (None, True, True, ),
122 'IEM_MC_FETCH_MEM_FLAT_U256_ALIGN_AVX': (None, True, False, ),
123 'IEM_MC_FETCH_MEM_FLAT_U256_NO_AC': (None, True, False, ),
124 'IEM_MC_FETCH_MEM_FLAT_U256': (None, True, False, ),
125 'IEM_MC_FETCH_MEM_FLAT_U32': (None, True, True, ),
126 'IEM_MC_FETCH_MEM_FLAT_U32_DISP': (None, True, True, ),
127 'IEM_MC_FETCH_MEM_FLAT_U32_SX_U64': (None, True, True, ),
128 'IEM_MC_FETCH_MEM_FLAT_U32_ZX_U64': (None, True, True, ),
129 'IEM_MC_FETCH_MEM_FLAT_U64': (None, True, True, ),
130 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U16': (None, True, True, ),
131 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U32': (None, True, True, ),
132 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U64': (None, True, True, ),
133 'IEM_MC_FETCH_MEM_FLAT_U8': (None, True, True, ),
134 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U16': (None, True, True, ),
135 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U32': (None, True, True, ),
136 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U64': (None, True, True, ),
137 'IEM_MC_FETCH_MEM_FLAT_XMM_ALIGN_SSE': (None, True, False, ),
138 'IEM_MC_FETCH_MEM_FLAT_XMM_U32': (None, True, False, ),
139 'IEM_MC_FETCH_MEM_FLAT_XMM_U64': (None, True, False, ),
140 'IEM_MC_FETCH_MEM_FLAT_U128_AND_XREG_U128': (None, True, False, ),
141 'IEM_MC_FETCH_MEM_FLAT_XMM_ALIGN_SSE_AND_XREG_XMM': (None, True, False, ),
142 'IEM_MC_FETCH_MEM_FLAT_XMM_U32_AND_XREG_XMM': (None, True, False, ),
143 'IEM_MC_FETCH_MEM_FLAT_XMM_U64_AND_XREG_XMM': (None, True, False, ),
144 'IEM_MC_FETCH_MEM_FLAT_U128_AND_XREG_U128_AND_RAX_RDX_U64': (None, True, False, ),
145 'IEM_MC_FETCH_MEM_FLAT_U128_AND_XREG_U128_AND_EAX_EDX_U32_SX_U64': (None, True, False, ),
146 'IEM_MC_MEM_FLAT_MAP_D80_WO': (None, True, True, ),
147 'IEM_MC_MEM_FLAT_MAP_I16_WO': (None, True, True, ),
148 'IEM_MC_MEM_FLAT_MAP_I32_WO': (None, True, True, ),
149 'IEM_MC_MEM_FLAT_MAP_I64_WO': (None, True, True, ),
150 'IEM_MC_MEM_FLAT_MAP_R32_WO': (None, True, True, ),
151 'IEM_MC_MEM_FLAT_MAP_R64_WO': (None, True, True, ),
152 'IEM_MC_MEM_FLAT_MAP_R80_WO': (None, True, True, ),
153 'IEM_MC_MEM_FLAT_MAP_U8_RO': (None, True, True, ),
154 'IEM_MC_MEM_FLAT_MAP_U8_RW': (None, True, True, ),
155 'IEM_MC_MEM_FLAT_MAP_U16_RO': (None, True, True, ),
156 'IEM_MC_MEM_FLAT_MAP_U16_RW': (None, True, True, ),
157 'IEM_MC_MEM_FLAT_MAP_U32_RO': (None, True, True, ),
158 'IEM_MC_MEM_FLAT_MAP_U32_RW': (None, True, True, ),
159 'IEM_MC_MEM_FLAT_MAP_U64_RO': (None, True, True, ),
160 'IEM_MC_MEM_FLAT_MAP_U64_RW': (None, True, True, ),
161 'IEM_MC_MEM_FLAT_MAP_U128_RW': (None, True, True, ),
162 'IEM_MC_STORE_MEM_FLAT_U128_ALIGN_SSE': (None, True, False, ),
163 'IEM_MC_STORE_MEM_FLAT_U128': (None, True, False, ),
164 'IEM_MC_STORE_MEM_FLAT_U16': (None, True, True, ),
165 'IEM_MC_STORE_MEM_FLAT_U16_CONST': (None, True, True, ),
166 'IEM_MC_STORE_MEM_FLAT_U256_ALIGN_AVX': (None, True, False, ),
167 'IEM_MC_STORE_MEM_FLAT_U256': (None, True, False, ),
168 'IEM_MC_STORE_MEM_FLAT_U32': (None, True, True, ),
169 'IEM_MC_STORE_MEM_FLAT_U32_CONST': (None, True, True, ),
170 'IEM_MC_STORE_MEM_FLAT_U64': (None, True, True, ),
171 'IEM_MC_STORE_MEM_FLAT_U64_CONST': (None, True, True, ),
172 'IEM_MC_STORE_MEM_FLAT_U8': (None, True, True, ),
173 'IEM_MC_STORE_MEM_FLAT_U8_CONST': (None, True, True, ),
174
175 # Flat Stack:
176 'IEM_MC_FLAT64_PUSH_U16': (None, True, False, ),
177 'IEM_MC_FLAT64_PUSH_U64': (None, True, False, ),
178 'IEM_MC_FLAT64_POP_U16': (None, True, False, ),
179 'IEM_MC_FLAT64_POP_U64': (None, True, False, ),
180 'IEM_MC_FLAT32_PUSH_U16': (None, True, False, ),
181 'IEM_MC_FLAT32_PUSH_U32': (None, True, False, ),
182 'IEM_MC_FLAT32_POP_U16': (None, True, False, ),
183 'IEM_MC_FLAT32_POP_U32': (None, True, False, ),
184};
185
186class NativeRecompFunctionVariation(object):
187 """
188 Class that deals with transforming a threaded function variation into a
189 native recompiler function.
190
191 This base class doesn't do any transforming and just renders the same
192 code as for the threaded function.
193 """
194
195 def __init__(self, oVariation, sHostArch):
196 self.oVariation = oVariation # type: ThreadedFunctionVariation
197 self.sHostArch = sHostArch;
198
199 def isRecompilable(self):
200 """
201 Predicate that returns whether the variant can be recompiled natively
202 (for the selected host architecture).
203 """
204 return True;
205
206 def raiseProblem(self, sMessage):
207 """ Raises a problem. """
208 raise Exception('%s:%s: error: %s'
209 % (self.oVariation.oParent.oMcBlock.sSrcFile, self.oVariation.oParent.oMcBlock.iBeginLine, sMessage,));
210
211 def __analyzeVariableLiveness(self, aoStmts, dVars, iDepth = 0):
212 """
213 Performs liveness analysis of the given statement list, inserting new
214 statements to signal to the native recompiler that a variable is no
215 longer used and can be freed.
216
217 Returns list of freed variables.
218 """
219
220 class VarInfo(object):
221 """ Variable info """
222 def __init__(self, oStmt):
223 self.oStmt = oStmt;
224 self.fIsArg = isinstance(oStmt, iai.McStmtArg);
225 self.oReferences = None # type: VarInfo
226 self.oReferencedBy = None # type: VarInfo
227
228 def isArg(self):
229 return self.fIsArg;
230
231 def makeReference(self, oLocal, oParent):
232 if not self.isArg():
233 oParent.raiseProblem('Attempt to make a reference out of an local variable: %s = &%s'
234 % (self.oStmt.sVarName, oLocal.oStmt.sVarName,));
235 if self.oReferences:
236 oParent.raiseProblem('Can only make a variable a reference once: %s = &%s; now = &%s'
237 % (self.oStmt.sVarName, self.oReferences.oStmt.sVarName, oLocal.oStmt.sVarName,));
238 if oLocal.isArg():
239 oParent.raiseProblem('Attempt to make a reference to an argument: %s = &%s'
240 % (self.oStmt.sVarName, oLocal.oStmt.sVarName,));
241 if oLocal.oReferencedBy:
242 oParent.raiseProblem('%s is already referenced by %s, so cannot make %s reference it as well'
243 % (oLocal.oStmt.sVarName, oLocal.oReferencedBy.oStmt.sVarName, self.oStmt.sVarName,));
244 self.oReferences = oLocal;
245 self.oReferences.oReferencedBy = self;
246 return True;
247
248 #
249 # Gather variable declarations and add them to dVars.
250 # Also keep a local list of them for scoping when iDepth > 0.
251 #
252 asVarsInScope = [];
253 for oStmt in aoStmts:
254 if isinstance(oStmt, iai.McStmtVar):
255 if oStmt.sVarName in dVars:
256 raise Exception('Duplicate variable: %s' % (oStmt.sVarName, ));
257
258 oInfo = VarInfo(oStmt);
259 if oInfo.isArg() and oStmt.sRefType == 'local':
260 oInfo.makeReference(dVars[oStmt.sRef], self);
261
262 dVars[oStmt.sVarName] = oInfo;
263 asVarsInScope.append(oStmt.sVarName);
264
265 elif oStmt.sName == 'IEM_MC_REF_LOCAL':
266 dVars[oStmt.asParams[0]].makeReference(dVars[oStmt.asParams[1]], self);
267
268 #
269 # Now work the statements backwards and look for the last reference to
270 # each of the variables in dVars. We remove the variables from the
271 # collections as we go along.
272 #
273 def freeVariable(aoStmts, iStmt, oVarInfo, dFreedVars, dVars, fIncludeReferences = True):
274 sVarName = oVarInfo.oStmt.sVarName;
275 if not oVarInfo.isArg():
276 aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_LOCAL', [sVarName,]));
277 assert not oVarInfo.oReferences;
278 else:
279 aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_ARG', [sVarName,]));
280 if fIncludeReferences and oVarInfo.sReference:
281 sRefVarName = oVarInfo.oReferences.oStmt.sVarName;
282 if sRefVarName in dVars:
283 dFreedVars[sRefVarName] = dVars[sRefVarName];
284 del dVars[sRefVarName];
285 aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_LOCAL', [sRefVarName,]));
286 dFreedVars[sVarName] = oVarInfo;
287 if dVars is not None:
288 del dVars[sVarName];
289
290 dFreedVars = {};
291 for iStmt in range(len(aoStmts) - 1, -1, -1):
292 oStmt = aoStmts[iStmt];
293 if isinstance(oStmt, iai.McStmtCond):
294 #
295 # Conditionals requires a bit more work...
296 #
297
298 # Start by replacing the conditional statement by a shallow copy.
299 oStmt = copy.copy(oStmt);
300 oStmt.aoIfBranch = list(oStmt.aoIfBranch);
301 oStmt.aoElseBranch = list(oStmt.aoElseBranch);
302 aoStmts[iStmt] = oStmt;
303
304 # Check the two branches for final references. Both branches must
305 # start processing with the same dVars set, fortunately as shallow
306 # copy suffices.
307 dFreedInIfBranch = self.__analyzeVariableLiveness(oStmt.aoIfBranch, dict(dVars), iDepth + 1);
308 dFreedInElseBranch = self.__analyzeVariableLiveness(oStmt.aoElseBranch, dVars, iDepth + 1);
309
310 # Add free statements to the start of the IF-branch for variables use
311 # for the last time in the else branch.
312 for sVarName, oVarInfo in dFreedInElseBranch.items():
313 if sVarName not in dFreedInIfBranch:
314 freeVariable(oStmt.aoIfBranch, -1, oVarInfo, dFreedVars, None, False);
315 else:
316 dFreedVars[sVarName] = oVarInfo;
317
318 # And vice versa.
319 for sVarName, oVarInfo in dFreedInIfBranch.items():
320 if sVarName not in dFreedInElseBranch:
321 freeVariable(oStmt.aoElseBranch, -1, oVarInfo, dFreedVars, dVars, False);
322
323 #
324 # Now check if any remaining variables are used for the last time
325 # in the conditional statement ifself, in which case we need to insert
326 # free statements to both branches.
327 #
328 if not oStmt.isCppStmt():
329 aoFreeStmts = [];
330 for sParam in oStmt.asParams:
331 if sParam in dVars:
332 freeVariable(aoFreeStmts, -1, dVars[sParam], dFreedVars, dVars);
333 for oFreeStmt in aoFreeStmts:
334 oStmt.aoIfBranch.insert(0, oFreeStmt);
335 oStmt.aoElseBranch.insert(0, oFreeStmt);
336
337 elif not oStmt.isCppStmt():
338 if isinstance(oStmt, iai.McStmtCall):
339 #
340 # Call statements will make use of all argument variables and
341 # will implicitly free them. So, iterate the variable and
342 # move them from dVars and onto dFreedVars.
343 #
344 # We explictly free any referenced variable that is still in
345 # dVar at this point (since only arguments can hold variable
346 # references).
347 #
348 for sParam in oStmt.asParams[oStmt.idxParams:]:
349 oVarInfo = dVars.get(sParam);
350 if oVarInfo:
351 if not oVarInfo.isArg():
352 self.raiseProblem('Argument %s in %s is not an argument!' % (sParam, oStmt.sName,));
353 if oVarInfo.oReferences:
354 sRefVarName = oVarInfo.oReferences.oStmt.sVarName;
355 if sRefVarName in dVars:
356 dFreedVars[sRefVarName] = dVars[sRefVarName];
357 del dVars[sRefVarName];
358 aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_LOCAL', [sRefVarName,]));
359 dFreedVars[sParam] = oVarInfo;
360 del dVars[sParam];
361 elif sParam in dFreedVars:
362 self.raiseProblem('Argument %s in %s was used after the call!' % (sParam, oStmt.sName,));
363 else:
364 self.raiseProblem('Argument %s in %s is not known to us' % (sParam, oStmt.sName,));
365
366 # Check for stray argument variables.
367 for oVarInfo in dVars.values():
368 if oVarInfo.isArg():
369 self.raiseProblem('Unused argument variable: %s' % (oVarInfo.oStmt.sVarName,));
370 else:
371 #
372 # Scan all the parameters of generic statements.
373 #
374 for sParam in oStmt.asParams:
375 if sParam in dVars:
376 freeVariable(aoStmts, iStmt, dVars[sParam], dFreedVars, dVars);
377
378 #
379 # Free anything left from asVarsInScope that's now going out of scope.
380 #
381 if iDepth > 0:
382 for sVarName in asVarsInScope:
383 if sVarName in dVars:
384 freeVariable(aoStmts, len(aoStmts) - 1, dVars[sVarName], dFreedVars, dVars);
385 return dFreedVars;
386
387 def __morphStatements(self, aoStmts):
388 """
389 Morphs the given statement list into something more suitable for
390 native recompilation.
391
392 The following is currently done here:
393 - Amend IEM_MC_BEGIN with all the IEM_CIMPL_F_XXX and IEM_MC_F_XXX
394 flags found and derived, including IEM_MC_F_WITHOUT_FLAGS which
395 we determine here.
396 - Insert IEM_MC_FREE_LOCAL when after the last statment a local
397 variable is last used.
398
399 Returns a new list of statements.
400 """
401
402 #
403 # We can skip IEM_MC_DEFER_TO_CIMPL_x_RET stuff.
404 #
405 if self.oVariation.oParent.oMcBlock.fDeferToCImpl:
406 return aoStmts;
407
408 #
409 # We make a shallow copy of the list, and only make deep copies of the
410 # statements we modify.
411 #
412 aoStmts = list(aoStmts) # type: list(iai.McStmt)
413
414 #
415 # First, amend the IEM_MC_BEGIN statment, adding all the flags found
416 # to it so the native recompiler can correctly process ARG and CALL
417 # statements (among other things).
418 #
419 # Also add IEM_MC_F_WITHOUT_FLAGS if this isn't a variation with eflags
420 # checking and clearing while there are such variations for this
421 # function (this sounds a bit backwards, but has to be done this way
422 # for the use we make of the flags in CIMPL calls).
423 #
424 for iStmt, oStmt in enumerate(aoStmts):
425 if oStmt.sName == 'IEM_MC_BEGIN':
426 fWithoutFlags = ( self.oVariation.isWithFlagsCheckingAndClearingVariation()
427 and self.oVariation.oParent.hasWithFlagsCheckingAndClearingVariation());
428 if fWithoutFlags or self.oVariation.oParent.dsCImplFlags:
429 oNewStmt = copy.deepcopy(oStmt);
430 if fWithoutFlags:
431 oNewStmt.asParams[2] = ' | '.join(sorted( list(self.oVariation.oParent.oMcBlock.dsMcFlags.keys())
432 + ['IEM_MC_F_WITHOUT_FLAGS',] ));
433 if self.oVariation.oParent.dsCImplFlags:
434 oNewStmt.asParams[3] = ' | '.join(sorted(self.oVariation.oParent.dsCImplFlags.keys()));
435 aoStmts[iStmt] = oNewStmt;
436 break;
437
438 #
439 # Do a simple liveness analysis of the variable and insert
440 # IEM_MC_FREE_LOCAL statements after the last statements using each
441 # variable. We do this recursively to best handle conditionals and
442 # scoping related to those.
443 #
444 self.__analyzeVariableLiveness(aoStmts, {});
445
446 return aoStmts;
447
448
449 def renderCode(self, cchIndent):
450 """
451 Returns the native recompiler function body for this threaded variant.
452 """
453 return iai.McStmt.renderCodeForList(self.__morphStatements(self.oVariation.aoStmtsForThreadedFunction), cchIndent);
454
455 @staticmethod
456 def checkStatements(aoStmts, sHostArch):
457 """
458 Checks that all the given statements are supported by the native recompiler.
459 Returns dictionary with the unsupported statments.
460 """
461 dRet = {};
462 _ = sHostArch;
463 for oStmt in aoStmts: # type: McStmt
464 if not oStmt.isCppStmt():
465 aInfo = iai.g_dMcStmtParsers.get(oStmt.sName);
466 if not aInfo:
467 aInfo = g_dMcStmtThreaded.get(oStmt.sName);
468 if not aInfo:
469 raise Exception('Unknown statement: %s' % (oStmt.sName, ));
470 if aInfo[2] is False:
471 dRet[oStmt.sName] = 1;
472 elif aInfo[2] is not True:
473 if isinstance(aInfo[2], str):
474 if aInfo[2] != sHostArch:
475 dRet[oStmt.sName] = 1;
476 elif sHostArch not in aInfo[2]:
477 dRet[oStmt.sName] = 1;
478 #elif not self.fDecode:
479
480 if isinstance(oStmt, iai.McStmtCond):
481 dRet.update(NativeRecompFunctionVariation.checkStatements(oStmt.aoIfBranch, sHostArch));
482 dRet.update(NativeRecompFunctionVariation.checkStatements(oStmt.aoElseBranch, sHostArch));
483
484 return dRet;
485
486
487## Statistics: Number of MC blocks (value) depending on each unsupported statement (key).
488g_dUnsupportedMcStmtStats = {}
489
490## Statistics: List of variations (value) that is only missing this one statement (key).
491g_dUnsupportedMcStmtLastOneStats = {}
492
493### Statistics: List of variations (value) with aimpl_[^0] calls that is only missing this one statement (key).
494#g_dUnsupportedMcStmtLastOneAImplStats = {}
495
496
497def analyzeVariantForNativeRecomp(oVariation,
498 sHostArch): # type: (ThreadedFunctionVariation, str) -> NativeRecompFunctionVariation
499 """
500 This function analyzes the threaded function variant and returns an
501 NativeRecompFunctionVariation instance for it, unless it's not
502 possible to recompile at present.
503
504 Returns NativeRecompFunctionVariation or the number of unsupported MCs.
505 """
506
507 #
508 # Analyze the statements.
509 #
510 aoStmts = oVariation.aoStmtsForThreadedFunction # type: list(McStmt)
511 dUnsupportedStmts = NativeRecompFunctionVariation.checkStatements(aoStmts, sHostArch);
512 if not dUnsupportedStmts:
513 return NativeRecompFunctionVariation(oVariation, sHostArch);
514
515 #
516 # Update the statistics.
517 #
518 for sStmt in dUnsupportedStmts:
519 g_dUnsupportedMcStmtStats[sStmt] = 1 + g_dUnsupportedMcStmtStats.get(sStmt, 0);
520
521 if len(dUnsupportedStmts) == 1:
522 for sStmt in dUnsupportedStmts:
523 if sStmt in g_dUnsupportedMcStmtLastOneStats:
524 g_dUnsupportedMcStmtLastOneStats[sStmt].append(oVariation);
525 else:
526 g_dUnsupportedMcStmtLastOneStats[sStmt] = [oVariation,];
527
528 #if ( len(dUnsupportedStmts) in (1,2)
529 # and iai.McStmt.findStmtByNames(aoStmts,
530 # { 'IEM_MC_CALL_AIMPL_3': 1,
531 # 'IEM_MC_CALL_AIMPL_4': 1,
532 # #'IEM_MC_CALL_VOID_AIMPL_0': 1, - can't test results... ?
533 # 'IEM_MC_CALL_VOID_AIMPL_1': 1,
534 # 'IEM_MC_CALL_VOID_AIMPL_2': 1,
535 # 'IEM_MC_CALL_VOID_AIMPL_3': 1,
536 # 'IEM_MC_CALL_VOID_AIMPL_4': 1,
537 # #'IEM_MC_CALL_FPU_AIMPL_1': 1,
538 # #'IEM_MC_CALL_FPU_AIMPL_2': 1,
539 # #'IEM_MC_CALL_FPU_AIMPL_3': 1,
540 # #'IEM_MC_CALL_MMX_AIMPL_2': 1,
541 # #'IEM_MC_CALL_MMX_AIMPL_3': 1,
542 # #'IEM_MC_CALL_SSE_AIMPL_2': 1,
543 # #'IEM_MC_CALL_SSE_AIMPL_3': 1,
544 # #'IEM_MC_CALL_AVX_AIMPL_2': 1,
545 # #'IEM_MC_CALL_AVX_AIMPL_3': 1,
546 # #'IEM_MC_CALL_AVX_AIMPL_4': 1,
547 # })):
548 # for sStmt in dUnsupportedStmts:
549 # if sStmt in g_dUnsupportedMcStmtLastOneAImplStats:
550 # g_dUnsupportedMcStmtLastOneAImplStats[sStmt].append(oVariation);
551 # else:
552 # g_dUnsupportedMcStmtLastOneAImplStats[sStmt] = [oVariation,];
553
554 return None;
555
556
557def displayStatistics(aoThreadedFuncs, sHostArch): # type (list(ThreadedFunction)) -> True
558 """
559 Displays statistics.
560 """
561 print('todo:', file = sys.stderr);
562 cTotal = 0;
563 cNative = 0;
564 for oThreadedFunction in aoThreadedFuncs:
565 for oVariation in oThreadedFunction.aoVariations:
566 cTotal += 1;
567 oVariation.oNativeRecomp = analyzeVariantForNativeRecomp(oVariation, sHostArch);
568 if oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
569 cNative += 1;
570 print('todo: %.1f%% / %u out of %u threaded function variations are recompilable'
571 % (cNative * 100.0 / cTotal, cNative, cTotal), file = sys.stderr);
572 if g_dUnsupportedMcStmtLastOneStats:
573 asTopKeys = sorted(g_dUnsupportedMcStmtLastOneStats, reverse = True,
574 key = lambda sSortKey: len(g_dUnsupportedMcStmtLastOneStats[sSortKey]))[:16];
575 print('todo:', file = sys.stderr);
576 print('todo: Top %s variations with one unsupported statement dependency:' % (len(asTopKeys),),
577 file = sys.stderr);
578 cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
579 for sKey in asTopKeys:
580 print('todo: %*s = %s (%s%s)'
581 % (cchMaxKey, sKey, len(g_dUnsupportedMcStmtLastOneStats[sKey]),
582 ', '.join([oVar.getShortName() for oVar in g_dUnsupportedMcStmtLastOneStats[sKey][:5]]),
583 ',...' if len(g_dUnsupportedMcStmtLastOneStats[sKey]) >= 5 else '', )
584 , file = sys.stderr);
585
586 asTopKeys = sorted(g_dUnsupportedMcStmtStats, reverse = True,
587 key = lambda sSortKey: g_dUnsupportedMcStmtStats[sSortKey])[:16];
588 print('todo:', file = sys.stderr);
589 print('todo: Top %d most used unimplemented statements:' % (len(asTopKeys),), file = sys.stderr);
590 cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
591 for i in range(0, len(asTopKeys), 2):
592 print('todo: %*s = %4d %*s = %4d'
593 % ( cchMaxKey, asTopKeys[i], g_dUnsupportedMcStmtStats[asTopKeys[i]],
594 cchMaxKey, asTopKeys[i + 1], g_dUnsupportedMcStmtStats[asTopKeys[i + 1]],),
595 file = sys.stderr);
596 print('todo:', file = sys.stderr);
597
598 #if g_dUnsupportedMcStmtLastOneAImplStats:
599 # asTopKeys = sorted(g_dUnsupportedMcStmtLastOneAImplStats, reverse = True,
600 # key = lambda sSortKey: len(g_dUnsupportedMcStmtLastOneAImplStats[sSortKey]))[:16];
601 # print('todo:', file = sys.stderr);
602 # print('todo: Top %s variations with AIMPL call and 1-2 unsupported statement dependencies:' % (len(asTopKeys),),
603 # file = sys.stderr);
604 # cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
605 # for sKey in asTopKeys:
606 # print('todo: %*s = %s (%s%s)'
607 # % (cchMaxKey, sKey, len(g_dUnsupportedMcStmtLastOneAImplStats[sKey]),
608 # ', '.join([oVar.getShortName() for oVar in g_dUnsupportedMcStmtLastOneAImplStats[sKey][:5]]),
609 # ',...' if len(g_dUnsupportedMcStmtLastOneAImplStats[sKey]) >= 5 else '', )
610 # , file = sys.stderr);
611
612 return True;
Note: See TracBrowser for help on using the repository browser.

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