VirtualBox

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

Last change on this file since 104073 was 104021, checked in by vboxsync, 13 months ago

VMM/IEM: Implement native emitters for IEM_MC_CALL_AVX_AIMPL_2() and IEM_MC_CALL_AVX_AIMPL_3(), bugref:10614

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette