VirtualBox

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

Last change on this file since 103023 was 102977, checked in by vboxsync, 13 months ago

VMM/IEM: Implemented generic fallback for misaligned x86 locking that is not compatible with the host. Using the existing split-lock solution with VINF_EM_EMULATE_SPLIT_LOCK from bugref:10052. We keep ignoring the 'lock' prefix in the recompiler for single CPU VMs (now also on amd64 hosts). bugref:10547

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