VirtualBox

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

Last change on this file since 103627 was 103613, checked in by vboxsync, 10 months ago

VMM/IEM: Experimental code for emitting native code instead of calling AImpl helper, experimenting on: xor reg32,reg32. bugref:10376

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 38.7 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllN8vePython.py 103613 2024-02-29 13:01:56Z 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: 103613 $"
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.oReferences:
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 if sVarName in dFreedVars:
444 del dFreedVars[sVarName]; ## @todo Try eliminate this one...
445 return dFreedVars;
446
447 def __morphStatements(self, aoStmts, fForLiveness):
448 """
449 Morphs the given statement list into something more suitable for
450 native recompilation.
451
452 The following is currently done here:
453 - Amend IEM_MC_BEGIN with all the IEM_CIMPL_F_XXX and IEM_MC_F_XXX
454 flags found and derived, including IEM_MC_F_WITHOUT_FLAGS which
455 we determine here.
456 - Insert IEM_MC_FREE_LOCAL when after the last statment a local
457 variable is last used.
458
459 Returns a new list of statements.
460 """
461 _ = fForLiveness;
462
463 #
464 # We can skip IEM_MC_DEFER_TO_CIMPL_x_RET stuff.
465 #
466 if self.oVariation.oParent.oMcBlock.fDeferToCImpl:
467 return aoStmts;
468
469 #
470 # We make a shallow copy of the list, and only make deep copies of the
471 # statements we modify.
472 #
473 aoStmts = list(aoStmts) # type: list(iai.McStmt)
474
475 #
476 # First, amend the IEM_MC_BEGIN statment, adding all the flags found
477 # to it so the native recompiler can correctly process ARG and CALL
478 # statements (among other things).
479 #
480 # Also add IEM_MC_F_WITHOUT_FLAGS if this isn't a variation with eflags
481 # checking and clearing while there are such variations for this
482 # function (this sounds a bit backwards, but has to be done this way
483 # for the use we make of the flags in CIMPL calls).
484 #
485 for iStmt, oStmt in enumerate(aoStmts):
486 if oStmt.sName == 'IEM_MC_BEGIN':
487 fWithoutFlags = ( self.oVariation.isWithFlagsCheckingAndClearingVariation()
488 and self.oVariation.oParent.hasWithFlagsCheckingAndClearingVariation());
489 if fWithoutFlags or self.oVariation.oParent.dsCImplFlags:
490 oNewStmt = copy.deepcopy(oStmt);
491 if fWithoutFlags:
492 oNewStmt.asParams[2] = ' | '.join(sorted( list(self.oVariation.oParent.oMcBlock.dsMcFlags.keys())
493 + ['IEM_MC_F_WITHOUT_FLAGS',] ));
494 if self.oVariation.oParent.dsCImplFlags:
495 oNewStmt.asParams[3] = ' | '.join(sorted(self.oVariation.oParent.dsCImplFlags.keys()));
496 aoStmts[iStmt] = oNewStmt;
497 break;
498
499 #
500 # Do a simple liveness analysis of the variable and insert
501 # IEM_MC_FREE_LOCAL statements after the last statements using each
502 # variable. We do this recursively to best handle conditionals and
503 # scoping related to those.
504 #
505 self.__analyzeVariableLiveness(aoStmts, {});
506
507 return aoStmts;
508
509
510 def renderCode(self, cchIndent, fForLiveness = False):
511 """
512 Returns the native recompiler function body for this threaded variant.
513 """
514 return iai.McStmt.renderCodeForList(self.__morphStatements(self.oVariation.aoStmtsForThreadedFunction, fForLiveness),
515 cchIndent);
516
517 @staticmethod
518 def checkStatements(aoStmts, sHostArch):
519 """
520 Checks that all the given statements are supported by the native recompiler.
521 Returns dictionary with the unsupported statments.
522 """
523 dRet = {};
524 _ = sHostArch;
525 for oStmt in aoStmts: # type: McStmt
526 if not oStmt.isCppStmt():
527 aInfo = iai.g_dMcStmtParsers.get(oStmt.sName);
528 if not aInfo:
529 aInfo = g_dMcStmtThreaded.get(oStmt.sName);
530 if not aInfo:
531 raise Exception('Unknown statement: %s' % (oStmt.sName, ));
532 if aInfo[3] is False:
533 dRet[oStmt.sName] = 1;
534 elif aInfo[3] is not True:
535 if isinstance(aInfo[3], str):
536 if aInfo[3] != sHostArch:
537 dRet[oStmt.sName] = 1;
538 elif sHostArch not in aInfo[3]:
539 dRet[oStmt.sName] = 1;
540 #elif not self.fDecode:
541
542 if isinstance(oStmt, iai.McStmtCond):
543 dRet.update(NativeRecompFunctionVariation.checkStatements(oStmt.aoIfBranch, sHostArch));
544 dRet.update(NativeRecompFunctionVariation.checkStatements(oStmt.aoElseBranch, sHostArch));
545
546 return dRet;
547
548
549## Statistics: Number of MC blocks (value) depending on each unsupported statement (key).
550g_dUnsupportedMcStmtStats = {}
551
552## Statistics: List of variations (value) that is only missing this one statement (key).
553g_dUnsupportedMcStmtLastOneStats = {}
554
555### Statistics: List of variations (value) with aimpl_[^0] calls that is only missing this one statement (key).
556#g_dUnsupportedMcStmtLastOneAImplStats = {}
557
558
559def analyzeVariantForNativeRecomp(oVariation,
560 sHostArch): # type: (ThreadedFunctionVariation, str) -> NativeRecompFunctionVariation
561 """
562 This function analyzes the threaded function variant and returns an
563 NativeRecompFunctionVariation instance for it, unless it's not
564 possible to recompile at present.
565
566 Returns NativeRecompFunctionVariation or the number of unsupported MCs.
567 """
568
569 #
570 # Analyze the statements.
571 #
572 aoStmts = oVariation.aoStmtsForThreadedFunction # type: list(McStmt)
573 dUnsupportedStmts = NativeRecompFunctionVariation.checkStatements(aoStmts, sHostArch);
574 if not dUnsupportedStmts:
575 return NativeRecompFunctionVariation(oVariation, sHostArch);
576
577 #
578 # Update the statistics.
579 #
580 for sStmt in dUnsupportedStmts:
581 g_dUnsupportedMcStmtStats[sStmt] = 1 + g_dUnsupportedMcStmtStats.get(sStmt, 0);
582
583 if len(dUnsupportedStmts) == 1:
584 for sStmt in dUnsupportedStmts:
585 if sStmt in g_dUnsupportedMcStmtLastOneStats:
586 g_dUnsupportedMcStmtLastOneStats[sStmt].append(oVariation);
587 else:
588 g_dUnsupportedMcStmtLastOneStats[sStmt] = [oVariation,];
589
590 #if ( len(dUnsupportedStmts) in (1,2)
591 # and iai.McStmt.findStmtByNames(aoStmts,
592 # { 'IEM_MC_CALL_AIMPL_3': 1,
593 # 'IEM_MC_CALL_AIMPL_4': 1,
594 # #'IEM_MC_CALL_VOID_AIMPL_0': 1, - can't test results... ?
595 # 'IEM_MC_CALL_VOID_AIMPL_1': 1,
596 # 'IEM_MC_CALL_VOID_AIMPL_2': 1,
597 # 'IEM_MC_CALL_VOID_AIMPL_3': 1,
598 # 'IEM_MC_CALL_VOID_AIMPL_4': 1,
599 # #'IEM_MC_CALL_FPU_AIMPL_1': 1,
600 # #'IEM_MC_CALL_FPU_AIMPL_2': 1,
601 # #'IEM_MC_CALL_FPU_AIMPL_3': 1,
602 # #'IEM_MC_CALL_MMX_AIMPL_2': 1,
603 # #'IEM_MC_CALL_MMX_AIMPL_3': 1,
604 # #'IEM_MC_CALL_SSE_AIMPL_2': 1,
605 # #'IEM_MC_CALL_SSE_AIMPL_3': 1,
606 # #'IEM_MC_CALL_AVX_AIMPL_2': 1,
607 # #'IEM_MC_CALL_AVX_AIMPL_3': 1,
608 # #'IEM_MC_CALL_AVX_AIMPL_4': 1,
609 # })):
610 # for sStmt in dUnsupportedStmts:
611 # if sStmt in g_dUnsupportedMcStmtLastOneAImplStats:
612 # g_dUnsupportedMcStmtLastOneAImplStats[sStmt].append(oVariation);
613 # else:
614 # g_dUnsupportedMcStmtLastOneAImplStats[sStmt] = [oVariation,];
615
616 return None;
617
618
619def displayStatistics(aoThreadedFuncs, sHostArch): # type (list(ThreadedFunction)) -> True
620 """
621 Displays statistics.
622 """
623 print('todo:', file = sys.stderr);
624 cTotal = 0;
625 cNative = 0;
626 for oThreadedFunction in aoThreadedFuncs:
627 for oVariation in oThreadedFunction.aoVariations:
628 cTotal += 1;
629 oVariation.oNativeRecomp = analyzeVariantForNativeRecomp(oVariation, sHostArch);
630 if oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
631 cNative += 1;
632 print('todo: %.1f%% / %u out of %u threaded function variations are recompilable'
633 % (cNative * 100.0 / cTotal, cNative, cTotal), file = sys.stderr);
634 if g_dUnsupportedMcStmtLastOneStats:
635 asTopKeys = sorted(g_dUnsupportedMcStmtLastOneStats, reverse = True,
636 key = lambda sSortKey: len(g_dUnsupportedMcStmtLastOneStats[sSortKey]))[:16];
637 print('todo:', file = sys.stderr);
638 print('todo: Top %s variations with one unsupported statement dependency:' % (len(asTopKeys),),
639 file = sys.stderr);
640 cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
641 for sKey in asTopKeys:
642 print('todo: %*s = %s (%s%s)'
643 % (cchMaxKey, sKey, len(g_dUnsupportedMcStmtLastOneStats[sKey]),
644 ', '.join([oVar.getShortName() for oVar in g_dUnsupportedMcStmtLastOneStats[sKey][:5]]),
645 ',...' if len(g_dUnsupportedMcStmtLastOneStats[sKey]) >= 5 else '', )
646 , file = sys.stderr);
647
648 asTopKeys = sorted(g_dUnsupportedMcStmtStats, reverse = True,
649 key = lambda sSortKey: g_dUnsupportedMcStmtStats[sSortKey])[:16];
650 print('todo:', file = sys.stderr);
651 print('todo: Top %d most used unimplemented statements:' % (len(asTopKeys),), file = sys.stderr);
652 cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
653 for i in range(0, len(asTopKeys), 2):
654 print('todo: %*s = %4d %*s = %4d'
655 % ( cchMaxKey, asTopKeys[i], g_dUnsupportedMcStmtStats[asTopKeys[i]],
656 cchMaxKey, asTopKeys[i + 1], g_dUnsupportedMcStmtStats[asTopKeys[i + 1]],),
657 file = sys.stderr);
658 print('todo:', file = sys.stderr);
659
660 #if g_dUnsupportedMcStmtLastOneAImplStats:
661 # asTopKeys = sorted(g_dUnsupportedMcStmtLastOneAImplStats, reverse = True,
662 # key = lambda sSortKey: len(g_dUnsupportedMcStmtLastOneAImplStats[sSortKey]))[:16];
663 # print('todo:', file = sys.stderr);
664 # print('todo: Top %s variations with AIMPL call and 1-2 unsupported statement dependencies:' % (len(asTopKeys),),
665 # file = sys.stderr);
666 # cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
667 # for sKey in asTopKeys:
668 # print('todo: %*s = %s (%s%s)'
669 # % (cchMaxKey, sKey, len(g_dUnsupportedMcStmtLastOneAImplStats[sKey]),
670 # ', '.join([oVar.getShortName() for oVar in g_dUnsupportedMcStmtLastOneAImplStats[sKey][:5]]),
671 # ',...' if len(g_dUnsupportedMcStmtLastOneAImplStats[sKey]) >= 5 else '', )
672 # , file = sys.stderr);
673
674 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