VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IEMAllThreadedPython.py@ 98881

Last change on this file since 98881 was 98881, checked in by vboxsync, 22 months ago

VMM/IEM: scm fixes. bugref:10369

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 14.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllThreadedPython.py 98881 2023-03-09 01:25:44Z vboxsync $
4# pylint: disable=invalid-name
5
6"""
7Annotates and generates threaded functions from IEMAllInstructions*.cpp.h.
8"""
9
10from __future__ import print_function;
11
12__copyright__ = \
13"""
14Copyright (C) 2023 Oracle and/or its affiliates.
15
16This file is part of VirtualBox base platform packages, as
17available from https://www.virtualbox.org.
18
19This program is free software; you can redistribute it and/or
20modify it under the terms of the GNU General Public License
21as published by the Free Software Foundation, in version 3 of the
22License.
23
24This program is distributed in the hope that it will be useful, but
25WITHOUT ANY WARRANTY; without even the implied warranty of
26MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27General Public License for more details.
28
29You should have received a copy of the GNU General Public License
30along with this program; if not, see <https://www.gnu.org/licenses>.
31
32SPDX-License-Identifier: GPL-3.0-only
33"""
34__version__ = "$Revision: 98881 $"
35
36# Standard python imports.
37import datetime;
38import os;
39import sys;
40import argparse;
41
42import IEMAllInstructionsPython as iai;
43
44
45# Python 3 hacks:
46if sys.version_info[0] >= 3:
47 long = int; # pylint: disable=redefined-builtin,invalid-name
48
49
50class LocalVar(object):
51 """
52 A IEM_MC_LOCAL* variable.
53 """
54
55 def __init__(self, sName, sType, sConstValue = None):
56 self.sName = sName;
57 self.sType = sType;
58 self.sConstValue = sConstValue; ##< None if not const, otherwise the const value.
59
60class CallArg(LocalVar):
61 """
62 A IEM_MC_ARG* variable.
63 """
64
65 def __init__(self, sName, sType, iArg, sConstValue = None, oRefLocal = None):
66 LocalVar.__init__(sName, sType, sConstValue);
67 self.iArg = iArg;
68 self.oRefLocal = oRefLocal;
69
70
71class ThreadedFunction(object):
72 """
73 A threaded function.
74 """
75
76 def __init__(self, oMcBlock):
77 self.oMcBlock = oMcBlock # type: IEMAllInstructionsPython.McBlock
78 ### Dictionary of local variables (IEM_MC_LOCAL[_CONST]) and call arguments (IEM_MC_ARG*).
79 #self.dVariables = {} # type: dict(str,LocalVar)
80 ###
81 #self.aoParams = [] # type:
82
83 @staticmethod
84 def dummyInstance():
85 """ Gets a dummy instance. """
86 return ThreadedFunction(iai.McBlock('null', 999999999, 999999999, 'nil', 999999999));
87
88 def getIndexName(self):
89 sName = self.oMcBlock.sFunction;
90 if sName.startswith('iemOp_'):
91 sName = sName[len('iemOp_'):];
92 if self.oMcBlock.iInFunction == 0:
93 return 'kIemThreadedFunc_%s' % ( sName, );
94 return 'kIemThreadedFunc_%s_%s' % ( sName, self.oMcBlock.iInFunction, );
95
96 def analyze(self):
97 """
98 Analyzes the code, identifying the number of parameters it requires and such.
99 May raise exceptions if we cannot grok the code.
100 """
101
102 #
103 # First we decode it,
104 #
105 aoStmts = self.oMcBlock.decode();
106
107 return True;
108
109
110 def generateInputCode(self):
111 """
112 Modifies the input code.
113 """
114 assert len(self.oMcBlock.asLines) > 2, "asLines=%s" % (self.oMcBlock.asLines,);
115 return ''.join(self.oMcBlock.asLines);
116
117
118class IEMThreadedGenerator(object):
119 """
120 The threaded code generator & annotator.
121 """
122
123 def __init__(self):
124 self.aoThreadedFuncs = [] # type: list(ThreadedFunction)
125 self.oOptions = None # type: argparse.Namespace
126 self.aoParsers = [] # type: list(IEMAllInstructionsPython.SimpleParser)
127
128 #
129 # Processing.
130 #
131
132 def processInputFiles(self):
133 """
134 Process the input files.
135 """
136
137 # Parse the files.
138 self.aoParsers = iai.parseFiles(self.oOptions.asInFiles);
139
140 # Wrap MC blocks into threaded functions and analyze these.
141 self.aoThreadedFuncs = [ThreadedFunction(oMcBlock) for oMcBlock in iai.g_aoMcBlocks];
142 for oThreadedFunction in self.aoThreadedFuncs:
143 oThreadedFunction.analyze();
144
145 return True;
146
147 #
148 # Output
149 #
150
151 def generateLicenseHeader(self):
152 """
153 Returns the lines for a license header.
154 """
155 return [
156 '/*',
157 ' * Autogenerated by $Id: IEMAllThreadedPython.py 98881 2023-03-09 01:25:44Z vboxsync $ ',
158 ' * Do not edit!',
159 ' */',
160 '',
161 '/*',
162 ' * Copyright (C) 2023-' + str(datetime.date.today().year) + ' Oracle and/or its affiliates.',
163 ' *',
164 ' * This file is part of VirtualBox base platform packages, as',
165 ' * available from https://www.virtualbox.org.',
166 ' *',
167 ' * This program is free software; you can redistribute it and/or',
168 ' * modify it under the terms of the GNU General Public License',
169 ' * as published by the Free Software Foundation, in version 3 of the',
170 ' * License.',
171 ' *',
172 ' * This program is distributed in the hope that it will be useful, but',
173 ' * WITHOUT ANY WARRANTY; without even the implied warranty of',
174 ' * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU',
175 ' * General Public License for more details.',
176 ' *',
177 ' * You should have received a copy of the GNU General Public License',
178 ' * along with this program; if not, see <https://www.gnu.org/licenses>.',
179 ' *',
180 ' * The contents of this file may alternatively be used under the terms',
181 ' * of the Common Development and Distribution License Version 1.0',
182 ' * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included',
183 ' * in the VirtualBox distribution, in which case the provisions of the',
184 ' * CDDL are applicable instead of those of the GPL.',
185 ' *',
186 ' * You may elect to license modified versions of this file under the',
187 ' * terms and conditions of either the GPL or the CDDL or both.',
188 ' *',
189 ' * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0',
190 ' */',
191 '',
192 '',
193 '',
194 ];
195
196
197 def generateThreadedFunctionsHeader(self, oOut):
198 """
199 Generates the threaded functions header file.
200 Returns success indicator.
201 """
202
203 asLines = self.generateLicenseHeader();
204
205 # Generate the threaded function table indexes.
206 asLines += [
207 'typedef enum IEMTHREADEDFUNCS',
208 '{',
209 ' kIemThreadedFunc_Invalid = 0,',
210 ];
211 for oFunc in self.aoThreadedFuncs:
212 asLines.append(' ' + oFunc.getIndexName() + ',');
213 asLines += [
214 ' kIemThreadedFunc_End',
215 '} IEMTHREADEDFUNCS;',
216 '',
217 ];
218
219 # Prototype the function table.
220 asLines += [
221 'extern const PFNRT g_apfnIemThreadedFunctions[kIemThreadedFunc_End];',
222 ];
223
224 oOut.write('\n'.join(asLines));
225 return True;
226
227 def generateThreadedFunctionsSource(self, oOut):
228 """
229 Generates the threaded functions source file.
230 Returns success indicator.
231 """
232
233 asLines = self.generateLicenseHeader();
234
235 oOut.write('\n'.join(asLines));
236 return True;
237
238 def getThreadedFunctionByIndex(self, idx):
239 """
240 Returns a ThreadedFunction object for the given index. If the index is
241 out of bounds, a dummy is returned.
242 """
243 if idx < len(self.aoThreadedFuncs):
244 return self.aoThreadedFuncs[idx];
245 return ThreadedFunction.dummyInstance();
246
247 def findEndOfMcEndStmt(self, sLine, offEndStmt):
248 """
249 Helper that returns the line offset following the 'IEM_MC_END();'.
250 """
251 assert sLine[offEndStmt:].startswith('IEM_MC_END');
252 off = sLine.find(';', offEndStmt + len('IEM_MC_END'));
253 assert off > 0, 'sLine="%s"' % (sLine, );
254 return off + 1 if off > 0 else 99999998;
255
256 def generateModifiedInput(self, oOut):
257 """
258 Generates the combined modified input source/header file.
259 Returns success indicator.
260 """
261 #
262 # File header.
263 #
264 oOut.write('\n'.join(self.generateLicenseHeader()));
265
266 #
267 # ASSUMING that g_aoMcBlocks/self.aoThreadedFuncs are in self.aoParsers
268 # order, we iterate aoThreadedFuncs in parallel to the lines from the
269 # parsers and apply modifications where required.
270 #
271 iThreadedFunction = 0;
272 oThreadedFunction = self.getThreadedFunctionByIndex(0);
273 for oParser in self.aoParsers: # IEMAllInstructionsPython.SimpleParser
274 oOut.write("\n\n/* ****** BEGIN %s ******* */\n" % (oParser.sSrcFile,));
275
276 iLine = 0;
277 while iLine < len(oParser.asLines):
278 sLine = oParser.asLines[iLine];
279 iLine += 1; # iBeginLine and iEndLine are 1-based.
280
281 # Can we pass it thru?
282 if ( iLine not in [oThreadedFunction.oMcBlock.iBeginLine, oThreadedFunction.oMcBlock.iEndLine]
283 or oThreadedFunction.oMcBlock.sSrcFile != oParser.sSrcFile):
284 oOut.write(sLine);
285 #
286 # Single MC block. Just extract it and insert the replacement.
287 #
288 elif oThreadedFunction.oMcBlock.iBeginLine != oThreadedFunction.oMcBlock.iEndLine:
289 assert sLine.count('IEM_MC_') == 1;
290 oOut.write(sLine[:oThreadedFunction.oMcBlock.offBeginLine]);
291 sModified = oThreadedFunction.generateInputCode().strip();
292 oOut.write(sModified);
293
294 iLine = oThreadedFunction.oMcBlock.iEndLine;
295 sLine = oParser.asLines[iLine - 1];
296 assert sLine.count('IEM_MC_') == 1;
297 oOut.write(sLine[self.findEndOfMcEndStmt(sLine, oThreadedFunction.oMcBlock.offEndLine) : ]);
298
299 # Advance
300 iThreadedFunction += 1;
301 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
302 #
303 # Macro expansion line that have sublines and may contain multiple MC blocks.
304 #
305 else:
306 offLine = 0;
307 while iLine == oThreadedFunction.oMcBlock.iBeginLine:
308 oOut.write(sLine[offLine : oThreadedFunction.oMcBlock.offBeginLine]);
309
310 sModified = oThreadedFunction.generateInputCode().strip();
311 assert sModified.startswith('IEM_MC_BEGIN'), 'sModified="%s"' % (sModified,);
312 oOut.write(sModified);
313
314 offLine = self.findEndOfMcEndStmt(sLine, oThreadedFunction.oMcBlock.offEndLine);
315
316 # Advance
317 iThreadedFunction += 1;
318 oThreadedFunction = self.getThreadedFunctionByIndex(iThreadedFunction);
319
320 # Last line segment.
321 if offLine < len(sLine):
322 oOut.write(sLine[offLine : ]);
323
324 oOut.write("/* ****** END %s ******* */\n" % (oParser.sSrcFile,));
325
326 return True;
327
328 #
329 # Main
330 #
331
332 def main(self, asArgs):
333 """
334 C-like main function.
335 Returns exit code.
336 """
337
338 #
339 # Parse arguments
340 #
341 sScriptDir = os.path.dirname(__file__);
342 oParser = argparse.ArgumentParser(add_help = False);
343 oParser.add_argument('asInFiles', metavar = 'input.cpp.h', nargs = '*',
344 default = [os.path.join(sScriptDir, asFM[0]) for asFM in iai.g_aasAllInstrFilesAndDefaultMap],
345 help = "Selection of VMMAll/IEMAllInstructions*.cpp.h files to use as input.");
346 oParser.add_argument('--out-funcs-hdr', metavar = 'file-funcs.h', dest = 'sOutFileFuncsHdr', action = 'store',
347 default = '-', help = 'The output header file for the functions.');
348 oParser.add_argument('--out-funcs-cpp', metavar = 'file-funcs.cpp', dest = 'sOutFileFuncsCpp', action = 'store',
349 default = '-', help = 'The output C++ file for the functions.');
350 oParser.add_argument('--out-mod-input', metavar = 'file-instr.cpp.h', dest = 'sOutFileModInput', action = 'store',
351 default = '-', help = 'The output C++/header file for the modified input instruction files.');
352 oParser.add_argument('--help', '-h', '-?', action = 'help', help = 'Display help and exit.');
353 oParser.add_argument('--version', '-V', action = 'version',
354 version = 'r%s (IEMAllThreadedPython.py), r%s (IEMAllInstructionsPython.py)'
355 % (__version__.split()[1], iai.__version__.split()[1],),
356 help = 'Displays the version/revision of the script and exit.');
357 self.oOptions = oParser.parse_args(asArgs[1:]);
358 print("oOptions=%s" % (self.oOptions,));
359
360 #
361 # Process the instructions specified in the IEM sources.
362 #
363 if self.processInputFiles():
364 #
365 # Generate the output files.
366 #
367 aaoOutputFiles = (
368 ( self.oOptions.sOutFileFuncsHdr, self.generateThreadedFunctionsHeader ),
369 ( self.oOptions.sOutFileFuncsCpp, self.generateThreadedFunctionsSource ),
370 ( self.oOptions.sOutFileModInput, self.generateModifiedInput ),
371 );
372 fRc = True;
373 for sOutFile, fnGenMethod in aaoOutputFiles:
374 if sOutFile == '-':
375 fRc = fnGenMethod(sys.stdout) and fRc;
376 else:
377 try:
378 oOut = open(sOutFile, 'w'); # pylint: disable=consider-using-with,unspecified-encoding
379 except Exception as oXcpt:
380 print('error! Failed open "%s" for writing: %s' % (sOutFile, oXcpt,), file = sys.stderr);
381 return 1;
382 fRc = fnGenMethod(oOut) and fRc;
383 oOut.close();
384 if fRc:
385 return 0;
386
387 return 1;
388
389
390if __name__ == '__main__':
391 sys.exit(IEMThreadedGenerator().main(sys.argv));
392
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