VirtualBox

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

Last change on this file since 103888 was 103859, checked in by vboxsync, 9 months ago

VMM/IEM: NativeRecompFunctionVariation::analyzeVariableLiveness needs to account for the pXState argument of IEM_MC_CALL_AVX_AIMPL_X calls because it's hidden in plain view. bugref:10614

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 42.1 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllN8vePython.py 103859 2024-03-14 19:10:18Z 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: 103859 $"
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 asCallParams = oStmt.asParams[oStmt.idxParams:];
387 if oStmt.sName.startswith('IEM_MC_CALL_AVX_AIMPL_'):
388 asCallParams.insert(0, 'pXState');
389 for sParam in asCallParams:
390 oVarInfo = dVars.get(sParam);
391 if oVarInfo:
392 if not oVarInfo.isArg():
393 self.raiseProblem('Argument %s in %s is not an argument!' % (sParam, oStmt.sName,));
394 if oVarInfo.oReferences:
395 sRefVarName = oVarInfo.oReferences.oStmt.sVarName;
396 if sRefVarName in dVars:
397 dFreedVars[sRefVarName] = dVars[sRefVarName];
398 del dVars[sRefVarName];
399 aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_LOCAL', [sRefVarName,]));
400 dFreedVars[sParam] = oVarInfo;
401 del dVars[sParam];
402 elif sParam in dFreedVars:
403 self.raiseProblem('Argument %s in %s was used after the call!' % (sParam, oStmt.sName,));
404 else:
405 self.raiseProblem('Argument %s in %s is not known to us' % (sParam, oStmt.sName,));
406
407 # Check for stray argument variables.
408 for oVarInfo in dVars.values():
409 if oVarInfo.isArg():
410 self.raiseProblem('Unused argument variable: %s' % (oVarInfo.oStmt.sVarName,));
411
412 elif oStmt.sName in ('IEM_MC_MEM_COMMIT_AND_UNMAP_RW', 'IEM_MC_MEM_COMMIT_AND_UNMAP_RO',
413 'IEM_MC_MEM_COMMIT_AND_UNMAP_WO', 'IEM_MC_MEM_ROLLBACK_AND_UNMAP_WO',
414 'IEM_MC_MEM_COMMIT_AND_UNMAP_ATOMIC',
415 'IEM_MC_MEM_COMMIT_AND_UNMAP_FOR_FPU_STORE_WO'):
416 #
417 # The unmap info variable passed to IEM_MC_MEM_COMMIT_AND_UNMAP_RW
418 # and friends is implictly freed and we must make sure it wasn't
419 # used any later. IEM_MC_MEM_COMMIT_AND_UNMAP_FOR_FPU_STORE_WO takes
420 # an additional a_u16FSW argument, which receives the same treatement.
421 #
422 for sParam in oStmt.asParams:
423 implicitFree(oStmt, dFreedVars, dVars, sParam);
424
425 elif oStmt.sName in ('IEM_MC_PUSH_U16', 'IEM_MC_PUSH_U32', 'IEM_MC_PUSH_U32_SREG', 'IEM_MC_PUSH_U64',
426 'IEM_MC_FLAT32_PUSH_U16', 'IEM_MC_FLAT32_PUSH_U32', 'IEM_MC_FLAT32_PUSH_U32_SREG',
427 'IEM_MC_FLAT64_PUSH_U16', 'IEM_MC_FLAT64_PUSH_U64',):
428 #
429 # The variable being pushed is implicitly freed.
430 #
431 for sParam in oStmt.asParams:
432 implicitFree(oStmt, dFreedVars, dVars, sParam);
433 else:
434 #
435 # Scan all the parameters of generic statements.
436 #
437 for sParam in oStmt.asParams:
438 if sParam in dVars:
439 freeVariable(aoStmts, iStmt, dVars[sParam], dFreedVars, dVars);
440
441 #
442 # Free anything left from asVarsInScope that's now going out of scope.
443 #
444 if iDepth > 0:
445 for sVarName in asVarsInScope:
446 if sVarName in dVars:
447 freeVariable(aoStmts, len(aoStmts) - 1, dVars[sVarName], dFreedVars, dVars);
448 if sVarName in dFreedVars:
449 del dFreedVars[sVarName]; ## @todo Try eliminate this one...
450 return dFreedVars;
451
452 kdOptionArchToVal = {
453 'amd64': 'RT_ARCH_VAL_AMD64',
454 'arm64': 'RT_ARCH_VAL_ARM64',
455 };
456
457 def __morphStatements(self, aoStmts, fForLiveness):
458 """
459 Morphs the given statement list into something more suitable for
460 native recompilation.
461
462 The following is currently done here:
463 - Amend IEM_MC_BEGIN with all the IEM_CIMPL_F_XXX and IEM_MC_F_XXX
464 flags found and derived, including IEM_MC_F_WITHOUT_FLAGS which
465 we determine here.
466 - Insert IEM_MC_FREE_LOCAL when after the last statment a local
467 variable is last used.
468
469 Returns a new list of statements.
470 """
471 _ = fForLiveness;
472
473 #
474 # We can skip IEM_MC_DEFER_TO_CIMPL_x_RET stuff.
475 #
476 if self.oVariation.oParent.oMcBlock.fDeferToCImpl:
477 return aoStmts;
478
479 #
480 # We make a shallow copy of the list, and only make deep copies of the
481 # statements we modify.
482 #
483 aoStmts = list(aoStmts) # type: list(iai.McStmt)
484
485 #
486 # First, amend the IEM_MC_BEGIN statment, adding all the flags found
487 # to it so the native recompiler can correctly process ARG and CALL
488 # statements (among other things).
489 #
490 # Also add IEM_MC_F_WITHOUT_FLAGS if this isn't a variation with eflags
491 # checking and clearing while there are such variations for this
492 # function (this sounds a bit backwards, but has to be done this way
493 # for the use we make of the flags in CIMPL calls).
494 #
495 # Second, eliminate IEM_MC_NATIVE_IF statements.
496 #
497 iConvArgToLocal = 0;
498 cStmts = len(aoStmts);
499 iStmt = 0;
500 while iStmt < cStmts:
501 oStmt = aoStmts[iStmt];
502 if oStmt.sName == 'IEM_MC_BEGIN':
503 fWithoutFlags = ( self.oVariation.isWithFlagsCheckingAndClearingVariation()
504 and self.oVariation.oParent.hasWithFlagsCheckingAndClearingVariation());
505 if fWithoutFlags or self.oVariation.oParent.dsCImplFlags:
506 oNewStmt = copy.deepcopy(oStmt);
507 if fWithoutFlags:
508 oNewStmt.asParams[2] = ' | '.join(sorted( list(self.oVariation.oParent.oMcBlock.dsMcFlags.keys())
509 + ['IEM_MC_F_WITHOUT_FLAGS',] ));
510 if self.oVariation.oParent.dsCImplFlags:
511 oNewStmt.asParams[3] = ' | '.join(sorted(self.oVariation.oParent.dsCImplFlags.keys()));
512 aoStmts[iStmt] = oNewStmt;
513 elif isinstance(oStmt, iai.McStmtNativeIf):
514 if self.kdOptionArchToVal[self.sHostArch] in oStmt.asArchitectures:
515 iConvArgToLocal += 1;
516 oBranch = oStmt.aoIfBranch;
517 else:
518 iConvArgToLocal = -999;
519 oBranch = oStmt.aoElseBranch;
520 aoStmts = aoStmts[:iStmt] + oBranch + aoStmts[iStmt+1:];
521 cStmts = len(aoStmts);
522 continue;
523
524 iStmt += 1;
525
526 #
527 # If we encountered a IEM_MC_NATIVE_IF and took the native branch,
528 # ASSUME that all ARG variables can be converted to LOCAL variables
529 # because no calls will be made.
530 #
531 if iConvArgToLocal > 0:
532 for iStmt, oStmt in enumerate(aoStmts):
533 if isinstance(oStmt, iai.McStmtArg):
534 if oStmt.sName == 'IEM_MC_ARG':
535 aoStmts[iStmt] = iai.McStmtVar('IEM_MC_LOCAL', oStmt.asParams[:2],
536 oStmt.sType, oStmt.sVarName);
537 elif oStmt.sName == 'IEM_MC_ARG_CONST':
538 aoStmts[iStmt] = iai.McStmtVar('IEM_MC_LOCAL_CONST', oStmt.asParams[:3],
539 oStmt.sType, oStmt.sVarName, oStmt.sValue);
540 else:
541 self.raiseProblem('Unexpected argument declaration when emitting native code: %s (%s)'
542 % (oStmt.sName, oStmt.asParams,));
543 assert(oStmt.sRefType == 'none');
544
545 #
546 # Do a simple liveness analysis of the variable and insert
547 # IEM_MC_FREE_LOCAL statements after the last statements using each
548 # variable. We do this recursively to best handle conditionals and
549 # scoping related to those.
550 #
551 self.__analyzeVariableLiveness(aoStmts, {});
552
553 return aoStmts;
554
555
556 def renderCode(self, cchIndent, fForLiveness = False):
557 """
558 Returns the native recompiler function body for this threaded variant.
559 """
560 return iai.McStmt.renderCodeForList(self.__morphStatements(self.oVariation.aoStmtsForThreadedFunction, fForLiveness),
561 cchIndent);
562
563 @staticmethod
564 def checkStatements(aoStmts, sHostArch):
565 """
566 Checks that all the given statements are supported by the native recompiler.
567 Returns dictionary with the unsupported statments.
568 """
569 dRet = {};
570 _ = sHostArch;
571 for oStmt in aoStmts: # type: McStmt
572 if not oStmt.isCppStmt():
573 aInfo = iai.g_dMcStmtParsers.get(oStmt.sName);
574 if not aInfo:
575 aInfo = g_dMcStmtThreaded.get(oStmt.sName);
576 if not aInfo:
577 raise Exception('Unknown statement: %s' % (oStmt.sName, ));
578 if aInfo[3] is False:
579 dRet[oStmt.sName] = 1;
580 elif aInfo[3] is not True:
581 if isinstance(aInfo[3], str):
582 if aInfo[3] != sHostArch:
583 dRet[oStmt.sName] = 1;
584 elif sHostArch not in aInfo[3]:
585 dRet[oStmt.sName] = 1;
586 #elif not self.fDecode:
587
588 if isinstance(oStmt, iai.McStmtCond):
589 dRet.update(NativeRecompFunctionVariation.checkStatements(oStmt.aoIfBranch, sHostArch));
590 dRet.update(NativeRecompFunctionVariation.checkStatements(oStmt.aoElseBranch, sHostArch));
591
592 return dRet;
593
594
595## Statistics: Number of MC blocks (value) depending on each unsupported statement (key).
596g_dUnsupportedMcStmtStats = {}
597
598## Statistics: List of variations (value) that is only missing this one statement (key).
599g_dUnsupportedMcStmtLastOneStats = {}
600
601### Statistics: List of variations (value) with aimpl_[^0] calls that is only missing this one statement (key).
602#g_dUnsupportedMcStmtLastOneAImplStats = {}
603
604
605def analyzeVariantForNativeRecomp(oVariation,
606 sHostArch): # type: (ThreadedFunctionVariation, str) -> NativeRecompFunctionVariation
607 """
608 This function analyzes the threaded function variant and returns an
609 NativeRecompFunctionVariation instance for it, unless it's not
610 possible to recompile at present.
611
612 Returns NativeRecompFunctionVariation or the number of unsupported MCs.
613 """
614
615 #
616 # Analyze the statements.
617 #
618 aoStmts = oVariation.aoStmtsForThreadedFunction # type: list(McStmt)
619 dUnsupportedStmts = NativeRecompFunctionVariation.checkStatements(aoStmts, sHostArch);
620 if not dUnsupportedStmts:
621 return NativeRecompFunctionVariation(oVariation, sHostArch);
622
623 #
624 # Update the statistics.
625 #
626 for sStmt in dUnsupportedStmts:
627 g_dUnsupportedMcStmtStats[sStmt] = 1 + g_dUnsupportedMcStmtStats.get(sStmt, 0);
628
629 if len(dUnsupportedStmts) == 1:
630 for sStmt in dUnsupportedStmts:
631 if sStmt in g_dUnsupportedMcStmtLastOneStats:
632 g_dUnsupportedMcStmtLastOneStats[sStmt].append(oVariation);
633 else:
634 g_dUnsupportedMcStmtLastOneStats[sStmt] = [oVariation,];
635
636 #if ( len(dUnsupportedStmts) in (1,2)
637 # and iai.McStmt.findStmtByNames(aoStmts,
638 # { 'IEM_MC_CALL_AIMPL_3': 1,
639 # 'IEM_MC_CALL_AIMPL_4': 1,
640 # #'IEM_MC_CALL_VOID_AIMPL_0': 1, - can't test results... ?
641 # 'IEM_MC_CALL_VOID_AIMPL_1': 1,
642 # 'IEM_MC_CALL_VOID_AIMPL_2': 1,
643 # 'IEM_MC_CALL_VOID_AIMPL_3': 1,
644 # 'IEM_MC_CALL_VOID_AIMPL_4': 1,
645 # #'IEM_MC_CALL_FPU_AIMPL_1': 1,
646 # #'IEM_MC_CALL_FPU_AIMPL_2': 1,
647 # #'IEM_MC_CALL_FPU_AIMPL_3': 1,
648 # #'IEM_MC_CALL_MMX_AIMPL_2': 1,
649 # #'IEM_MC_CALL_MMX_AIMPL_3': 1,
650 # #'IEM_MC_CALL_SSE_AIMPL_2': 1,
651 # #'IEM_MC_CALL_SSE_AIMPL_3': 1,
652 # #'IEM_MC_CALL_AVX_AIMPL_2': 1,
653 # #'IEM_MC_CALL_AVX_AIMPL_3': 1,
654 # #'IEM_MC_CALL_AVX_AIMPL_4': 1,
655 # })):
656 # for sStmt in dUnsupportedStmts:
657 # if sStmt in g_dUnsupportedMcStmtLastOneAImplStats:
658 # g_dUnsupportedMcStmtLastOneAImplStats[sStmt].append(oVariation);
659 # else:
660 # g_dUnsupportedMcStmtLastOneAImplStats[sStmt] = [oVariation,];
661
662 return None;
663
664
665def analyzeThreadedFunctionsForNativeRecomp(aoThreadedFuncs, sHostArch): # type (list(ThreadedFunction)) -> True
666 """
667 Displays statistics.
668 """
669 print('todo:', file = sys.stderr);
670 cTotal = 0;
671 cNative = 0;
672 for oThreadedFunction in aoThreadedFuncs:
673 cNativeVariations = 0;
674 for oVariation in oThreadedFunction.aoVariations:
675 cTotal += 1;
676 oVariation.oNativeRecomp = analyzeVariantForNativeRecomp(oVariation, sHostArch);
677 if oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
678 cNativeVariations += 1;
679 cNative += cNativeVariations;
680
681 # If all variations can be recompiled natively, annotate the threaded
682 # function name accordingly so it'll be easy to spot in the stats.
683 if oThreadedFunction.sSubName:
684 if cNativeVariations == len(oThreadedFunction.aoVariations):
685 aoStmts = oThreadedFunction.oMcBlock.decode();
686 oStmt = iai.McStmt.findStmtByNames(aoStmts, {'IEM_MC_NATIVE_IF': True,});
687 if oStmt and NativeRecompFunctionVariation.kdOptionArchToVal[sHostArch] in oStmt.asArchitectures:
688 oThreadedFunction.sSubName += '_ne'; # native emit
689 elif oThreadedFunction.sSubName.find('aimpl') >= 0:
690 oThreadedFunction.sSubName += '_na'; # native aimpl
691 else:
692 oThreadedFunction.sSubName += '_nn'; # native native
693 elif cNativeVariations == 0:
694 oThreadedFunction.sSubName += '_ntodo'; # native threaded todo
695 else:
696 oThreadedFunction.sSubName += '_nm'; # native mixed
697
698
699 print('todo: %.1f%% / %u out of %u threaded function variations are recompilable'
700 % (cNative * 100.0 / cTotal, cNative, cTotal), file = sys.stderr);
701 if g_dUnsupportedMcStmtLastOneStats:
702 asTopKeys = sorted(g_dUnsupportedMcStmtLastOneStats, reverse = True,
703 key = lambda sSortKey: len(g_dUnsupportedMcStmtLastOneStats[sSortKey]))[:16];
704 print('todo:', file = sys.stderr);
705 print('todo: Top %s variations with one unsupported statement dependency:' % (len(asTopKeys),),
706 file = sys.stderr);
707 cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
708 for sKey in asTopKeys:
709 print('todo: %*s = %s (%s%s)'
710 % (cchMaxKey, sKey, len(g_dUnsupportedMcStmtLastOneStats[sKey]),
711 ', '.join([oVar.getShortName() for oVar in g_dUnsupportedMcStmtLastOneStats[sKey][:5]]),
712 ',...' if len(g_dUnsupportedMcStmtLastOneStats[sKey]) >= 5 else '', )
713 , file = sys.stderr);
714
715 asTopKeys = sorted(g_dUnsupportedMcStmtStats, reverse = True,
716 key = lambda sSortKey: g_dUnsupportedMcStmtStats[sSortKey])[:16];
717 print('todo:', file = sys.stderr);
718 print('todo: Top %d most used unimplemented statements:' % (len(asTopKeys),), file = sys.stderr);
719 cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
720 for i in range(0, len(asTopKeys), 2):
721 print('todo: %*s = %4d %*s = %4d'
722 % ( cchMaxKey, asTopKeys[i], g_dUnsupportedMcStmtStats[asTopKeys[i]],
723 cchMaxKey, asTopKeys[i + 1], g_dUnsupportedMcStmtStats[asTopKeys[i + 1]],),
724 file = sys.stderr);
725 print('todo:', file = sys.stderr);
726
727 #if g_dUnsupportedMcStmtLastOneAImplStats:
728 # asTopKeys = sorted(g_dUnsupportedMcStmtLastOneAImplStats, reverse = True,
729 # key = lambda sSortKey: len(g_dUnsupportedMcStmtLastOneAImplStats[sSortKey]))[:16];
730 # print('todo:', file = sys.stderr);
731 # print('todo: Top %s variations with AIMPL call and 1-2 unsupported statement dependencies:' % (len(asTopKeys),),
732 # file = sys.stderr);
733 # cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
734 # for sKey in asTopKeys:
735 # print('todo: %*s = %s (%s%s)'
736 # % (cchMaxKey, sKey, len(g_dUnsupportedMcStmtLastOneAImplStats[sKey]),
737 # ', '.join([oVar.getShortName() for oVar in g_dUnsupportedMcStmtLastOneAImplStats[sKey][:5]]),
738 # ',...' if len(g_dUnsupportedMcStmtLastOneAImplStats[sKey]) >= 5 else '', )
739 # , file = sys.stderr);
740
741 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