Skip to content

Commit a322ad4

Browse files
committed
Cleanup
1 parent 7a6d819 commit a322ad4

File tree

5 files changed

+166
-204
lines changed

5 files changed

+166
-204
lines changed

Lib/test/test_jit_stencils.py

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,67 @@
1-
21
import pathlib
32
import shlex
43
import sys
54
import sysconfig
65
import tempfile
76
import test.support
8-
import unittest
9-
107
import test.support.script_helper
11-
8+
import unittest
129

1310
_CPYTHON = pathlib.Path(test.support.REPO_ROOT).resolve()
1411
_TOOLS_JIT = _CPYTHON / "Tools" / "jit"
1512
_TOOLS_JIT_TEST = _TOOLS_JIT / "test"
13+
_TOOLS_JIT_TEST_TEST_EXECUTOR_CASES_C_H = _TOOLS_JIT_TEST / "test_executor_cases.c.h"
1614
_TOOLS_JIT_BUILD_PY = _TOOLS_JIT / "build.py"
1715

18-
@unittest.skipIf(test.support.Py_DEBUG, "XXX")
19-
@unittest.skipUnless(sys._jit.is_available(), "XXX")
20-
@unittest.skipIf(test.support.Py_GIL_DISABLED, "XXX")
21-
@unittest.skipUnless(sysconfig.is_python_build(), "XXX")
16+
17+
@test.support.cpython_only
18+
@unittest.skipIf(test.support.Py_DEBUG, "Debug stencils aren't tested.")
19+
@unittest.skipIf(test.support.Py_GIL_DISABLED, "Free-threaded stencils aren't tested.")
20+
@unittest.skipUnless(sysconfig.is_python_build(), "Requires a local Python build.")
2221
class TestJITStencils(unittest.TestCase):
2322

23+
def _build_jit_stencils(self, target: str) -> str:
24+
with tempfile.TemporaryDirectory() as work:
25+
jit_stencils_h = pathlib.Path(work, f"jit_stencils-{target}.h").resolve()
26+
pyconfig_h = pathlib.Path(sysconfig.get_config_h_filename()).resolve()
27+
result, args = test.support.script_helper.run_python_until_end(
28+
_TOOLS_JIT_BUILD_PY,
29+
"--input-file", _TOOLS_JIT_TEST_TEST_EXECUTOR_CASES_C_H,
30+
"--output-dir", jit_stencils_h.parent,
31+
"--pyconfig-dir", pyconfig_h.parent,
32+
target,
33+
__isolated=False,
34+
)
35+
if result.rc:
36+
self.skipTest(f"Build failed: {shlex.join(map(str, args))}")
37+
body = jit_stencils_h.read_text()
38+
# Strip out two lines of header comments:
39+
_, _, body = body.split("\n", 2)
40+
return body
41+
42+
def _check_jit_stencils(
43+
self, expected: str, actual: str, test_jit_stencils_h: pathlib.Path
44+
) -> None:
45+
try:
46+
self.assertEqual(expected.strip("\n"), actual.strip("\n"))
47+
except AssertionError as e:
48+
# Make it easy to re-validate the expected output:
49+
relative = test_jit_stencils_h.relative_to(_CPYTHON)
50+
message = f"If this is expected, replace {relative} with:"
51+
banner = "=" * len(message)
52+
e.add_note("\n".join([banner, message, banner]))
53+
e.add_note(actual)
54+
raise
55+
2456
def test_jit_stencils(self):
2557
self.maxDiff = None
2658
found = False
27-
pyconfig_dir = pathlib.Path(sysconfig.get_config_h_filename()).parent
28-
with tempfile.TemporaryDirectory() as work:
29-
output_dir = pathlib.Path(work).resolve()
30-
for test_jit_stencils_h in sorted(_TOOLS_JIT_TEST.glob("test_jit_stencils-*.h")):
31-
target = test_jit_stencils_h.stem.removeprefix("test_jit_stencils-")
32-
jit_stencils_h = output_dir / f"jit_stencils-{target}.h"
33-
with self.subTest(target):
34-
# relative = jit_stencils_h.relative_to(_CPYTHON)
35-
result, args = test.support.script_helper.run_python_until_end(
36-
_TOOLS_JIT_BUILD_PY,
37-
"--input-file", _TOOLS_JIT_TEST / "test_executor_cases.c.h",
38-
"--output-dir", output_dir,
39-
"--pyconfig-dir", pyconfig_dir,
40-
target,
41-
__isolated=False
42-
)
43-
if result.rc:
44-
self.skipTest(shlex.join(map(str, args)))
45-
found = True
46-
expected = test_jit_stencils_h.read_text()
47-
actual = "".join(jit_stencils_h.read_text().splitlines(True)[3:])
48-
self.assertEqual(expected, actual)
49-
self.assertTrue(found, "No JIT stencil tests run!")
59+
for test_jit_stencils_h in _TOOLS_JIT_TEST.glob("test_jit_stencils-*.h"):
60+
target = test_jit_stencils_h.stem.removeprefix("test_jit_stencils-")
61+
with self.subTest(target):
62+
expected = test_jit_stencils_h.read_text()
63+
actual = self._build_jit_stencils(target)
64+
found = True
65+
self._check_jit_stencils(expected, actual, test_jit_stencils_h)
66+
# This is a local build. If the JIT is available, at least one test should run:
67+
assert found or not sys._jit.is_available(), "No JIT stencils built!"

