VirtualBox

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

Last change on this file since 103773 was 103768, checked in by vboxsync, 9 months ago

VMM/IEM: Some more threaded function name annotating to make the native recompilation state more visible in the statistics. bugref:10376

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