VirtualBox

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

Last change on this file since 103254 was 103233, checked in by vboxsync, 14 months ago

VMM/IEM: Liveness analysis, part 8: Propagating EFLAGS annotations to the liveness code, asserting that flag modifications are within the annotations, gather some statistics on potential EFLAGS updating gains. bugref:10372 bugref:10375

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