Tools/jit/_targets.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,36 +566,43 @@ def get_target(host: str) -> _COFF32 | _COFF64 | _ELF | _MachO:
566566
optimizer: type[_optimizers.Optimizer]
567567
target: _COFF32 | _COFF64 | _ELF | _MachO
568568
if re.fullmatch(r"aarch64-apple-darwin.*", host):
569+
host = "aarch64-apple-darwin"
569570
condition = "defined(__aarch64__) && defined(__APPLE__)"
570571
optimizer = _optimizers.OptimizerAArch64
571572
target = _MachO(host, condition, optimizer=optimizer)
572573
elif re.fullmatch(r"aarch64-pc-windows-msvc", host):
574+
host = "aarch64-pc-windows-msvc"
573575
args = ["-fms-runtime-lib=dll", "-fplt"]
574576
condition = "defined(_M_ARM64)"
575577
optimizer = _optimizers.OptimizerAArch64
576578
target = _COFF64(host, condition, args=args, optimizer=optimizer)
577579
elif re.fullmatch(r"aarch64-.*-linux-gnu", host):
580+
host = "aarch64-unknown-linux-gnu"
578581
# -mno-outline-atomics: Keep intrinsics from being emitted.
579582
args = ["-fpic", "-mno-outline-atomics"]
580583
condition = "defined(__aarch64__) && defined(__linux__)"
581584
optimizer = _optimizers.OptimizerAArch64
582585
target = _ELF(host, condition, args=args, optimizer=optimizer)
583586
elif re.fullmatch(r"i686-pc-windows-msvc", host):
587+
host = "i686-pc-windows-msvc"
584588
# -Wno-ignored-attributes: __attribute__((preserve_none)) is not supported here.
585589
args = ["-DPy_NO_ENABLE_SHARED", "-Wno-ignored-attributes"]
586590
optimizer = _optimizers.OptimizerX86
587591
condition = "defined(_M_IX86)"
588592
target = _COFF32(host, condition, args=args, optimizer=optimizer)
589593
elif re.fullmatch(r"x86_64-apple-darwin.*", host):
594+
host = "x86_64-apple-darwin"
590595
condition = "defined(__x86_64__) && defined(__APPLE__)"
591596
optimizer = _optimizers.OptimizerX86
592597
target = _MachO(host, condition, optimizer=optimizer)
593598
elif re.fullmatch(r"x86_64-pc-windows-msvc", host):
599+
host = "x86_64-pc-windows-msvc"
594600
args = ["-fms-runtime-lib=dll"]
595601
condition = "defined(_M_X64)"
596602
optimizer = _optimizers.OptimizerX86
597603
target = _COFF64(host, condition, args=args, optimizer=optimizer)
598604
elif re.fullmatch(r"x86_64-.*-linux-gnu", host):
605+
host = "x86_64-unknown-linux-gnu"
599606
args = ["-fno-pic", "-mcmodel=medium", "-mlarge-data-threshold=0"]
600607
condition = "defined(__x86_64__) && defined(__linux__)"
601608
optimizer = _optimizers.OptimizerX86

Tools/jit/test/test_executor_cases.c.h

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
case 0: {
2+
// Zero-length jumps should be removed:
23
break;
34
}
45

