VirtualBox

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

Last change on this file since 102092 was 102082, checked in by vboxsync, 13 months ago

VMM/IEM: Native translation of IEM_MC_FETCH_GREG_U8_THREADED. 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: 31.6 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllN8vePython.py 102082 2023-11-13 12:57:44Z 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: 102082 $"
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, False, ),
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, False, ),
96 'IEM_MC_FETCH_GREG_U8_SX_U32_THREADED': (None, False, False, ),
97 'IEM_MC_FETCH_GREG_U8_SX_U64_THREADED': (None, False, False, ),
98 'IEM_MC_FETCH_GREG_U8_ZX_U16_THREADED': (None, False, False, ),
99 'IEM_MC_FETCH_GREG_U8_ZX_U32_THREADED': (None, False, False, ),
100 'IEM_MC_FETCH_GREG_U8_ZX_U64_THREADED': (None, False, False, ),
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, False, ),
117 'IEM_MC_FETCH_MEM_FLAT_U16_SX_U32': (None, True, False, ),
118 'IEM_MC_FETCH_MEM_FLAT_U16_SX_U64': (None, True, False, ),
119 'IEM_MC_FETCH_MEM_FLAT_U16': (None, True, False, ),
120 'IEM_MC_FETCH_MEM_FLAT_U16_ZX_U32': (None, True, False, ),
121 'IEM_MC_FETCH_MEM_FLAT_U16_ZX_U64': (None, True, False, ),
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_DISP': (None, True, False, ),
126 'IEM_MC_FETCH_MEM_FLAT_U32_SX_U64': (None, True, False, ),
127 'IEM_MC_FETCH_MEM_FLAT_U32': (None, True, False, ),
128 'IEM_MC_FETCH_MEM_FLAT_U32_ZX_U64': (None, True, False, ),
129 'IEM_MC_FETCH_MEM_FLAT_U64': (None, True, False, ),
130 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U16': (None, True, False, ),
131 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U32': (None, True, False, ),
132 'IEM_MC_FETCH_MEM_FLAT_U8_SX_U64': (None, True, False, ),
133 'IEM_MC_FETCH_MEM_FLAT_U8': (None, True, False, ),
134 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U16': (None, True, False, ),
135 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U32': (None, True, False, ),
136 'IEM_MC_FETCH_MEM_FLAT_U8_ZX_U64': (None, True, False, ),
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_EX': (None, True, False, ),
147 'IEM_MC_MEM_FLAT_MAP': (None, True, False, ),
148 'IEM_MC_MEM_FLAT_MAP_U16_RO': (None, True, False, ),
149 'IEM_MC_MEM_FLAT_MAP_U16_RW': (None, True, False, ),
150 'IEM_MC_MEM_FLAT_MAP_U32_RO': (None, True, False, ),
151 'IEM_MC_MEM_FLAT_MAP_U32_RW': (None, True, False, ),
152 'IEM_MC_MEM_FLAT_MAP_U64_RO': (None, True, False, ),
153 'IEM_MC_MEM_FLAT_MAP_U64_RW': (None, True, False, ),
154 'IEM_MC_MEM_FLAT_MAP_U8_RO': (None, True, False, ),
155 'IEM_MC_MEM_FLAT_MAP_U8_RW': (None, True, False, ),
156 'IEM_MC_STORE_MEM_FLAT_U128_ALIGN_SSE': (None, True, False, ),
157 'IEM_MC_STORE_MEM_FLAT_U128': (None, True, False, ),
158 'IEM_MC_STORE_MEM_FLAT_U16': (None, True, False, ),
159 'IEM_MC_STORE_MEM_FLAT_U256_ALIGN_AVX': (None, True, False, ),
160 'IEM_MC_STORE_MEM_FLAT_U256': (None, True, False, ),
161 'IEM_MC_STORE_MEM_FLAT_U32': (None, True, False, ),
162 'IEM_MC_STORE_MEM_FLAT_U64': (None, True, False, ),
163 'IEM_MC_STORE_MEM_FLAT_U8_CONST': (None, True, False, ),
164 'IEM_MC_STORE_MEM_FLAT_U8': (None, True, False, ),
165
166 # Flat Stack:
167 'IEM_MC_FLAT64_PUSH_U16': (None, True, False, ),
168 'IEM_MC_FLAT64_PUSH_U64': (None, True, False, ),
169 'IEM_MC_FLAT64_POP_U16': (None, True, False, ),
170 'IEM_MC_FLAT64_POP_U64': (None, True, False, ),
171 'IEM_MC_FLAT32_PUSH_U16': (None, True, False, ),
172 'IEM_MC_FLAT32_PUSH_U32': (None, True, False, ),
173 'IEM_MC_FLAT32_POP_U16': (None, True, False, ),
174 'IEM_MC_FLAT32_POP_U32': (None, True, False, ),
175};
176
177class NativeRecompFunctionVariation(object):
178 """
179 Class that deals with transforming a threaded function variation into a
180 native recompiler function.
181
182 This base class doesn't do any transforming and just renders the same
183 code as for the threaded function.
184 """
185
186 def __init__(self, oVariation, sHostArch):
187 self.oVariation = oVariation # type: ThreadedFunctionVariation
188 self.sHostArch = sHostArch;
189
190 def isRecompilable(self):
191 """
192 Predicate that returns whether the variant can be recompiled natively
193 (for the selected host architecture).
194 """
195 return True;
196
197 def raiseProblem(self, sMessage):
198 """ Raises a problem. """
199 raise Exception('%s:%s: error: %s'
200 % (self.oVariation.oParent.oMcBlock.sSrcFile, self.oVariation.oParent.oMcBlock.iBeginLine, sMessage,));
201
202 def __analyzeVariableLiveness(self, aoStmts, dVars, iDepth = 0):
203 """
204 Performs liveness analysis of the given statement list, inserting new
205 statements to signal to the native recompiler that a variable is no
206 longer used and can be freed.
207
208 Returns list of freed variables.
209 """
210
211 class VarInfo(object):
212 """ Variable info """
213 def __init__(self, oStmt):
214 self.oStmt = oStmt;
215 self.fIsArg = isinstance(oStmt, iai.McStmtArg);
216 self.oReferences = None # type: VarInfo
217 self.oReferencedBy = None # type: VarInfo
218
219 def isArg(self):
220 return self.fIsArg;
221
222 def makeReference(self, oLocal, oParent):
223 if not self.isArg():
224 oParent.raiseProblem('Attempt to make a reference out of an local variable: %s = &%s'
225 % (self.oStmt.sVarName, oLocal.oStmt.sVarName,));
226 if self.oReferences:
227 oParent.raiseProblem('Can only make a variable a reference once: %s = &%s; now = &%s'
228 % (self.oStmt.sVarName, self.oReferences.oStmt.sVarName, oLocal.oStmt.sVarName,));
229 if oLocal.isArg():
230 oParent.raiseProblem('Attempt to make a reference to an argument: %s = &%s'
231 % (self.oStmt.sVarName, oLocal.oStmt.sVarName,));
232 if oLocal.oReferencedBy:
233 oParent.raiseProblem('%s is already referenced by %s, so cannot make %s reference it as well'
234 % (oLocal.oStmt.sVarName, oLocal.oReferencedBy.oStmt.sVarName, self.oStmt.sVarName,));
235 oInfo.oReferences = oLocal;
236 oInfo.oReferences.oReferencedBy = self;
237 return True;
238
239 #
240 # Gather variable declarations and add them to dVars.
241 # Also keep a local list of them for scoping when iDepth > 0.
242 #
243 asVarsInScope = [];
244 for oStmt in aoStmts:
245 if isinstance(oStmt, iai.McStmtVar):
246 if oStmt.sVarName in dVars:
247 raise Exception('Duplicate variable: %s' % (oStmt.sVarName, ));
248
249 oInfo = VarInfo(oStmt);
250 if oInfo.isArg() and oStmt.sRefType == 'local':
251 oInfo.makeReference(dVars[oStmt.sRef], self);
252
253 dVars[oStmt.sVarName] = oInfo;
254 asVarsInScope.append(oStmt.sVarName);
255
256 elif oStmt.sName == 'IEM_MC_REF_LOCAL':
257 dVars[oStmt.asParam[0]].makeReference(dVars[oStmt.asParam[1]], self);
258
259 #
260 # Now work the statements backwards and look for the last reference to
261 # each of the variables in dVars. We remove the variables from the
262 # collections as we go along.
263 #
264 def freeVariable(aoStmts, iStmt, oVarInfo, dFreedVars, dVars, fIncludeReferences = True):
265 sVarName = oVarInfo.oStmt.sVarName;
266 if not oVarInfo.isArg():
267 aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_LOCAL', [sVarName,]));
268 assert not oVarInfo.oReferences;
269 else:
270 aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_ARG', [sVarName,]));
271 if fIncludeReferences and oVarInfo.sReference:
272 sRefVarName = oVarInfo.oReferences.oStmt.sVarName;
273 if sRefVarName in dVars:
274 dFreedVars[sRefVarName] = dVars[sRefVarName];
275 del dVars[sRefVarName];
276 aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_LOCAL', [sRefVarName,]));
277 dFreedVars[sVarName] = oVarInfo;
278 if dVars is not None:
279 del dVars[sVarName];
280
281 dFreedVars = {};
282 for iStmt in range(len(aoStmts) - 1, -1, -1):
283 oStmt = aoStmts[iStmt];
284 if isinstance(oStmt, iai.McStmtCond):
285 #
286 # Conditionals requires a bit more work...
287 #
288
289 # Start by replacing the conditional statement by a shallow copy.
290 oStmt = copy.copy(oStmt);
291 oStmt.aoIfBranch = list(oStmt.aoIfBranch);
292 oStmt.aoElseBranch = list(oStmt.aoElseBranch);
293 aoStmts[iStmt] = oStmt;
294
295 # Check the two branches for final references. Both branches must
296 # start processing with the same dVars set, fortunately as shallow
297 # copy suffices.
298 dFreedInIfBranch = self.__analyzeVariableLiveness(oStmt.aoIfBranch, dict(dVars), iDepth + 1);
299 dFreedInElseBranch = self.__analyzeVariableLiveness(oStmt.aoElseBranch, dVars, iDepth + 1);
300
301 # Add free statements to the start of the IF-branch for variables use
302 # for the last time in the else branch.
303 for sVarName, oVarInfo in dFreedInElseBranch.items():
304 if sVarName not in dFreedInIfBranch:
305 freeVariable(oStmt.aoIfBranch, -1, oVarInfo, dFreedVars, None, False);
306 else:
307 dFreedVars[sVarName] = oVarInfo;
308
309 # And vice versa.
310 for sVarName, oVarInfo in dFreedInIfBranch.items():
311 if sVarName not in dFreedInElseBranch:
312 freeVariable(oStmt.aoElseBranch, -1, oVarInfo, dFreedVars, dVars, False);
313
314 #
315 # Now check if any remaining variables are used for the last time
316 # in the conditional statement ifself, in which case we need to insert
317 # free statements to both branches.
318 #
319 if not oStmt.isCppStmt():
320 aoFreeStmts = [];
321 for sParam in oStmt.asParams:
322 if sParam in dVars:
323 freeVariable(aoFreeStmts, -1, dVars[sParam], dFreedVars, dVars);
324 for oFreeStmt in aoFreeStmts:
325 oStmt.aoIfBranch.insert(0, oFreeStmt);
326 oStmt.aoElseBranch.insert(0, oFreeStmt);
327
328 elif not oStmt.isCppStmt():
329 if isinstance(oStmt, iai.McStmtCall):
330 #
331 # Call statements will make use of all argument variables and
332 # will implicitly free them. So, iterate the variable and
333 # move them from dVars and onto dFreedVars.
334 #
335 # We explictly free any referenced variable that is still in
336 # dVar at this point (since only arguments can hold variable
337 # references).
338 #
339 for sParam in oStmt.asParams[oStmt.idxParams:]:
340 oVarInfo = dVars.get(sParam);
341 if oVarInfo:
342 if not oVarInfo.isArg():
343 self.raiseProblem('Argument %s in %s is not an argument!' % (sParam, oStmt.sName,));
344 if oVarInfo.oReferences:
345 sRefVarName = oVarInfo.oReferences.oStmt.sVarName;
346 if sRefVarName in dVars:
347 dFreedVars[sRefVarName] = dVars[sRefVarName];
348 del dVars[sRefVarName];
349 aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_LOCAL', [sRefVarName,]));
350 dFreedVars[sParam] = oVarInfo;
351 del dVars[sParam];
352 elif sParam in dFreedVars:
353 self.raiseProblem('Argument %s in %s was used after the call!' % (sParam, oStmt.sName,));
354 else:
355 self.raiseProblem('Argument %s in %s is not known to us' % (sParam, oStmt.sName,));
356
357 # Check for stray argument variables.
358 for oVarInfo in dVars.values():
359 if oVarInfo.isArg():
360 self.raiseProblem('Unused argument variable: %s' % (oVarInfo.oStmt.sVarName,));
361 else:
362 #
363 # Scan all the parameters of generic statements.
364 #
365 for sParam in oStmt.asParams:
366 if sParam in dVars:
367 freeVariable(aoStmts, iStmt, dVars[sParam], dFreedVars, dVars);
368
369 #
370 # Free anything left from asVarsInScope that's now going out of scope.
371 #
372 if iDepth > 0:
373 for sVarName in asVarsInScope:
374 if sVarName in dVars:
375 freeVariable(aoStmts, len(aoStmts) - 1, dVars[sVarName], dFreedVars, dVars);
376 return dFreedVars;
377
378 def __morphStatements(self, aoStmts):
379 """
380 Morphs the given statement list into something more suitable for
381 native recompilation.
382
383 The following is currently done here:
384 - Amend IEM_MC_BEGIN with all the IEM_CIMPL_F_XXX and IEM_MC_F_XXX
385 flags found and derived, including IEM_MC_F_WITHOUT_FLAGS which
386 we determine here.
387 - Insert IEM_MC_FREE_LOCAL when after the last statment a local
388 variable is last used.
389
390 Returns a new list of statements.
391 """
392
393 #
394 # We can skip IEM_MC_DEFER_TO_CIMPL_x_RET stuff.
395 #
396 if self.oVariation.oParent.oMcBlock.fDeferToCImpl:
397 return aoStmts;
398
399 #
400 # We make a shallow copy of the list, and only make deep copies of the
401 # statements we modify.
402 #
403 aoStmts = list(aoStmts) # type: list(iai.McStmt)
404
405 #
406 # First, amend the IEM_MC_BEGIN statment, adding all the flags found
407 # to it so the native recompiler can correctly process ARG and CALL
408 # statements (among other things).
409 #
410 # Also add IEM_MC_F_WITHOUT_FLAGS if this isn't a variation with eflags
411 # checking and clearing while there are such variations for this
412 # function (this sounds a bit backwards, but has to be done this way
413 # for the use we make of the flags in CIMPL calls).
414 #
415 for iStmt, oStmt in enumerate(aoStmts):
416 if oStmt.sName == 'IEM_MC_BEGIN':
417 fWithoutFlags = ( self.oVariation.isWithFlagsCheckingAndClearingVariation()
418 and self.oVariation.oParent.hasWithFlagsCheckingAndClearingVariation());
419 if fWithoutFlags or self.oVariation.oParent.dsCImplFlags:
420 oNewStmt = copy.deepcopy(oStmt);
421 if fWithoutFlags:
422 oNewStmt.asParams[2] = ' | '.join(sorted( list(self.oVariation.oParent.oMcBlock.dsMcFlags.keys())
423 + ['IEM_MC_F_WITHOUT_FLAGS',] ));
424 if self.oVariation.oParent.dsCImplFlags:
425 oNewStmt.asParams[3] = ' | '.join(sorted(self.oVariation.oParent.dsCImplFlags.keys()));
426 aoStmts[iStmt] = oNewStmt;
427 break;
428
429 #
430 # Do a simple liveness analysis of the variable and insert
431 # IEM_MC_FREE_LOCAL statements after the last statements using each
432 # variable. We do this recursively to best handle conditionals and
433 # scoping related to those.
434 #
435 self.__analyzeVariableLiveness(aoStmts, {});
436
437 return aoStmts;
438
439
440 def renderCode(self, cchIndent):
441 """
442 Returns the native recompiler function body for this threaded variant.
443 """
444 return iai.McStmt.renderCodeForList(self.__morphStatements(self.oVariation.aoStmtsForThreadedFunction), cchIndent);
445
446 @staticmethod
447 def checkStatements(aoStmts, sHostArch):
448 """
449 Checks that all the given statements are supported by the native recompiler.
450 Returns dictionary with the unsupported statments.
451 """
452 dRet = {};
453 _ = sHostArch;
454 for oStmt in aoStmts: # type: McStmt
455 if not oStmt.isCppStmt():
456 aInfo = iai.g_dMcStmtParsers.get(oStmt.sName);
457 if not aInfo:
458 aInfo = g_dMcStmtThreaded.get(oStmt.sName);
459 if not aInfo:
460 raise Exception('Unknown statement: %s' % (oStmt.sName, ));
461 if aInfo[2] is False:
462 dRet[oStmt.sName] = 1;
463 elif aInfo[2] is not True:
464 if isinstance(aInfo[2], str):
465 if aInfo[2] != sHostArch:
466 dRet[oStmt.sName] = 1;
467 elif sHostArch not in aInfo[2]:
468 dRet[oStmt.sName] = 1;
469 #elif not self.fDecode:
470
471 if isinstance(oStmt, iai.McStmtCond):
472 dRet.update(NativeRecompFunctionVariation.checkStatements(oStmt.aoIfBranch, sHostArch));
473 dRet.update(NativeRecompFunctionVariation.checkStatements(oStmt.aoElseBranch, sHostArch));
474
475 return dRet;
476
477
478## Statistics: Number of MC blocks (value) depending on each unsupported statement (key).
479g_dUnsupportedMcStmtStats = {}
480
481## Statistics: List of variations (value) that is only missing this one statement (key).
482g_dUnsupportedMcStmtLastOneStats = {}
483
484### Statistics: List of variations (value) with aimpl_[^0] calls that is only missing this one statement (key).
485#g_dUnsupportedMcStmtLastOneAImplStats = {}
486
487
488def analyzeVariantForNativeRecomp(oVariation,
489 sHostArch): # type: (ThreadedFunctionVariation, str) -> NativeRecompFunctionVariation
490 """
491 This function analyzes the threaded function variant and returns an
492 NativeRecompFunctionVariation instance for it, unless it's not
493 possible to recompile at present.
494
495 Returns NativeRecompFunctionVariation or the number of unsupported MCs.
496 """
497
498 #
499 # Analyze the statements.
500 #
501 aoStmts = oVariation.aoStmtsForThreadedFunction # type: list(McStmt)
502 dUnsupportedStmts = NativeRecompFunctionVariation.checkStatements(aoStmts, sHostArch);
503 if not dUnsupportedStmts:
504 return NativeRecompFunctionVariation(oVariation, sHostArch);
505
506 #
507 # Update the statistics.
508 #
509 for sStmt in dUnsupportedStmts:
510 g_dUnsupportedMcStmtStats[sStmt] = 1 + g_dUnsupportedMcStmtStats.get(sStmt, 0);
511
512 if len(dUnsupportedStmts) == 1:
513 for sStmt in dUnsupportedStmts:
514 if sStmt in g_dUnsupportedMcStmtLastOneStats:
515 g_dUnsupportedMcStmtLastOneStats[sStmt].append(oVariation);
516 else:
517 g_dUnsupportedMcStmtLastOneStats[sStmt] = [oVariation,];
518
519 #if ( len(dUnsupportedStmts) in (1,2)
520 # and iai.McStmt.findStmtByNames(aoStmts,
521 # { 'IEM_MC_CALL_AIMPL_3': 1,
522 # 'IEM_MC_CALL_AIMPL_4': 1,
523 # #'IEM_MC_CALL_VOID_AIMPL_0': 1, - can't test results... ?
524 # 'IEM_MC_CALL_VOID_AIMPL_1': 1,
525 # 'IEM_MC_CALL_VOID_AIMPL_2': 1,
526 # 'IEM_MC_CALL_VOID_AIMPL_3': 1,
527 # 'IEM_MC_CALL_VOID_AIMPL_4': 1,
528 # #'IEM_MC_CALL_FPU_AIMPL_1': 1,
529 # #'IEM_MC_CALL_FPU_AIMPL_2': 1,
530 # #'IEM_MC_CALL_FPU_AIMPL_3': 1,
531 # #'IEM_MC_CALL_MMX_AIMPL_2': 1,
532 # #'IEM_MC_CALL_MMX_AIMPL_3': 1,
533 # #'IEM_MC_CALL_SSE_AIMPL_2': 1,
534 # #'IEM_MC_CALL_SSE_AIMPL_3': 1,
535 # #'IEM_MC_CALL_AVX_AIMPL_2': 1,
536 # #'IEM_MC_CALL_AVX_AIMPL_3': 1,
537 # #'IEM_MC_CALL_AVX_AIMPL_4': 1,
538 # })):
539 # for sStmt in dUnsupportedStmts:
540 # if sStmt in g_dUnsupportedMcStmtLastOneAImplStats:
541 # g_dUnsupportedMcStmtLastOneAImplStats[sStmt].append(oVariation);
542 # else:
543 # g_dUnsupportedMcStmtLastOneAImplStats[sStmt] = [oVariation,];
544
545 return None;
546
547
548def displayStatistics(aoThreadedFuncs, sHostArch): # type (list(ThreadedFunction)) -> True
549 """
550 Displays statistics.
551 """
552 print('todo:', file = sys.stderr);
553 cTotal = 0;
554 cNative = 0;
555 for oThreadedFunction in aoThreadedFuncs:
556 for oVariation in oThreadedFunction.aoVariations:
557 cTotal += 1;
558 oVariation.oNativeRecomp = analyzeVariantForNativeRecomp(oVariation, sHostArch);
559 if oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
560 cNative += 1;
561 print('todo: %.1f%% / %u out of %u threaded function variations are recompilable'
562 % (cNative * 100.0 / cTotal, cNative, cTotal), file = sys.stderr);
563 if g_dUnsupportedMcStmtLastOneStats:
564 asTopKeys = sorted(g_dUnsupportedMcStmtLastOneStats, reverse = True,
565 key = lambda sSortKey: len(g_dUnsupportedMcStmtLastOneStats[sSortKey]))[:16];
566 print('todo:', file = sys.stderr);
567 print('todo: Top %s variations with one unsupported statement dependency:' % (len(asTopKeys),),
568 file = sys.stderr);
569 cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
570 for sKey in asTopKeys:
571 print('todo: %*s = %s (%s%s)'
572 % (cchMaxKey, sKey, len(g_dUnsupportedMcStmtLastOneStats[sKey]),
573 ', '.join([oVar.getShortName() for oVar in g_dUnsupportedMcStmtLastOneStats[sKey][:5]]),
574 ',...' if len(g_dUnsupportedMcStmtLastOneStats[sKey]) >= 5 else '', )
575 , file = sys.stderr);
576
577 asTopKeys = sorted(g_dUnsupportedMcStmtStats, reverse = True,
578 key = lambda sSortKey: g_dUnsupportedMcStmtStats[sSortKey])[:16];
579 print('todo:', file = sys.stderr);
580 print('todo: Top %d most used unimplemented statements:' % (len(asTopKeys),), file = sys.stderr);
581 cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
582 for i in range(0, len(asTopKeys), 2):
583 print('todo: %*s = %4d %*s = %4d'
584 % ( cchMaxKey, asTopKeys[i], g_dUnsupportedMcStmtStats[asTopKeys[i]],
585 cchMaxKey, asTopKeys[i + 1], g_dUnsupportedMcStmtStats[asTopKeys[i + 1]],),
586 file = sys.stderr);
587 print('todo:', file = sys.stderr);
588
589 #if g_dUnsupportedMcStmtLastOneAImplStats:
590 # asTopKeys = sorted(g_dUnsupportedMcStmtLastOneAImplStats, reverse = True,
591 # key = lambda sSortKey: len(g_dUnsupportedMcStmtLastOneAImplStats[sSortKey]))[:16];
592 # print('todo:', file = sys.stderr);
593 # print('todo: Top %s variations with AIMPL call and 1-2 unsupported statement dependencies:' % (len(asTopKeys),),
594 # file = sys.stderr);
595 # cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
596 # for sKey in asTopKeys:
597 # print('todo: %*s = %s (%s%s)'
598 # % (cchMaxKey, sKey, len(g_dUnsupportedMcStmtLastOneAImplStats[sKey]),
599 # ', '.join([oVar.getShortName() for oVar in g_dUnsupportedMcStmtLastOneAImplStats[sKey][:5]]),
600 # ',...' if len(g_dUnsupportedMcStmtLastOneAImplStats[sKey]) >= 5 else '', )
601 # , file = sys.stderr);
602
603 return True;
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