1010# Dictionary mapping branch instructions to their inverted branch instructions.
1111# If a branch cannot be inverted, the value is None:
1212_X86_BRANCHES = {
13+ # https://www.felixcloutier.com/x86/jcc
1314 "ja" : "jna" ,
1415 "jae" : "jnae" ,
1516 "jb" : "jnb" ,
2526 "jo" : "jno" ,
2627 "jp" : "jnp" ,
2728 "jpe" : "jpo" ,
28- "jrxz " : None ,
29+ "jrcxz " : None ,
2930 "js" : "jns" ,
3031 "jz" : "jnz" ,
32+ # https://www.felixcloutier.com/x86/loop:loopcc
3133 "loop" : None ,
3234 "loope" : None ,
3335 "loopne" : None ,
4244class _Block :
4345 label : str | None = None
4446 # Non-instruction lines like labels, directives, and comments:
45- noise : list [str ] = dataclasses .field (default_factory = list )
47+ noninstructions : list [str ] = dataclasses .field (default_factory = list )
4648 # Instruction lines:
4749 instructions : list [str ] = dataclasses .field (default_factory = list )
4850 # If this block ends in a jump, where to?
@@ -74,7 +76,9 @@ class Optimizer:
7476 _root : _Block = dataclasses .field (init = False , default_factory = _Block )
7577 _labels : dict [str , _Block ] = dataclasses .field (init = False , default_factory = dict )
7678 # No groups:
77- _re_noise : typing .ClassVar [re .Pattern [str ]] = re .compile (r"\s*(?:\.|#|//|$)" )
79+ _re_noninstructions : typing .ClassVar [re .Pattern [str ]] = re .compile (
80+ r"\s*(?:\.|#|//|$)"
81+ )
7882 # One group (label):
7983 _re_label : typing .ClassVar [re .Pattern [str ]] = re .compile (
8084 r'\s*(?P<label>[\w."$?@]+):'
@@ -91,23 +95,23 @@ class Optimizer:
9195
9296 def __post_init__ (self ) -> None :
9397 # Split the code into a linked list of basic blocks. A basic block is an
94- # optional label, followed by zero or more non-instruction ("noise")
95- # lines, followed by zero or more instruction lines (only the last of
96- # which may be a branch, jump, or return):
98+ # optional label, followed by zero or more non-instruction lines,
99+ # followed by zero or more instruction lines (only the last of which may
100+ # be a branch, jump, or return):
97101 text = self ._preprocess (self .path .read_text ())
98102 block = self ._root
99103 for line in text .splitlines ():
100104 # See if we need to start a new block:
101105 if match := self ._re_label .match (line ):
102106 # Label. New block:
103107 block .link = block = self ._lookup_label (match ["label" ])
104- block .noise .append (line )
108+ block .noninstructions .append (line )
105109 continue
106- if self ._re_noise .match (line ):
110+ if self ._re_noninstructions .match (line ):
107111 if block .instructions :
108- # Noise lines. New block:
112+ # Non-instruction lines. New block:
109113 block .link = block = _Block ()
110- block .noise .append (line )
114+ block .noninstructions .append (line )
111115 continue
112116 if block .target or not block .fallthrough :
113117 # Current block ends with a branch, jump, or return. New block:
@@ -174,17 +178,15 @@ def _body(self) -> str:
174178 hot = block .hot
175179 # Make it easy to tell at a glance where cold code is:
176180 lines .append (f"# JIT: { 'HOT' if hot else 'COLD' } " .ljust (80 , "#" ))
177- lines .extend (block .noise )
181+ lines .extend (block .noninstructions )
178182 lines .extend (block .instructions )
179183 return "\n " .join (lines )
180184
181185 def _predecessors (self , block : _Block ) -> typing .Generator [_Block , None , None ]:
182186 # This is inefficient, but it's never wrong:
183- for predecessor in self ._blocks ():
184- if predecessor .target is block or (
185- predecessor .fallthrough and predecessor .link is block
186- ):
187- yield predecessor
187+ for pre in self ._blocks ():
188+ if pre .target is block or pre .fallthrough and pre .link is block :
189+ yield pre
188190
189191 def _insert_continue_label (self ) -> None :
190192 # Find the block with the last instruction:
@@ -199,10 +201,10 @@ def _insert_continue_label(self) -> None:
199201 # _JIT_CONTINUE:
200202 # This lets the assembler encode _JIT_CONTINUE jumps at build time!
201203 align = _Block ()
202- align .noise .append (f"\t .balign\t { self ._alignment } " )
204+ align .noninstructions .append (f"\t .balign\t { self ._alignment } " )
203205 continuation = self ._lookup_label (f"{ self .prefix } _JIT_CONTINUE" )
204206 assert continuation .label
205- continuation .noise .append (f"{ continuation .label } :" )
207+ continuation .noninstructions .append (f"{ continuation .label } :" )
206208 end .link , align .link , continuation .link = align , continuation , end .link
207209
208210 def _mark_hot_blocks (self ) -> None :
@@ -212,11 +214,7 @@ def _mark_hot_blocks(self) -> None:
212214 while todo :
213215 block = todo .pop ()
214216 block .hot = True
215- todo .extend (
216- predecessor
217- for predecessor in self ._predecessors (block )
218- if not predecessor .hot
219- )
217+ todo .extend (pre for pre in self ._predecessors (block ) if not pre .hot )
220218
221219 def _invert_hot_branches (self ) -> None :
222220 for branch in self ._blocks ():
0 commit comments