56
case 1: {
6-
if (CURRENT_OPARG()) {
7-
JUMP_TO_JUMP_TARGET();
7+
// -Os duplicates less code than -O3:
8+
PyAPI_DATA(bool) sausage;
9+
PyAPI_DATA(bool) spammed;
10+
PyAPI_FUNC(void) order_eggs_and_bacon(void);
11+
PyAPI_FUNC(void) order_eggs_sausage_and_bacon(void);
12+
if (!sausage) {
13+
order_eggs_and_bacon();
814
}
15+
else {
16+
order_eggs_sausage_and_bacon();
17+
}
18+
spammed = false;
919
break;
1020
}
1121

1222
case 2: {
13-
if (CURRENT_OPARG()) {
23+
// The assembly optimizer inverts hot branches:
24+
PyAPI_DATA(bool) spam;
25+
if (spam) {
1426
JUMP_TO_ERROR();
1527
}
1628
break;
1729
}
18-
19-
case 3: {
20-
GOTO_TIER_ONE((void *)CURRENT_OPERAND0() + CURRENT_TARGET());
21-
break;
22-
}
23-
24-
case 4: {
25-
GOTO_TIER_TWO((void *)CURRENT_OPERAND1());
26-
break;
27-
}

Tools/jit/test/test_jit_stencils-aarch64-unknown-linux-gnu.h

Lines changed: 60 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -61,109 +61,81 @@ emit_1(
6161
const _PyUOpInstruction *instruction, jit_state *state)
6262
{
6363
// 0000000000000000 <_JIT_ENTRY>:
64-
// 0: 90000008 adrp x8, 0x0 <_JIT_ENTRY>
65-
// 0000000000000000: R_AARCH64_ADR_GOT_PAGE _JIT_OPARG
66-
// 4: f9400108 ldr x8, [x8]
67-
// 0000000000000004: R_AARCH64_LD64_GOT_LO12_NC _JIT_OPARG
68-
// 8: 72003d1f tst w8, #0xffff
69-
// c: 54000040 b.eq 0x14 <_JIT_ENTRY+0x14>
70-
// 10: 14000000 b 0x10 <_JIT_ENTRY+0x10>
71-
// 0000000000000010: R_AARCH64_JUMP26 _JIT_JUMP_TARGET
72-
const unsigned char code_body[20] = {
64+
// 0: a9bf7bfd stp x29, x30, [sp, #-0x10]!
65+
// 4: 90000008 adrp x8, 0x0 <_JIT_ENTRY>
66+
// 0000000000000004: R_AARCH64_ADR_GOT_PAGE sausage
67+
// 8: 910003fd mov x29, sp
68+
// c: f9400108 ldr x8, [x8]
69+
// 000000000000000c: R_AARCH64_LD64_GOT_LO12_NC sausage
70+
// 10: 39400108 ldrb w8, [x8]
71+
// 14: 36000088 tbz w8, #0x0, 0x24 <_JIT_ENTRY+0x24>
72+
// 18: 90000008 adrp x8, 0x0 <_JIT_ENTRY>
73+
// 0000000000000018: R_AARCH64_ADR_GOT_PAGE order_eggs_sausage_and_bacon
74+
// 1c: f9400108 ldr x8, [x8]
75+
// 000000000000001c: R_AARCH64_LD64_GOT_LO12_NC order_eggs_sausage_and_bacon
76+
// 20: 14000003 b 0x2c <_JIT_ENTRY+0x2c>
77+
// 24: 90000008 adrp x8, 0x0 <_JIT_ENTRY>
78+
// 0000000000000024: R_AARCH64_ADR_GOT_PAGE order_eggs_and_bacon
79+
// 28: f9400108 ldr x8, [x8]
80+
// 0000000000000028: R_AARCH64_LD64_GOT_LO12_NC order_eggs_and_bacon
81+
// 2c: d63f0100 blr x8
82+
// 30: 90000008 adrp x8, 0x0 <_JIT_ENTRY>
83+
// 0000000000000030: R_AARCH64_ADR_GOT_PAGE spammed
84+
// 34: f9400108 ldr x8, [x8]
85+
// 0000000000000034: R_AARCH64_LD64_GOT_LO12_NC spammed
86+
// 38: 3900011f strb wzr, [x8]
87+
// 3c: a8c17bfd ldp x29, x30, [sp], #0x10
88+
const unsigned char code_body[64] = {
89+
0xfd, 0x7b, 0xbf, 0xa9, 0x08, 0x00, 0x00, 0x90,
90+
0xfd, 0x03, 0x00, 0x91, 0x08, 0x01, 0x40, 0xf9,
91+
0x08, 0x01, 0x40, 0x39, 0x88, 0x00, 0x00, 0x36,
7392
0x08, 0x00, 0x00, 0x90, 0x08, 0x01, 0x40, 0xf9,
74-
0x1f, 0x3d, 0x00, 0x72, 0x40, 0x00, 0x00, 0x54,
75-
0x00, 0x00, 0x00, 0x14,
76-
};
77-
// 0: OPARG
78-
patch_64(data + 0x0, instruction->oparg);
79-
memcpy(code, code_body, sizeof(code_body));
80-
patch_aarch64_33rx(code + 0x0, (uintptr_t)data);
81-
patch_aarch64_26r(code + 0x10, state->instruction_starts[instruction->jump_target]);
82-
}
83-
84-
void
85-
emit_2(
86-
unsigned char *code, unsigned char *data, _PyExecutorObject *executor,
87-
const _PyUOpInstruction *instruction, jit_state *state)
88-
{
89-
// 0000000000000000 <_JIT_ENTRY>:
90-
// 0: 90000008 adrp x8, 0x0 <_JIT_ENTRY>
91-
// 0000000000000000: R_AARCH64_ADR_GOT_PAGE _JIT_OPARG
92-
// 4: f9400108 ldr x8, [x8]
93-
// 0000000000000004: R_AARCH64_LD64_GOT_LO12_NC _JIT_OPARG
94-
// 8: 72003d1f tst w8, #0xffff
95-
// c: 54000040 b.eq 0x14 <_JIT_ENTRY+0x14>
96-
// 10: 14000000 b 0x10 <_JIT_ENTRY+0x10>
97-
// 0000000000000010: R_AARCH64_JUMP26 _JIT_ERROR_TARGET
98-
const unsigned char code_body[20] = {
93+
0x03, 0x00, 0x00, 0x14, 0x08, 0x00, 0x00, 0x90,
94+
0x08, 0x01, 0x40, 0xf9, 0x00, 0x01, 0x3f, 0xd6,
9995
0x08, 0x00, 0x00, 0x90, 0x08, 0x01, 0x40, 0xf9,
100-
0x1f, 0x3d, 0x00, 0x72, 0x40, 0x00, 0x00, 0x54,
101-
0x00, 0x00, 0x00, 0x14,
96+
0x1f, 0x01, 0x00, 0x39, 0xfd, 0x7b, 0xc1, 0xa8,
10297
};
103-
// 0: OPARG
104-
patch_64(data + 0x0, instruction->oparg);
98+
// 0: &sausage+0x0
99+
// 8: &order_eggs_sausage_and_bacon+0x0
100+
// 10: &order_eggs_and_bacon+0x0
101+
// 18: &spammed+0x0
102+
patch_64(data + 0x0, (uintptr_t)&sausage);
103+
patch_64(data + 0x8, (uintptr_t)&order_eggs_sausage_and_bacon);
104+
patch_64(data + 0x10, (uintptr_t)&order_eggs_and_bacon);
105+
patch_64(data + 0x18, (uintptr_t)&spammed);
105106
memcpy(code, code_body, sizeof(code_body));
106-
patch_aarch64_33rx(code + 0x0, (uintptr_t)data);
107-
patch_aarch64_26r(code + 0x10, state->instruction_starts[instruction->error_target]);
107+
patch_aarch64_21rx(code + 0x4, (uintptr_t)data);
108+
patch_aarch64_12x(code + 0xc, (uintptr_t)data);
109+
patch_aarch64_33rx(code + 0x18, (uintptr_t)data + 0x8);
110+
patch_aarch64_33rx(code + 0x24, (uintptr_t)data + 0x10);
111+
patch_aarch64_33rx(code + 0x30, (uintptr_t)data + 0x18);
108112
}
109113

110114
void
111-
emit_3(
112-
unsigned char *code, unsigned char *data, _PyExecutorObject *executor,
113-
const _PyUOpInstruction *instruction, jit_state *state)
114-
{
115-
// 0000000000000000 <_JIT_ENTRY>:
116-
// 0: 90000008 adrp x8, 0x0 <_JIT_ENTRY>
117-
// 0000000000000000: R_AARCH64_ADR_GOT_PAGE _JIT_TARGET
118-
// 4: 90000009 adrp x9, 0x0 <_JIT_ENTRY>
119-
// 0000000000000004: R_AARCH64_ADR_GOT_PAGE _JIT_OPERAND0
120-
// 8: f9400108 ldr x8, [x8]
121-
// 0000000000000008: R_AARCH64_LD64_GOT_LO12_NC _JIT_TARGET
122-
// c: f9400129 ldr x9, [x9]
123-
// 000000000000000c: R_AARCH64_LD64_GOT_LO12_NC _JIT_OPERAND0
124-
// 10: f9008adf str xzr, [x22, #0x110]
125-
// 14: f9002295 str x21, [x20, #0x40]
126-
// 18: 8b284120 add x0, x9, w8, uxtw
127-
// 1c: d65f03c0 ret
128-
const unsigned char code_body[32] = {
129-
0x08, 0x00, 0x00, 0x90, 0x09, 0x00, 0x00, 0x90,
130-
0x08, 0x01, 0x40, 0xf9, 0x29, 0x01, 0x40, 0xf9,
131-
0xdf, 0x8a, 0x00, 0xf9, 0x95, 0x22, 0x00, 0xf9,
132-
0x20, 0x41, 0x28, 0x8b, 0xc0, 0x03, 0x5f, 0xd6,
133-
};
134-
// 0: TARGET
135-
// 8: OPERAND0
136-
patch_64(data + 0x0, instruction->target);
137-
patch_64(data + 0x8, instruction->operand0);
138-
memcpy(code, code_body, sizeof(code_body));
139-
patch_aarch64_21rx(code + 0x0, (uintptr_t)data);
140-
patch_aarch64_21rx(code + 0x4, (uintptr_t)data + 0x8);
141-
patch_aarch64_12x(code + 0x8, (uintptr_t)data);
142-
patch_aarch64_12x(code + 0xc, (uintptr_t)data + 0x8);
143-
}
144-
145-
void
146-
emit_4(
115+
emit_2(
147116
unsigned char *code, unsigned char *data, _PyExecutorObject *executor,
148117
const _PyUOpInstruction *instruction, jit_state *state)
149118
{
150119
// 0000000000000000 <_JIT_ENTRY>:
151120
// 0: 90000008 adrp x8, 0x0 <_JIT_ENTRY>
152-
// 0000000000000000: R_AARCH64_ADR_GOT_PAGE _JIT_OPERAND1
121+
// 0000000000000000: R_AARCH64_ADR_GOT_PAGE spam
153122
// 4: f9400108 ldr x8, [x8]
154-
// 0000000000000004: R_AARCH64_LD64_GOT_LO12_NC _JIT_OPERAND1
155-
// 8: f9403d00 ldr x0, [x8, #0x78]
156-
// c: f9008ac8 str x8, [x22, #0x110]
157-
// 10: d61f0000 br x0
158-
const unsigned char code_body[20] = {
123+
// 0000000000000004: R_AARCH64_LD64_GOT_LO12_NC spam
124+
// 8: 39400108 ldrb w8, [x8]
125+
// c: 7100051f cmp w8, #0x1
126+
// 10: 54000041 b.ne 0x18 <_JIT_ENTRY+0x18>
127+
// 14: 14000000 b 0x14 <_JIT_ENTRY+0x14>
128+
// 0000000000000014: R_AARCH64_JUMP26 _JIT_ERROR_TARGET
129+
const unsigned char code_body[24] = {
159130
0x08, 0x00, 0x00, 0x90, 0x08, 0x01, 0x40, 0xf9,
160-
0x00, 0x3d, 0x40, 0xf9, 0xc8, 0x8a, 0x00, 0xf9,
161-
0x00, 0x00, 0x1f, 0xd6,
131+
0x08, 0x01, 0x40, 0x39, 0x1f, 0x05, 0x00, 0x71,
132+
0x41, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x14,
162133
};
163-
// 0: OPERAND1
164-
patch_64(data + 0x0, instruction->operand1);
134+
// 0: &spam+0x0
135+
patch_64(data + 0x0, (uintptr_t)&spam);
165136
memcpy(code, code_body, sizeof(code_body));
166137
patch_aarch64_33rx(code + 0x0, (uintptr_t)data);
138+
patch_aarch64_26r(code + 0x14, state->instruction_starts[instruction->error_target]);
167139
}
168140

169141
static_assert(SYMBOL_MASK_WORDS >= 1, "SYMBOL_MASK_WORDS too small");
@@ -181,10 +153,8 @@ static const StencilGroup shim = {emit_shim, 104, 0, {0}};
181153

182154
static const StencilGroup stencil_groups[MAX_UOP_ID + 1] = {
183155
[0] = {emit_0, 0, 0, {0}},
184-
[1] = {emit_1, 20, 8, {0}},
185-
[2] = {emit_2, 20, 8, {0}},
186-
[3] = {emit_3, 32, 16, {0}},
187-
[4] = {emit_4, 20, 8, {0}},
156+
[1] = {emit_1, 64, 32, {0}},
157+
[2] = {emit_2, 24, 8, {0}},
188158
};
189159

190160
static const void * const symbols_map[1] = {

0 commit comments

Comments
 (0)