@@ -96,6 +96,8 @@ class InstructionKind(enum.Enum):
9696 LONG_BRANCH = enum .auto ()
9797 SHORT_BRANCH = enum .auto ()
9898 RETURN = enum .auto ()
99+ SMALL_CONST_1 = enum .auto ()
100+ SMALL_CONST_2 = enum .auto ()
99101 OTHER = enum .auto ()
100102
101103
@@ -172,6 +174,7 @@ class Optimizer:
172174 )
173175 # Override everything that follows in subclasses:
174176 _supports_external_relocations = True
177+ supports_small_constants = False
175178 _branches : typing .ClassVar [dict [str , tuple [str | None , str | None ]]] = {}
176179 # Short branches are instructions that can branch within a micro-op,
177180 # but might not have the reach to branch anywhere within a trace.
@@ -184,6 +187,9 @@ class Optimizer:
184187 _re_return : typing .ClassVar [re .Pattern [str ]] = _RE_NEVER_MATCH
185188 text : str = ""
186189 globals : set [str ] = dataclasses .field (default_factory = set )
190+ _re_small_const_1 = _RE_NEVER_MATCH
191+ _re_small_const_2 = _RE_NEVER_MATCH
192+ const_reloc = "<Not supported>"
187193
188194 def __post_init__ (self ) -> None :
189195 # Split the code into a linked list of basic blocks. A basic block is an
@@ -253,6 +259,14 @@ def _parse_instruction(self, line: str) -> Instruction:
253259 elif match := self ._re_return .match (line ):
254260 name = line
255261 kind = InstructionKind .RETURN
262+ elif match := self ._re_small_const_1 .match (line ):
263+ target = match ["value" ]
264+ name = match ["instruction" ]
265+ kind = InstructionKind .SMALL_CONST_1
266+ elif match := self ._re_small_const_2 .match (line ):
267+ target = match ["value" ]
268+ name = match ["instruction" ]
269+ kind = InstructionKind .SMALL_CONST_2
256270 else :
257271 name , * _ = line .split (" " )
258272 kind = InstructionKind .OTHER
@@ -385,7 +399,7 @@ def _remove_redundant_jumps(self) -> None:
385399 block .fallthrough = True
386400 block .instructions .pop ()
387401 # Before:
388- # br ? FOO:
402+ # branch FOO:
389403 # ...
390404 # FOO:
391405 # jump BAR
@@ -461,6 +475,70 @@ def _fixup_external_labels(self) -> None:
461475 )
462476 block .instructions .append (branch .update_target ("0" ))
463477
478+ def _make_temp_label (self , index : int ) -> Instruction :
479+ marker = f"jit_temp_{ index } :"
480+ return Instruction (InstructionKind .OTHER , "" , marker , None )
481+
482+ def _fixup_constants (self ) -> None :
483+ if not self .supports_small_constants :
484+ return
485+ index = 0
486+ for block in self ._blocks ():
487+ fixed : list [Instruction ] = []
488+ small_const_index = - 1
489+ for inst in block .instructions :
490+ if inst .kind == InstructionKind .SMALL_CONST_1 :
491+ marker = f"jit_pending_{ inst .target } { index } :"
492+ fixed .append (self ._make_temp_label (index ))
493+ index += 1
494+ small_const_index = len (fixed )
495+ fixed .append (inst )
496+ elif inst .kind == InstructionKind .SMALL_CONST_2 :
497+ if small_const_index < 0 :
498+ fixed .append (inst )
499+ continue
500+ small_const_1 = fixed [small_const_index ]
501+ if not self ._small_consts_match (small_const_1 , inst ):
502+ small_const_index = - 1
503+ fixed .append (inst )
504+ continue
505+ assert small_const_1 .target is not None
506+ if small_const_1 .target .endswith ("16" ):
507+ fixed [small_const_index ] = self ._make_temp_label (index )
508+ index += 1
509+ else :
510+ assert small_const_1 .target .endswith ("32" )
511+ patch_kind , replacement = self ._small_const_1 (small_const_1 )
512+ if replacement is not None :
513+ label = f"{ self .const_reloc } { patch_kind } _JIT_RELOCATION_CONST{ small_const_1 .target [:- 3 ]} _JIT_RELOCATION_{ index } :"
514+ index += 1
515+ fixed [small_const_index - 1 ] = Instruction (
516+ InstructionKind .OTHER , "" , label , None
517+ )
518+ fixed [small_const_index ] = replacement
519+ patch_kind , replacement = self ._small_const_2 (inst )
520+ if replacement is not None :
521+ assert inst .target is not None
522+ label = f"{ self .const_reloc } { patch_kind } _JIT_RELOCATION_CONST{ inst .target [:- 3 ]} _JIT_RELOCATION_{ index } :"
523+ index += 1
524+ fixed .append (
525+ Instruction (InstructionKind .OTHER , "" , label , None )
526+ )
527+ fixed .append (replacement )
528+ small_const_index = - 1
529+ else :
530+ fixed .append (inst )
531+ block .instructions = fixed
532+
533+ def _small_const_1 (self , inst : Instruction ) -> tuple [str , Instruction | None ]:
534+ raise NotImplementedError ()
535+
536+ def _small_const_2 (self , inst : Instruction ) -> tuple [str , Instruction | None ]:
537+ raise NotImplementedError ()
538+
539+ def _small_consts_match (self , inst1 : Instruction , inst2 : Instruction ) -> bool :
540+ raise NotImplementedError ()
541+
464542 def run (self ) -> None :
465543 """Run this optimizer."""
466544 self ._insert_continue_label ()
@@ -472,6 +550,7 @@ def run(self) -> None:
472550 self ._remove_redundant_jumps ()
473551 self ._remove_unreachable ()
474552 self ._fixup_external_labels ()
553+ self ._fixup_constants ()
475554 self .path .write_text (self ._body ())
476555
477556
@@ -492,6 +571,54 @@ class OptimizerAArch64(Optimizer): # pylint: disable = too-few-public-methods
492571 # https://developer.arm.com/documentation/ddi0602/2025-09/Base-Instructions/RET--Return-from-subroutine-
493572 _re_return = re .compile (r"\s*ret\b" )
494573
574+ supports_small_constants = True
575+ _re_small_const_1 = re .compile (
576+ r"\s*(?P<instruction>adrp)\s+.*(?P<value>_JIT_OP(ARG|ERAND(0|1))_(16|32)).*"
577+ )
578+ _re_small_const_2 = re .compile (
579+ r"\s*(?P<instruction>ldr)\s+.*(?P<value>_JIT_OP(ARG|ERAND(0|1))_(16|32)).*"
580+ )
581+ const_reloc = "CUSTOM_AARCH64_CONST"
582+
583+ def _get_reg (self , inst : Instruction ) -> str :
584+ _ , rest = inst .text .split (inst .name )
585+ reg , * _ = rest .split ("," )
586+ return reg .strip ()
587+
588+ def _small_const_1 (self , inst : Instruction ) -> tuple [str , Instruction | None ]:
589+ assert inst .kind is InstructionKind .SMALL_CONST_1
590+ assert inst .target is not None
591+ if "16" in inst .target :
592+ return "" , None
593+ pre , _ = inst .text .split (inst .name )
594+ return "16a" , Instruction (
595+ InstructionKind .OTHER , "movz" , f"{ pre } movz { self ._get_reg (inst )} , 0" , None
596+ )
597+
598+ def _small_const_2 (self , inst : Instruction ) -> tuple [str , Instruction | None ]:
599+ assert inst .kind is InstructionKind .SMALL_CONST_2
600+ assert inst .target is not None
601+ pre , _ = inst .text .split (inst .name )
602+ if "16" in inst .target :
603+ return "16a" , Instruction (
604+ InstructionKind .OTHER ,
605+ "movz" ,
606+ f"{ pre } movz { self ._get_reg (inst )} , 0" ,
607+ None ,
608+ )
609+ else :
610+ return "16b" , Instruction (
611+ InstructionKind .OTHER ,
612+ "movk" ,
613+ f"{ pre } movk { self ._get_reg (inst )} , 0, lsl #16" ,
614+ None ,
615+ )
616+
617+ def _small_consts_match (self , inst1 : Instruction , inst2 : Instruction ) -> bool :
618+ reg1 = self ._get_reg (inst1 )
619+ reg2 = self ._get_reg (inst2 )
620+ return reg1 == reg2
621+
495622
496623class OptimizerX86 (Optimizer ): # pylint: disable = too-few-public-methods
497624 """i686-pc-windows-msvc/x86_64-apple-darwin/x86_64-unknown-linux-gnu"""
0 commit comments