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