|
9 | 9 | _RE_NEVER_MATCH=re.compile(r"(?!)") |
10 | 10 | # Dictionary mapping branch instructions to their inverted branch instructions. |
11 | 11 | # If a branch cannot be inverted, the value is None: |
12 | | -_X86_BRANCHES= { |
| 12 | +_X86_BRANCH_NAMES= { |
13 | 13 | # https://www.felixcloutier.com/x86/jcc |
14 | 14 | "ja":"jna", |
15 | 15 | "jae":"jnae", |
|
37 | 37 | "loopz":None, |
38 | 38 | } |
39 | 39 | # Update with all of the inverted branches, too: |
40 | | -_X86_BRANCHES|= {v:kfork,vin_X86_BRANCHES.items()ifv} |
| 40 | +_X86_BRANCH_NAMES|= {v:kfork,vin_X86_BRANCH_NAMES.items()ifv} |
| 41 | +# No custom relocations needed |
| 42 | +_X86_BRANCHES:dict[str,tuple[str|None,str|None]]= { |
| 43 | +k: (v,None)fork,vin_X86_BRANCH_NAMES.items() |
| 44 | +} |
41 | 45 |
|
42 | 46 | _AARCH64_COND_CODES= { |
43 | 47 | # https://developer.arm.com/documentation/dui0801/b/CJAJIHAD?lang=en |
|
58 | 62 | "hi":"ls", |
59 | 63 | "ls":"hi", |
60 | 64 | } |
| 65 | +# MyPy doesn't understand that a invariant variable can be initialized by a covariant value |
| 66 | +CUSTOM_AARCH64_BRANCH19:str|None="CUSTOM_AARCH64_BRANCH19" |
| 67 | + |
61 | 68 | # Branches are either b.{cond} or bc.{cond} |
62 | | -_AARCH64_BRANCHES= { |
63 | | -"b."+cond: ("b."+inverseifinverseelseNone) |
| 69 | +_AARCH64_BRANCHES:dict[str,tuple[str|None,str|None]]= { |
| 70 | +"b."+cond: (("b."+inverseifinverseelseNone),CUSTOM_AARCH64_BRANCH19) |
64 | 71 | for (cond,inverse)in_AARCH64_COND_CODES.items() |
65 | 72 | }| { |
66 | | -"bc."+cond: ("bc."+inverseifinverseelseNone) |
| 73 | +"bc."+cond: (("bc."+inverseifinverseelseNone),CUSTOM_AARCH64_BRANCH19) |
67 | 74 | for (cond,inverse)in_AARCH64_COND_CODES.items() |
68 | 75 | } |
69 | 76 |
|
@@ -113,7 +120,8 @@ class Optimizer: |
113 | 120 | r'\s*(?P<label>[\w."$?@]+):' |
114 | 121 | ) |
115 | 122 | # Override everything that follows in subclasses: |
116 | | -_branches:typing.ClassVar[dict[str,str|None]]= {} |
| 123 | +_supports_external_relocations=True |
| 124 | +_branches:typing.ClassVar[dict[str,tuple[str|None,str|None]]]= {} |
117 | 125 | # Two groups (instruction and target): |
118 | 126 | _re_branch:typing.ClassVar[re.Pattern[str]]=_RE_NEVER_MATCH |
119 | 127 | # One group (target): |
@@ -170,7 +178,10 @@ def _preprocess(self, text: str) -> str: |
170 | 178 | def_invert_branch(cls,line:str,target:str)->str|None: |
171 | 179 | match=cls._re_branch.match(line) |
172 | 180 | assertmatch |
173 | | -inverted=cls._branches.get(match["instruction"]) |
| 181 | +inverted_reloc=cls._branches.get(match["instruction"]) |
| 182 | +ifinverted_relocisNone: |
| 183 | +returnNone |
| 184 | +inverted=inverted_reloc[0] |
174 | 185 | ifnotinverted: |
175 | 186 | returnNone |
176 | 187 | (a,b), (c,d)=match.span("instruction"),match.span("target") |
@@ -302,27 +313,45 @@ def _remove_redundant_jumps(self) -> None: |
302 | 313 | block.fallthrough=True |
303 | 314 | block.instructions.pop() |
304 | 315 |
|
| 316 | +def_fixup_external_labels(self)->None: |
| 317 | +ifself._supports_external_relocations: |
| 318 | +# Nothing to fix up |
| 319 | +return |
| 320 | +forblockinself._blocks(): |
| 321 | +ifblock.targetandblock.fallthrough: |
| 322 | +branch=block.instructions[-1] |
| 323 | +match=self._re_branch.match(branch) |
| 324 | +assertmatchisnotNone |
| 325 | +target=match["target"] |
| 326 | +reloc=self._branches[match["instruction"]][1] |
| 327 | +ifrelocisnotNoneandnottarget.startswith(self.label_prefix): |
| 328 | +name=target[len(self.symbol_prefix) :] |
| 329 | +block.instructions[-1]= ( |
| 330 | +f"// target='{target}' prefix='{self.label_prefix}'" |
| 331 | + ) |
| 332 | +block.instructions.append( |
| 333 | +f"{self.symbol_prefix}{reloc}_JIT_RELOCATION_{name}:" |
| 334 | + ) |
| 335 | +a,b=match.span("target") |
| 336 | +branch="".join([branch[:a],"0",branch[b:]]) |
| 337 | +block.instructions.append(branch) |
| 338 | + |
305 | 339 | defrun(self)->None: |
306 | 340 | """Run this optimizer.""" |
307 | 341 | self._insert_continue_label() |
308 | 342 | self._mark_hot_blocks() |
309 | 343 | self._invert_hot_branches() |
310 | 344 | self._remove_redundant_jumps() |
| 345 | +self._fixup_external_labels() |
311 | 346 | self.path.write_text(self._body()) |
312 | 347 |
|
313 | 348 |
|
314 | | -# Mach-O does not support the 19 bit branch locations needed for branch reordering |
315 | | -classOptimizerAArch64_MachO(Optimizer):# pylint: disable = too-few-public-methods |
316 | | -"""aarch64-apple-darwin""" |
317 | | - |
318 | | -# https://developer.arm.com/documentation/ddi0602/2025-03/Base-Instructions/B--Branch- |
319 | | -_re_jump=re.compile(r"\s*b\s+(?P<target>[\w.]+)") |
320 | | - |
321 | | - |
322 | 349 | classOptimizerAArch64(Optimizer):# pylint: disable = too-few-public-methods |
323 | | -"""aarch64-pc-windows-msvc/aarch64-unknown-linux-gnu""" |
| 350 | +"""aarch64-pc-windows-msvc/aarch64-apple-darwin/aarch64-unknown-linux-gnu""" |
324 | 351 |
|
325 | 352 | _branches=_AARCH64_BRANCHES |
| 353 | +# Mach-O does not support the 19 bit branch locations needed for branch reordering |
| 354 | +_supports_external_relocations=False |
326 | 355 | _re_branch=re.compile( |
327 | 356 | rf"\s*(?P<instruction>{'|'.join(_AARCH64_BRANCHES)})\s+(.+,\s+)*(?P<target>[\w.]+)" |
328 | 357 | ) |
|