VirtualBox

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

Last change on this file since 103834 was 103828, checked in by vboxsync, 13 months ago

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