VirtualBox

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

最後變更 在這個檔案從103922是 103916,由 vboxsync 提交於 12 月 前

VMM/IEM: Convert iemMemStoreDataU256NoAc()/iemMemStoreDataU256NoAcJmp() to use the memory RW template and implement native emitters for IEM_MC_FETCH_MEM_U256_NO_AC()/IEM_MC_FETCH_MEM_FLAT_U256_NO_AC(), bugref:10614

  • 屬性 svn:eol-style 設為 LF
  • 屬性 svn:executable 設為 *
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 42.2 KB
 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllN8vePython.py 103916 2024-03-19 13:11:09Z 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.alldomusa.eu.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: 103916 $"
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, False, ),
139 'IEM_MC_FETCH_MEM_FLAT_R64': (None, True, True, False, ),
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, False, ),
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, False, ),
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, False, ),
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, False, ),
197 'IEM_MC_STORE_MEM_FLAT_U128_ALIGN_SSE': (None, True, True, False, ),
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, False, ),
202 'IEM_MC_STORE_MEM_FLAT_U256_ALIGN_AVX': (None, True, True, False, ),
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 if oStmt.sName.startswith('IEM_MC_CALL_AVX_AIMPL_'):
391 asCallParams.insert(0, 'pXState');
392 for sParam in asCallParams:
393 oVarInfo = dVars.get(sParam);
394 if oVarInfo:
395 if not oVarInfo.isArg():
396 self.raiseProblem('Argument %s in %s is not an argument!' % (sParam, oStmt.sName,));
397 if oVarInfo.oReferences:
398 sRefVarName = oVarInfo.oReferences.oStmt.sVarName;
399 if sRefVarName in dVars:
400 dFreedVars[sRefVarName] = dVars[sRefVarName];
401 del dVars[sRefVarName];
402 aoStmts.insert(iStmt + 1, iai.McStmt('IEM_MC_FREE_LOCAL', [sRefVarName,]));
403 dFreedVars[sParam] = oVarInfo;
404 del dVars[sParam];
405 elif sParam in dFreedVars:
406 self.raiseProblem('Argument %s in %s was used after the call!' % (sParam, oStmt.sName,));
407 else:
408 self.raiseProblem('Argument %s in %s is not known to us' % (sParam, oStmt.sName,));
409
410 # Check for stray argument variables.
411 for oVarInfo in dVars.values():
412 if oVarInfo.isArg():
413 self.raiseProblem('Unused argument variable: %s' % (oVarInfo.oStmt.sVarName,));
414
415 elif oStmt.sName in ('IEM_MC_MEM_COMMIT_AND_UNMAP_RW', 'IEM_MC_MEM_COMMIT_AND_UNMAP_RO',
416 'IEM_MC_MEM_COMMIT_AND_UNMAP_WO', 'IEM_MC_MEM_ROLLBACK_AND_UNMAP_WO',
417 'IEM_MC_MEM_COMMIT_AND_UNMAP_ATOMIC',
418 'IEM_MC_MEM_COMMIT_AND_UNMAP_FOR_FPU_STORE_WO'):
419 #
420 # The unmap info variable passed to IEM_MC_MEM_COMMIT_AND_UNMAP_RW
421 # and friends is implictly freed and we must make sure it wasn't
422 # used any later. IEM_MC_MEM_COMMIT_AND_UNMAP_FOR_FPU_STORE_WO takes
423 # an additional a_u16FSW argument, which receives the same treatement.
424 #
425 for sParam in oStmt.asParams:
426 implicitFree(oStmt, dFreedVars, dVars, sParam);
427
428 elif oStmt.sName in ('IEM_MC_PUSH_U16', 'IEM_MC_PUSH_U32', 'IEM_MC_PUSH_U32_SREG', 'IEM_MC_PUSH_U64',
429 'IEM_MC_FLAT32_PUSH_U16', 'IEM_MC_FLAT32_PUSH_U32', 'IEM_MC_FLAT32_PUSH_U32_SREG',
430 'IEM_MC_FLAT64_PUSH_U16', 'IEM_MC_FLAT64_PUSH_U64',):
431 #
432 # The variable being pushed is implicitly freed.
433 #
434 for sParam in oStmt.asParams:
435 implicitFree(oStmt, dFreedVars, dVars, sParam);
436 else:
437 #
438 # Scan all the parameters of generic statements.
439 #
440 for sParam in oStmt.asParams:
441 if sParam in dVars:
442 freeVariable(aoStmts, iStmt, dVars[sParam], dFreedVars, dVars);
443
444 #
445 # Free anything left from asVarsInScope that's now going out of scope.
446 #
447 if iDepth > 0:
448 for sVarName in asVarsInScope:
449 if sVarName in dVars:
450 freeVariable(aoStmts, len(aoStmts) - 1, dVars[sVarName], dFreedVars, dVars);
451 if sVarName in dFreedVars:
452 del dFreedVars[sVarName]; ## @todo Try eliminate this one...
453 return dFreedVars;
454
455 kdOptionArchToVal = {
456 'amd64': 'RT_ARCH_VAL_AMD64',
457 'arm64': 'RT_ARCH_VAL_ARM64',
458 };
459
460 def __morphStatements(self, aoStmts, fForLiveness):
461 """
462 Morphs the given statement list into something more suitable for
463 native recompilation.
464
465 The following is currently done here:
466 - Amend IEM_MC_BEGIN with all the IEM_CIMPL_F_XXX and IEM_MC_F_XXX
467 flags found and derived, including IEM_MC_F_WITHOUT_FLAGS which
468 we determine here.
469 - Insert IEM_MC_FREE_LOCAL when after the last statment a local
470 variable is last used.
471
472 Returns a new list of statements.
473 """
474 _ = fForLiveness;
475
476 #
477 # We can skip IEM_MC_DEFER_TO_CIMPL_x_RET stuff.
478 #
479 if self.oVariation.oParent.oMcBlock.fDeferToCImpl:
480 return aoStmts;
481
482 #
483 # We make a shallow copy of the list, and only make deep copies of the
484 # statements we modify.
485 #
486 aoStmts = list(aoStmts) # type: list(iai.McStmt)
487
488 #
489 # First, amend the IEM_MC_BEGIN statment, adding all the flags found
490 # to it so the native recompiler can correctly process ARG and CALL
491 # statements (among other things).
492 #
493 # Also add IEM_MC_F_WITHOUT_FLAGS if this isn't a variation with eflags
494 # checking and clearing while there are such variations for this
495 # function (this sounds a bit backwards, but has to be done this way
496 # for the use we make of the flags in CIMPL calls).
497 #
498 # Second, eliminate IEM_MC_NATIVE_IF statements.
499 #
500 iConvArgToLocal = 0;
501 cStmts = len(aoStmts);
502 iStmt = 0;
503 while iStmt < cStmts:
504 oStmt = aoStmts[iStmt];
505 if oStmt.sName == 'IEM_MC_BEGIN':
506 fWithoutFlags = ( self.oVariation.isWithFlagsCheckingAndClearingVariation()
507 and self.oVariation.oParent.hasWithFlagsCheckingAndClearingVariation());
508 if fWithoutFlags or self.oVariation.oParent.dsCImplFlags:
509 oNewStmt = copy.deepcopy(oStmt);
510 if fWithoutFlags:
511 oNewStmt.asParams[2] = ' | '.join(sorted( list(self.oVariation.oParent.oMcBlock.dsMcFlags.keys())
512 + ['IEM_MC_F_WITHOUT_FLAGS',] ));
513 if self.oVariation.oParent.dsCImplFlags:
514 oNewStmt.asParams[3] = ' | '.join(sorted(self.oVariation.oParent.dsCImplFlags.keys()));
515 aoStmts[iStmt] = oNewStmt;
516 elif isinstance(oStmt, iai.McStmtNativeIf):
517 if self.kdOptionArchToVal[self.sHostArch] in oStmt.asArchitectures:
518 iConvArgToLocal += 1;
519 oBranch = oStmt.aoIfBranch;
520 else:
521 iConvArgToLocal = -999;
522 oBranch = oStmt.aoElseBranch;
523 aoStmts = aoStmts[:iStmt] + oBranch + aoStmts[iStmt+1:];
524 cStmts = len(aoStmts);
525 continue;
526
527 iStmt += 1;
528
529 #
530 # If we encountered a IEM_MC_NATIVE_IF and took the native branch,
531 # ASSUME that all ARG variables can be converted to LOCAL variables
532 # because no calls will be made.
533 #
534 if iConvArgToLocal > 0:
535 for iStmt, oStmt in enumerate(aoStmts):
536 if isinstance(oStmt, iai.McStmtArg):
537 if oStmt.sName == 'IEM_MC_ARG':
538 aoStmts[iStmt] = iai.McStmtVar('IEM_MC_LOCAL', oStmt.asParams[:2],
539 oStmt.sType, oStmt.sVarName);
540 elif oStmt.sName == 'IEM_MC_ARG_CONST':
541 aoStmts[iStmt] = iai.McStmtVar('IEM_MC_LOCAL_CONST', oStmt.asParams[:3],
542 oStmt.sType, oStmt.sVarName, oStmt.sValue);
543 else:
544 self.raiseProblem('Unexpected argument declaration when emitting native code: %s (%s)'
545 % (oStmt.sName, oStmt.asParams,));
546 assert(oStmt.sRefType == 'none');
547
548 #
549 # Do a simple liveness analysis of the variable and insert
550 # IEM_MC_FREE_LOCAL statements after the last statements using each
551 # variable. We do this recursively to best handle conditionals and
552 # scoping related to those.
553 #
554 self.__analyzeVariableLiveness(aoStmts, {});
555
556 return aoStmts;
557
558
559 def renderCode(self, cchIndent, fForLiveness = False):
560 """
561 Returns the native recompiler function body for this threaded variant.
562 """
563 return iai.McStmt.renderCodeForList(self.__morphStatements(self.oVariation.aoStmtsForThreadedFunction, fForLiveness),
564 cchIndent);
565
566 @staticmethod
567 def checkStatements(aoStmts, sHostArch):
568 """
569 Checks that all the given statements are supported by the native recompiler.
570 Returns dictionary with the unsupported statments.
571 """
572 dRet = {};
573 _ = sHostArch;
574 for oStmt in aoStmts: # type: McStmt
575 if not oStmt.isCppStmt():
576 aInfo = iai.g_dMcStmtParsers.get(oStmt.sName);
577 if not aInfo:
578 aInfo = g_dMcStmtThreaded.get(oStmt.sName);
579 if not aInfo:
580 raise Exception('Unknown statement: %s' % (oStmt.sName, ));
581 if aInfo[3] is False:
582 dRet[oStmt.sName] = 1;
583 elif aInfo[3] is not True:
584 if isinstance(aInfo[3], str):
585 if aInfo[3] != sHostArch:
586 dRet[oStmt.sName] = 1;
587 elif sHostArch not in aInfo[3]:
588 dRet[oStmt.sName] = 1;
589 #elif not self.fDecode:
590
591 if isinstance(oStmt, iai.McStmtCond):
592 dRet.update(NativeRecompFunctionVariation.checkStatements(oStmt.aoIfBranch, sHostArch));
593 dRet.update(NativeRecompFunctionVariation.checkStatements(oStmt.aoElseBranch, sHostArch));
594
595 return dRet;
596
597
598## Statistics: Number of MC blocks (value) depending on each unsupported statement (key).
599g_dUnsupportedMcStmtStats = {}
600
601## Statistics: List of variations (value) that is only missing this one statement (key).
602g_dUnsupportedMcStmtLastOneStats = {}
603
604### Statistics: List of variations (value) with aimpl_[^0] calls that is only missing this one statement (key).
605#g_dUnsupportedMcStmtLastOneAImplStats = {}
606
607
608def analyzeVariantForNativeRecomp(oVariation,
609 sHostArch): # type: (ThreadedFunctionVariation, str) -> NativeRecompFunctionVariation
610 """
611 This function analyzes the threaded function variant and returns an
612 NativeRecompFunctionVariation instance for it, unless it's not
613 possible to recompile at present.
614
615 Returns NativeRecompFunctionVariation or the number of unsupported MCs.
616 """
617
618 #
619 # Analyze the statements.
620 #
621 aoStmts = oVariation.aoStmtsForThreadedFunction # type: list(McStmt)
622 dUnsupportedStmts = NativeRecompFunctionVariation.checkStatements(aoStmts, sHostArch);
623 if not dUnsupportedStmts:
624 return NativeRecompFunctionVariation(oVariation, sHostArch);
625
626 #
627 # Update the statistics.
628 #
629 for sStmt in dUnsupportedStmts:
630 g_dUnsupportedMcStmtStats[sStmt] = 1 + g_dUnsupportedMcStmtStats.get(sStmt, 0);
631
632 if len(dUnsupportedStmts) == 1:
633 for sStmt in dUnsupportedStmts:
634 if sStmt in g_dUnsupportedMcStmtLastOneStats:
635 g_dUnsupportedMcStmtLastOneStats[sStmt].append(oVariation);
636 else:
637 g_dUnsupportedMcStmtLastOneStats[sStmt] = [oVariation,];
638
639 #if ( len(dUnsupportedStmts) in (1,2)
640 # and iai.McStmt.findStmtByNames(aoStmts,
641 # { 'IEM_MC_CALL_AIMPL_3': 1,
642 # 'IEM_MC_CALL_AIMPL_4': 1,
643 # #'IEM_MC_CALL_VOID_AIMPL_0': 1, - can't test results... ?
644 # 'IEM_MC_CALL_VOID_AIMPL_1': 1,
645 # 'IEM_MC_CALL_VOID_AIMPL_2': 1,
646 # 'IEM_MC_CALL_VOID_AIMPL_3': 1,
647 # 'IEM_MC_CALL_VOID_AIMPL_4': 1,
648 # #'IEM_MC_CALL_FPU_AIMPL_1': 1,
649 # #'IEM_MC_CALL_FPU_AIMPL_2': 1,
650 # #'IEM_MC_CALL_FPU_AIMPL_3': 1,
651 # #'IEM_MC_CALL_MMX_AIMPL_2': 1,
652 # #'IEM_MC_CALL_MMX_AIMPL_3': 1,
653 # #'IEM_MC_CALL_SSE_AIMPL_2': 1,
654 # #'IEM_MC_CALL_SSE_AIMPL_3': 1,
655 # #'IEM_MC_CALL_AVX_AIMPL_2': 1,
656 # #'IEM_MC_CALL_AVX_AIMPL_3': 1,
657 # #'IEM_MC_CALL_AVX_AIMPL_4': 1,
658 # })):
659 # for sStmt in dUnsupportedStmts:
660 # if sStmt in g_dUnsupportedMcStmtLastOneAImplStats:
661 # g_dUnsupportedMcStmtLastOneAImplStats[sStmt].append(oVariation);
662 # else:
663 # g_dUnsupportedMcStmtLastOneAImplStats[sStmt] = [oVariation,];
664
665 return None;
666
667
668def analyzeThreadedFunctionsForNativeRecomp(aoThreadedFuncs, sHostArch): # type (list(ThreadedFunction)) -> True
669 """
670 Displays statistics.
671 """
672 print('todo:', file = sys.stderr);
673 cTotal = 0;
674 cNative = 0;
675 for oThreadedFunction in aoThreadedFuncs:
676 cNativeVariations = 0;
677 for oVariation in oThreadedFunction.aoVariations:
678 cTotal += 1;
679 oVariation.oNativeRecomp = analyzeVariantForNativeRecomp(oVariation, sHostArch);
680 if oVariation.oNativeRecomp and oVariation.oNativeRecomp.isRecompilable():
681 cNativeVariations += 1;
682 cNative += cNativeVariations;
683
684 # If all variations can be recompiled natively, annotate the threaded
685 # function name accordingly so it'll be easy to spot in the stats.
686 if oThreadedFunction.sSubName:
687 if cNativeVariations == len(oThreadedFunction.aoVariations):
688 aoStmts = oThreadedFunction.oMcBlock.decode();
689 oStmt = iai.McStmt.findStmtByNames(aoStmts, {'IEM_MC_NATIVE_IF': True,});
690 if oStmt and NativeRecompFunctionVariation.kdOptionArchToVal[sHostArch] in oStmt.asArchitectures:
691 oThreadedFunction.sSubName += '_ne'; # native emit
692 elif oThreadedFunction.sSubName.find('aimpl') >= 0:
693 oThreadedFunction.sSubName += '_na'; # native aimpl
694 else:
695 oThreadedFunction.sSubName += '_nn'; # native native
696 elif cNativeVariations == 0:
697 oThreadedFunction.sSubName += '_ntodo'; # native threaded todo
698 else:
699 oThreadedFunction.sSubName += '_nm'; # native mixed
700
701
702 print('todo: %.1f%% / %u out of %u threaded function variations are recompilable'
703 % (cNative * 100.0 / cTotal, cNative, cTotal), file = sys.stderr);
704 if g_dUnsupportedMcStmtLastOneStats:
705 asTopKeys = sorted(g_dUnsupportedMcStmtLastOneStats, reverse = True,
706 key = lambda sSortKey: len(g_dUnsupportedMcStmtLastOneStats[sSortKey]))[:16];
707 print('todo:', file = sys.stderr);
708 print('todo: Top %s variations with one unsupported statement dependency:' % (len(asTopKeys),),
709 file = sys.stderr);
710 cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
711 for sKey in asTopKeys:
712 print('todo: %*s = %s (%s%s)'
713 % (cchMaxKey, sKey, len(g_dUnsupportedMcStmtLastOneStats[sKey]),
714 ', '.join([oVar.getShortName() for oVar in g_dUnsupportedMcStmtLastOneStats[sKey][:5]]),
715 ',...' if len(g_dUnsupportedMcStmtLastOneStats[sKey]) >= 5 else '', )
716 , file = sys.stderr);
717
718 asTopKeys = sorted(g_dUnsupportedMcStmtStats, reverse = True,
719 key = lambda sSortKey: g_dUnsupportedMcStmtStats[sSortKey])[:16];
720 print('todo:', file = sys.stderr);
721 print('todo: Top %d most used unimplemented statements:' % (len(asTopKeys),), file = sys.stderr);
722 cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
723 for i in range(0, len(asTopKeys), 2):
724 print('todo: %*s = %4d %*s = %4d'
725 % ( cchMaxKey, asTopKeys[i], g_dUnsupportedMcStmtStats[asTopKeys[i]],
726 cchMaxKey, asTopKeys[i + 1], g_dUnsupportedMcStmtStats[asTopKeys[i + 1]],),
727 file = sys.stderr);
728 print('todo:', file = sys.stderr);
729
730 #if g_dUnsupportedMcStmtLastOneAImplStats:
731 # asTopKeys = sorted(g_dUnsupportedMcStmtLastOneAImplStats, reverse = True,
732 # key = lambda sSortKey: len(g_dUnsupportedMcStmtLastOneAImplStats[sSortKey]))[:16];
733 # print('todo:', file = sys.stderr);
734 # print('todo: Top %s variations with AIMPL call and 1-2 unsupported statement dependencies:' % (len(asTopKeys),),
735 # file = sys.stderr);
736 # cchMaxKey = max([len(sKey) for sKey in asTopKeys]);
737 # for sKey in asTopKeys:
738 # print('todo: %*s = %s (%s%s)'
739 # % (cchMaxKey, sKey, len(g_dUnsupportedMcStmtLastOneAImplStats[sKey]),
740 # ', '.join([oVar.getShortName() for oVar in g_dUnsupportedMcStmtLastOneAImplStats[sKey][:5]]),
741 # ',...' if len(g_dUnsupportedMcStmtLastOneAImplStats[sKey]) >= 5 else '', )
742 # , file = sys.stderr);
743
744 return True;
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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