VirtualBox

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

Last change on this file since 104315 was 104195, checked in by vboxsync, 10 months ago

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