VirtualBox

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

Last change on this file since 103374 was 103259, checked in by vboxsync, 10 months ago

VMM/IEM: Fix regression causing alignment exceptions for SSE/AVX based unaligned data fetches and stores which are handled fine on real hardware. [build fix] bugref:9898

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