Skip to content

Commit 8b64dd8

Browse files
gh-139757: Treat call specially in JIT assembly backend optimizer on x86-64 and AArch64 (GH-142907)
Co-authored-by: Savannah Ostrowski <savannah@python.org>
1 parent 6e625f8 commit 8b64dd8

File tree

2 files changed

+19
-0
lines changed

2 files changed

+19
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix building JIT stencils on free-threaded builds.

Tools/jit/_optimizers.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class InstructionKind(enum.Enum):
9595
JUMP = enum.auto()
9696
LONG_BRANCH = enum.auto()
9797
SHORT_BRANCH = enum.auto()
98+
CALL = enum.auto()
9899
RETURN = enum.auto()
99100
SMALL_CONST_1 = enum.auto()
100101
SMALL_CONST_2 = enum.auto()
@@ -182,6 +183,8 @@ class Optimizer:
182183
# Two groups (instruction and target):
183184
_re_branch: typing.ClassVar[re.Pattern[str]] = _RE_NEVER_MATCH
184185
# One group (target):
186+
_re_call: typing.ClassVar[re.Pattern[str]] = _RE_NEVER_MATCH
187+
# One group (target):
185188
_re_jump: typing.ClassVar[re.Pattern[str]] = _RE_NEVER_MATCH
186189
# No groups:
187190
_re_return: typing.ClassVar[re.Pattern[str]] = _RE_NEVER_MATCH
@@ -225,6 +228,11 @@ def __post_init__(self) -> None:
225228
assert inst.target is not None
226229
block.target = self._lookup_label(inst.target)
227230
assert block.fallthrough
231+
elif inst.kind == InstructionKind.CALL:
232+
# A block ending in a call has a target and return point after call:
233+
assert inst.target is not None
234+
block.target = self._lookup_label(inst.target)
235+
assert block.fallthrough
228236
elif inst.kind == InstructionKind.JUMP:
229237
# A block ending in a jump has a target and no fallthrough:
230238
assert inst.target is not None
@@ -256,6 +264,10 @@ def _parse_instruction(self, line: str) -> Instruction:
256264
target = match["target"]
257265
name = line[: -len(target)].strip()
258266
kind = InstructionKind.JUMP
267+
elif match := self._re_call.match(line):
268+
target = match["target"]
269+
name = line[: -len(target)].strip()
270+
kind = InstructionKind.CALL
259271
elif match := self._re_return.match(line):
260272
name = line
261273
kind = InstructionKind.RETURN
@@ -463,6 +475,8 @@ def _fixup_external_labels(self) -> None:
463475
for index, block in enumerate(self._blocks()):
464476
if block.target and block.fallthrough:
465477
branch = block.instructions[-1]
478+
if branch.kind == InstructionKind.CALL:
479+
continue
466480
assert branch.is_branch()
467481
target = branch.target
468482
assert target is not None
@@ -566,6 +580,8 @@ class OptimizerAArch64(Optimizer): # pylint: disable = too-few-public-methods
566580
rf"\s*(?P<instruction>{'|'.join(_branch_patterns)})\s+(.+,\s+)*(?P<target>[\w.]+)"
567581
)
568582

583+
# https://developer.arm.com/documentation/ddi0406/b/Application-Level-Architecture/Instruction-Details/Alphabetical-list-of-instructions/BL--BLX--immediate-
584+
_re_call = re.compile(r"\s*blx?\s+(?P<target>[\w.]+)")
569585
# https://developer.arm.com/documentation/ddi0602/2025-03/Base-Instructions/B--Branch-
570586
_re_jump = re.compile(r"\s*b\s+(?P<target>[\w.]+)")
571587
# https://developer.arm.com/documentation/ddi0602/2025-09/Base-Instructions/RET--Return-from-subroutine-
@@ -628,6 +644,8 @@ class OptimizerX86(Optimizer): # pylint: disable = too-few-public-methods
628644
_re_branch = re.compile(
629645
rf"\s*(?P<instruction>{'|'.join(_X86_BRANCHES)})\s+(?P<target>[\w.]+)"
630646
)
647+
# https://www.felixcloutier.com/x86/call
648+
_re_call = re.compile(r"\s*callq?\s+(?P<target>[\w.]+)")
631649
# https://www.felixcloutier.com/x86/jmp
632650
_re_jump = re.compile(r"\s*jmp\s+(?P<target>[\w.]+)")
633651
# https://www.felixcloutier.com/x86/ret

0 commit comments

Comments
 (0)